Hack The Planet

๋ฐ˜๊ฐ‘์Šต๋‹ˆ๋‹ค, cyalume์˜ ๋ธ”๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.

pwn/study note

์•ˆํ‹ฐ ๋ฆฌ๋ฒ„์‹ฑ ํ•ต์‹ฌ์›๋ฆฌ

cyalume 2024. 10. 27. 23:20

Table of Contents

 

Dynamic Anti-Reversing

    1. Exception

    2. Software Breakpoint Detection

    3. Hardware Breakpoint Detection

    4. Timing Check

    5. Single Step Execution Detection

    6. Patching Detection

    7. Anti-Disassembly

    8. PE Image Switching

    9. Self-Execution

   10. Self-Debugging

   11. Nanomite

   12. Code Obfuscation

   13. Encryption/Decryption

   14. Stolen Bytes

   15. Multi-Threaded Packers

   16. Code Virtualization

   17. API Redirection

   18. API Wrapping

 

Static Anti-Reversing

    1. PEB

    2. TEB

    3. Static Anti-Debugging with Native API (NT)

    7. TLS Callback Function

    8. Static Anti-Debugging with Normal API (WinAPI)

 

Attacking Debugger

    1. NtSetInformationThread()

    2. BlockInput()

    3. Disable Breakpoint

    4. UnhandledExceptionFilter()

    5. Exploit Debugger with Format String Bug

    6. ??

 

Dynamic Anti-Reversing Techniques


1. Using Exceptions

๋””๋ฒ„๊น… ์ค‘ ๋””๋ฒ„๊ธฐ์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋””๋ฒ„๊ฑฐ๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค. ๋””๋ฒ„๊ธฐ์— ์ •์˜๋œ Exception Handler๊ฐ€ ์žˆ์–ด๋„ ๋ง์ด๋‹ค. ์ด ํŠน์„ฑ์„ ์ด์šฉํ•˜์—ฌ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ , ์ด๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฃผ์ฒด๋ฅผ ์‹๋ณ„ํ•˜์—ฌ anti-debugging ๊ธฐ๋ฒ•์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฃผ๋กœ SEH Chain์„ ์ด์šฉํ•˜๊ฑฐ๋‚˜, kernel32.dll์˜ `SetUnhandledExceptionFilter()` ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ฃผ์ฒด๋ฅผ ๋“ฑ๋กํ•œ๋‹ค. 

1) SEH (Structured Exception Handler)

SEH๋Š” `_EXCEPTION_REGISTRATION_RECORD` ๊ตฌ์กฐ์ฒด์˜ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋กœ ๊ตฌ์„ฑ๋˜๋ฉฐ, ์ด๋Š” ์Šคํƒ์— ์ €์žฅ๋œ๋‹ค. (๋”ฐ๋ผ์„œ ๋ฒ”์œ„ ์ข…์†์ ์ด๋‹ค. -> ์•ฝ๊ฐ„์˜ ํ™•์ธ ํ•„์š”, ๋ฒ”์œ„๋ฅผ ๋„˜์–ด๊ฐ€ SEH top ์š”์†Œ๊ฐ€ ๋ฎ์–ด์“ฐ์ด๋ฉด fs:\[0]์€ ์–ด๋–ป๊ฒŒ ๋˜๋Š”๊ฐ€?) ์ด๋ฅผ ๊ฐ€๋ฆฌ์ผœ SEH Chain์ด๋ผ ์นญํ•œ๋‹ค. ์ฒซ ์š”์†Œ๋ถ€ํ„ฐ ๋งˆ์ง€๋ง‰ ์š”์†Œ๊นŒ์ง€, ์˜ˆ์™ธ๊ฐ€ ์ฒ˜๋ฆฌ๋  ๋•Œ๊นŒ์ง€ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.

 

(1) `_EXCEPTION_REGISTRATION_RECORD` ๊ตฌ์กฐ์ฒด

`_EXCEPTION_REGISTRASTION_RECORD` ๊ตฌ์กฐ์ฒด์˜ ์ •์˜๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

typedef struct _EXCEPTION_REGISTRATION_RECORD{
PEXCEPTION_REGISTRATION_RECORD Next;
PEXCEPTION_DISPOSITION Handler;
} EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD;


`Next` ๋ฉค๋ฒ„๋Š” ์Šคํƒ์— ์žˆ๋Š” ๋‹ค์Œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์ด ๊ฐ’์ด 0xFFFFFFFF์ด๋ผ๋ฉด ์ด ๋…ธ๋“œ๊ฐ€ SEH Chain์˜ ๋งˆ์ง€๋ง‰ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ๋ผ๋Š” ๊ฒƒ์„ ๋œปํ•œ๋‹ค.

`Handler` ๋ฉค๋ฒ„๋Š” ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์— ์‚ฌ์šฉ๋  ํ•จ์ˆ˜์˜ ์ฃผ์†Œ๋ฅผ ์ €์žฅํ•œ๋‹ค. `Handler`๋Š” ์‹œ์Šคํ…œ์— ์˜ํ•ด ํ˜ธ์ถœ๋˜๋Š” callback ํ•จ์ˆ˜๋กœ, ์ •์˜๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
(a) `Handler` calllback function
func `_except_handler()` (winnt.h)

EXCEPTION_DISPOSITION _except_handler(
EXCEPTION_RECORD *pRecord,
EXCEPTION_REGISTRATION_RECORD *pFrame,
CONTEXT *pContext,
PVOID DispatcherContext // ์‹œ์Šคํ…œ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ’. ์‹ ๊ฒฝ ์“ธ ํ•„์š” x
)


์ด ํ•จ์ˆ˜๋Š” SEH Chain์˜ ์ผ๋ถ€๋กœ, ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์กด์žฌํ•œ๋‹ค. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ(`handler`)๊ฐ€ ์„ธ ๋ฒˆ์งธ ์ธ์ž `CONTEXT` ๊ตฌ์กฐ์ฒด์˜ ์‹œ์ž‘์ ์œผ๋กœ๋ถ€ํ„ฐ 0xB8๋งŒํผ ๋–จ์–ด์ง„ `Eip` ๋ฉค๋ฒ„๋ฅผ ์ ์ ˆํžˆ ๋ณ€๊ฒฝํ•จ์œผ๋กœ์จ ์˜ˆ์™ธ ๋ฐœ์ƒ ์ง€์ ์œผ๋กœ๋ถ€ํ„ฐ ์‹คํ–‰ ํ๋ฆ„์„ ์˜ฎ๊ธฐ๋Š” ๋ฐฉ์‹์œผ๋กœ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. (bytecode์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ๊นŠ๋‹ค๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ `pRecord->ExceptionAddress`์˜ Opcode๋ฅผ ์ ์ ˆํžˆ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ๋„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค. -> ์ด๊ฑฐ ์žฌ๋ฏธ์žˆ์–ด ๋ณด์ด๋Š”๋ฐ ๊ตฌํ˜„ ใ„ฑใ„ฑ)

์•„๋ž˜๋Š” `CONTEXT.Eip`๋ฅผ 2๋งŒํผ ์ฆ๊ฐ€์‹œ์ผœ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฐ„๋‹จํ•œ `handler`์˜ ์ฝ”๋“œ์ด๋‹ค.

mov eax, dword ptr ss:[esp + 0x04] 
// pContext์˜ ์ฃผ์†Œ ์˜ฎ๊น€. [esp] = pValue, [esp+8] = pFrame, [esp+C] = pRecord
mov ecx, dword ptr ds:[eax + 0xB8] // pContext.Eip ๊ฐ’์„ eax์— ์˜ฎ๊น€
add ecx, 2
mov dword ptr ds:[eax+0xB8], ecx
xor eax, eax
retn 4 // handler์˜ ์ธ์ž๊ฐ€ 4๊ฐœ์ด๋ฏ€๋กœ, ์ด๋ฅผ ๋ชจ๋‘ ์ •๋ฆฌํ•œ ๋’ค return.
// ์•„๋งˆ __stdcall, win32์—์„œ๋Š” ๊ฐ€๋ณ€์ธ์žํ•จ์ˆ˜๋ฅผ ์ œ์™ธํ•œ ๋ชจ๋“  ํ•จ์ˆ˜๋Š” __stdcall ์‚ฌ์šฉ


(a-1) `Handler`'s 1st param: `_EXCEPTION_RECORD *` (winnt.h)

typedef struct _EXCEPTION_RECORD { 
DWORD ExceptionCode; // ์‹œ์Šคํ…œ์ด exception์— ํ• ๋‹นํ•œ ์ˆซ์ž
DWORD ExceptionFlags; //
struct _EXCEPTION_RECORD *ExceptionRecord; 
PVOID ExceptionAddress; // exception์ด ๋ฐœ์ƒํ•œ ์ฃผ์†Œ
DWORD NumberParameters; 
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; 
} EXCEPTION_RECORD;

 

[Microsoft: EXCEPTION_RECORD structure (winnt.h)](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record)

 

`ExceptionCode`๋Š” ์˜ˆ์™ธ ๋ฒˆํ˜ธ์ธ๋ฐ, winnt.h์—์„œ `#define STATUS_` ๋ฅผ ๊ฒ€์ƒ‰ํ•ด ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค. ๋” ๋งŽ์€ exception code๋Š” Windows NT DDK์˜ ntstatus.h์—์„œ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ๋‹ค.

`ExceptionFlags`๋Š” winnt.h์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜๋˜์–ด ์žˆ๋‹ค.

#define EXCEPTION_NONCONTINUABLE 0x1    // Noncontinuable exception
#define EXCEPTION_UNWINDING 0x2         // Unwind is in progress
#define EXCEPTION_EXIT_UNWIND 0x4       // Exit unwind is in progress
#define EXCEPTION_STACK_INVALID 0x8     // Stack out of limits or unaligned
#define EXCEPTION_NESTED_CALL 0x10      // Nested exception handler call
#define EXCEPTION_TARGET_UNWIND 0x20    // Target unwind in progress
#define EXCEPTION_COLLIDED_UNWIND 0x40  // Collided exception handler call



(a-2) `Handler`'s 2nd param: `EXCEPTION_REGISTRATION_RECORD *` (winnt.h)
์ด ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” establisher frame structure๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. ์ด๋Š” ํ˜ธ์ถœ๋œ SEH handler๊ฐ€ ์†ํ•œ `_EXCEPTION_REGISTRATION_RECORD` ๊ตฌ์กฐ์ฒด์˜ ์‹œ์ž‘ ์ฃผ์†Œ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. (`*pFrame` = `Next`์— ์ €์žฅ๋œ ๊ฐ’, `**pFrame` = ๋‹ค์Œ SEH ๋…ธ๋“œ์˜ Next์— ์ €์žฅ๋œ ์ฃผ์†Œ)

์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์ด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

// x86 debug, VS19
#include <Windows.h>
#include <stdio.h>

EXCEPTION_DISPOSITION 
_cdecl
handler(
EXCEPTION_RECORD* pRecord,
EXCEPTION_REGISTRATION_RECORD* pFrame,
CONTEXT* pContext,
PVOID pValue
) {
MessageBox(NULL,
L"Exception Occurred",
L"Exception Handler 1",
MB_ICONERROR);

printf("Exception Occurred at: %p\n", pRecord->ExceptionAddress);
printf("Exception filter 1 called at: %p\n", pFrame);

return ExceptionContinueSearch;
}

EXCEPTION_DISPOSITION
_cdecl
handler2(
EXCEPTION_RECORD* pRecord,
EXCEPTION_REGISTRATION_RECORD* pFrame,
CONTEXT* pContext,
PVOID pValue
) {
MessageBox(NULL,
L"Exception Occurred",
L"Exception Handler 2",
MB_ICONERROR);

pContext->Eip += 7;
printf("Exception Occurred at: %p\n", pRecord->ExceptionAddress);
printf("Exception filter 2 called at: %p\n", pFrame);

return ExceptionContinueExecution;
}

int main() {
DWORD handlerAddr = 0;
DWORD temp = 0;

__asm {
push handler2
push dword ptr fs:[0x00]

push handler
lea eax, [esp+4]
push eax

mov dword ptr fs:[0x00], esp

lea eax, [esp]
mov handlerAddr, eax
}

printf("SEH[0] is now set at  %p\n", (void*)handlerAddr);
printf("Handler 1 at %p\n", handler);
printf("Handler 2 at %p\n", handler2);

__asm {
xor eax, eax
mov dword ptr ds:[eax], 1 // Exception: Access Violation

mov eax, dword ptr fs:[0x00]
mov temp, eax
}

printf("Exception Successfully Handled\nContinue Execution...\n");

__asm {
xor eax, eax
mov dword ptr ds : [eax] , 1 // Exception: Access Violation
}

printf("Exception 2 Successfully Handled\nContinue Execution...\n");

__asm {
add esp, 0x10 // SEH ์„ค์น˜ํ•˜๋ฉด์„œ push ํ–ˆ๋˜ ๊ฒƒ ์ •๋ฆฌ.
}
}


