Malware에서 사용되는 공통 API

Reading time: 9 minutes

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

일반

네트워킹

Raw SocketsWinAPI Sockets
socket()WSAStratup()
bind()bind()
listen()listen()
accept()accept()
connect()connect()
read()/recv()recv()
write()send()
shutdown()WSACleanup()

TLS pinning 및 chunked transport

많은 loaders는 TCP 스트림을 SslStream으로 래핑하고 서버의 leaf certificate를 임베디드 복사본과 비교하여 고정(certificate pinning)합니다. Bot 정보/작업은 압축되어 전송됩니다(예: GZip). 응답이 임계값(약 1 MB)을 초과하면, 데이터는 사이즈 기반 휴리스틱을 회피하고 역직렬화 동안 메모리 급증을 줄이기 위해 작은 청크(예: 16 KB 세그먼트)로 분할됩니다.

Persistence

RegistryFileService
RegCreateKeyEx()GetTempPath()OpenSCManager
RegOpenKeyEx()CopyFile()CreateService()
RegSetValueEx()CreateFile()StartServiceCtrlDispatcher()
RegDeleteKeyEx()WriteFile()
RegGetValue()ReadFile()

암호화

Name
WinCrypt
CryptAcquireContext()
CryptGenKey()
CryptDeriveKey()
CryptDecrypt()
CryptReleaseContext()

안티 분석/VM

Function NameAssembly Instructions
IsDebuggerPresent()CPUID()
GetSystemInfo()IN()
GlobalMemoryStatusEx()
GetVersion()
CreateToolhelp32Snapshot [Check if a process is running]
CreateFileW/A [Check if a file exist]

로케일/키보드 기반 실행 가드

많은 stealers/loaders는 연구자를 회피하고 위협 행위자의 제약을 준수하기 위해 특정 로케일에서 실행을 중단합니다. 일반적인 체크:

  • GetKeyboardLayout to enumerate installed layouts (per-thread/user)
  • GetLocaleInfoA/W to resolve country/region codes
  • GetSystemDefaultLangID / GetUserDefaultLangID

만약 어떤 항목이라도 차단 목록(일반적으로 CIS countries)과 일치하면, loader는 network IOCs 또는 injection 전에 즉시 종료합니다.

방어/헌팅

  • 실행 초기에 여러 로케일/키보드 API를 조회한 뒤 아무런 관찰 가능한 활동 없이 종료하는 프로세스를 플래그로 표시하세요.
  • 오픈소스 프로젝트(예: VMDetector)에서 재사용되는 anti-VM 검사(BIOS strings, PnP devices, disk model, services)와 상관관계를 만들어 gated execution을 탐지하세요.

에뮬레이터 API 지문화 및 슬립 회피

Malware는 종종 Defender의 virtualised exports(=Malware Protection Emulator에서 관찰된)를 검색하여 샌드박스 에뮬레이터를 지문화합니다. 이러한 심볼이 프로세스에 존재하면(프로세스에 대해 대소문자 구분 없는 스캔), 실행은 10–30분 동안 지연되고 재확인되어 분석 시간을 낭비시킵니다.

Examples of API names used as canaries:

  • MpVmp32Entry, MpVmp32FastEnter, MpCallPreEntryPointCode, MpCallPostEntryPointCode, MpFinalize, MpReportEvent*, MpSwitchToNextThread*
  • VFS_* family: VFS_Open, VFS_Read, VFS_MapViewOfFile, VFS_UnmapViewOfFile, VFS_FindFirstFile/FindNextFile, VFS_CopyFile, VFS_DeleteFile, VFS_MoveFile
  • ThrdMgr_*: ThrdMgr_GetCurrentThreadHandle, ThrdMgr_SaveTEB, ThrdMgr_SwitchThreads

Typical delay primitive (user-land):

cmd
cmd /c timeout /t %RANDOM_IN_[600,1800]% > nul

Argument gatekeeping

  • 운영자는 페이로드 실행 전에 무해해 보이는 CLI 스위치가 존재할 것을 요구할 때가 있다(예: Chromium 자식 프로세스를 흉내내기 위한 /i:--type=renderer). 스위치가 없으면 로더는 즉시 종료되어 단순한 샌드박스 실행을 방해한다.

은폐

Name
VirtualAlloc메모리 할당 (패커)
VirtualProtect메모리 권한 변경 (섹션에 실행 권한을 부여하는 패커)
ReadProcessMemory외부 프로세스 주입
WriteProcessMemoryA/W외부 프로세스 주입
NtWriteVirtualMemory
CreateRemoteThreadDLL/Process injection...
NtUnmapViewOfSection
QueueUserAPC
CreateProcessInternalA/W

실행

Function Name
CreateProcessA/W
ShellExecute
WinExec
ResumeThread
NtResumeThread

