πŸ” Anti-Debugging, VM λ‚œλ…ν™” ꡬ쑰, CrackMe μ˜ˆμ‹œ

리버싱 기둝


πŸ“Œ 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

MalClownμ—μ„œ 더 μ•Œμ•„λ³΄κΈ°

μ§€κΈˆ κ΅¬λ…ν•˜μ—¬ 계속 읽고 전체 μ•„μΉ΄μ΄λΈŒμ— μ•‘μ„ΈμŠ€ν•˜μ„Έμš”.

계속 읽기