[태그:] pe

  • 🔍 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