Files
tobias 0a00835493 Add malware patterns & recognition exam cheat sheet
Covers: technique identification by API sequence (process hollowing,
code injection, DLL injection, .NET reflective loading, hook-based
injection, resource droppers), packer recognition (UPX, entropy,
section names, tail jump, breakpoint strategies), anti-analysis
patterns (IsDebuggerPresent, PEB, SEH, TLS, RDTSC, tool detection),
shellcode indicators (NOP sled, GetEIP, PEB walk), document malware
indicators (PDF keywords, VBA triggers, RTF exploits), and two
quick-reference tables mapping APIs→techniques and assembly→behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 08:24:45 +02:00

12 KiB

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)

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

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)

; 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:

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):

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:

MOV EAX, FS:[30h]          ; PEB
TEST [EAX+68h], 0x70       ; NtGlobalFlag (0x70 when debugger-launched)
JNE  debugger_found

Timing check (RDTSC):

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

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

; 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 <file> 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 <file> — 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 <file> → streams marked "M" contain macros → extract with -s <n> -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 <Base64>

Decode: echo <Base64> | 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)