Finding Malicious Code in Memory: A Digital Forensics Guide
Understanding Memory-Based Attacks
Modern malware increasingly relies on memory-resident techniques to avoid detection. These attacks inject malicious code directly into legitimate processes, making them harder to spot with traditional antivirus solutions. The key to detecting these threats lies in analyzing memory dumps and looking for suspicious patterns in process behavior, memory permissions, and network connections.
Identifying Malicious Processes
Process List Analysis with pslist
The pslist command provides a comprehensive view of all running processes at the time the memory dump was created. This is typically your starting point for any memory analysis investigation.
❯ vol -f basicloading.mem windows.pslist
Volatility 3 Framework 2.5.0
Progress: 100.00 PDB scanning finished
PID PPID ImageFileName Offset(V) Threads Handles SessionId Wow64 CreateTime ExitTime File output
4 0 System 0xb308f169d040 122 - N/A False 2023-09-29 06:28:30.000000 N/A Disabled
92 4 Registry 0xb308f16c4080 4 - N/A False 2023-09-29 06:28:18.000000 N/A Disabled
300 4 smss.exe 0xb308f471f040 2 - N/A False 2023-09-29 06:28:30.000000 N/A Disabled
416 408 csrss.exe 0xb308f560c2c0 10 - 0 False 2023-09-29 06:28:34.000000 N/A Disabled
488 408 wininit.exe 0xb308f5893140 1 - 0 False 2023-09-29 06:28:35.000000 N/A Disabled
496 480 csrss.exe 0xb308f58952c0 13 - 1 False 2023-09-29 06:28:35.000000 N/A Disabled
584 480 winlogon.exe 0xb308f5904100 6 - 1 False 2023-09-29 06:28:35.000000 N/A Disabled
624 488 services.exe 0xb308f590c080 7 - 0 False 2023-09-29 06:28:35.000000 N/A Disabled
648 488 lsass.exe 0xb308f591d0c0 10 - 0 False 2023-09-29 06:28:35.000000 N/A Disabled
When analyzing process lists, pay attention to these key fields:
- PID - Process ID number
- PPID - Parent process ID number
- ImageFileName - Name of the running process
- Offset - Hexadecimal value representing the location in memory where the process is running
- CreateTime - Time when the process started
- ExitTime - Time when the process ended
Process Tree Analysis with pstree
Understanding parent-child relationships between processes is crucial for spotting suspicious activity. The pstree command visualizes these relationships, making it easier to identify processes that shouldn’t be spawning certain child processes.
❯ vol -f basicloading.mem windows.pstree.PsTree
Volatility 3 Framework 2.5.0
Progress: 100.00 PDB scanning finished
PID PPID ImageFileName Offset(V) Threads Handles SessionId Wow64 CreateTime ExitTime
4 0 System 0xb308f169d040 122 - N/A False 2023-09-29 06:28:30.000000 N/A
* 1608 4 MemCompression 0xb308f62d0040 18 - N/A False 2023-09-29 06:28:39.000000 N/A
* 92 4 Registry 0xb308f16c4080 4 - N/A False 2023-09-29 06:28:18.000000 N/A
* 300 4 smss.exe 0xb308f471f040 2 - N/A False 2023-09-29 06:28:30.000000 N/A
416 408 csrss.exe 0xb308f560c2c0 10 - 0 False 2023-09-29 06:28:34.000000 N/A
488 408 wininit.exe 0xb308f5893140 1 - 0 False 2023-09-29 06:28:35.000000 N/A
* 624 488 services.exe 0xb308f590c080 7 - 0 False 2023-09-29 06:28:35.000000 N/A
** 8 624 svchost.exe 0xb308f60ac080 7 - 0 False 2023-09-29 06:28:38.000000 N/A
** 3096 624 svchost.exe 0xb308f69b10c0 6 - 0 False 2023-09-29 06:28:45.000000 N/A
** 4136 624 svchost.exe 0xb308f7592080 5 - 1 False 2023-09-29 06:29:36.000000 N/A
** 1584 624 svchost.exe 0xb308f62cd0c0 3 - 0 False 2023-09-29 06:28:39.000000 N/A
** 6708 624 svchost.exe 0xb308f821c080 12 - 0 False 2023-09-29 06:30:46.000000 N/A
** 1592 624 svchost.exe 0xb308f62d2080 5 - 0 False 2023-09-29 06:28:39.000000 N/A
** 3132 624 svchost.exe 0xb308f69dd080 14 - 0 False 2023-09-29 06:28:45.000000 N/A
** 1092 624 svchost.exe 0xb308f6461080 8 - 0 False 2023-09-29 06:28:41.000000 N/A
*** 4692 1092 sihost.exe 0xb308f6371080 13 - 1 False 2023-09-29 06:29:36.000000 N/A
The tree structure uses asterisks (*) to indicate the depth of parent-child relationships. Look for unusual patterns like:
- Unexpected processes spawning cmd.exe or powershell.exe
- System processes with suspicious child processes
- Processes running from unusual locations
Identifying Malicious Network Connections
Network Scan Analysis with netscan
Network connections can reveal command and control (C2) communications or data exfiltration attempts. The netscan command shows all network connections associated with processes in the memory dump.
vol -f basicloading.mem windows.netscan
Volatility 3 Framework 2.5.0
Progress: 100.00 PDB scanning finished
Offset Proto LocalAddr LocalPort ForeignAddr ForeignPort State PID Owner Created
0xb308f6c32010 TCPv4 192.168.228.129 52503 172.16.10.100 9001 SYN_SENT 6444 notepad.exe 2023-09-29 06:32:03.000000
Key fields to analyze:
- Offset - Location in memory
- Proto - Network protocol used by the process
- LocalAddr - Source address of the network connection
- LocalPort - Source port of the network connection
- ForeignAddr - Destination address of the network connection
- ForeignPort - Destination port of the network connection
- State - State of the network connection (established, closed, listening)
- PID - Process ID of the associated process
- Owner - Account associated with the process
- Created - Time when the network connection was initiated
In this example, notepad.exe making a network connection to port 9001 is highly suspicious and warrants further investigation.
Detecting Injected Code
Finding Suspicious Memory Regions with malfind
The malfind command is your primary tool for detecting code injection. It identifies memory regions with suspicious characteristics, particularly those with Read-Write-Execute (RWX) permissions that may contain injected code.
❯ vol -f basicloading.mem windows.malfind
Volatility 3 Framework 2.5.0
Progress: 100.00 PDB scanning finished
PID Process Start VPN End VPN Tag Protection CommitCharge PrivateMemory File output Hexdump Disasm
6444 notepad.exe 0x2234ec10000 0x2234ec10fff VadS PAGE_EXECUTE_READWRITE 1 1 Disabled
fc 48 83 e4 f0 e8 cc 00 .H......
00 00 41 51 41 50 52 48 ..AQAPRH
31 d2 51 56 65 48 8b 52 1.QVeH.R
60 48 8b 52 18 48 8b 52 `H.R.H.R
20 4d 31 c9 48 8b 72 50 .M1.H.rP
48 0f b7 4a 4a 48 31 c0 H..JJH1.
ac 3c 61 7c 02 2c 20 41 .<a|.,.A
c1 c9 0d 41 01 c1 e2 ed ...A....
0x2234ec10000: cld
0x2234ec10001: and rsp, 0xfffffffffffffff0
0x2234ec10005: call 0x2234ec100d6
0x2234ec1000a: push r9
0x2234ec1000c: push r8
0x2234ec1000e: push rdx
0x2234ec1000f: xor rdx, rdx
0x2234ec10012: push rcx
0x2234ec10013: push rsi
0x2234ec10014: mov rdx, qword ptr gs:[rdx + 0x60]
0x2234ec10019: mov rdx, qword ptr [rdx + 0x18]
0x2234ec1001d: mov rdx, qword ptr [rdx + 0x20]
0x2234ec10021: xor r9, r9
0x2234ec10024: mov rsi, qword ptr [rdx + 0x50]
0x2234ec10028: movzx rcx, word ptr [rdx + 0x4a]
0x2234ec1002d: xor rax, rax
0x2234ec10030: lodsb al, byte ptr [rsi]
0x2234ec10031: cmp al, 0x61
0x2234ec10033: jl 0x2234ec10037
0x2234ec10035: sub al, 0x20
0x2234ec10037: ror r9d, 0xd
0x2234ec1003b: add r9d, eax
0x2234ec1003e: loop 0x2234ec1002d
This output shows classic shellcode patterns in notepad.exe, including:
- RWX memory permissions (PAGE_EXECUTE_READWRITE)
- Assembly code that manipulates the Process Environment Block (PEB)
- API hashing techniques commonly used in shellcode
This command shows which pages are memory resident and can dump suspicious memory regions for further analysis.
Common Injection Techniques
1. Shellcode Injection
Shellcode injection is the most basic in-memory technique. The attack follows these steps:
- Open a target process (
OpenProcess) - Allocate memory in the process (
VirtualAllocEx) - Write shellcode payload to the allocated section (
WriteProcessMemory) - Create a new thread to execute the shellcode (
CreateRemoteThread)
Detection indicators:
- Processes with unexpected RWX memory regions
- Unusual network connections from legitimate processes
- Assembly code patterns typical of shellcode
Here’s an example of shellcode injection detected by malfind:
6444 notepad.exe 0x2234ec10000 0x2234ec10fff VadS PAGE_EXECUTE_READWRITE 1 1 Disabled
fc 48 83 e4 f0 e8 cc 00 .H......
00 00 41 51 41 50 52 48 ..AQAPRH
31 d2 51 56 65 48 8b 52 1.QVeH.R
60 48 8b 52 18 48 8b 52 `H.R.H.R
20 4d 31 c9 48 8b 72 50 .M1.H.rP
48 0f b7 4a 4a 48 31 c0 H..JJH1.
ac 3c 61 7c 02 2c 20 41 .<a|.,.A
c1 c9 0d 41 01 c1 e2 ed ...A....
0x2234ec10000: cld
0x2234ec10001: and rsp, 0xfffffffffffffff0
0x2234ec10005: call 0x2234ec100d6
0x2234ec1000a: push r9
0x2234ec1000c: push r8
0x2234ec1000e: push rdx
0x2234ec1000f: xor rdx, rdx
0x2234ec10012: push rcx
0x2234ec10013: push rsi
0x2234ec10014: mov rdx, qword ptr gs:[rdx + 0x60]
0x2234ec10019: mov rdx, qword ptr [rdx + 0x18]
0x2234ec1001d: mov rdx, qword ptr [rdx + 0x20]
0x2234ec10021: xor r9, r9
0x2234ec10024: mov rsi, qword ptr [rdx + 0x50]
0x2234ec10028: movzx rcx, word ptr [rdx + 0x4a]
0x2234ec1002d: xor rax, rax
0x2234ec10030: lodsb al, byte ptr [rsi]
0x2234ec10031: cmp al, 0x61
0x2234ec10033: jl 0x2234ec10037
0x2234ec10035: sub al, 0x20
0x2234ec10037: ror r9d, 0xd
0x2234ec1003b: add r9d, eax
0x2234ec1003e: loop 0x2234ec1002d
This shows classic shellcode characteristics: PEB manipulation, API hashing, and direct assembly instructions without the MZ header that would indicate a full PE file.
2. Process Hollowing
Process hollowing creates a legitimate process in a suspended state, then replaces its memory with malicious code:
- Create the target process (e.g.,
notepad.exe) in a suspended state - Query the process to extract its base address pointer from the Process Environment Block (PEB)
- Read memory pointed to by the image base address to get the actual base address value
- Read the PE structure to get the EntryPoint address
- Write shellcode to the EntryPoint address and resume thread execution
Detection indicators:
- Processes with modified entry points
- Legitimate process names with suspicious behavior
- Memory regions that don’t match the original executable
Here’s an example of process hollowing detected by malfind:
1730 smartscreen.exe 0x1ac37560000 0x1ac37577fff VadS PAGE_EXECUTE_READWRITE 1 1 Disabled
48 89 54 24 10 48 89 4c H.T$.H.L
24 08 4c 80 44 24 18 4c $.L.D$.L
39 4c 24 20 48 8b 41 28 9L$ H.A(
48 8b 48 08 48 8b 51 50 H.H.H.QP
48 83 c2 f8 48 8b ca 48 H...H..H
08 60 00 56 37 ac 01 00 .`.V7...
00 48 2b c8 48 81 f9 70 .H+.H..p
0f 00 00 76 09 48 c7 c1 ...v.H..
0x1ac37560000: mov qword ptr [rsp + 0x10], rdx
0x1ac37560005: mov qword ptr [rsp + 8], rcx
0x1ac3756000a: mov qword ptr [rsp + 0x18], r8
0x1ac3756000f: mov qword ptr [rsp + 0x20], r9
0x1ac37560014: mov rax, qword ptr [rcx + 0x28]
0x1ac37560018: mov rcx, qword ptr [rax + 8]
0x1ac3756001c: mov rdx, qword ptr [rcx + 0x50]
0x1ac37560020: and rdx, 0xfffffffffffffff8
0x1ac37560024: mov rcx, rdx
0x1ac37560027: movabs rax, 0x1ac37560060
0x1ac37560031: sub rcx, rax
0x1ac37560034: cmp rcx, 0x70f
0x1ac3756003b: jbe 0x1ac37560046
2700 notepad.exe 0x400000 0x1392fff VadS PAGE_EXECUTE_READWRITE 3987 1 Disabled
4d 5a 90 00 03 00 00 00 MZ......
04 00 00 00 ff ff 00 00 ........
b8 00 00 00 00 00 00 00 ........
40 00 00 00 00 00 00 00 @.......
00 00 00 00 00 00 00 00 ........
00 00 00 00 00 00 00 00 ........
00 00 00 00 80 00 00 00 ........
0x400000: pop r10
0x400002: nop
0x400003: add byte ptr [rbx], al
0x400005: add byte ptr [rax], al
0x400007: add byte ptr [rax + rax], al
0x40000a: add byte ptr [rax], al
This example shows process hollowing characteristics: the notepad.exe process has an MZ header at its base address (0x400000), but the memory region has RWX permissions, indicating the original executable has been replaced with malicious code while maintaining the PE structure.
3. Reflective DLL Injection
Reflective DLL injection uses a self-mapping DLL that loads itself into memory without relying on the Windows loader:
- Open target process and allocate memory
- Copy the DLL into the allocated memory
- Copy function name hash and arguments after the DLL
- Copy bootstrap shellcode that calls the reflective loader
- Create a remote thread using the shellcode address as entry point
Detection indicators:
- MZ headers found in
malfindoutput (indicating PE files in memory) - DLL-like structures in unexpected memory locations
- Self-modifying code patterns
Here’s an example of what reflective DLL injection looks like in malfind output:
7516 notepad.exe 0x1f67c8c0000 0x1f67c91afff VadS PAGE_EXECUTE_READWRITE 91 1 Disabled
4d 5a 90 00 03 00 00 00 MZ......
04 00 00 00 ff ff 00 00 ........
b8 00 00 00 00 00 00 00 ........
40 00 00 00 00 00 00 00 @.......
00 00 00 00 00 00 00 00 ........
The key indicator here is the MZ header (4d 5a) at the beginning of the memory region, which is the signature of a Windows PE (Portable Executable) file. This suggests that a complete DLL has been loaded into memory through reflective injection, rather than just shellcode.
Reference: [Process Injection Detection with Malfind](https://www.linkedin.com/pulse /process-injection-detection-malfind-britton-manahan/) by Britton Manahan