`handler()`๋Š” ์ž์‹ ์˜ `pFrame`์„ ์ถœ๋ ฅํ•˜๊ณ , ์˜ˆ์™ธ๋ฅผ ๋‹ค์Œ SEH ๋…ธ๋“œ๋กœ ๋„˜๊ธด๋‹ค. ๋‹ค์Œ SEH ๋…ธ๋“œ์—๋Š” `handler2()`๊ฐ€ ์กด์žฌํ•˜๋ฉฐ, ์—ฌ๊ธฐ์„œ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•œ ๋’ค ์ž์‹ ์˜ `pFrame`์„ ์ถœ๋ ฅ, ์‹คํ–‰์„ ์žฌ๊ฐœํ•œ๋‹ค.
์œ„ ์ฝ”๋“œ์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

SEH[0] is now set at  00CDFAC4
Handler 1 at 00D713CA
Handler 2 at 00D713CF
Exception Occurred at: 00D753DD
Exception filter 1 called at: 00CDFAC4
Exception Occurred at: 00D753DD
Exception filter 2 called at: 00CDFACC
Exception Successfully Handled
Continue Execution...
Exception Occurred at: 00D753FC
Exception filter 1 called at: 00CDFAC4
Exception Occurred at: 00D753FC
Exception filter 2 called at: 00CDFACC
Exception 2 Successfully Handled
Continue Execution...


๋ญ.. ์ฃผ์†Œ์•ผ ์‹คํ–‰ ์‹œ๋งˆ๋‹ค ๋‹ฌ๋ผ์ง€๊ฒ ์ง€๋งŒ, `FS:[0x00]`์— ๋‹ด๊ธด ๊ฐ’์ด ์ฒซ SEH ๋…ธ๋“œ์˜ ์‹œ์ž‘ ์ฃผ์†Œ, ์ฆ‰ `handler()`์˜ ์ฃผ์†Œ๊ฐ€ ํฌํ•จ๋œ `_EXCEPTION_REGISTRATION_RECORD` ๊ตฌ์กฐ์ฒด์˜ ์‹œ์ž‘ ์ฃผ์†Œ์ด๊ณ  (์Šคํƒ ์˜์—ญ) ๋˜ํ•œ `handler()`์˜ `pFrame`์— ๋‹ด๊ธด ์ฃผ์†Œ์ด๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ `handler2()`์˜ `pFrame`์œผ๋กœ๋Š” `handler2()`์˜ ์ฃผ์†Œ๊ฐ€ ํฌํ•จ๋œ `_EXCEPTION_REGISTRATION_RECORD` ๊ตฌ์กฐ์ฒด์˜ ์ฃผ์†Œ๊ฐ€ ๋“ค์–ด๊ฐ„๋‹ค.

์œ„ ์ฝ”๋“œ์—์„œ๋Š” Stack์— `handler2()`๋ฅผ ์œ„ํ•œ `_EXCEPTION_REGISTRATION_RECORD` ๊ตฌ์กฐ์ฒด๋ฅผ ๋งŒ๋“  ํ›„ `handler()`๋ฅผ ์œ„ํ•œ ๊ตฌ์กฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‘ `pFrame`์— ์ €์žฅ๋œ ์ฃผ์†Œ๊ฐ’์˜ ์ฐจ์ด๊ฐ€ `_EXCEPTION_REGISTRATION_RECORD` ๊ตฌ์กฐ์ฒด์˜ ํฌ๊ธฐ์ธ 8byte๋งŒํผ ๋ฐœ์ƒํ•œ๋‹ค. 

์ด๋Š” ์–ด๋””๊นŒ์ง€๋‚˜ ์ถ”๊ฐ€์ ์ธ ์ฆ๋ช…์ผ ๋ฟ์ด๊ณ , ์•„๋ž˜ SEH ๊ตฌํ˜„ ๋ถ€๋ถ„์„ ์ฝ์–ด์•ผ ์ดํ•ด๊ฐ€ ๋  ๊ฒƒ์ด๋‹ค. ์ง€๊ธˆ์œผ๋กœ์„œ๋Š” ๋„˜์–ด๊ฐ€๋„ ์ข‹๋‹ค.
(a-3) `Handler`'s 3rd param: struct `_CONTEXT` (winnt.h)
`CONTEXT` ๊ตฌ์กฐ์ฒด๋Š” multi-threading ํ™˜๊ฒฝ์„ ์œ„ํ•ด ํŠน์ • thread์˜ ๋ ˆ์ง€์Šคํ„ฐ ๊ฐ’์„ ๋ฐฑ์—…ํ•ด ๋†“๋Š” ์šฉ๋„์˜ ๊ตฌ์กฐ์ฒด์ด๋‹ค. ๋ ˆ์ง€์Šคํ„ฐ๋ฅผ ์ €์žฅํ•˜๋‹ค ๋ณด๋‹ˆ x86 ๋ฒ„์ „๊ณผ x64 ๋ฒ„์ „, amd๋‚˜ arm ๋ฒ„์ „ ๋“ฑ ์•„ํ‚คํ…์ฒ˜์— ๋”ฐ๋ผ ์ •์˜๊ฐ€ ์กฐ๊ธˆ์”ฉ ๋‹ค๋ฅธ๋ฐ, ์ด๋“ค ๋ชจ๋‘ winnt.h์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์•„๋ž˜๋Š” intel x86 (IA-32) ์ „์šฉ `_CONTEXT` ๊ตฌ์กฐ์ฒด์˜ ์ •์˜. (MSDN์— `CONTEXT` ๊ตฌ์กฐ์ฒด๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ฉด ๋‚˜์˜ค๋Š” ์ฝ”๋“œ๋Š” x64 ๋ฒ„์ „์ด๋‹ค.)

typedef struct _CONTEXT {
  DWORD                    ContextFlags;
  DWORD                    Dr0;
  DWORD                    Dr1;
  DWORD                    Dr2;
  DWORD                    Dr3;
  DWORD                    Dr6;
  DWORD                    Dr7;
  FLOATING_SAVE_AREA FloatSave;
  DWORD                    SegGs;
  DWORD                    SegFs;
  DWORD                    SegEs;
  DWORD                    SegDs;
  DWORD                    Edi;
  DWORD                    Esi;
  DWORD                    Ebx;
  DWORD                    Edx;
  DWORD                    Ecx;
  DWORD                    Eax;
  DWORD                    Ebp;
  DWORD                    Eip; // B8h
  DWORD                    SegCs;
  DWORD                    EFlags;
  DWORD                    Esp;
  DWORD                    SegSs;
  BYTE                     ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
};


64-bit Windows์—์„œ 32-bit ํ”„๋กœ๊ทธ๋žจ์„ ๋Œ๋ฆฐ๋‹ค๋ฉด ๋™์ผํ•œ ๊ตฌ์„ฑ์„ ๊ฐ€์ง„ `_WOW64_CONTEXT`์„ ์ฐพ์•„๋ด๋„ ๋œ๋‹ค. ์•„๋งˆ..
ํ•œ ์Šค๋ ˆ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ ์‹คํ–‰ ํ๋ฆ„์„ ๋ฐ”๊ฟ€ ๋•Œ ๋ ˆ์ง€์Šคํ„ฐ๋“ค์˜ ์ƒํƒœ(context)๋ฅผ ์ด ๊ตฌ์กฐ์ฒด์— ๋ฐฑ์—…ํ•ด๋†“๊ณ  ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋ฅผ ์‹คํ–‰, ๋‹ค์‹œ ๋ณธ ์Šค๋ ˆ๋“œ๋กœ ๋Œ์•„์˜ฌ ๋•Œ์—๋Š” ๋ ˆ์ง€์Šคํ„ฐ๋“ค์„ ์ด ๊ตฌ์กฐ์ฒด์— ์ €์žฅ๋œ ๊ฐ’์œผ๋กœ ๋ฎ์–ด ์“ฐ๊ณ  ์‹คํ–‰์„ ์žฌ๊ฐœํ•œ๋‹ค.