기타

  • GetAsyncKeyState() -- Key logging
  • SetWindowsHookEx -- Key logging
  • GetForeGroundWindow -- 실행 중인 창 이름 가져오기 (또는 브라우저에서 웹사이트)
  • LoadLibrary() -- 라이브러리 로드
  • GetProcAddress() -- 라이브러리 함수 주소 조회
  • CreateToolhelp32Snapshot() -- 실행 중인 프로세스 나열
  • GetDC() -- 화면 캡처
  • BitBlt() -- 화면 캡처
  • InternetOpen(), InternetOpenUrl(), InternetReadFile(), InternetWriteFile() -- 인터넷 접근
  • FindResource(), LoadResource(), LockResource() -- 실행 파일의 리소스 접근

악성코드 기법

DLL Injection

Execute an arbitrary DLL inside another process

  1. Locate the process to inject the malicious DLL: CreateToolhelp32Snapshot, Process32First, Process32Next
    악성 DLL을 주입할 프로세스를 찾는다: CreateToolhelp32Snapshot, Process32First, Process32Next
  2. Open the process: GetModuleHandle, GetProcAddress, OpenProcess
    프로세스를 연다: GetModuleHandle, GetProcAddress, OpenProcess
  3. Write the path to the DLL inside the process: VirtualAllocEx, WriteProcessMemory
    프로세스 내부에 DLL 경로를 쓴다: VirtualAllocEx, WriteProcessMemory
  4. Create a thread in the process that will load the malicious DLL: CreateRemoteThread, LoadLibrary
    악성 DLL을 로드할 스레드를 프로세스 내에 생성한다: CreateRemoteThread, LoadLibrary

Other functions to use: NTCreateThreadEx, RtlCreateUserThread

Reflective DLL Injection

Load a malicious DLL without calling normal Windows API calls.
The DLL is mapped inside a process, it will resolve the import addresses, fix the relocations and call the DllMain function.
표준 Windows API 호출 없이 악성 DLL을 로드한다. DLL이 프로세스 내부에 매핑되며 임포트 주소를 해결하고 재배치(relocations)를 수정한 뒤 DllMain 함수를 호출한다.

Thread Hijacking

Find a thread from a process and make it load a malicious DLL

  1. Find a target thread: CreateToolhelp32Snapshot, Thread32First, Thread32Next
    대상 스레드를 찾는다: CreateToolhelp32Snapshot, Thread32First, Thread32Next
  2. Open the thread: OpenThread
    스레드를 연다: OpenThread
  3. Suspend the thread: SuspendThread
    스레드를 일시중단한다: SuspendThread
  4. Write the path to the malicious DLL inside the victim process: VirtualAllocEx, WriteProcessMemory
    피해자 프로세스 내부에 악성 DLL 경로를 쓴다: VirtualAllocEx, WriteProcessMemory
  5. Resume the thread loading the library: ResumeThread
    라이브러리를 로드하도록 스레드를 다시 시작한다: ResumeThread

PE Injection

Portable Execution Injection: The executable will be written in the memory of the victim process and it will be executed from there.
Portable Executable 주입: 실행 파일이 대상 프로세스의 메모리에 기록되고 그곳에서 실행된다.

Process Hollowing (a.k.a RunPE)

Process Hollowing is one of the favourite defence-evasion / execution tricks used by Windows malware. The idea is to launch a legitimate process in the suspended state, remove (hollow) its original image from memory and copy an arbitrary PE in its place. When the primary thread is finally resumed the malicious entry-point executes under the guise of a trusted binary (often signed by Microsoft).
Process Hollowing은 Windows 악성코드에서 자주 사용되는 defence-evasion / execution 기법 중 하나이다. 아이디어는 정상적인 프로세스를 일시중단 상태로 실행한 후 메모리에서 원래 이미지를 제거(비우기)하고 그 자리에 임의의 PE를 복사하는 것이다. 주 스레드가 다시 시작되면 악성 엔트리 포인트가 신뢰된 바이너리(종종 Microsoft에 의해 서명됨)로 가장하여 실행된다.

Typical workflow:

  1. Spawn a benign host (e.g. RegAsm.exe, rundll32.exe, msbuild.exe) suspended so that no instructions run yet.
