# Common API used in Malware {{#include ../banners/hacktricks-training.md}} ## Generic ### Networking | 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 Many loaders wrap their TCP stream in `SslStream` and pin the server’s leaf certificate against an embedded copy (certificate pinning). Bot info/tasks are compressed (e.g., GZip). When responses exceed a threshold (~1 MB), data is fragmented into small chunks (e.g., 16 KB segments) to avoid size-based heuristics and reduce memory spikes during deserialisation. ### 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() | ### 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] | | ### Emulator API fingerprinting & sleep evasion Malware often fingerprints sandbox emulators by searching for Defender’s virtualised exports (seen in the Malware Protection Emulator). If any of these symbols are present (case-insensitive scan of the process), execution is delayed for 10–30 minutes and re-checked to waste analysis time. 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 - Operators sometimes require a benign-looking CLI switch to be present before running the payload (e.g., `/i:--type=renderer` to mimic Chromium child processes). If the switch is absent, the loader exits immediately, hindering naive sandbox execution. ### Stealth | Name | | | ------------------------ | -------------------------------------------------------------------------- | | 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 | Function Name | | ---------------- | | CreateProcessA/W | | ShellExecute | | WinExec | | ResumeThread | | NtResumeThread | ### Miscellaneous - GetAsyncKeyState() -- Key logging - SetWindowsHookEx -- Key logging - GetForeGroundWindow -- Get running window name (or the website from a browser) - LoadLibrary() -- Import library - GetProcAddress() -- Import library - CreateToolhelp32Snapshot() -- List running processes - GetDC() -- Screenshot - BitBlt() -- Screenshot - InternetOpen(), InternetOpenUrl(), InternetReadFile(), InternetWriteFile() -- Access the Internet - FindResource(), LoadResource(), LockResource() -- Access resources of the executable ## 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); } ``` Practical notes observed in the **DarkCloud Stealer** campaign: * The loader picked `RegAsm.exe` (part of the .NET Framework) as host – a signed binary unlikely to draw attention. * The decrypted VB6 stealer (`holographies.exe`) is *not* dropped on disk; it only ever exists inside the hollowed process making static detection harder. * Sensitive strings (regexes, paths, Telegram credentials) are **RC4-encrypted** per-string and only decrypted at runtime, further complicating memory scanning. Detection ideas: * Alert on `CREATE_SUSPENDED` processes that never create GUI/console windows before a memory region is allocated as **RWX** (rare for benign code). * Look for a call sequence `NtUnmapViewOfSection ➜ VirtualAllocEx ➜ WriteProcessMemory` across different processes. ## 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. - A rootkit may modify these pointer to addresses that he controls - **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. ## 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}}