winnt.h์˜ ์†Œ์Šค ์ฝ”๋“œ๋Š” ์•„๋ž˜ ๋งํฌ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
[winnt.h](https://codemachine.com/downloads/win80/winnt.h)

(a-4) `Handler`'s 3rd param: PVOID `DispatcherContext
(a-5) `Handler`'s return value: enum `EXCEPTION_DISPOSITION`

typedef enum _EXCEPTION_DISPOSITION {
         ExceptionContinueExecution = 0, // ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์™„๋ฃŒ, ์ฝ”๋“œ ์‹คํ–‰
         ExceptionContinueSearch = 1, // ์ฒ˜๋ฆฌ ์‹คํŒจ, SEH Chain์˜ ๋‹ค์Œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ ์‹คํ–‰
         ExceptionNestedException = 2, // OS์—์„œ ์‚ฌ์šฉ๋จ
         ExceptionCollidedUnwind = 3 // OS์—์„œ ์‚ฌ์šฉ๋จ
} EXCEPTION_DISPOSITION;


`Handler`์˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํ›„, ์‹œ์Šคํ…œ์˜ ๋™์ž‘์„ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค. ๊ทผ๋ฐ ์˜ˆ์™ธ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ์•ˆ ํ•˜๊ณ  ๋ฌด์ž‘์ • 0์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด, ์‹œ์Šคํ…œ์ด ์‹คํ–‰์„ ์žฌ๊ฐœํ–ˆ์„ ๋•Œ ๋˜‘๊ฐ™์€ ๋ถ€๋ถ„์—์„œ ๋‹ค์‹œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด ์ด ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋ฌดํ•œ์ • ์žฌํ˜ธ์ถœ๋˜๋Š” ์ผ์ด ์ƒ๊ธด๋‹ค. ์•„๋ž˜์˜ ์ฝ”๋“œ๊ฐ€ ๊ทธ ์˜ˆ์‹œ์ด๋‹ค.

//x86 debug, VS19
#include <stdio.h>

int handler(){
printf("Exception Occurred; And I, exception handler, will do nothing.\n");
return 0;
}

int main(){
__asm{
push handler
push dword ptr FS:[0]
mov dword ptr FS:[0], esp

xor eax, eax
mov dword ptr [eax], 1 // Exception: Access Violation
}
}


์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด `handler()` ํ•จ์ˆ˜๊ฐ€ ๊ณ„์†ํ•ด์„œ ํ˜ธ์ถœ๋œ๋‹ค. Access Violation ์˜ˆ์™ธ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์€ ์ฑ„๋กœ `ExceptionContinueExecution` ์‹ ํ˜ธ๋ฅผ ๋ณด๋‚ด์„œ, ์ฒ˜๋ฆฌ๊ฐ€ ์™„๋ฃŒ๋œ ์ค„ ์•ˆ ์‹œ์Šคํ…œ์ด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ์ฝ”๋“œ ๋ถ€๋ถ„๋ถ€ํ„ฐ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์—ฌ ๊ณ„์† ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ , ๋˜ ๋˜‘๊ฐ™์€ `handler()`๊ฐ€ ๊ทธ๊ฑธ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. `handler()`๊ฐ€ 1์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ์‹คํ–‰ํ•˜๋ฉด, `handler()`๊ฐ€ ํ•œ ๋ฒˆ ํ˜ธ์ถœ๋œ ๋’ค ์‹œ์Šคํ…œ์ด ์„ค์ •ํ•œ ๊ธฐ๋ณธ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ๊ฐ€ ์˜ˆ์™ธ๋ฅผ ๋„˜๊ฒจ๋ฐ›์•„ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ข…๋ฃŒํ•œ๋‹ค. 

๋ณดํ†ต์€ ์ด๋Ÿฌํ•œ ์ผ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๊ฒŒ๋”, `handler()`์—์„œ ์ „๋‹ฌ๋œ `CONTEXT` ๊ตฌ์กฐ์ฒด์˜ `Eip` ๋ฉค๋ฒ„(`&CONTEXT + 0xB8`)๋ฅผ ์ ์ ˆํžˆ ๋ณ€๊ฒฝํ•œ ๋’ค ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค. (์•„๋ž˜ ์‚ฌ์šฉ ์˜ˆ์ œ๋ฅผ ์ฐธ๊ณ .)

 

(2) SEH ์„ค์น˜ํ•˜๊ธฐ

SEH์˜ ์‹œ์ž‘ ์ฃผ์†Œ๋Š” `TEB.NtTib.ExceptionList`์— ์ €์žฅ๋˜์–ด ์žˆ๋‹ค.
์•„๋ž˜๋Š” TEB์™€ TEB.NtTib์˜ ๊ตฌ์กฐ์ด๋‹ค. WinDbg๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.


(a) TEB (Thread Environment Block / TIB) ๊ตฌ์กฐ
Windbg์—์„œ `dt _TEB` ํ˜น์€ `dt TEB` ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ๊ตฌ์กฐ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. (x86 on x86, x64 on x64)
x86 debugee on x64 Windbg์˜ ๊ฒฝ์šฐ, `dt _TEB32` ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ์•ผ ํ•œ๋‹ค.

0:000> dt _TEB
ntdll!_TEB
   +0x000 NtTib            : _NT_TIB
   +0x01c EnvironmentPointer : Ptr32 Void
   +0x020 ClientId         : _CLIENT_ID
   +0x028 ActiveRpcHandle  : Ptr32 Void
   +0x02c ThreadLocalStoragePointer : Ptr32 Void
   +0x030 ProcessEnvironmentBlock : Ptr32 _PEB
   +0x034 LastErrorValue   : Uint4B
   +0x038 CountOfOwnedCriticalSections : Uint4B
   +0x03c CsrClientThread  : Ptr32 Void
   +0x040 Win32ThreadInfo  : Ptr32 Void
   +0x044 User32Reserved   : [26] Uint4B
   +0x0ac UserReserved     : [5] Uint4B
   +0x0c0 WOW32Reserved    : Ptr32 Void
   +0x0c4 CurrentLocale    : Uint4B
   +0x0c8 FpSoftwareStatusRegister : Uint4B
   +0x0cc ReservedForDebuggerInstrumentation : [16] Ptr32 Void
   +0x10c SystemReserved1  : [26] Ptr32 Void
   +0x174 PlaceholderCompatibilityMode : Char
   +0x175 PlaceholderHydrationAlwaysExplicit : UChar
   +0x176 PlaceholderReserved : [10] Char
   +0x180 ProxiedProcessId : Uint4B
   +0x184 _ActivationStack : _ACTIVATION_CONTEXT_STACK
   +0x19c WorkingOnBehalfTicket : [8] UChar
   +0x1a4 ExceptionCode    : Int4B
   +0x1a8 ActivationContextStackPointer : Ptr32 _ACTIVATION_CONTEXT_STACK
   +0x1ac InstrumentationCallbackSp : Uint4B
   +0x1b0 InstrumentationCallbackPreviousPc : Uint4B
   +0x1b4 InstrumentationCallbackPreviousSp : Uint4B
   +0x1b8 InstrumentationCallbackDisabled : UChar
   +0x1b9 SpareBytes       : [23] UChar
   +0x1d0 TxFsContext      : Uint4B
   +0x1d4 GdiTebBatch      : _GDI_TEB_BATCH
   +0x6b4 RealClientId     : _CLIENT_ID
   +0x6bc GdiCachedProcessHandle : Ptr32 Void
   +0x6c0 GdiClientPID     : Uint4B
   +0x6c4 GdiClientTID     : Uint4B
   +0x6c8 GdiThreadLocalInfo : Ptr32 Void
   +0x6cc Win32ClientInfo  : [62] Uint4B
   +0x7c4 glDispatchTable  : [233] Ptr32 Void
   +0xb68 glReserved1      : [29] Uint4B
   +0xbdc glReserved2      : Ptr32 Void
   +0xbe0 glSectionInfo    : Ptr32 Void
   +0xbe4 glSection        : Ptr32 Void
   +0xbe8 glTable          : Ptr32 Void
   +0xbec glCurrentRC      : Ptr32 Void
   +0xbf0 glContext        : Ptr32 Void
   +0xbf4 LastStatusValue  : Uint4B
   +0xbf8 StaticUnicodeString : _UNICODE_STRING
   +0xc00 StaticUnicodeBuffer : [261] Wchar
   +0xe0c DeallocationStack : Ptr32 Void
   +0xe10 TlsSlots         : [64] Ptr32 Void
   +0xf10 TlsLinks         : _LIST_ENTRY
   +0xf18 Vdm              : Ptr32 Void
   +0xf1c ReservedForNtRpc : Ptr32 Void
   +0xf20 DbgSsReserved    : [2] Ptr32 Void
   +0xf28 HardErrorMode    : Uint4B
   +0xf2c Instrumentation  : [9] Ptr32 Void
   +0xf50 ActivityId       : _GUID
   +0xf60 SubProcessTag    : Ptr32 Void
   +0xf64 PerflibData      : Ptr32 Void
   +0xf68 EtwTraceData     : Ptr32 Void
   +0xf6c WinSockData      : Ptr32 Void
   +0xf70 GdiBatchCount    : Uint4B
   +0xf74 CurrentIdealProcessor : _PROCESSOR_NUMBER
   +0xf74 IdealProcessorValue : Uint4B
   +0xf74 ReservedPad0     : UChar
   +0xf75 ReservedPad1     : UChar
   +0xf76 ReservedPad2     : UChar
   +0xf77 IdealProcessor   : UChar
   +0xf78 GuaranteedStackBytes : Uint4B
   +0xf7c ReservedForPerf  : Ptr32 Void
   +0xf80 ReservedForOle   : Ptr32 Void
   +0xf84 WaitingOnLoaderLock : Uint4B
   +0xf88 SavedPriorityState : Ptr32 Void
   +0xf8c ReservedForCodeCoverage : Uint4B
   +0xf90 ThreadPoolData   : Ptr32 Void
   +0xf94 TlsExpansionSlots : Ptr32 Ptr32 Void
   +0xf98 MuiGeneration    : Uint4B
   +0xf9c IsImpersonating  : Uint4B
   +0xfa0 NlsCache         : Ptr32 Void
   +0xfa4 pShimData        : Ptr32 Void
   +0xfa8 HeapData         : Uint4B
   +0xfac CurrentTransactionHandle : Ptr32 Void
   +0xfb0 ActiveFrame      : Ptr32 _TEB_ACTIVE_FRAME
   +0xfb4 FlsData          : Ptr32 Void
   +0xfb8 PreferredLanguages : Ptr32 Void
   +0xfbc UserPrefLanguages : Ptr32 Void
   +0xfc0 MergedPrefLanguages : Ptr32 Void
   +0xfc4 MuiImpersonation : Uint4B
   +0xfc8 CrossTebFlags    : Uint2B
   +0xfc8 SpareCrossTebBits : Pos 0, 16 Bits
   +0xfca SameTebFlags     : Uint2B
   +0xfca SafeThunkCall    : Pos 0, 1 Bit
   +0xfca InDebugPrint     : Pos 1, 1 Bit
   +0xfca HasFiberData     : Pos 2, 1 Bit
   +0xfca SkipThreadAttach : Pos 3, 1 Bit
   +0xfca WerInShipAssertCode : Pos 4, 1 Bit
   +0xfca RanProcessInit   : Pos 5, 1 Bit
   +0xfca ClonedThread     : Pos 6, 1 Bit
   +0xfca SuppressDebugMsg : Pos 7, 1 Bit
   +0xfca DisableUserStackWalk : Pos 8, 1 Bit
   +0xfca RtlExceptionAttached : Pos 9, 1 Bit
   +0xfca InitialThread    : Pos 10, 1 Bit
   +0xfca SessionAware     : Pos 11, 1 Bit
   +0xfca LoadOwner        : Pos 12, 1 Bit
   +0xfca LoaderWorker     : Pos 13, 1 Bit
   +0xfca SkipLoaderInit   : Pos 14, 1 Bit
   +0xfca SkipFileAPIBrokering : Pos 15, 1 Bit
   +0xfcc TxnScopeEnterCallback : Ptr32 Void
   +0xfd0 TxnScopeExitCallback : Ptr32 Void
   +0xfd4 TxnScopeContext  : Ptr32 Void
   +0xfd8 LockCount        : Uint4B
   +0xfdc WowTebOffset     : Int4B
   +0xfe0 ResourceRetValue : Ptr32 Void
   +0xfe4 ReservedForWdf   : Ptr32 Void
   +0xfe8 ReservedForCrt   : Uint8B
   +0xff0 EffectiveContainerId : _GUID
   +0x1000 LastSleepCounter : Uint8B
   +0x1008 SpinCallCount    : Uint4B
   +0x1010 ExtendedFeatureDisableMask : Uint8B


(b) PEB.NtTib ๊ตฌ์กฐ
TEB์˜ ์ฒซ ๋ฒˆ์งธ ๋ฉค๋ฒ„์ธ `NtTib`์˜ ๊ตฌ์กฐ์ด๋‹ค. ๋ฌผ๋ก  32bit PE์— ์“ฐ์ธ๋‹ค.

0:000> dt _NT_TIB
ntdll!_NT_TIB
   +0x000 ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD
   +0x004 StackBase        : Ptr32 Void
   +0x008 StackLimit       : Ptr32 Void
   +0x00c SubSystemTib     : Ptr32 Void
   +0x010 FiberData        : Ptr32 Void
   +0x010 Version          : Uint4B
   +0x014 ArbitraryUserPointer : Ptr32 Void
   +0x018 Self             : Ptr32 _NT_TIB

`ExceptionList` ๋ฉค๋ฒ„์— SEH Chain์˜ ์‹œ์ž‘์ ์ด ์ €์žฅ๋œ๋‹ค.


(c) FS ๋ ˆ์ง€์Šคํ„ฐ๋กœ SEH ์ ‘๊ทผํ•˜๊ธฐ
x86 usermode์˜ FS ๋ ˆ์ง€์Šคํ„ฐ๋Š” `TEB` ์˜ ์‹œ์ž‘ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋‹ค. `NtTib`๋Š” `TEB`์˜ ์ฒซ ๋ฉค๋ฒ„, ๊ทธ๋ฆฌ๊ณ  `ExceptionList`๋Š” `NtTib`์˜ ์ฒซ ๋ฉค๋ฒ„์ด๋ฏ€๋กœ `FS:[0]`์„ ํ†ตํ•ด SEH Chain์˜ ์‹œ์ž‘์ ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

FS:[0] == TEB.NtTib.ExceptionList
mov eax, dword ptr FS:[0x00] // eax: SEH Chain ์‹œ์ž‘ ์ฃผ์†Œ


x64 usermode์—์„œ๋Š” `GS:[0x30]`์— `TEB`์˜ ์ฃผ์†Œ๊ฐ€ ๋‹ด๊ฒจ์žˆ๊ณ , ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ `GS:[0x60]`์„ ํ†ตํ•ด `PEB`์˜ ์ฃผ์†Œ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค๋งŒ, ์ด๋Ÿฐ ๋ฐฉ์‹์˜ ์˜ˆ์™ธ ํ•ธ๋“ค๋ง์€ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋“ฏํ•˜๋‹ค. (์ถ”๊ฐ€ ์กฐ์‚ฌ ํ•„์š”)


(d) SEH Chain์— Handler ์ถ”๊ฐ€ํ•˜๊ธฐ
์•„๋ž˜์™€ ๊ฐ™์€ ์ผ๋ จ์˜ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด SEH Chain์˜ Top์— ์ƒˆ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

push handler // Handler
push dword ptr FS:[0x00] // Next
mov dword ptr FS:[0x00], esp


`push handler`๋กœ ์Šคํƒ์— handler ํ•จ์ˆ˜์˜ ์ฃผ์†Œ๊ฐ€ ์ €์žฅ๋˜๋ฉฐ, ๋’ค์ด์€ `push dword ptr FS:[0x00]`์œผ๋กœ ์ด์ „ SEH Chain์˜ ์‹œ์ž‘์ ์ด ์Šคํƒ์— ๋“ค์–ด๊ฐ„๋‹ค. ์ด๋กœ์จ ์Šคํƒ์— `_EXCEPTION_REGISTRATION_RECORD` ๊ตฌ์กฐ์ฒด๊ฐ€ ์ž๋ฆฌ์žก๋Š”๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ `mov dword ptr FS:[0x00], esp` ๋ช…๋ น์–ด๋กœ `TEB.NtTib.ExceptionList`์— ์ƒˆ๋กœ์šด `_EXCEPTION_REGISTRATION_RECORD` ๊ตฌ์กฐ์ฒด ์ฃผ์†Œ๋ฅผ ์ €์žฅํ•œ๋‹ค. (์ด๋•Œ esp๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ฃผ์†Œ์—๋Š” ์ด์ „์˜ SEH Chain์˜ Top, ์ฆ‰, ์ด์ „์˜ `FS:[0x00]` ๊ฐ’์ด ๋“ค์–ด ์žˆ๋‹ค.)

SEH Chain์˜ ์ฒซ `Handler` ์ฝœ๋ฐฑ ํ•จ์ˆ˜์˜ ์ฃผ์†Œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.

mov eax, fs:[0x00] // stack ์ƒ์˜ SEH Chain ์‹œ์ž‘ ์ฃผ์†Œ
mov eax, [eax + 4] // SEH Chain์˜ ์‹œ์ž‘์ ์œผ๋กœ๋ถ€ํ„ฐ 4 ๋–จ์–ด์ง„ ์ฃผ์†Œ์— ์ €์žฅ๋œ ๊ฐ’ -> ํ•ธ๋“ค๋Ÿฌ ์ฃผ์†Œ


(e) SEH ์‚ฌ์šฉ ์˜ˆ์ œ
์•„๋ž˜ ์ฝ”๋“œ๋Š” ์ง์ ‘ SEH Chain์— `handler()` ํ•จ์ˆ˜๋ฅผ ๋“ฑ๋กํ•˜๊ณ , Access Violation ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ `handler()`๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ๋” ํ•œ๋‹ค.

// x86 debug, VS19
#include <Windows.h>
#include <stdio.h>

EXCEPTION_DISPOSITION 
_cdecl
handler(
EXCEPTION_RECORD* pRecord,
EXCEPTION_REGISTRATION_RECORD* pFrame,
CONTEXT* pContext,
PVOID pValue
) {
MessageBox(NULL,
L"Exception Occurred",
L"Exception Handler",
MB_ICONERROR);

pContext->Eip += 7;
printf("Exception Occurred at: %p\n", pRecord->ExceptionAddress);

return ExceptionContinueExecution;
}

int main() {
DWORD handlerAddr = 0;

__asm {
push handler
push dword ptr fs:[0x00]

mov dword ptr fs:[0x00], esp

mov eax, dword ptr fs:[0x00]
mov eax, dword ptr ds:[eax+4]
mov handlerAddr, eax 
// mov dword ptr [handlerAddr], eax ๊ฐ™์€ ํ‘œ๊ธฐ๋„ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘
}

printf("SEH handler is now set at  %p\n", (void*)handlerAddr);

__asm {
xor eax, eax
mov dword ptr ds:[eax], 1 // Exception 1: Access Violation
}

printf("Exception Successfully Handled\nContinue Execution...\n");

__asm {
xor eax, eax
mov dword ptr ds : [eax] , 1 // Exception 2: Access Violation
}

printf("Exception 2 Successfully Handled\nContinue Execution...\n");

__asm {
add esp, 8 
// SEH ์„ค์น˜ํ•˜๋ฉด์„œ ๋‘ ๋ฒˆ push ํ–ˆ๋˜ ๊ฒƒ ๋•Œ๋ฌธ์— esp์— 4*2 ๋”ํ•ด์ค˜์•ผ ํ•จ.
// ์•ˆ ๊ทธ๋Ÿฌ๋ฉด ์ž˜๋ชป๋œ ESP ๊ฐ’ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜ ๋ฐœ์ƒ. (__RTC_CheckEsp())
}
}


`handler()` ํ•จ์ˆ˜ ๋‚ด์—์„œ๋Š” ์ธ์ž๋กœ ๋ฐ›์€ `pContext->Eip`์˜ ๊ฐ’์„ 7 ์ฆ๊ฐ€์‹œ์ผœ ์˜ˆ์™ธ ๋ฐœ์ƒ ์ฝ”๋“œ๋ฅผ ๊ฑด๋„ˆ ๋œ€์œผ๋กœ์จ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค.

์œ„ ์ฝ”๋“œ๋ฅผ x86 release mode๋กœ ์ปดํŒŒ์ผํ•˜๋ฉด `mov dword ptr ds:[eax], 1` ๋ถ€๋ถ„์—์„œ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด SEH Chain์— ๋“ฑ๋ก๋œ `handler()` ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š”๋ฐ, ์ด ํ˜ธ์ถœ ๋ถ€๋ถ„์—์„œ ๋˜ ํ•œ ๋ฒˆ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. (STATUS_INVALID_EXCEPTION_HANDLER) ์ด๋Š” Visual Studio์˜ release mode์—์„œ๋Š” `/SAFESEH` ๋ผ๋Š” ๋ง์ปค ์˜ต์…˜์„ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”ํ•ด๋†“๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ”„๋กœ์ ํŠธ์˜ ๋ง์ปค ์˜ต์…˜์—์„œ `Image Has Safe Exception Handlers` ์˜ต์…˜์„ ๋„๊ณ  ์ปดํŒŒ์ผํ•œ๋‹ค๋ฉด ์˜๋„ํ•œ ๋™์ž‘์„ ํ•˜๊ฒ ์ง€๋งŒ, SEH Overwrite ๊ณต๊ฒฉ ๋“ฑ์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค. (๋ฌผ๋ก  ์žˆ์–ด๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ข€ ๋ณต์žกํ•ด์งˆ ๋ฟ.)

์ž์„ธํ•œ ๊ฑด [[WinPwn - SEH Overwrite]] ์ฐธ๊ณ .

SafeSEH๋ž€, `Handler` ๋ณ€์ˆ˜์— ๋‹ด๊ธด `__except_handler()`์˜ ์ฃผ์†Œ๊ฐ€ ์Šคํƒ์˜ ์ฃผ์†Œ ๋ฒ”์œ„์— ํฌํ•จ๋  ๋•Œ, ํ˜น์€ PE ํ—ค๋”์˜ `IMAGE_LOAD_CONFIG_DIRECTORY`์˜ `SEHandlerTable` ๊ฐ’๊ณผ ๋‹ค๋ฅผ ๋•Œ ์ด ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š” ๊ธฐ๋ฒ•์ด๋‹ค. ์œ„ ์ฝ”๋“œ๋ฅผ release ๋ชจ๋“œ๋กœ ์ปดํŒŒ์ผํ•œ ๊ฒฝ์šฐ SafeSEH๊ฐ€ ๊ธฐ๋ณธ ์ ์šฉ๋˜๋ฉฐ, `handler()`์˜ ์ฃผ์†Œ๊ฐ€ `SEHandlerTable` ๊ฐ’๊ณผ ๋‹ฌ๋ผ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒƒ์ด๋‹ค.

(f) ntdll์˜ ์˜ˆ์™ธ ํ•ธ๋“ค๋ง ์ˆœ์„œ (x86)
์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ˆœ์œผ๋กœ ํ•จ์ˆ˜๋“ค์ด ์‹คํ–‰๋œ๋‹ค.

ntdll!KiUserExceptionDispatcher()
ntdll!RtlDispatchException()
ntdll!RtlpExecuteHandlerForException()
ntdll!ExceptionHandler2()
SEH called here!


`ExceptionHandler2()` ํ•จ์ˆ˜์˜ ์–ด์…ˆ๋ธ”๋ฆฌ ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

77229CDC  | push ebp                                  |
77229CDD  | mov ebp,esp                               |
77229CDF  | push dword ptr ss:[ebp+C]                 |
77229CE2  | push edx                                  | edx: 77229D20
77229CE3  | push dword ptr fs:[0]                     |
77229CEA  | mov dword ptr fs:[0],esp                  |
77229CF1  | push dword ptr ss:[ebp+14]                |
77229CF4  | push dword ptr ss:[ebp+10]                |
77229CF7  | push dword ptr ss:[ebp+C]                 |
77229CFA  | push dword ptr ss:[ebp+8]                 |
77229CFD  | mov ecx,dword ptr ss:[ebp+18]             |
77229D00  | call ecx                                  | call _except_handler
77229D02  | mov esp,dword ptr fs:[0]                  |
77229D09  | pop dword ptr fs:[0]                      |
77229D10  | mov esp,ebp                               |
77229D12  | pop ebp                                   |
77229D13  | ret 14                                    |
77229D16  | lea esp,dword ptr ss:[esp]                | 
77229D1D  | lea ecx,dword ptr ds:[ecx]                |
77229D20  | mov ecx,dword ptr ss:[esp+4]              | SEH chain์˜ ์ฒซ ๋…ธ๋“œ๋กœ ์‚ฝ์ž…๋จ
77229D24  | test dword ptr ds:[ecx+4],6               |
77229D2B  | mov eax,1                                 |
77229D30  | jne ntdll.77229D44                        |
77229D32  | mov ecx,dword ptr ss:[esp+8]              |
77229D36  | mov edx,dword ptr ss:[esp+10]             | 
77229D3A  | 8mov eax,dword ptr ds:[ecx+8]             |
77229D3D  | mov dword ptr ds:[edx],eax                | 
77229D3F  | mov eax,2                                 |
77229D44  | ret 10                                    |
77229D47  | lea esp,dword ptr ss:[esp]                | 
77229D4E  | mov edi,edi                               |
77229D50  | mov ecx,dword ptr ss:[esp+4]              |
77229D54  | test dword ptr ds:[ecx+4],6               |
77229D5B  | mov eax,1                                 |
77229D60  | je ntdll.77229D74                         |
77229D62  | mov ecx,dword ptr ss:[esp+8]              |
77229D66  | mov edx,dword ptr ss:[esp+10]             | 
77229D6A  | mov eax,dword ptr ds:[ecx+8]              |
77229D6D  | mov dword ptr ds:[edx],eax                | 
77229D6F  | mov eax,3                                 |
77229D74  | ret 10                                    |


์ด ํ•จ์ˆ˜์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์—์„œ `push ebp -> push fs:[0] -> mov fs:[0], esp`๋ฅผ ํ†ตํ•ด SEH Chain์˜ ์‹œ์ž‘ ์ง€์ ์— ntdll ์˜์—ญ์˜ ์ฃผ์†Œ๋ฅผ ์˜ˆ์™ธ ํ•ธ๋“ค๋Ÿฌ์˜ ์ฃผ์†Œ๋กœ ํฌํ•จํ•œ ์ƒˆ ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•œ๋‹ค. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๊ฒƒ์ด๊ณ , ์ƒˆ๋กœ ๋“ฑ๋ก๋œ ํ•ธ๋“ค๋Ÿฌ์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. ์ด ์—ญ์‹œ handler callback function์˜ ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ฅธ๋‹ค.

77229D20  | mov ecx,dword ptr ss:[esp+4]         | pRecord
77229D24  | test dword ptr ds:[ecx+4],6          | pRecord->ExceptionFlag์™€ 6์„ ๋น„๊ต
77229D2B  | mov eax,1                            | ExceptionContinueExecution
77229D30  | jne ntdll.77229D44                   | return
77229D32  | mov ecx,dword ptr ss:[esp+8]         | pFrame
77229D36  | mov edx,dword ptr ss:[esp+10]        | 4th param, DispatcherContext
77229D3A  | mov eax,dword ptr ds:[ecx+8]         | ์ด๊ฑฐ ํ˜ธ์ถœ ์ „ SEH ๋…ธ๋“œ์˜ Frame ์ฃผ์†Œ
77229D3D  | mov dword ptr ds:[edx],eax           | 
77229D3F  | mov eax,2                            | ExceptionNestedException
77229D44  | ret 10                               |


์ด ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ค‘ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ํ˜ธ์ถœ๋œ๋‹ค. ์ด ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ์„ ๋•Œ์˜ `pRecord->ExceptionFlags` ๊ฐ’๊ณผ 6์„ and ์—ฐ์‚ฐํ•œ ๊ฐ’์ด 0์ด ์•„๋‹ˆ๋ผ๋ฉด `ExceptionNestedException`์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. (์‚ฌ์‹ค์ƒ `ExceptionFlags`๊ฐ€ `EXCEPTION_UNWINDING(0x02)`, `EXCEPTION_EXIT_UNWIND(0x04)` ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ๋ชจ๋‘ `ExceptionNestedException`์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋œ๋‹ค.)

์ด ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ๊ฐ’์€ `RtlDispatchException()`์œผ๋กœ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ๋œ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋Š” `RtlpExecuteHandlerForException()` ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’์— ๋”ฐ๋ผ์„œ ์˜ˆ์™ธ๋ฅผ ํ•ด์ œํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” `DISPOSION_DISMISS`๋ฅผ, ์˜ˆ์™ธ ์บก์Аํ™” ์ฒ˜๋ฆฌ๊ธฐ ์ˆ˜์ค€๊นŒ์ง€ ์˜ˆ์™ธ๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” `DISPOSION_CONTINUE_SEARCH`์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. [__except_handler3](https://learn.microsoft.com/ko-kr/cpp/c-runtime-library/except-handler3?view=msvc-170)

์œ ์ € ๋ชจ๋“œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์˜ ๊ฐ€์žฅ ๋ฐ”๊นฅ์ชฝ์—์„œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๋Š” `KiUserExceptionDispatcher()`์ด๋‹ค. ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ์ปค๋„์—์„œ ์ด๋ฅผ ์ธ์ง€ํ•œ ๋’ค ์œ ์ €๋ชจ๋“œ๋กœ ๋ณต๊ท€ํ•  ๋•Œ ์ด ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ์ปค๋„์—์„œ ํ˜ธ์ถœ๋  ๋•Œ `ExceptionRecord`์™€ `Context`๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค. `KiUserExceptionDispatcher()`๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ `RtlDispatchException()` ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋Š”๋ฐ, ์ด์˜ ๋ฐ˜ํ™˜ ๊ฐ’์— ๋”ฐ๋ผ `NtContinue()`๋กœ ์˜ˆ์™ธ ๋ฐœ์ƒ ์ฝ”๋“œ๋ถ€ํ„ฐ ์‹คํ–‰๋˜๊ฑฐ๋‚˜(`DISPOSITION_DISMISS`์˜ ๊ฒฝ์šฐ) `NtRaiseException()`์œผ๋กœ ์˜ˆ์™ธ๋ฅผ ๋‹ค์‹œ ๋ฐœ์ƒ์‹œ์ผœ(`DISPOSITION_CONTINUE_SEARCH`์˜ ๊ฒฝ์šฐ) ๋””๋ฒ„๊ฑฐ/์œˆ๋„์šฐ์˜ ์˜ˆ์™ธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ฐพ๊ธฐ๋„ ํ•œ๋‹ค. `NtContinue()`๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ ์ธ์ž๋กœ `Context`๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š”๋ฐ, `NtContinue()`๋Š” `Context` ๊ตฌ์กฐ์ฒด์˜ ์‹œ์ž‘ ์ง€์ ์œผ๋กœ๋ถ€ํ„ฐ 0xB8 ์˜คํ”„์…‹๋งŒํผ ๋–จ์–ด์ง„ ๊ณณ์— ์œ„์น˜ํ•œ ๋ฉค๋ฒ„์ธ `pContext->Eip`๋ฅผ ๋ณด๊ณ  ์‹คํ–‰์„ ์žฌ๊ฐœํ•  ์œ„์น˜๋ฅผ ํŒ๋‹จํ•œ๋‹ค. 

์—ฌ๊ธฐ๊นŒ์ง€๋Š” ์–ด์…ˆ๋ธ”๋ฆฌ์–ด ์ˆ˜์ค€์—์„œ SEH๋ฅผ ๋งŒ๋“ค์—ˆ์„ ๋•Œ์˜ ์ด์•ผ๊ธฐ๊ณ , Windows์—์„œ ์ œ๊ณตํ•˜๋Š” `__try{}__except(){}` ๋ฌธ์„ ์ด์šฉํ•œ SEH๋Š” custom handler ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ `__exception_handler3()`๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค. (๊ทธ๋ ‡์ง€๋งŒ ์—ญ์‹œ `FS:[0]`์— ์ด๋ฅผ ๋“ฑ๋กํ•ด๋†“๊ณ  ์‚ฌ์šฉํ•œ๋‹ค.) ์ด ๋•Œ์—๋Š” Scope Table๊ณผ TryLevel์ด ์กด์žฌํ•œ๋‹ค. (์ด๊ฑด ์ž˜ ๋ชจ๋ฅด๊ฒ ์œผ๋‹ˆ ๊ฒ€์ƒ‰ ใ„ฑใ„ฑ)

VC++์—์„œ /GS ์˜ต์…˜์„ ํ™œ์„ฑํ™”ํ•˜๊ณ  ์ปดํŒŒ์ผํ•˜๋ฉด `__except_handler3()` ๋Œ€์‹  `__except_handler4()`๊ฐ€ ํ˜ธ์ถœ๋˜๋Š”๋ฐ, ์ด๋Š” TryLevel ์ดˆ๊นƒ๊ฐ’์ด `0xFFFFFFFE`๋ผ๋Š” ๊ฒƒ๊ณผ Stack cookie ๊ฒ€์‚ฌ๋ฅผ ํ•œ๋‹ค๋Š” ๊ฒƒ ์™ธ์—๋Š” `__except_handler3()`๊ณผ ๋”ฑํžˆ ๋‹ค๋ฅธ ์ ์ด ์—†๋‹ค.

 

2) kernel32!SetUnhandledExceptionFilter()

SEH์—์„œ ์˜ˆ์™ธ๊ฐ€ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ๋“ฑ๋ก๋œ SEH๊ฐ€ ์—†์„ ๊ฒฝ์šฐ kernel32!UnhandledExceptionFilter() API๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค. kernel32!UnhandledExceptionFilter() ํ•จ์ˆ˜์—์„œ๋Š” Top Level Exception Filter๋ผ๋Š” ์‹œ์Šคํ…œ์˜ ๋งˆ์ง€๋ง‰ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์‹คํ–‰ํ•ด, '์ž‘๋™์ด ์ค‘์ง€๋˜์—ˆ์Šต๋‹ˆ๋‹ค' ๊ฒฝ๊ณ  ์ฐฝ์„ ๋„์šฐ๊ณ  ํ”„๋กœ์„ธ์Šค๋ฅผ ์ข…๋ฃŒํ•œ๋‹ค. ์ด ํ•จ์ˆ˜์—์„œ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ntdll!NtQueryInformationProcess(ProcessDebugPort) API๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋””๋ฒ„๊น… ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จ, ๋””๋ฒ„๊น… ์ค‘์ด๋ผ๋ฉด ๋””๋ฒ„๊ฑฐ์— ์ œ์–ด๊ถŒ์„ ๋„˜๊ธฐ๊ณ , ๋””๋ฒ„๊น… ์ค‘์ด ์•„๋‹ˆ๋ผ๋ฉด ์‹œ์Šคํ…œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ์— ์ „๋‹ฌํ•œ๋‹ค.

kernel32!SetUnhandledExceptionFilter() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์‹œ์Šคํ…œ์˜ Top Level Exception Filter๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ํ•จ์ˆ˜์˜ ์›ํ˜•์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter( 
[in] LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter 
);


[Microsoft: SetUnhandledExceptionFilter function (errhandlingapi.h)](https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-setunhandledexceptionfilter)
`lpTopLevelExceptionFilter` ์ธ์ž์— ์ƒˆ๋กœ ๋“ฑ๋กํ•  Top Level Exception Filter์˜ ํ•จ์ˆ˜ ์ฃผ์†Œ๋ฅผ ๋„˜๊ฒจ์ฃผ๋ฉด ๋œ๋‹ค. ๋ฐ˜ํ™˜ ๊ฐ’์€ ์ด์ „์˜ Top Level Exception Filter ํ•จ์ˆ˜ ์ฃผ์†Œ. (์—†๋‹ค๋ฉด NULL.)

ํ”„๋กœ์„ธ์Šค์—์„œ ๊ณ ์˜๋กœ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์‚ฌ์šฉ์ž ์ •์˜ Top Level Exception Filter๋ฅผ ํ†ตํ•ด EIP ๊ฐ’์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ˆ˜์ •ํ•˜๋ฉด, ๋””๋ฒ„๊น… ์‹คํ–‰ ์‹œ์—๋Š” ์˜ˆ์™ธ๊ฐ€ ๋””๋ฒ„๊ฑฐ์—์„œ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ข…๋ฃŒ๋˜์ง€๋งŒ, ๋””๋ฒ„๊น… ์ค‘์ด ์•„๋‹ ๋•Œ์—๋Š” ์˜ˆ์™ธ๊ฐ€ Top Level Exception Filter์— ์ „๋‹ฌ๋˜์–ด ์ฒ˜๋ฆฌ๋˜๋ฏ€๋กœ ์ •์ƒ ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

#### (1) `SetUnhandledExceptionFilter()` ์‚ฌ์šฉ ์˜ˆ์ œ
์•„๋ž˜์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

// x86 debug, VS19
#include <stdio.h>
#include <Windows.h>
#include <errhandlingapi.h>

LONG WINAPI handler(PEXCEPTION_POINTERS ExceptionInfo) {
MessageBox(NULL,
L"Handler called!",
L"Exception Handler",
MB_ICONERROR);

ExceptionInfo->ContextRecord->Eip += 7;
printf("Exception at %p\n", ExceptionInfo->ExceptionRecord->ExceptionAddress);

return EXCEPTION_CONTINUE_EXECUTION;
}

int main() {
SetUnhandledExceptionFilter(handler);

__asm {
xor eax, eax
mov dword ptr ds:[eax], 1 // Exception: Access Violation
}

printf("Exception Successfully Handled!\nContinue Execution... \n");

}


์ธ์ž๋กœ ๋ฐ›์€ `EXCEPTION_POINTERS` ๊ตฌ์กฐ์ฒด ํฌ์ธํ„ฐ์˜ `->ContextRecord->Eip`์˜ ๊ฐ’์„ ์ง์ ‘ ์ˆ˜์ •ํ•ด ์˜ˆ์™ธ ๋ฐœ์ƒ ์ฝ”๋“œ๋ฅผ ๊ฑด๋„ˆ๋›ฐ๋Š” ๋ฐฉ์‹์œผ๋กœ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” `handler()` ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

์œ„ ์ฝ”๋“œ๋ฅผ ๋””๋ฒ„๊ฑฐ์—์„œ ์‹คํ–‰ํ•˜๋ฉด `mov dword ptr ds:[eax], 1` ๋ช…๋ น์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ , ๋””๋ฒ„๊ฑฐ๊ฐ€ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•˜์—ฌ ๋””๋ฒ„๊น…์ด ์ค‘์ง€๋œ๋‹ค.

x64 ํ™˜๊ฒฝ์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด, `Eip` ๋Œ€์‹  `Rip` ๋ฉค๋ฒ„๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.

//x64 debug, VS19
#include <stdio.h>
#include <Windows.h>
#include <errhandlingapi.h>

LONG WINAPI handler(PEXCEPTION_POINTERS ExceptionInfo) {
MessageBox(NULL,
L"Handler called!",
L"Exception Handler",
MB_ICONERROR);

ExceptionInfo->ContextRecord->Rip += 6;
printf("Exception at %p\n", ExceptionInfo->ExceptionRecord->ExceptionAddress);

return EXCEPTION_CONTINUE_EXECUTION;
}

int main() {
SetUnhandledExceptionFilter(handler);

int zero = 0;
int value = 3;
value = value / zero; // Exception: Division by 0

printf("Exception Successfully Handled!\nContinue Execution... \n");

}



### 3) ์šฐํšŒ
๊ทธ๋ƒฅ ์‹คํ–‰์‹œํ‚จ ๋’ค ์˜ˆ์™ธ ๋ฐœ์ƒ ์ง€์ ์„ ์ง€๋‚˜ debugger๋ฅผ attachํ•˜๊ฑฐ๋‚˜, `Shift+F7/F8/F9` ๋“ฑ์˜ ํ‚ค๋ฅผ ํ†ตํ•ด `StepIn/StepOver/Run` ์‹œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ debugee์—๊ฒŒ ๋„˜๊ธฐ๊ฑฐ๋‚˜ ํ•˜๋ฉด ๋œ๋‹ค. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๊ณ  ์‹ถ์œผ๋ฉด SEH Chain ๋“ฑ๋ก ๋ถ€๋ถ„์—์„œ pushํ•˜๋Š” ์ฃผ์†Œ (์ผ๋ฐ˜ํ™”ํ•˜์ž๋ฉด x86๊ธฐ์ค€ `fs:[0]`์— ์˜ฎ๊ฒจ์ง€๋Š” esp์— 4๋ฅผ ๋”ํ•œ ์ฃผ์†Œ์— ์ €์žฅ๋œ ๊ฐ’)๋ฅผ ์‚ดํŽด๋ณด๊ณ  ๊ทธ ์ฃผ์†Œ์˜ ์ฝ”๋“œ์— breakpoint๋ฅผ ๊ฑธ๋ฉด ๋˜๊ณ , `SetUnhandledExceptionFilter()`๋ฅผ ์ด์šฉํ•œ ๊ฒฝ์šฐ์—๋„ ์ธ์ž๋กœ ๋“ค์–ด๊ฐ€๋Š” `handler` ํ•จ์ˆ˜์˜ ์‹œ์ž‘ ์ง€์ ์— bp๋ฅผ ์„ค์น˜ํ•˜๋ฉด ๋œ๋‹ค. (๋ฌผ๋ก  `Shift+F7/F8/F9`๋กœ ์‹คํ–‰ํ•ด์•ผ ์ด ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์ œ๋Œ€๋กœ ํ˜ธ์ถœ๋œ๋‹ค.) 
(x64dbg์—์„œ๋Š” ์ด๋ฅผ erun/ego ๋“ฑ์œผ๋กœ ๋ถ€๋ฅด๋ฉฐ, first change exception์„ debuggee์— ๋„˜๊ฒจ ์ฒ˜๋ฆฌํ•œ๋‹ค. Swallow exception and run์€ `Ctrl+Alt+Shift+F7/F8/F9`์ด๋‹ค.)

## 2. Software Breakpoint Detection
ํ”„๋กœ์„ธ์Šค๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฒ€์‚ฌํ•จ์œผ๋กœ์จ debugger์˜ ์กด์žฌ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค. Debugger๋Š” ์‹คํ–‰์„ ๋ฉˆ์ถ”๊ณ ์ž ํ•˜๋Š” instruction์˜ ์ฒซ 1๋ฐ”์ดํŠธ๋ฅผ 0xCC (INT3)์œผ๋กœ ํŒจ์น˜ํ•˜์—ฌ software breakpoint๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค. ์ด ์ ์„ ์ด์šฉํ•˜์—ฌ ์ฝ”๋“œ ์˜์—ญ์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฒ€์‚ฌํ•จ์œผ๋กœ์จ software bp๊ฐ€ ์ ์šฉ๋˜์—ˆ๋Š”์ง€ ํŒ๋‹จํ•˜๊ณ  ์•ˆํ‹ฐ๋””๋ฒ„๊น… ๋ฃจํ‹ด์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. 

###### +TODO!("undefined instruction(0f 0b)๋ฅผ ์‚ฌ์šฉํ•ด software bp๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์œผ๋ฏ€๋กœ ์ด๊ฒƒ์„ coverํ• ๋งŒํ•œ ๊ตฌํ˜„์ฒด๋„ ํ•„์š”")

์•„๋ž˜๋Š” software bp๋ฅผ ํƒ์ง€ํ•˜๋Š” C++ ์ฝ”๋“œ์ด๋‹ค.

#include <Windows.h>
#include <wtypes.h>
#include <WinDNS.h>

#include <stdio.h>

BOOL checkByte(BYTE, PVOID, SIZE_T);
BOOL checkBP(PVOID, SIZE_T);
BOOL isJmpTable(PVOID);

int critical() {
printf("This function is critical!\n");
return 0;
}

int main() {
BOOL flag = checkBP((PVOID)critical, 0x50);

if (flag) {
printf("Software BP detected.\n");
}
else {
printf("Software BP not detected.\n");
}
}

BOOL checkByte(BYTE bByte, PVOID pMem, SIZE_T nSize = 0) {
PBYTE bMem = (PBYTE)pMem;

for (SIZE_T i = 0; i < nSize; i++) {
if (*(bMem + i) == 0xC3) {
break;
}

if (*(bMem + i) == bByte) {
return 1;
}
}

return 0;
}

BOOL checkBP(PVOID pMem, SIZE_T n) {
BOOL result = 0;

if (isJmpTable(pMem)) {
DWORD dwOffset = *(DWORD*)((PBYTE)pMem + 1) + 5; // 5: size of 1 complete jmp instruction (with operand)
PVOID pFunc = (PBYTE)pMem + dwOffset;

result = checkByte(0xCC, pFunc, n);
} else {
result = checkByte(0xCC, pMem, n); // when using real addr of function
}

return result;

/* [false positives]
- EncStackInitStart : 
moves 0xCCCCCCCC to [edi] <- mov eax, 0xCCCCCCCC; rep stosd; (only x86)
- 0xCC as data : 
some offset/data can include 0xCC 
(how to detect them, then? -> needs to disassemble the function (WTF))

[false negatives]
- ret (0xC3) in the middle of the function

[shortcomings]
- Detecting function scope with just using machine code

Debugger inserts 0xCC to the start of the instruction to stop at. -> Then, increase index by the size of instruction (WTF2)
*/
}

BOOL isJmpTable(PVOID pMem) {
int i = 0, j = 0;

while (*((PBYTE)pMem + 5 * i) == 0xE9) { // if pattern is `jmp rel32`
i++;
}

while (*((PBYTE)pMem - 5 * j) == 0xE9) {
j++;
}

if (i + j > 0x10) { // false negative: small jmp tables
return 1;
} else {
return 0;
}
}


ํ•จ์ˆ˜ ์ž์ฒด๊ฐ€ high level์˜ ๊ฐœ๋…์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๊ณ„์–ด ์ฝ”๋“œ๋งŒ ๊ฐ–๊ณ  ํŒ๋‹จํ•˜๊ธฐ์—๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ๋‹ค. ํ•จ์ˆ˜์˜ ์ฃผ์†Œ๋กœ๋ถ€ํ„ฐ ์ •ํ•ด์ง„ ๋ฐ”์ดํŠธ ์ˆ˜๋งŒํผ ์ฝ๊ณ  ๊ฒ€์‚ฌํ•˜๋„๋ก ๊ตฌํ˜„ํ• ์ˆ˜๋„, `ret`๊นŒ์ง€๋งŒ ์ฝ๊ณ  ๊ฒ€์‚ฌํ•˜๋„๋ก ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ (์—ญ์‹œ ๋ฆฌ๋ฒ„์„œ ๋งˆ์Œ๋Œ€๋กœ) ์—ฌ๊ธฐ์„œ๋Š” ์ตœ๋Œ€ ์ฃผ์–ด์ง„ ๊ธธ์ด๊นŒ์ง€ ์ฝ๋˜ `ret` ๋ช…๋ น์„ ๋งŒ๋‚˜๋ฉด ๊ฒ€์‚ฌ๋ฅผ ์ข…๋ฃŒํ•˜๋„๋ก ๋งŒ๋“ค์—ˆ๋‹ค. (์‚ฌ์šฉ์ž๊ฐ€ ํ•จ์ˆ˜์˜ ์‹ค์ œ ํฌ๊ธฐ๋ฅผ ๋ชจ๋ฅด๋ฉฐ, ํ•จ์ˆ˜์˜ ํฌ๊ธฐ๋ณด๋‹ค ๋” ํฐ ๊ฐ’์„ ์ธ์ž๋กœ ๋„ฃ์„ ๊ฒƒ์„ ๊ฐ€์ •.)

msvc๋กœ ์ปดํŒŒ์ผํ•˜๋‹ˆ ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ jmp table์„ ๋งŒ๋“ค์–ด ์ฃผ๊ณ , ํ•จ์ˆ˜(์ฃผ์†Œ)๋ฅผ ์ธ์ž๋กœ ์ „๋‹ฌํ•  ๋•Œ์—๋„ ์ด jmp table์˜ ์ฃผ์†Œ๋ฅผ ๋„ฃ์–ด์ค€๋‹ค. ์ด ๋•Œ๋ฌธ์— ํ•จ์ˆ˜์˜ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์—์„œ software bp์˜ ์œ ๋ฌด๋ฅผ ๊ฒ€์‚ฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด jmp table์— ์œ„์น˜ํ•˜๋Š” jmp instruction์˜ ์ธ์ž (offset)์™€ jmp instruction ํ•˜๋‚˜์˜ ํฌ๊ธฐ์ธ 5byte๋ฅผ ์ธ์ž๋กœ ์ฃผ์–ด์ง„ ์ฃผ์†Œ์— ๋”ํ•˜๋ฉด ๋œ๋‹ค. ์ด์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฝ”๋“œ๋Š” `checkBP()` ์•ˆ์— ์œ„์น˜ํ•œ๋‹ค.

DWORD dwOffset = *(DWORD*)((PBYTE)pMem + 1) + 5;
PVOID pFunc = (PBYTE)pMem + dwOffset;


๋ฌผ๋ก  ์ด ๊ฒฝ์šฐ๋„ ๋‚ด ํ™˜๊ฒฝ์— specificํ•œ ๊ตฌํ˜„์ด๊ธฐ ๋•Œ๋ฌธ์— ์“ฐ์‹ค ๋•Œ์—๋Š” ๋ณธ์ธ ํ™˜๊ฒฝ์— ๋งž์ถฐ ์ž˜ ๊ตฌ์„ฑํ•ด ์“ฐ์‹œ๋ฉด ๋˜๊ฒ ๋‹ค. ์ธ์ž๋กœ ์ „๋‹ฌ๋œ ํ•จ์ˆ˜์˜ ์ฃผ์†Œ๊ฐ€ jmp table์˜ ์ฃผ์†Œ์ธ์ง€๋ฅผ ํŒ๋‹จํ•˜๊ธฐ ์œ„ํ•ด `isJmpTable()`์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ด ๋†“์•˜๋Š”๋ฐ, ์•ž ๋’ค๋กœ jmp ๋ช…๋ น์–ด์˜ ๊ฐœ์ˆ˜๋ฅผ ์„ธ์„œ ์ด ๊ฐ’์ด ํŠน์ • ๊ฐ’ ์ด์ƒ์ด๋ผ๋ฉด jmp table๋กœ ํŒ๋‹จํ•œ๋‹ค. (ํœด๋ฆฌ์Šคํ‹ฑ์— ์˜์กด)

๊ตฌํ˜„์ด ๋‹จ์ˆœํ• ์ˆ˜๋ก false positive๊ฐ€ ๋งŽ์•„์ง€๋Š” ๋ฐฉ๋ฒ•์ด๋ฏ€๋กœ ๊ธฐ๊ณ„์–ด ์ฝ”๋“œ๋ฅผ instruction ๋‹จ์œ„๋กœ ์ฒ˜๋ฆฌํ•  ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๋ฉด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•˜์ง€ ์•Š๋Š”๋‹ค. false positive์˜ ํ•œ ์˜ˆ์‹œ๋กœ, msvc x86 debug mode๋กœ ์ปดํŒŒ์ผํ•˜๋ฉด ๊ธฐ๋ณธ `/RTC` ์˜ต์…˜์ด ์ถ”๊ฐ€๋˜์–ด ์•„๋ž˜์™€ ๋น„์Šทํ•œ ์–ด์…ˆ๋ธ”๋ฆฌ์–ด ์ฝ”๋“œ๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค. (uninitialized stack memory๋ฅผ ๊ตฌ๋ณ„ํ•˜๊ธฐ ์œ„ํ•จ)
```asm
mov edi, ebp
mov eax, 0xCCCCCCCC
rep stosd
```
`checkByte()`๋Š” ์œ„ ์ฝ”๋“œ์˜ ๋ฐ์ดํ„ฐ๋กœ ๋“ค์–ด๊ฐ„ 0xCC ๋ฐ”์ดํŠธ๋ฅผ ์ฝ๊ณ  software bp๋ผ ํŒ๋‹จํ•˜์—ฌ true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋ฐ์ดํ„ฐ์™€ ์ฝ”๋“œ๋ฅผ ์ •๊ตํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•˜๋ ค๋ฉด ์ธ์ž๋กœ ๋ฐ›์€ ํ•จ์ˆ˜์˜ ์ฝ”๋“œ๋ฅผ instruction ๋‹จ์œ„๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ์•ผ ํ•˜๋ฉฐ, ์ด ๋ฐฉ์‹์€ ํ•จ์ˆ˜ ๋‚ด์—์„œ ๋ช…๋ น์–ด์˜ ์ค‘๊ฐ„์œผ๋กœ jmpํ•˜๋Š” ๊ฒฝ์šฐ ๋ถˆ์™„์ „ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.


###### + TODO!("x86 release, x86-64 debug-release ๋ชจ๋“œ์— ๋Œ€ํ•œ software bp detection code ์ž‘์„ฑ for msvc & gcc"), ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…์ด๋ผ๋„..


## 3. Hardware Breakpoint Detection
 Hardware breakpoint๋Š” thread์˜ debug register์— ์‹คํ–‰์„ ๋ฉˆ์ถ”๊ณ ์ž ํ•˜๋Š” ์ฃผ์†Œ๋ฅผ ๋„ฃ๋Š” ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. Hardware bp๋Š” thread ๋‚ด์—์„œ Dr0~Dr3์— ์ €์žฅ๋œ ์ฃผ์†Œ์— ์ ‘๊ทผ/์“ฐ๊ธฐ/์‹คํ–‰ ๋“ฑ์˜ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ single step interrupt (INT1)๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•œ๋‹ค. (Hardware bp mechanism์ด ํ˜„์žฌ ์‹คํ–‰๋˜๋Š” ๋ช…๋ น์˜ ์ฃผ์†Œ๋ฅผ ๊ณ„์†ํ•ด์„œ ํ™•์ธํ•จ) Hardware bp์— ์˜ํ•ด INT1 ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, JTAG module์ด ํ”„๋กœ์„ธ์„œ์˜ ์ œ์–ด๊ถŒ์„ ๊ฐ€์ ธ๊ฐ„๋‹ค. Software breakpoint์™€ ๋‹ค๋ฅด๊ฒŒ hardware breakpoint๋Š” ์•„ํ‚คํ…์ฒ˜์— ์˜์กด์ ์ด๋ฏ€๋กœ, cpu ์„ค๊ณ„์— ๋”ฐ๋ผ ์ž‘๋™ ๋ฐฉ์‹์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค. ๋ณธ ๋ฌธ์„œ์—์„œ๋Š” Intel x86์„ ๊ธฐ์ค€์œผ๋กœ ์„ค๋ช…ํ•  ๊ฒƒ์ด๋‹ค.


### 1) Debug Registers
Intel x86์—๋Š” ์ด 7๊ฐœ์˜ debug register๊ฐ€ ์กด์žฌํ•œ๋‹ค. (Dr0 ~ Dr7). winnt.h ํ—ค๋” ํŒŒ์ผ์— ์ •์˜๋˜์–ด ์žˆ๋Š” `CONTEXT` ๊ตฌ์กฐ์ฒด์˜ Dr0 ~ Dr7์ด ๋ฐ”๋กœ debug register์ด๋‹ค. ์•„๋ž˜๋Š” `CONTEXT` ๊ตฌ์กฐ์ฒด์˜ ์›ํ˜•. winnt.h์— ์ฃผ์„์œผ๋กœ ์„ค๋ช…์ด ์ž˜ ๋˜์–ด์žˆ๋‹ค.

typedef struct DECLSPEC_NOINITALL _CONTEXT {
    DWORD ContextFlags;

    DWORD   Dr0;
    DWORD   Dr1;
    DWORD   Dr2;
    DWORD   Dr3;
    DWORD   Dr6;
    DWORD   Dr7;

    FLOATING_SAVE_AREA FloatSave;
    
    DWORD   SegGs;
    DWORD   SegFs;
    DWORD   SegEs;
    DWORD   SegDs;
    
    DWORD   Edi;
    DWORD   Esi;
    DWORD   Ebx;
    DWORD   Edx;
    DWORD   Ecx;
    DWORD   Eax;

    DWORD   Ebp;
    DWORD   Eip;
    DWORD   SegCs;
    DWORD   EFlags;
    DWORD   Esp;
    DWORD   SegSs;

    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];

} CONTEXT;


