๐Ÿ” PE ํŒŒ์ผ์˜ Import Table ์žฌ๊ตฌ์„ฑ ํ๋ฆ„

์•…์„ฑ์ฝ”๋“œ๋‚˜ ํŒจ์ปค๊ฐ€ ์ ์šฉ๋œ ์‹คํ–‰ ํŒŒ์ผ์„ ๋ถ„์„ํ•˜๋‹ค ๋ณด๋ฉด,
๊ฐ€์žฅ ๋จผ์ € ๋ฌด๋„ˆ์ ธ ์žˆ๋Š” ๋ถ€๋ถ„์ด Import Table์ž…๋‹ˆ๋‹ค.
์˜ค๋Š˜์€ Import Table์ด ํ›ผ์†๋œ PE ํŒŒ์ผ์„ ์–ด๋–ป๊ฒŒ ์žฌ๊ตฌ์„ฑํ•˜๋Š”์ง€,
๊ทธ๋ฆฌ๊ณ  ์•…์„ฑ์ฝ”๋“œ๊ฐ€ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ Import๋ฅผ ์ˆจ๊ธฐ๋Š”์ง€ ๊ธฐ๋ก ์ค‘์‹ฌ์œผ๋กœ ์ •๋ฆฌํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

๋ฆฌ๋ฒ„์‹ฑ ๊ธฐ๋ก


## 1) ๐Ÿ“Œ ๋™์  ๋กœ๋”ฉ ๊ธฐ๋ฐ˜ Import ์€๋‹‰ ๊ธฐ๋ฒ•

๋Œ€ํ‘œ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” API๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • LoadLibraryA / LoadLibraryW
  • GetProcAddress
  • LdrLoadDll
  • LdrGetProcedureAddress

์•…์„ฑ์ฝ”๋“œ์—์„œ ๋งŽ์ด ๋ณด์ด๋Š” ์ „ํ˜•์ ์ธ C ๊ตฌ์กฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.


## 2) ๐Ÿ”ง C ์ฝ”๋“œ ์˜ˆ์‹œ โ€” API ํ•ด์‹œ ๊ธฐ๋ฐ˜ ๋™์  ๋กœ๋”ฉ

DWORD hash(char* s) {
    DWORD h = 0;
    while (*s) {
        h = ((h << 5) + h) + *s;
        s++;
    }
    return h;
}

FARPROC resolve(const char* dll, DWORD func_hash) {
    HMODULE mod = LoadLibraryA(dll);
    if (!mod) return NULL;

    PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)mod;
    PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((BYTE*)mod + dos->e_lfanew);

    DWORD rva = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    PIMAGE_EXPORT_DIRECTORY exp = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)mod + rva);

    DWORD* names = (DWORD*)((BYTE*)mod + exp->AddressOfNames);
    WORD* ord   = (WORD*)((BYTE*)mod + exp->AddressOfNameOrdinals);
    DWORD* funcs = (DWORD*)((BYTE*)mod + exp->AddressOfFunctions);

    for (DWORD i = 0; i < exp->NumberOfNames; i++) {
        char* name = (char*)mod + names[i];
        if (hash(name) == func_hash) {
            return (FARPROC)((BYTE*)mod + funcs[ord[i]]);
        }
    }
    return NULL;
}

๐Ÿ” ์ƒ์„ธ ๋ถ„์„

  • hash()๋Š” ์ด๋ฆ„ ๊ธฐ๋ฐ˜ ํ•ด์‹œ ์ƒ์„ฑ
  • Export Directory๋ฅผ ์ง์ ‘ ์ˆœํšŒ
  • ๋ฌธ์ž ๋น„๊ต ๋Œ€์‹  ํ•ด์‹œ ๋น„๊ต๋กœ ํƒ์ง€ ํšŒํ”ผ
  • ์‹ค์ œ ์•…์„ฑ์ฝ”๋“œ์—์„œ ๊ฐ€์žฅ ํ”ํ•˜๊ฒŒ ์“ฐ์ž„
  • ์ •์  ๋ถ„์„ ๋„๊ตฌ๊ฐ€ Import๋ฅผ ์žฌ๊ตฌ์„ฑํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“œ๋Š” ๊ตฌ์กฐ

## 3) ๐Ÿ”ง Assembly ์˜ˆ์‹œ โ€” Export ๊ตฌ์กฐ ์ง์ ‘ ์ฐธ์กฐ

mov     ebx, [LoadLibraryA]
push    offset dll_name
call    ebx

mov     esi, eax                ; module base
mov     edi, [esi+3Ch]          ; e_lfanew
add     edi, esi                ; PE header

mov     eax, [edi+78h]          ; RVA of export directory
add     eax, esi                ; export directory VA

mov     ecx, [eax+18h]          ; NumberOfNames
mov     edx, [eax+20h]          ; AddressOfNames
add     edx, esi

next_name:
    mov     ebx, [edx]
    add     ebx, esi            ; name address
    push    ebx
    call    hash_function
    cmp     eax, target_hash
    je      found
    add     edx, 4
    loop    next_name

๐Ÿ” ๋ ˆ์ง€์Šคํ„ฐ ๊ธฐ๋ฐ˜ ์ƒ์„ธ ์„ค๋ช…

  • esi = ๋ชจ๋“ˆ ๋ฒ ์ด์Šค
  • edi = NT Header ์‹œ์ž‘
  • eax = Export Directory ์ฃผ์†Œ
  • ecx = ์ด๋ฆ„ ๊ฐœ์ˆ˜
  • API ์ด๋ฆ„ ํ•˜๋‚˜์”ฉ ์ˆœํšŒํ•˜๋ฉฐ ํ•ด์‹œ ๋น„๊ต
  • ์‹ค์ œ ํŒจ์ปค๋“ค์ด ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹

## 4) ๐Ÿ“Œ Import Table ์žฌ๊ตฌ์„ฑ ํ๋ฆ„ (Forensics ๊ด€์ )

์•…์„ฑ์ฝ”๋“œ ๋ถ„์„ ์‹œ Import Table์ด ํŒŒ๊ดด๋œ ๊ฒฝ์šฐ,
๋ณดํ†ต ์•„๋ž˜ ๋‹จ๊ณ„๋กœ ๋ณต์›ํ•ฉ๋‹ˆ๋‹ค.

  1. ์‹คํ–‰ ํŒŒ์ผ ์ „์ฒด์— BP on GetProcAddress
  2. ์‹คํ–‰ ์ค‘ ํ˜ธ์ถœ๋˜๋Š” ์‹ค์ œ API ๋ชฉ๋ก ์ˆ˜์ง‘
  3. ํ˜ธ์ถœ ์ˆœ์„œยทDLL ๋งคํ•‘ ๊ธฐ๋ก
  4. Scylla, ImportREC ๋“ฑ์œผ๋กœ Import Table ์žฌ์ƒ์„ฑ
  5. ํŒจ์ปค ์ œ๊ฑฐ ํ›„ ์ •์  ๋ถ„์„ ์ง„ํ–‰

๐Ÿ“ Written by Code & Compass

MalClown์—์„œ ๋” ์•Œ์•„๋ณด๊ธฐ

์ง€๊ธˆ ๊ตฌ๋…ํ•˜์—ฌ ๊ณ„์† ์ฝ๊ณ  ์ „์ฒด ์•„์นด์ด๋ธŒ์— ์•ก์„ธ์Šคํ•˜์„ธ์š”.

๊ณ„์† ์ฝ๊ธฐ