c
STARTUPINFOA  si = { sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcessA("C:\\Windows\\Microsoft.NET\\Framework32\\v4.0.30319\\RegAsm.exe",
NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);

무해한 호스트(예: RegAsm.exe, rundll32.exe, msbuild.exe)를 일시중단 상태로 생성하여 아직 어떤 명령도 실행되지 않도록 한다. 2. Read the malicious payload into memory and parse its PE headers to obtain SizeOfImage, sections and the new EntryPoint.
악성 페이로드를 메모리로 읽어들여 PE 헤더를 파싱하여 SizeOfImage, 섹션 및 새 EntryPoint를 얻는다. 3. NtUnmapViewOfSection / ZwUnmapViewOfSection – unmap the original image base of the suspended process.
NtUnmapViewOfSection / ZwUnmapViewOfSection – 일시중단된 프로세스의 원래 이미지 베이스를 언맵한다. 4. VirtualAllocEx – reserve RWX memory of SizeOfImage inside the remote process.
VirtualAllocEx – 원격 프로세스 내부에 SizeOfImage 크기의 RWX 메모리를 예약한다. 5. WriteProcessMemory – copy the Headers first, then iterate over sections copying their raw data.
WriteProcessMemory – 먼저 Headers를 복사한 뒤 각 섹션의 원시 데이터를 순회하며 복사한다. 6. SetThreadContext – patch the value of EAX/RAX (RCX on x64) or Rip in the context structure so that EIP points to the payload’s EntryPoint.
SetThreadContext – 컨텍스트 구조에서 EAX/RAX(x64의 경우 RCX) 또는 Rip 값을 패치하여 EIP가 페이로드의 EntryPoint를 가리키도록 한다. 7. ResumeThread – the thread continues, executing the attacker-supplied code.
ResumeThread – 스레드가 계속되어 공격자가 제공한 코드를 실행한다.

Minimal proof-of-concept (x86) skeleton:

c
void RunPE(LPCSTR host, LPVOID payload, DWORD payloadSize){
// 1. create suspended process
STARTUPINFOA si = {sizeof(si)}; PROCESS_INFORMATION pi;
CreateProcessA(host, NULL,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi);

// 2. read remote PEB to get ImageBaseAddress
CONTEXT ctx; ctx.ContextFlags = CONTEXT_FULL;
GetThreadContext(pi.hThread,&ctx);
PVOID baseAddr;
ReadProcessMemory(pi.hProcess,(PVOID)(ctx.Ebx+8),&baseAddr,4,NULL);

// 3. unmap original image & allocate new region at same base
NtUnmapViewOfSection(pi.hProcess,baseAddr);
PVOID newBase = VirtualAllocEx(pi.hProcess,baseAddr,pHdr->OptionalHeader.SizeOfImage,
MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
// 4-5. copy headers & sections …
// 6. write new image base into PEB and set Eip
WriteProcessMemory(pi.hProcess,(PVOID)(ctx.Ebx+8),&baseAddr,4,NULL);
ctx.Eax = (DWORD)(newBase) + pHdr->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(pi.hThread,&ctx);
// 7. run!
ResumeThread(pi.hThread);
}

Practical notes observed in the DarkCloud Stealer campaign:

  • 로더는 RegAsm.exe (.NET Framework의 일부)를 호스트로 선택했습니다 – 서명된 바이너리여서 주목을 덜 받을 가능성이 큽니다.
  • 복호화된 VB6 stealer (holographies.exe)는 디스크에 드롭되지 않습니다; 오직 hollowed process 내부에서만 존재하여 정적 탐지를 어렵게 만듭니다.
  • 민감한 문자열 (regexes, paths, Telegram credentials)은 문자열별로 RC4-encrypted 되어 런타임에만 복호화되므로 메모리 스캔을 더 어렵게 만듭니다.

Detection ideas:

  • 메모리 영역이 RWX로 할당되기 전에 GUI/console 창을 생성하지 않는 CREATE_SUSPENDED 프로세스에 대해 경보를 생성하십시오 (정상 코드에선 드뭅니다).
  • 다른 프로세스들에서 NtUnmapViewOfSection ➜ VirtualAllocEx ➜ WriteProcessMemory 호출 시퀀스를 찾아보세요.
  • 특히 MSBuild.exe, RegAsm.exe, rundll32.exe 같은 신뢰받는 개발자 유틸리티가 hollowing hosts로 비정상적으로 사용되고 짧게 실행되는 로더가 부모로 있는 경우 의심하세요.
  • 사용자 쓰기 가능한 경로에서 spawn되거나 대응하는 .sln/.proj 컨텍스트 없이 생성되어 외부 연결을 시도하는 msbuild.exe를 찾아보세요 (ATT&CK T1127.001 + T1055.012).

Common host processes and path resolution

  • MSBuild.exe는 개발 도구와 섞이기 위해 hollowing host로 자주 선택됩니다. 로더는 종종 아키텍처에 맞는 위치를 검색합니다:
  • C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe
  • C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe
  • C:\Windows\System32\MSBuild.exe
  • C:\Windows\SysWOW64\MSBuild.exe
  • 현재 payload/OS 아키텍처에 맞는 호스트를 선택한 다음 CreateProcess(..., CREATE_SUSPENDED, ...)를 호출하십시오.

Hooking

  • The SSDT (System Service Descriptor Table) points to kernel functions (ntoskrnl.exe) or GUI driver (win32k.sys) so user processes can call these functions.
  • rootkit은 이러한 포인터를 자신이 제어하는 주소로 수정할 수 있습니다.
  • The IRP (I/O Request Packets) transmit pieces of data from one component to another. Almost everything in the kernel uses IRPs and each device object has its own function table that can be hooked: DKOM (Direct Kernel Object Manipulation)
  • The IAT (Import Address Table) is useful to resolve dependencies. It's possible to hook this table in order to hijack the code that will be called.
  • EAT (Export Address Table) Hooks. This hooks can be done from userland. The goal is to hook exported functions by DLLs.
  • Inline Hooks: This type are difficult to achieve. This involve modifying the code of the functions itself. Maybe by putting a jump at the beginning of this.

참고자료

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기