악성코드나 패커가 적용된 실행 파일을 분석하다 보면,
가장 먼저 무너져 있는 부분이 Import Table입니다.
오늘은 Import Table이 훼손된 PE 파일을 어떻게 재구성하는지,
그리고 악성코드가 어떤 방식으로 Import를 숨기는지 기록 중심으로 정리해봤습니다.
리버싱 기록
## 1) 📌 동적 로딩 기반 Import 은닉 기법
대표적으로 사용하는 API는 다음과 같습니다:
LoadLibraryA / LoadLibraryWGetProcAddressLdrLoadDllLdrGetProcedureAddress
악성코드에서 많이 보이는 전형적인 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이 파괴된 경우,
보통 아래 단계로 복원합니다.
- 실행 파일 전체에 BP on GetProcAddress
- 실행 중 호출되는 실제 API 목록 수집
- 호출 순서·DLL 매핑 기록
- Scylla, ImportREC 등으로 Import Table 재생성
- 패커 제거 후 정적 분석 진행
📍 Written by Code & Compass