Dr0~Dr3 ๋ ˆ์ง€์Šคํ„ฐ์—๋Š” hardware bp๋ฅผ ์„ค์ •ํ•  ์„ ํ˜• ์ฃผ์†Œ(linear address)๊ฐ€ ์ €์žฅ๋œ๋‹ค. Dr6์—๋Š” ๋น„ํŠธ ๋‹จ์œ„๋กœ debug status๊ฐ€ ์ €์žฅ๋˜๋Š”๋ฐ, ์ด๋Š” debug exception handler๋กœ ์ œ์–ด๊ถŒ์ด ๋„˜์–ด๊ฐ€๊ธฐ ์ „์— ์„ค์ •๋œ๋‹ค. Dr6์˜ ๊ฐ ๋น„ํŠธ๊ฐ€ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

###### +TODO!("์•„๋ž˜ ํ‘œ ์ •๋ฆฌ")

| Bits  | Abbreviation  | Description                                                                                                                                                                                                                                                                                                                              |
| ----- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0     | B0            | Breakpoint #0 (Dr0) Condition Detected                                                                                                                                                                                                                                                                                                   |
| 1     | B1            | Breakpoint #1 (Dr1) Condition Detected                                                                                                                                                                                                                                                                                                   |
| 2     | B2            | Breakpoint #2 (Dr2) Condition Detected                                                                                                                                                                                                                                                                                                   |
| 3     | B3            | Breakpoint #3 (Dr3) Condition Detected                                                                                                                                                                                                                                                                                                   |
| 10:4  | —             | Reserved.  <br>Read as all-0s on 386/486 processors, all-1s on later processors.                                                                                                                                                                                                                                                         |
| 11    | BLD           | Cleared to 0 by the processor for Bus Lock Trap exceptions.<br>On processors that don't support Bus Lock Trap exceptions, bit 11 of DR6 is a read-only bit, acting in the same way as bits 10:4.                                                                                                                                         |
| 12    | BK,  <br>SMMS | (386/486 only) SMM or ICE mode entered (see also DR7, bit 12).  <br>Reserved and read as 0 on all later processors.                                                                                                                                                                                                                      |
| 13    | BD            | Debug Register Access Detected (see also DR7, bit 13). (Never cleared by hardware - manually cleaning this bits in debug handler is recommended)                                                                                                                                                                                         |
| 14    | BS            | Single-Step execution (enabled by EFLAGS.TF) (Never cleared by hardware - manually cleaning this bits in debug handler is recommended)(Never cleared by hardware - manually cleaning this bits in debug handler is recommended)                                                                                                          |
| 15    | BT            | Task Switch breakpoint.<br>Occurs when a task switch is done with a [TSS](https://en.wikipedia.org/wiki/Task_state_segment "Task state segment") that has the T (debug trap flag) bit set. (Never cleared by hardware - manually cleaning this bits in debug handler is recommended)                                                     |
| 16    | RTM           | (Processors with [Intel TSX](https://en.wikipedia.org/wiki/Intel_TSX "Intel TSX") only)  <br>Cleared to 0 by the processor for debug exceptions inside RTM transactions, set to 1 for all debug exceptions outside transactions.  <br>On processors without TSX, bit 16 of DR6 is a read-only bit, acting in the same way as bits 31:17. |
| 31:17 | —             | Reserved.  <br>Read as all-0s on 386/486/6x86 processors, all-1s on later processors.                                                                                                                                                                                                                                                    |
| 63:32 | —             | (x86-64 only) Reserved.  <br>Read as all-0s. Must be written as all-0s.                                                                                                                                                                                                                                                                  |
(์ถœ์ฒ˜: [Wikipedia - x86 debug register](https://en.wikipedia.org/wiki/X86_debug_register))

Dr7์€ debug control register๋กœ, ๊ฐ ๋น„ํŠธ๋Š” ๊ฐ hardware bp์— ๋Œ€ํ•œ ์ค‘๋‹จ ์กฐ๊ฑด์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฐ์— ์‚ฌ์šฉ๋œ๋‹ค. ๊ฐ ๋น„ํŠธ ํ•„๋“œ์˜ ์˜๋ฏธ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

| Bits  | Abbreviation  | Description                                                                                                                                                                                                                                                             |
| ----- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0     | L0            | Local enable for breakpoint #0.                                                                                                                                                                                                                                         |
| 1     | G0            | Global enable for breakpoint #0.                                                                                                                                                                                                                                        |
| 2     | L1            | Local enable for breakpoint #1.                                                                                                                                                                                                                                         |
| 3     | G1            | Global enable for breakpoint #1.                                                                                                                                                                                                                                        |
| 4     | L2            | Local enable for breakpoint #2.                                                                                                                                                                                                                                         |
| 5     | G2            | Global enable for breakpoint #2.                                                                                                                                                                                                                                        |
| 6     | L3            | Local enable for breakpoint #3.                                                                                                                                                                                                                                         |
| 7     | G3            | Global enable for breakpoint #3.                                                                                                                                                                                                                                        |
| 8     | LE            | (386 only) Local Exact Breakpoint Enable.                                                                                                                                                                                                                               |
| 9     | GE            | (386 only) Global Exact Breakpoint Enable.                                                                                                                                                                                                                              |
| 10    | —             | Reserved, read-only, read as 1 and should be written as 1.                                                                                                                                                                                                              |
| 11    | RTM           | (Processors with [Intel TSX](https://en.wikipedia.org/wiki/Intel_TSX "Intel TSX") only)  <br>Enable advanced debugging of RTM transactions (only if `DEBUGCTL` bit 15 is also set)  <br>On other processors: reserved, read-only, read as 0 and should be written as 0. |
| 12    | IR,  <br>SMIE | (386/486 processors only) Action on breakpoint match:  <br>0 = INT 1 (#DB exception, default)  <br>1 = Break to ICE/SMM<br>On other processors: Reserved, read-only, read as 0 and should be written as 0.                                                              |
| 13    | GD            | General Detect Enable. If set, will cause a debug exception on any attempt at accessing the DR0-DR7 registers.                                                                                                                                                          |
| 15:14 | —             | Reserved, should be written as all-0s.                                                                                                                                                                                                                                  |
| 17:16 | R/W0          | Breakpoint condition for breakpoint #0.                                                                                                                                                                                                                                 |
| 19:18 | LEN0          | Breakpoint length for breakpoint #0.                                                                                                                                                                                                                                    |
| 21:20 | R/W1          | Breakpoint condition for breakpoint #1.                                                                                                                                                                                                                                 |
| 23:22 | LEN1          | Breakpoint length for breakpoint #1.                                                                                                                                                                                                                                    |
| 25:24 | R/W2          | Breakpoint condition for breakpoint #2.                                                                                                                                                                                                                                 |
| 27:26 | LEN2          | Breakpoint length for breakpoint #2.                                                                                                                                                                                                                                    |
| 29:28 | R/W3          | Breakpoint condition for breakpoint #3.                                                                                                                                                                                                                                 |
| 31:30 | LEN3          | Breakpoint length for breakpoint #3.                                                                                                                                                                                                                                    |
| 32    | DR0_PT_LOG    | Enable DR0/1/2/3 breakpoint match as a trigger input for PTTT (Processor Trace Trigger Tracing).<br><br>Read as 0 and must be written as all-0s on processors that don't support PTTT.                                                                                  |
| 33    | DR1_PT_LOG    | "                                                                                                                                                                                                                                                                       |
| 34    | DR2_PT_LOG    | "                                                                                                                                                                                                                                                                       |
| 35    | DR3_PT_LOG    | "                                                                                                                                                                                                                                                                       |
| 63:36 | —             | (x86-64 only) Reserved.  <br>Read as all-0s. Must be written as all-0s.                                                                                                                                                                                                 |
  
Breakpoint condition representation in bits:

|Value|Break on|
|---|---|
|`00b`|Instruction execution only|
|`01b`|Data writes only|
|`10b`|I/O reads and writes  <br>(only defined if [CR4.DE](https://en.wikipedia.org/wiki/Control_register#CR4 "Control register")=1)|
|`11b`|Data reads and writes|

Breakpoint length representation in bits:

|Value|Breakpoint length|
|---|---|
|`00b`|1 byte|
|`01b`|2 bytes|
|`10b`|8 bytes  <br>(only defined in 64-bit mode)|
|`11b`|4 bytes|

Dr4์™€ Dr5๋Š” ์‹ค์ œ ๋ ˆ์ง€์Šคํ„ฐ๊ฐ€ ์•„๋‹ˆ๋‹ค. CR4.DE bit์„ ์ง€์›ํ•˜๋Š” CPU (Intel Pentium ์ดํ›„)์—์„œ Dr4/5์˜ ํ–‰๋™์€ CR4.DE์— ์˜ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜๋œ๋‹ค.
CR4.DE = 0: Dr4์™€ Dr5๋Š” Dr6, Dr7์˜ alias๋‹ค.
CR4.DE = 1: Dr4/5์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์€ UD (undefined instruction) exception์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

Debug register๋Š” ํ•œ์ •๋œ ์ž์›์ด๊ธฐ ๋•Œ๋ฌธ์— debug register์— ๊ฐ’์„ ์“ฐ๋Š” ๊ฒฝ์šฐ, ring 0 (kernel mode)์˜ ๊ถŒํ•œ์ด ํ•„์š”ํ•˜๋‹ค. (๋‚ฎ์€ ๊ถŒํ•œ์—์„œ debug register์— ์ ‘๊ทผ ์‹œ general protection fault ๋ฐœ์ƒ)
#### (1) GetThreadContext()
##### (a) GetThreadContext() Example
Windows๊ฐ€ ์ œ๊ณตํ•˜๋Š” `GetThreadContext()` API๋ฅผ ์‚ฌ์šฉํ•ด์„œ thread์˜ context๋ฅผ ์–ป์–ด์˜ฌ ์ˆ˜ ์žˆ๋‹ค. Context์— ํฌํ•จ๋œ debug register๋ฅผ ํ™•์ธํ•˜์—ฌ hardware breakpoint๊ฐ€ ์„ค์ •๋˜์—ˆ๋Š”์ง€ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋‹ค.

์•„๋ž˜๋Š” thread์˜ context๋ฅผ ๋ฐ›์•„์™€ ์ฝ๋Š” C ์ฝ”๋“œ์ด๋‹ค.

// x86 debug, VS19
#include <stdio.h>
#include <Windows.h>
#include <errhandlingapi.h>

int main() {
CONTEXT ctx;

DWORD threadId = GetCurrentThreadId();
HANDLE hThread = OpenThread(THREAD_GET_CONTEXT, FALSE, threadId);

DWORD e = GetLastError();
if(e) {
printf("error info: 0x%x\n", e);
}

printf("ThreadId: %x\n", threadId);
printf("hThread: %p\n", hThread);

// ContextFlags๋ฅผ ๋จผ์ € ์„ค์ • ์•ˆ ํ•ด์ฃผ๋ฉด 0x3eb ์˜ค๋ฅ˜ ๋ฐœ์ƒ
ctx.ContextFlags = CONTEXT_ALL;

if (GetThreadContext(hThread, &ctx) != 0) {
printf("\n");

printf("[registers]\n");
printf("Eip: 0x%08x\n", ctx.Eip);
printf("Ebp: 0x%08x\n", ctx.Ebp);
printf("Esp: 0x%08x\n", ctx.Esp);
printf("Eax: 0x%08x\n\n", ctx.Eax);

printf("[debug registers]\n");
printf("Dr0: 0x%08x\n", ctx.Dr0);
printf("Dr1: 0x%08x\n", ctx.Dr1);
printf("Dr2: 0x%08x\n", ctx.Dr2);
printf("Dr3: 0x%08x\n", ctx.Dr3);
printf("Dr6: 0x%08x\n", ctx.Dr6);
printf("Dr7: 0x%08x\n", ctx.Dr7);

} else {
printf("failed to get the context\n");
e = GetLastError();
printf("error info: 0x%x\n", e);
}

}


`GetThreadId()`๋กœ ํ˜„์žฌ thread์˜ ID๋ฅผ ์–ป์–ด์˜จ ๋‹ค์Œ, `OpenThread()`๋กœ ์ด thread์— ๋Œ€ํ•ด `THREAD_GET_CONTEXT` ๊ถŒํ•œ์„ ๊ฐ€์ง„ ํ•ธ๋“ค์„ ๋ฐ›์•„์˜จ๋‹ค. `GetThreadContext()`๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์—, `CONTEXT` ๊ตฌ์กฐ์ฒด์˜ `ContextFlags` ๋ฉค๋ฒ„๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค. (`GetThreadContext()`๋Š” `Context.ContextFlags` ๋ฉค๋ฒ„๋ฅผ ์ฝ๊ณ  context์— ์ €์žฅํ•ด์•ผ ํ•  ๋ถ€๋ถ„์„ ํŒ๋‹จํ•˜๊ธฐ ๋•Œ๋ฌธ.) ์ด ์˜ˆ์ œ์—์„œ๋Š” ๋‹จ์ˆœํžˆ context ์ •๋ณด ์ „์ฒด๋ฅผ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•ด `CONTEXT_ALL`์„ ์‚ฌ์šฉํ•˜์˜€์œผ๋‚˜, debug register๋งŒ ์–ป์–ด์˜ค๊ธฐ ์œ„ํ•ด์„œ๋Š” `CONTEXT_DEBUG_REGISTERS`๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
###### (a-1) CONTEXT.ContextFlags ๊ฐ’
ContextFlags์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒ์ˆ˜ ๊ฐ’๋“ค์ด ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. (winnt.h ์ฐธ๊ณ )

#define CONTEXT_CONTROL         (CONTEXT_i386 | 0x00000001L) // SS:SP, CS:IP, FLAGS, BP
#define CONTEXT_INTEGER         (CONTEXT_i386 | 0x00000002L) // AX, BX, CX, DX, SI, DI
#define CONTEXT_SEGMENTS        (CONTEXT_i386 | 0x00000004L) // DS, ES, FS, GS
#define CONTEXT_FLOATING_POINT  (CONTEXT_i386 | 0x00000008L) // 387 state
#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L) // DB 0-3,6,7
#define CONTEXT_EXTENDED_REGISTERS  (CONTEXT_i386 | 0x00000020L) // cpu specific extensions

#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS)

#define CONTEXT_ALL            (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS)

#define CONTEXT_XSTATE          (CONTEXT_i386 | 0x00000040L)

#define CONTEXT_EXCEPTION_ACTIVE    0x08000000L
#define CONTEXT_SERVICE_ACTIVE      0x10000000L
#define CONTEXT_EXCEPTION_REQUEST   0x40000000L
#define CONTEXT_EXCEPTION_REPORTING 0x80000000L


`Context.ContextFlags`๋ฅผ ์„ค์ •ํ–ˆ์œผ๋ฉด, `GetThreadContext()`๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ context๋ฅผ ๋ฐ›์•„์˜จ๋‹ค. ๊ทธ ๋’ค์— context์˜ ๊ฐ ๋ฉค๋ฒ„์— ์ ‘๊ทผํ•˜์—ฌ ์–ด๋–ค ๊ฐ’์ด ์ €์žฅ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

debugger๋ฅผ ๋ถ™์—ฌ hardware bp๋ฅผ ์„ค์ •ํ•˜๊ณ  ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด๊ธธ ๋ฐ”๋ž€๋‹ค.

ThreadId: 54a0
hThread: 00000140

[registers]
Eip: 0x77637b0c
Ebp: 0x0133f71c
Esp: 0x0133f710
Eax: 0x00000000

[debug registers]
Dr0: 0x00191994
Dr1: 0x00195607
Dr2: 0x00000000
Dr3: 0x00000000
Dr6: 0xffff0ff0
Dr7: 0x00000005


๋””๋ฒ„๊ฑฐ๋ฅผ ๋ถ™์—ฌ ์‹คํ–‰ํ•˜๋ฉด ์œ„์™€ ๊ฐ™์ด ์„ค์ •๋œ hardware bp๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด์ œ ์ด ์ •๋ณด๋ฅผ ์ฝ์–ด์„œ anti-debugging์— ์ ์šฉํ•ด๋ณด์ž.
##### (b) Anti-debugging with GetThreadContext()
๊ฐ„๋‹จํžˆ Dr0 ~ Dr3์— 0์ด ์•„๋‹Œ ๊ฐ’์ด ๋“ค์–ด์žˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ์„ ์ข…๋ฃŒ์‹œํ‚ค๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜์˜ ์ฝ”๋“œ๋Š” hardware breakpoint check๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

// x86 debug, VS19
#include <stdio.h>
#include <Windows.h>
#include <errhandlingapi.h>

int main() {
CONTEXT ctx;

DWORD threadId = GetCurrentThreadId();
HANDLE hThread = OpenThread(THREAD_GET_CONTEXT, FALSE, threadId);

ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;

if (GetThreadContext(hThread, &ctx) != 0) {
if ((ctx.Dr0 | ctx.Dr1 | ctx.Dr2 | ctx.Dr3) != 0) {
printf("Hardware breakpoint detected.\n");
} else {
printf("Hardware breakpoint not detected.\n");
}

}
else {
printf("failed to get the context\n");
DWORD e = GetLastError();
printf("error info: 0x%x\n", e);
}

}


์ง์ ‘ ๋””๋ฒ„๊น…ํ•ด๋ณด๋ฉฐ ํŒ๋‹จํ•˜๊ธธ ๋ฐ”๋ž€๋‹ค.


#### (2) Set SEH to check debug registers


## 4. Single Step Check
### 1) Trap Flag (TF)
### 2) PUSHFD/POPFD
### 3) INT 2D

## 5. Timing Check
### 1) RDTSC
### 2) QueryPerformanceCount()
### 3) GetTickCount()
### 4) timeGetTime()
#### (1) \_ftime()

## 6. Patching Detection
### 1) Scanning 0xCC
### 2) Checksum

## 7. Anti-Disassembly
### 1) Jump Over Invalid Bytes
### 2) Instruction Nesting
## 8. PE Image Switching

## 9. Self-Execution

## 10. Self-Debugging

## 11. Nanomite

## 12. Code Obfuscation

## 13. Encryption/Decryption

## 14. Stolen Bytes

## 15. Multi-Threaded Packers

## 16. Code Virtualization

## 17. API Redirection

## 18. API Wrapping

## 19. ptrace (linux)

## 20. Platform-Independent Program (PIP)

## 21. Execution-based Steganography
# Static Anti-Reversing Techniques
## 1. PEB
### 1) PEB.BeingDebugged (PEB + 0x02)
### 2) PEB.Ldr (PEB + 0x0C)

### 3) PEB.ProcessHeap (PEB + 0x18)
#### (1) SegmentFlags (\_Heap + 0x0C)
#### (2) SegmentListEntry (\_Heap + 0x10)

#### (3) Flags (\_Heap + 0x40)

#### (4) ForceFlags (\_Heap + 0x44)

### 4) NtGlobalFlag (PEB + 0x68)

## 2. TEB

## 3. Native APIs
### 1) ntdll!NtQueryInformationProcess(), ntdll!ZwQueryInformationProcess()

### 2) ntdll!NtQuerySystemInformation()

### 3) ntdll!NtQueryObject()

### 4) SeDebugPrivilege()

## 4. TLS callback function

## 5. Using Normal APIs
### 1) FindWindow(), FindWindowEx() (Window Name)

### 2) Process32First(), Process32Next() (Parent Process)

# Attacking Debugger
## 1. ntdll!NtSetInformationThread(), ntdll!ZwSetInformationThread()

## 2. user32!BlockInput()

## 3. Disable breakpoints

## 4. kernel32!UnhandledExceptionFilter()

## 5. Exploit Format String Vulns in debugger

## 6. Set

 

๊ท€์ฐฎ์•„์„œ ์•„์ง ์—…๋ฐ์ดํŠธ ์•ˆ ํ•œ ๊ธ€๋“ค์ด ์‚ฐ๋”๋ฏธ์ž…๋‹ˆ๋‹ค. ์•ˆํ‹ฐ ๋ฆฌ๋ฒ„์‹ฑ ๊ธฐ๋ฒ• ์ค‘์—๋Š” ์žฌ๋ฏธ์žˆ๋Š” ๊ฒƒ์ด ์•„์ฃผ ๋งŽ์œผ๋‹ˆ ํ•œ ๋ฒˆ์”ฉ ์‹คํ—˜ํ•ด๋ณด์„ธ์š”.

๊ฐœ์ธ ์˜ต์‹œ๋””์–ธ์— ๋งˆํฌ๋‹ค์šด ํ˜•์‹์œผ๋กœ ์ •๋ฆฌํ–ˆ๋˜ ๊ฒƒ๋“ค์ด๋ผ html ํ™˜๊ฒฝ์—์„œ๋Š” ๊ฐ€๋…์„ฑ์ด ์ข€ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

์•„๋งˆ 2025๋…„์ด ๋๋‚  ์ฆˆ์Œ์—๋Š” ์™„์„ฑ๋˜์–ด ์žˆ์ง€ ์•Š์„๊นŒ... ๋ผ๊ณ  ์ƒ๊ฐ๋ฉ๋‹ˆ๋‹ค.