mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
198 lines
9.4 KiB
Markdown
198 lines
9.4 KiB
Markdown
# 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() |
|
||
|
||
### 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] | |
|
||
|
||
### 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/)
|
||
|
||
{{#include ../banners/hacktricks-training.md}}
|
||
|
||
|
||
|