IAT Stomping 기반 흐름 분석

본 문서는 공격자가 Import Address Table(IAT) Stomping을 활용해
정적 분석을 회피하고, 동적 호출 전용 API 재해석 루틴을 삽입하는 과정에서 발생하는
메모리 변조 패턴, 레지스터 조작, 스택 프레임 변화,
그리고 PE 구조 관점의 무결성이 깨지는 지점을 작성함.

리버싱 기록


1. 개요 — IAT Stomping의 역할과 특징

IAT Stomping은 PE 파일에 존재하는 정적 Import Address Table의
개별 함수 주소 필드를 공격자가 임의 함수(대개 커스텀 로더 또는 난독화된 wrapper)로
직접 덮어써 호출 흐름을 변조하는 기법이다.

진단 관점에서 나타나는 특징:

  • IAT 엔트리가 원본 DLL 범위를 벗어난 Private Memory 주소로 변경
  • 정적 분석에서 확인한 함수 호출과 런타임 제어 흐름이 불일치
  • API 호출 규약(Calling Convention)이 원본 함수와 맞지 않아 스택 비정상 패턴 발생
  • 언패킹/로더 루틴 진입부가 정상 API 호출 직후 등장

이 기법은 Packing, Shellcode Loader, Process Injection 초기화 코드에서 빈번히 등장한다.


2. IAT 엔트리 변조 흐름

아래는 단순화된 Stomping 패턴이다.

// 샘플 코드
BOOL Demo_IATStomp(BYTE* moduleBase, LPVOID fakeFuncPtr)
{
    IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)moduleBase;
    IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(moduleBase + dos->e_lfanew);

    // IAT RVA
    DWORD iatRVA = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress;
    if (!iatRVA) return FALSE;

    IMAGE_THUNK_DATA* iat = (IMAGE_THUNK_DATA*)(moduleBase + iatRVA);

    // 첫 번째 엔트리에 fakeFuncPtr 삽입 (예시)
    SIZE_T bytesWritten = 0;
    DWORD oldProtect = 0;
    VirtualProtect(iat, sizeof(LPVOID), PAGE_READWRITE, &oldProtect);

    iat[0].u1.Function = (ULONGLONG)fakeFuncPtr;

    VirtualProtect(iat, sizeof(LPVOID), oldProtect, &oldProtect);
    return TRUE;
}

분석 시 주목 포인트

  • IMAGE_DIRECTORY_ENTRY_IAT 기반 엔트리 접근
  • VirtualProtect를 통한 메모리 보호 속성 변경
  • 원본 DLL 모듈 주소 범위와 비교하여
    IAT 필드가 Private Memory를 가리키는지 여부
  • PE 구조의 Import Table 재해석을 통해 실제 호출 흐름 파악 가능

3. Assembly 관점 — Stomping 이후 호출 흐름 패턴

다음은 실제 호출이 IAT를 경유하여
공격자 커스텀 함수로 전이되는 형태를 단순화한 패턴이다.

; --- 정상 API 호출 흐름 ---
call    dword ptr [IAT_GetProcAddress]     ; 원래는 kernel32!GetProcAddress

; --- IAT Stomping 후 흐름 ---
call    dword ptr [IAT_GetProcAddress]     ; IAT 엔트리가 이미 공격자 fakeFuncPtr로 변조됨
                                            ; → Private Memory 주소로 제어 흐름 전이

; 공격자 커스텀 루틴 시작점 (가상 코드)
fakeFuncPtr:
    push    ebp
    mov     ebp, esp
    sub     esp, 20h
    ; 스택 프레임 생성, 이후 실제 API 호출 대신 자체 로직 수행
    ; (예: 해시 기반 API 재해석, 언패킹 루틴, Anti-Debugging)
    leave
    ret

레지스터 동작 분석

레지스터의미
EIPIAT 엔트리의 변경된 주소(Private Memory)로 이동
ESP/EBP호출 규약이 원본 함수와 달라 Return Address 불일치 가능
EAX/ECX/EDXFake 함수 내부에서 임의 목적에 맞게 재활용

4. PE 구조 기반 무결성 관찰

일부 PE 분석 기준에 따르면
IAT Stomping은 아래 요소에서 명확한 이상 패턴을 발생시킨다.

(1) Import Address Table 엔트리 무결성 붕괴

  • IAT 엔트리가 ImageBase ~ ImageSize 범위에서 벗어남
  • 일반적으로는 kernel32.dll, user32.dll 등 모듈 내 주소여야 정상

(2) Import Descriptor의 OriginalFirstThunk 대비 불일치

  • 정적 Import Table에 정의된 함수 주소와 런타임 주소 비교 시
    변조 여부가 즉시 노출된다

(3) 메모리 보호 속성 변동

  • .idata는 원래 READONLY 상태이나
    Stomping 전후로 PAGE_READWRITEPAGE_READONLY 변경 흔적 확인 가능

5. 동적 API 해석(Dynamic API Resolution)과의 결합 패턴

Stomping은 단독으로 사용되기보다는 다음 패턴들과 연계된다:

  • 해시 기반 GetProcAddress Stub
  • PEB.LoaderData 를 통한 모듈 열거
  • ROR/ROR 기반 해시 연산 난독화
  • API 호출 전후의 RetSpoofing 형태 통제
  • Anti-Debugging: NtQueryInformationProcess(ProcessDebugFlags) 호출

이는 IAT Stomping으로 진입한 fake 함수 내부에서
초기화 루틴을 수행하는 구조로 관찰된다.


6. 스택 프레임 및 호출 규약 무결성 검증

IAT Stomping 후에는 다음과 같은 스택·프레임 이상 징후가 나타난다.

비정상 패턴

  • 원래 stdcall 함수였으나 fake 함수는 cdecl 형태로 처리
  • 호출자 정리(Call-site cleanup) 불일치
  • Return Address가 모듈 내부가 아닌 Private Memory를 가리킴
  • Prologue/epilogue 패턴이 정상 라이브러리 함수와 다름
    (push ebp / mov ebp, esp 부재 또는 변형)

포렌식에서는 Call Stack Reconstruction 시
이러한 지점에서 Stack Trace Disruption이 흔하게 발생한다.


7. 메모리 포렌식에서 확인되는 IOC

(1) IAT 엔트리 주소가 정상 DLL 범위를 벗어남

(2) .idata 섹션의 보호 속성 변경 흔적

(3) Private Memory 영역에서 PE Header 단편(MZ/PE)이 발견

(4) 호출 흐름 분석 시 IAT → Private Memory → API Resolver Stub 패턴

(5) API 호출 빈도 이상 (정상 대비 높은 LoadLibrary / GetProcAddress 사용량)


8. 결론

IAT Stomping은 정적 분석을 막고,
동적 API 해석 루틴과 결합되어 흐름을 은폐하는 데 사용되는
전형적인 악성 로더 기법이다.

PE 구조 기반 검증, 메모리 보호 속성 관찰,
레지스터·스택 프레임 분석을 병행하면
공격자가 구현한 은폐형 호출 경로는 충분히 추적 가능하다.


📍 Written by Code & Compass

MalClown에서 더 알아보기

지금 구독하여 계속 읽고 전체 아카이브에 액세스하세요.

계속 읽기