리λ²μ± κΈ°λ‘
π 1. Anti-Debugging μ¬ν λΆμ
κΈ°λ³Έμ μΈ IsDebuggerPresent νΈμΆμ λμ΄μ, μ€μ ν¬λλ―Έλ μ μ±μ½λμμ μμ£Ό μ¬μ©νλ μν° λλ²κΉ κΈ°λ² μ 리.
π§© (1) PEB μ§μ μ κ·Ό κΈ°λ° Anti-Debugging
PEB ꡬ쑰체 λ΄λΆμ BeingDebugged νλκ·Έλ₯Ό μ§μ μ½μ΄μ λλ²κ±° μ¬λΆ νμΈνλ λ°©μ.
#include <stdio.h>
int main() {
unsigned char *peb = (unsigned char*)__readfsdword(0x30);
unsigned char BeingDebugged = peb[2]; // PEB + 0x2
if (BeingDebugged)
printf("Debugger detected via PEB check!\n");
else
printf("No debugger detected.\n");
}
μμ½
- __readfsdword(0x30) β x86 νκ²½μμ PEB μ£Όμ μ»λ λ°©μ
- peb[2] = BeingDebugged νλκ·Έ
- κ°μ΄ 1μ΄λ©΄ λλ²κ±° μ‘΄μ¬
ASM νλ¦
mov eax, fs:[30h] mov al, [eax+2] test al, al jnz debugger_found
λΆμ κ΄μ
- [eax+2] κ°μ 0μΌλ‘ ν¨μΉνλ λ°©μ
- λλ jnz β jz λ°μ
π§© (2) NtQueryInformationProcess κΈ°λ° νμ§
Native APIλ₯Ό μ΄μ©ν΄ λλ²κ·Έ νλκ·Έ νμΈνλ λ°©μ.
#include <Windows.h>
#include <winternl.h>
typedef NTSTATUS (WINAPI *PFN)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
int main() {
PFN NtQueryInformationProcess =
(PFN)GetProcAddress(GetModuleHandleA("ntdll"), "NtQueryInformationProcess");
DWORD flags = 0;
NtQueryInformationProcess(GetCurrentProcess(),
0x1f,
&flags, sizeof(flags), NULL);
if (flags == 0)
printf("Debugger detected (DebugFlags == 0)\n");
else
printf("No debugger detected.\n");
}
μμ½
- ProcessDebugFlags = 0 β λλ²κ±° μ‘΄μ¬
- κ°μ κ°μ λ‘ 1λ‘ ν¨μΉνλ λ°©μ
π§© (3) Timing κΈ°λ° Anti-Debugging
#include <Windows.h>
int main() {
DWORD t1 = GetTickCount();
for (volatile int i = 0; i < 10000000; i++);
DWORD t2 = GetTickCount();
if ((t2 - t1) > 50)
printf("Debugger likely detected.\n");
else
printf("Normal execution.\n");
}
μμ½
- λλ²κΉ μ 루ν μ€ν μκ° μ¦κ° β threshold μ΄μμ΄λ©΄ νμ§
- νμ΄λ° λΉκ΅λ¬Έ ν¨μΉ λ°©μ
π 2. VM κΈ°λ° λλ ν ꡬ쑰 λΆμ
μ½λλ₯Ό μ§μ μ€ννμ§ μκ³ VM λͺ λ Ή μ§ν©(bytecode)μΌλ‘ λ³ννμ¬ νΈλ€λ¬ μμμ μ€ννλ λ°©μ. λμ΄λ λμ λλ ν κΈ°λ².
𧩠(1) VM Dispatcher ꡬ쑰
VM_Dispatch:
movzx eax, byte [esi]
inc esi
jmp [HandlerTable + eax*4]
μμ½
- esi = VM λ°μ΄νΈμ½λ ν¬μΈν°
- opcode = [esi]
- HandlerTable[opcode] β ν΄λΉ μ°μ° νΈλ€λ¬λ‘ μ ν
π§© (2) VM Handler μμ
Handler_ADD:
mov edx, [stack_top]
mov ecx, [stack_top - 4]
add ecx, edx
mov [stack_top - 4], ecx
sub stack_top, 4
jmp VM_Dispatch
μμ½
- μ€ν μλ¨ λ κ° pop β add μ°μ°
- κ²°κ³Όλ₯Ό pushνλ ꡬ쑰
- Dispatcherλ‘ λ³΅κ·
λΆμ κ΄μ
- νΈλ€λ¬ κΈ°λ₯μ ν μ΄λΈννμ¬ μλ―Έ λ§€ν
- λ°μ΄νΈμ½λλ₯Ό μμ°¨ λΆμνμ¬ μλ λ‘μ§ λ³΅μ
π 3. CrackMe μμ
π (1) Anti-Debugging μ°ν
CALL IsDebuggerPresent TEST EAX, EAX JNZ fail
μμ½
- EAX != 0 β λλ²κ±° νμ§
- JNZ β JZ ν¨μΉ λ°©μ
π (2) Serial κ²μ¦ λ£¨ν΄ λΆμ
xor eax, eax
mov ecx, [input]
xor_loop:
mov dl, [ecx]
test dl, dl
jz check_end
xor al, dl
inc ecx
jmp xor_loop
check_end:
cmp al, 3Ch
je correct
jmp fail
μμ½
- λ¬Έμ λ°λ³΅ XOR λμ λ°©μ
- κ²°κ³Όκ° == 0x3C β correct
β μμ μ λ΅
ABCDEF<
μ 리:
- Anti-Debuggingμ API κ²μ¬ β PEB β νμ΄λ° κ²μ¬ μμΌλ‘ κ³ λν
- VM λλ νλ Dispatcher/Handler ꡬ쑰 νμ μ΄ ν΅μ¬
- CrackMeλ μμ±μμ μλ νμ μ€μ¬ λΆμ
πWritten by Code & Compass