pengantar
Dalam cerita ini, saya akan menceritakan tentang petualangan seru yang menuntun saya untuk memecahkan teka-teki yang saya tanyakan pada diri sendiri. Solusinya adalah detail kecil dalam mekanisme pemuat aplikasi 32-bit di Windows 7 ke atas, dan proses penyelesaiannya adalah perjalanan panjang seorang pejuang yang mengikuti jalan hati.
Jika Anda datang ke halaman ini untuk mencari jawaban atas sebuah pertanyaan, maka tontonlah spoiler di bawah ini, karena konten utama mungkin menarik bagi mereka yang hanya mencoba memahami mekanisme SEH.
Seluruh masalahnya adalah saya menggunakan deskripsi yang salah tentang struktur dataDirectory yang diambil dari Wikipedia. Sebagai ganti bidang boundImport, sebenarnya ada bidang loadConfigTable , yang menunjuk ke struktur IMAGE_LOAD_CONFIG_DIRECTORY32. Struktur ini berisi bidang SEHandlerTable. Jika nol, maka / SAFESEH dinonaktifkan. Jika ini adalah penunjuk virtual ke tabel penangan aman, maka hanya penangan yang ditentukan dalam tabel yang akan berfungsi. Tabel adalah daftar offset relatif terhadap alamat virtual bagian .text. Jumlah penangan diatur di bidang SEHandlerCount.
Bagaimana semuanya dimulai
Berpikir tentang cara untuk melindungi program saya dari penyalinan, saya ingat artikel oleh Chris Kaspersky, di mana saya belajar tentang keberadaan teknik anti-debugging. Mencoba dengan sia-sia untuk menerapkan contoh yang dianalisis Chris dalam program saya, saya mengalami kebingungan di pihak Windows. Masalahnya adalah Windows menolak untuk menggunakan penangan pengecualian saya, menganggapnya "tidak aman".
Kurang lebih detail tentang SEH bisa saya petik dari artikel ini . Namun, bagaimanapun, sampai saya sendiri memeriksa mekanisme ini dengan kaca pembesar dan peralatan, saya memiliki gagasan yang sangat kabur tentang strukturnya. Saya melepaskan rantai penangan, mengatur breakpoints pada mereka, mengamati urutan eksekusi mereka, mempertimbangkan nilai pengembalian, dll.
Langsung ke intinya
( Microsoft Visual C++ )
int main()
{
__asm
{
mov eax, DWORD PTR SS : [0]
}
}
, eax 0.
, OllyDbg.
«access violation when reading 0x00000000».
, , 0 - 6 . Eip, ( ). 6 : 36 A1 00 00 00 00.
, __try, __except .. .
!
, - :
struct _EXCEPTION_RECORD* exceptionRecord,
void* establisherFrame,
struct _CONTEXT* contextRecord,
void* dispatcherContext
exceptionRecord – , , , contextRecord – ( Eip). - __cdecl, :
typedef enum _EXCEPTION_DISPOSITION
{
ExceptionContinueExecution,
ExceptionContinueSearch,
ExceptionNestedException,
ExceptionCollidedUnwind
} EXCEPTION_DISPOSITION;
:
EXCEPTION_DISPOSITION __cdecl ExceptionHanler(
struct _EXCEPTION_RECORD* exceptionRecord,
void* establisherFrame,
struct _CONTEXT* contextRecord,
void* dispatcherContext
)
{
contextRecord->Eip += 6;
MessageBoxA(0, "Exteption was handled", "Success!", 0);
return ExceptionContinueExecution;
}
Eip 6 , ! : ExceptionContinueExecution – . , Eip + 6 .
- . , . , , . - , : Next Handler. Next , ( , ). Handler -. TIB (thread information block), , fs:[0]. .
main:
int main()
{
__asm
{
push ExceptionHanler // -
push fs:[0] //
// , 2 :
//
mov fs:[0] , esp // ,
// fs:[0]
mov eax, DWORD PTR SS:[0] // 0
add esp, 8 // , 8 ( )
}
}
, - /SAFESEH , , - fs:[0]. , .
– 0 «» !
, . . /SAFESEH:NO.
, , :
«» . .
, -, , ? ? , … , , /SAFESEH, , , mov fs:[0], esp, -, , ? , /SAFESEH .
, - « ». , ? ? , , ? …
, …
, , crt0 ( main), ntdll.dll. , fs:[0]! , , ?
. , /SAFESEH, , , fs:[0] JMP ExceptionHandler ( ). ! ! , «»? , . .
entry point main EXE , /SAFESEH /SAFESEH:NO, , WinApi , . . , , . .
crt0 -. , ! push main, ret. , main, ret «» main main , crt0! ( JMP, )
, ! , : EXE, , , .
, PE ? - LoaderFlags? … , rdata. rdata , , ? , …
, - , . ! , , , -, , . , . , rdata , importTable, debug boundImport. , /SAFESEH! dataDirectories . , , - , /SAFESEH , « EXE ».
, «» , EXE . - . , 2 , , , . , , , ( 3-) .
, «» , mov eax, DWORD PTR SS : [0] play. . play.
! ntdll.dll.
. 0x1341d20 rdata 0x1be0, , EBX – 0x1000. , imageBase + 0x1000 ! - . 0x1be0, 0x2080 0x2351 . ! !
0x1341d20 0x1be0 0x1000 … !
! Windows, . ntdll.dll, !
, .
, . , - , – 3, .
- -.
! , /SAFESEH , /SAFESEH:NO!
, ?
… - , … Total Commander?!
, PE ? boundImport. Microsoft PE .
… , Microsoft boundImport. - -? ?
, .. , except… .. , .sxdata - . . sxdata? . boundImport, - -.
... , , pdata . , ? , boundImport, , .
... The Load Configuration Structure. ! , IMAGE_LOAD_CONFIG_DIRECTORY - , SEH.
, -. , , boundImport IMAGE_LOAD_CONFIG_DIRECTORY32 . ! , .
Itu saja, seluruh rahasianya adalah bahwa boundImport di header PE (diuraikan menurut tabel dari Wikipedia) menunjuk ke struktur IMAGE_LOAD_CONFIG_DIRECTORY32. Struktur ini berisi bidang yang secara drastis akan mengubah cara kerja program! Sekarang kita dapat dengan percaya diri membuat tabel handler kita sendiri dan menambahkan hanya apa yang kita anggap perlu untuk itu!
Mungkin di suatu tempat di kedalaman dokumentasi ada informasi bahwa boundImport sudah disebut salah di platform saya? Atau informasi bahwa pengangkatannya telah berubah? Mungkin boundImport dikecualikan atau digeser?