# FOR610 Malware Patterns & Recognition Cheat Sheet ## Technique Identification: API Sequences ### Process Hollowing (T1055.012) ``` CreateProcess(SUSPENDED) ← dwCreationFlags = 0x4 NtUnmapViewOfSection() ← gut the target process VirtualAllocEx() ← allocate space for payload WriteProcessMemory() ← inject malicious code ResumeThread() ← wake up with injected code ``` **How to spot:** capa shows "Create Suspended Process". In Ghidra: CreateProcess with 0x4 flag, followed by NtUnmapViewOfSection (often loaded dynamically via GetProcAddress to hide from IAT). **Lab:** WinHost32.exe (S5, Lab 5.4) --- ### Classic Code Injection — CreateRemoteThread (T1055.001) ``` OpenProcess() ← get handle to target VirtualAllocEx(RWX) ← allocate executable memory (0x40 = PAGE_EXECUTE_READWRITE) WriteProcessMemory() ← write shellcode to target CreateRemoteThread() ← execute in target process ``` **How to spot:** Search imports for CreateRemoteThread. VirtualAllocEx with flProtect=0x40 is a red flag. **Lab:** great.exe (S4, Lab 4.9) --- ### DLL Injection (T1055.001) ``` OpenProcess() ← target process VirtualAllocEx() ← allocate space for DLL path string WriteProcessMemory() ← write DLL path into target CreateRemoteThread( ← start address = LoadLibraryA lpStartAddress=LoadLibraryA, lpParameter=remote_dll_path) ``` **How to spot:** CreateRemoteThread where lpStartAddress points to LoadLibrary. --- ### DLL Side-Loading / Sideloading (T1574.002) ``` Trusted.exe (signed) ← legitimate executable → LoadLibraryW("evil.dll") ← loads malicious DLL from same directory → DllRegisterServer() ← DLL export runs malicious code → CreateProcessW() ← spawns payload ``` **How to spot:** Signed executable loading DLL from non-standard path. DLL exports suspicious functions. PeStudio shows expired but valid signature. **Lab:** Package.exe + iviewers.dll (S3, Lab 3.10) --- ### .NET Reflective Loading (T1620) ```csharp byte[] payload = DecodePayload(); // XOR/Base64 decode Assembly asm = Assembly.Load(payload); // Load from byte[] in memory asm.GetTypes()[0].InvokeMember(...); // Execute ``` **How to spot:** Search ILSpy decompiled code for "Assembly.Load" or ".Load". Set breakpoint AFTER Assembly.Load in dnSpyEx → extract byte[] from Locals window. **Lab:** chatroom.exe (S4, Lab 4.8) **This is the answer to "what technique is being used when a .NET binary extracts malicious code directly into the memory of its running process?"** → **Reflective Loading via Assembly.Load(byte[])** --- ### .NET In-Memory Compilation ```csharp CSharpCodeProvider csc = new CSharpCodeProvider(); string source = Decode(encoded_source); // Base64+XOR decode CompilerResults result = csc.CompileAssemblyFromSource(params, source); result.CompiledAssembly.EntryPoint.Invoke(...); ``` **How to spot:** Search for "CSharpCodeProvider" or "CompileAssemblyFromSource" in decompiled code. **Lab:** rwvg1.exe (S3, Lab 3.12) --- ### Hook-Based Injection — SetWindowsHookEx (T1056) ``` SetWindowsHookExA( 0x0E, ← WH_MOUSE_LL (low-level mouse hook) hook_function, ← pointer to malicious code GetModuleHandleA(0), ← own module 0) ← all threads ``` **How to spot:** SetWindowsHookExA with idHook=0x0E (mouse) or 0x0D (keyboard). Anti-sandbox: waits for real user activity before executing. **Lab:** vbprop.exe (S5, Lab 5.5) --- ### Resource Dropper Pattern ``` FindResourceW() ← locate embedded resource SizeofResource() ← get payload size LoadResource() ← load into memory LockResource() ← get pointer to data CreateFileA() ← create output file WriteFile() ← write payload to disk CreateProcessA() ← execute dropped file ``` **How to spot:** Ghidra Symbol Table shows FindResource + WriteFile + CreateProcess sequence. Resources visible in PeStudio. **Lab:** ishelp.dll dropper (S2, Lab 2.7) --- ## Packer Recognition ### How to Identify a Packed Binary | Indicator | What to check | Tool | |-----------|--------------|------| | **High entropy** | Sections >7.0 entropy | PeStudio, peframe | | **Few imports** | Only LoadLibrary + GetProcAddress | PeStudio, peframe | | **No readable strings** | Barely any strings extracted | strings, FLOSS | | **Unusual section names** | UPX0, UPX1, .packed, .code | PeStudio, diec | | **Small IAT** | Very few imported functions | PeStudio | | **Packer signature** | Known packer detected | DIE/diec, ExeInfo PE | ### UPX Packer Indicators ``` Section names: UPX0 (empty), UPX1 (compressed code), .rsrc Entry point: In UPX1 section (not .text) Assembly: PUSHAD → [decompression loop] → POPAD → JMP OEP Unpack: upx -d packed.exe (fails if modified) ``` ### The Unpacking Tail Jump (assembly) ```asm ; End of unpacker — restore registers and jump to real code POPAD ; restore all saved registers JMP 0x140003F94 ; ← this is the OEP (Original Entry Point) ``` **How to find it:** Set breakpoint at end of UPX1 section. Look for JMP to address in UPX0 (or .text). ### Breakpoint Strategies for Manual Unpacking | Strategy | When to use | How | |----------|------------|-----| | **Tail jump** | Known packer structure | Find JMP at end of unpacker | | **VirtualAlloc** | Unpacker allocates new memory | BP on VirtualAlloc, watch for RWX allocation | | **VirtualProtect** | Unpacker changes permissions | BP on VirtualProtect with 0x40 (RWX) | | **Stack breakpoint (ESP trick)** | SEH-based packers | Set hardware BP on value written to stack after PUSH | | **LoadLibrary** | Unpacker resolves imports | BP on LoadLibraryA when loading unexpected DLLs | | **RtlDecompressBuffer** | Compression-based packer | BP on decompression API | --- ## Anti-Analysis Recognition ### Debugger Detection Patterns **IsDebuggerPresent:** ```asm CALL IsDebuggerPresent TEST EAX, EAX ; zero = no debugger JNE debugger_found ; non-zero = debugger! ``` **Bypass:** Set EAX=0 in debugger, or NOP the JNE. Lab: getdown.exe (S5) **PEB.BeingDebugged (avoid API call):** ```asm MOV EAX, FS:[30h] ; get PEB address MOVZX EAX, [EAX+2] ; offset 0x2 = BeingDebugged byte TEST EAX, EAX JNE debugger_found ``` **Bypass:** Zero the byte at PEB+2 in debugger. Lab: lansrv.exe (S5) **NtGlobalFlag check:** ```asm MOV EAX, FS:[30h] ; PEB TEST [EAX+68h], 0x70 ; NtGlobalFlag (0x70 when debugger-launched) JNE debugger_found ``` **Timing check (RDTSC):** ```asm RDTSC ; read timestamp → EDX:EAX MOV [saved], EAX ; save ; ... code to time ... RDTSC ; read again SUB EAX, [saved] ; compute delta CMP EAX, threshold ; if too large → stepping detected JA debugger_found ``` ### SEH Anti-Debug Pattern ```asm PUSH handler_addr ; push exception handler PUSH FS:[0] ; push current SEH chain MOV FS:[0], ESP ; install new handler XOR ECX, ECX DIV ECX ; ← deliberate divide-by-zero exception! ; execution jumps to handler_addr ; Analyst expects code to continue here, but it doesn't! ``` **How to handle:** Set breakpoint on handler_addr. In x32dbg: Options → Preferences → Exceptions → "Do not break on DIV0". Lab: want.exe (S5, Lab 5.7) ### TLS Callback Anti-Debug ``` PE Header → TLS Directory → TLS Callback address Code at TLS callback runs BEFORE entry point Typically contains: IsDebuggerPresent + XOR decryption loop ``` **How to handle:** PeStudio shows TLS section. Set hardware breakpoint at TLS callback address. Lab: lansrv.exe (S5, Lab 5.9) ### Tool Detection Patterns ```asm ; Check for security DLLs CALL GetModuleHandleW, "avghookx.dll" ; AVG TEST EAX, EAX JNE tool_found ; Check for debugger windows CALL FindWindowW, "OLLYDBG", NULL ; OllyDbg CALL FindWindowW, "WinDbgFrameClass", NULL ; WinDbg TEST EAX, EAX JNE tool_found ; Enumerate processes for analysis tools CALL CreateToolhelp32Snapshot CALL Process32FirstW / Process32NextW ; loop comparing names ``` **Bypass:** ScyllaHide plugin hides all of these. Lab: raas.exe (S5, Lab 5.6) --- ## Shellcode Indicators | Pattern | Hex/Assembly | Meaning | |---------|-------------|---------| | **NOP sled** | `90 90 90 90 90...` | Shellcode padding — buffer overflow indicator | | **GetEIP (CALL+POP)** | `E8 00 00 00 00 58` | CALL next + POP EAX — shellcode locates itself | | **PEB walk** | `MOV EAX, FS:[30h]` | Find kernel32.dll base address | | **API hash loop** | Hash compare + loop | Resolve API addresses without strings | | **XOR decode loop** | `XOR [ESI], AL; INC ESI; DEC ECX; JNZ` | Self-decrypting shellcode | **XORSearch detects:** `XORSearch -W -d 3 ` scans for GetEIP, kernel32 finder, NOP sled --- ## Document Malware Indicators ### PDF Suspicious Keywords | Keyword | Risk | What it does | |---------|------|-------------| | `/JavaScript` | HIGH | Embedded script execution | | `/OpenAction` | HIGH | Auto-execute on open | | `/Launch` | HIGH | Launch external program | | `/AA` | HIGH | Additional actions (multiple triggers) | | `/AcroForm` | MEDIUM | Interactive form (can execute) | | `/URI` | LOW-MED | Clickable URL (phishing) | | `/EmbeddedFile` | MEDIUM | Embedded file content | | `/RichMedia` | MEDIUM | Flash/media content | **Scan:** `pdfid.py ` — any non-zero count for HIGH keywords = investigate ### Office VBA Auto-Execute Triggers | Function | Trigger | |----------|---------| | `AutoOpen()` | Document opened (Word) | | `Document_Open()` | Document opened (Word) | | `Auto_Open()` | Workbook opened (Excel) | | `Workbook_Open()` | Workbook opened (Excel) | | `AutoExec()` | Application start | | `AutoClose()` | Document closed | **Detect:** `oledump.py ` → streams marked "M" contain macros → extract with `-s -v` ### RTF Exploit Indicators | Indicator | What to look for | |-----------|-----------------| | Deeply nested groups | rtfdump.py shows nesting level >3 | | Large hex data | Group with many hex bytes | | `\objdata` keyword | Embedded OLE object | | `\*\objclass` | Object class identifier | ### PowerShell Encoded Command Pattern ``` powershell.exe -WindowStyle Hidden -EncodedCommand ``` Decode: `echo | base64 -d` or CyberChef (From Base64 → Decode UTF-16LE) --- ## API → Technique Quick Reference | If you see these APIs... | Technique | |--------------------------|-----------| | CreateProcess(SUSPENDED) + NtUnmapViewOfSection + WriteProcessMemory + ResumeThread | **Process Hollowing** | | VirtualAllocEx(0x40) + WriteProcessMemory + CreateRemoteThread | **Code Injection** | | CreateRemoteThread(LoadLibraryA, dll_path) | **DLL Injection** | | Assembly.Load(byte[]) + InvokeMember() | **.NET Reflective Loading** | | CSharpCodeProvider + CompileAssemblyFromSource | **.NET In-Memory Compilation** | | SetWindowsHookExA(0x0E) | **Mouse Hook Anti-Sandbox** | | FindResource + WriteFile + CreateProcess | **Resource Dropper** | | LoadLibraryW (DLL not in IAT, from same dir) | **DLL Side-Loading** | | InternetOpen + HttpSendRequest + InternetReadFile | **HTTP C2** | | RegSetValueEx("...\\Run", malware_path) | **Registry Persistence** | | IsDebuggerPresent / FS:[30h]+2 / NtGlobalFlag | **Anti-Debugging** | | GetModuleHandle("avghookx.dll") / FindWindow("OLLYDBG") | **Tool Detection** | | RDTSC + delta comparison | **Timing Anti-Debug** | | FS:[0] manipulation + intentional exception | **SEH Anti-Debug** | | BlockInput(TRUE) | **Analyst Lockout** | | CreateToolhelp32Snapshot + Process32First/Next | **Process Enumeration** | | VirtualAlloc + memcpy/rep movsb + JMP | **Runtime Unpacking** | | PUSHAD...POPAD...JMP OEP | **UPX-Style Packer** | --- ## Assembly Pattern Quick Reference | Assembly Pattern | What It Means | |-----------------|---------------| | `XOR EAX, EAX` | Zero out register (common idiom) | | `TEST EAX, EAX` then `JZ/JNZ` | Check if value is zero | | `PUSH EBP; MOV EBP,ESP; SUB ESP,n` | Function prologue | | `LEAVE; RET` | Function epilogue | | `CALL; ADD ESP,n` | cdecl call (caller cleans stack) | | `FS:[30h]` | PEB access (anti-debug or API resolution) | | `FS:[0]` | SEH chain access | | `XOR [reg], key` in loop | String/code decryption | | `PUSHAD...POPAD...JMP addr` | Packer wrapper (UPX-style) | | `MOV byte ptr [EBP-x], imm8` (repeated) | Stack string building | | `E8 00 00 00 00` then `POP reg` | GetEIP shellcode technique | | `REP MOVSB` (ESI→EDI) | Memory copy (memcpy) | | `VirtualAlloc` then `REP MOVSB` then `JMP EAX` | Unpack and execute | | `90 90 90 90...` | NOP sled (shellcode indicator) |