YARA[1] is a beautiful tool for malware researchers and incident responders. No need to present it again. It became a standard tool to add to your arsenal. While teaching FOR610 (Malware Analysis & Reverse Engineering), a student asked me how to detect specific API calls with dangerous parameters during the triage phase. This phase will help you quickly assess the malware sample and help you decide how to perform the following steps.
A classic suspicious API call/parameter combo is VirtualAlloc() with the value 0x40 passed as flProtect parameter. This value corresponds to PAGE_EXECUTE_READWRITE[2]. If you see this, it means that the program will allocate some new memory that will contain executable code. This is a typical step to load a shell code in memory and execute it.
In the example below, the malware uses this technique, and we can detect the call to VirtualAlloc():
[email protected]:~$ capa -vv WinHost32.exe? ... allocate RWX memory (2 matches) namespace host-interaction/process/inject author [email protected] scope basic block mbc Memory::Allocate Memory [C0007] examples Practical Malware Analysis Lab 03-03.exe_:0x4010EA, 563653399B82CD443F120ECEFF836EA3678D4CF11D9B351BB737573C2D856299:0x140001ABA basic block @ 0x401000 and: match: allocate memory @ 0x401000 or: api: kernel32.VirtualAlloc @ 0x401077 number: 0x40 = PAGE_EXECUTE_READWRITE @ 0x401068 basic block @ 0x4021EE and: match: allocate memory @ 0x4021EE or: api: kernel32.VirtualAllocEx @ 0x40220D number: 0x40 = PAGE_EXECUTE_READWRITE @ 0x402203 ...
They are two calls to VirtualAlloc. The first one is located at 0x401000:
[email protected]:~$ objdump -d WinHost32.exe WinHost32.exe: file format pei-i386 Disassembly of section .text: 00401000 : ... 401068: 6a 40 push 0x40 40106a: 68 00 30 00 00 push 0x3000 40106f: 50 push eax 401070: 6a 00 push 0x0 401072: a3 94 ec 40 00 mov ds:0x40ec94,eax 401077: ff 15 b8 b1 40 00 call DWORD PTR ds:0x40b1b8 ...
VirtualAlloc() expects four parameters. In a 32bits architecture, they are passed on the stack from write to left. The last one (flProtect) is pushed on the stack at 0x401068. How to read this code:
VirtualAlloc(0, EAX_value, 0x3000, 0x40)
How to detect this with the help of a YARA? Here is a very simple rule:
rule VirtualAlloc40 { meta: description = “Simple rule to detect PAGE_EXECUTE_READWRITE memory allocation” strings: $hex_string = { 6A 40 68 00 30 00 00 [5-15] (FF 15 | E8 ) } condition: $hex_string }
I’m looking for the following code (see the objdump output above)
- push a byte (0x6A) on the stack: 0x40
- push a dword (0x68) on the stack: 0x00003000
- a suite of 5 to 10 bytes (because the remaining parameters may be something else)
- call an address (where VirtualAlloc is loaded)
This rule gave me good results, but it remains basic. Indeed, it won’t detect simple obfuscation like this:
mov ecx, 0x40 push ecx push 0x3000 ...
If you’ve ideas to improve this simple rule or another interesting API call/parameter combination (example: CreateProcess / SUSPENDED_MODE), please share them with us!
[1] https://yara.readthedocs.io/en/latest/
[2] https://learn.microsoft.com/en-us/windows/win32/Memory/memory-protection-constants
Xavier Mertens (@xme)
Xameco
Senior ISC Handler – Freelance Cyber Security Consultant
PGP Key
(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.