Fileless malware, living-off-the-land, and kernel rootkits all share one trait: they try to leave nothing on disk. That makes RAM the place the evidence actually lives. Memory forensics is the practice of capturing that volatile state and reading it back, the running processes, the injected code, the network connections, the things that vanish on reboot.
This is a working guide to the analysis, not an overview. It covers acquiring memory cleanly, the process-level techniques for spotting hidden, injected, and hollowed processes, walking the VAD tree, and hunting kernel rootkits, DLL hijacking, and persistence. The example code leans toward Volatility, with detours through Rekall and some scripting sketches for the parts you’d usually automate.
One thing to set up front: the command examples use Volatility 2 syntax, including the --profile=Win7SP1x64-style
profile flag. Volatility 3 dropped explicit profiles and auto-detects the OS from symbol tables, so on a current install
you’ll run the same plugins without the profile argument. The concepts carry over unchanged; only the invocation moved.
Memory acquisition fundamentals#
Analysis is only as good as the capture that fed it. A sloppy acquisition can corrupt the image, miss regions, or tip off malware that watches for it, so it’s worth getting this part right before touching a single plugin.
Memory acquisition methods#
Windows memory acquisition#
# WinPmem, https://github.com/Velocidex/WinPmem
# Current builds take the output path as a positional argument (no -o flag):
winpmem_mini_x64.exe memory_dump.rawREM Windows: Using DumpIt (simple GUI tool)
REM Download from official sources
DumpIt.exe /Q /O memory_dump.raw#!/bin/bash
# Linux: Using LiME (Linux Memory Extractor)
# Security Note: LiME requires kernel module loading, which may be logged
# Only use on systems you own or have explicit permission to analyze
# Load LiME kernel module
insmod lime.ko "path=/tmp/mem_dump.lime format=lime"
# Or AVML, Microsoft's "Acquire Volatile Memory for Linux", self-contained, no module to load:
avml acquire /tmp/memory_dump.lime
# Hash the image the moment it's captured:
sha256sum /tmp/memory_dump.lime > memory_dump.sha256Linux memory acquisition#
#!/bin/bash
# Using /proc/kcore (requires root, may be detected)
dd if=/proc/kcore of=/tmp/kcore_dump.raw bs=1M
# Using LiME with Volatility profile
insmod lime.ko "path=/tmp/mem_dump.lime format=lime"
# fmem was the classic /dev/fmem approach but is abandoned and breaks on
# modern kernels. LiME and AVML above are the paths that still work.macOS memory acquisition#
#!/bin/bash
# macOS is the hard case. On older Intel Macs, osxpmem (part of the pmem suite)
# was the standard tool:
sudo osxpmem.app/osxpmem -o /Volumes/External/memory_dump.aff4
# On modern macOS (SIP, and especially Apple Silicon) a full RAM capture is
# largely closed off. Plan around live triage rather than a clean image.Acquisition best practices#
- Minimize System Impact: Use acquisition methods that don’t require extensive kernel modifications
- Chain of Custody: Document acquisition process, tools used, and hash verification
- Anti-Forensic Awareness: Some malware detects memory acquisition attempts
- Live vs. Dead Acquisition: Choose method based on whether system is running or powered off
- Compression: Use compression to reduce storage requirements and transfer times
Validating the dump#
import hashlib
import os
def validate_memory_dump(dump_path, expected_hash=None):
"""Validate memory dump integrity"""
# Calculate SHA256 hash
sha256 = hashlib.sha256()
with open(dump_path, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b""):
sha256.update(chunk)
actual_hash = sha256.hexdigest()
if expected_hash:
if actual_hash == expected_hash:
print(f"✓ Memory dump integrity verified: {actual_hash}")
return True
else:
print(f"✗ Hash mismatch! Expected: {expected_hash}, Got: {actual_hash}")
return False
else:
print(f"Memory dump hash: {actual_hash}")
return actual_hash
# Usage
validate_memory_dump('memory_dump.raw')Terminology and core concepts#
Before we dive into advanced analysis techniques, let’s establish a solid foundation of key concepts that form the basis of memory forensics.
What memory forensics covers#
Memory forensics encompasses the extraction, preservation, and analysis of volatile system memory (RAM) to investigate digital incidents. Unlike traditional forensics that examines persistent storage, memory analysis reveals:
- Runtime State: Active processes, network connections, and loaded modules
- Ephemeral Artifacts: Data that exists only in memory and disappears on reboot
- Malware Behavior: In-memory execution, code injection, and rootkit functionality
- Temporal Evidence: Process timelines and execution sequences
Virtual memory architecture#
Virtual address space (VAS)#
Each process operates within its own virtual address space, an isolated memory environment that provides:
- Isolation: Processes cannot directly access each other’s memory
- Abstraction: Virtual addresses map to physical memory through page tables
- Protection: Memory protection mechanisms (read/write/execute permissions)
- Scaling: Allows processes to use more memory than physically available through paging
Page tables and translation#
# Conceptual page table translation
def virtual_to_physical(virtual_address):
"""
Simplified page table walk (x86-64)
In reality, this involves multiple levels of page tables
"""
# Extract components from virtual address
# x86-64: 48-bit virtual address, 4KB pages
page_offset = virtual_address & 0xFFF # 12 bits
page_table_index = (virtual_address >> 12) & 0x1FF # 9 bits
page_directory_index = (virtual_address >> 21) & 0x1FF # 9 bits
page_directory_pointer_index = (virtual_address >> 30) & 0x1FF # 9 bits
page_map_level_4_index = (virtual_address >> 39) & 0x1FF # 9 bits
# Page table walk would continue here...
# Return physical address = page_frame * 4096 + offset
return physical_addressMalware concepts worth knowing#
Kernel-level rootkits#
Kernel-mode rootkits operate at Ring 0 (highest privilege level) and can:
- Hook System Calls: Intercept and modify kernel functions
- Manipulate Process Lists: Hide processes from enumeration
- Control Hardware Access: Direct I/O operations
- Bypass Security Software: Disable or evade endpoint detection
Common rootkit techniques:
- SSDT Hooking: Modify System Service Descriptor Table
- IRP Hooking: Intercept I/O Request Packets
- DKOM (Direct Kernel Object Manipulation): Modify kernel data structures
- Kernel Module Injection: Load malicious kernel modules
DLL hijacking variants#
- Search Order Hijacking: Place malicious DLL in directory searched before legitimate location
- Phantom DLL Hijacking: Create DLL with same name as non-existent dependency
- DLL Proxying: Forward legitimate calls while injecting malicious functionality
- Side-Loading: Abuse legitimate application loading unsigned DLLs
Process hollowing mechanics#
Process hollowing involves:
- Process Creation: Start legitimate process in suspended state
- Memory Unmapping: Unmap original executable image
- Code Injection: Allocate new memory and inject malicious code
- Context Modification: Update process context (entry point, image base)
- Thread Resumption: Resume main thread to execute malicious code
Persistence mechanisms#
- Registry Run Keys: Autorun entries in Windows Registry
- Scheduled Tasks: System scheduler persistence
- Service Creation: Install as Windows service
- WMI Subscriptions: Event-driven persistence via Windows Management Instrumentation
- Boot Sector Modification: Modify master boot record for pre-OS execution
- Firmware Implants: UEFI/BIOS-level persistence (extremely advanced)
Virtual address descriptors (VAD)#
VAD nodes contain critical forensic information:
class VADNode:
def __init__(self):
self.start_vpn = 0 # Starting Virtual Page Number
self.end_vpn = 0 # Ending Virtual Page Number
self.protection = 0 # Protection: a 3-bit index (0-7), NOT ORed R/W/X bits
self.vad_type = 0 # Type of VAD (Private/Mapped/File)
self.control_area = None # Points to file object for mapped files
def get_size(self):
return (self.end_vpn - self.start_vpn + 1) * 4096 # 4KB pages
def is_suspicious(self):
# Windows stores VAD protection as an index into MmProtectToValue,
# not as ORed permission bits. The value to watch is EXECUTE_READWRITE (6):
# private RWX memory is the classic injected-code signature.
PAGE_EXECUTE_READWRITE = 6
return self.protection == PAGE_EXECUTE_READWRITEVAD analysis reveals:
- Memory Layout: How process memory is organized
- Injected Code: Regions with suspicious protection flags
- Mapped Files: DLLs and memory-mapped files
- Heap Allocations: Dynamically allocated memory regions
- Shared Memory: Inter-process communication channels
Step-by-step analysis techniques#
Using process timelining, high-low level analysis, and walking the VAD tree are essential for identifying and investigating sophisticated attacks that rely on in-memory execution or rootkit-like capabilities to evade detection.
Process timelining#
Process timelining helps you spot suspicious activity by looking at when processes ran, not just which ones are running now.
Process list vs. process timeline#
Before we dive into the details of process timelining, it’s important to understand the difference between a process list and a process timeline. A process list is a static snapshot of the processes that are currently running on a system. A process timeline, on the other hand, is a chronological sequence of the processes that have executed on a system over a period of time.
Process timelining involves analyzing the process timeline to identify any processes that are unusual or suspicious. By analyzing the timeline, we can identify processes that may have been hidden or terminated, as well as processes that may have executed with unusual arguments or in unusual contexts.
Process timelining techniques#
Creating comprehensive process timelines requires multiple complementary approaches, each revealing different aspects of system activity.
Pslist and Pstree Analysis
#!/bin/bash # Security Note: These commands analyze memory dumps for process enumeration # Only run on memory dumps from systems you own or have permission to analyze # Basic process listing with detailed information volatility -f memory_dump.raw --profile=Win7SP1x64 pslist # Process tree showing parent-child relationships volatility -f memory_dump.raw --profile=Win7SP1x64 pstree # Full command lines and arguments for each process volatility -f memory_dump.raw --profile=Win7SP1x64 cmdlinePsscan and Psxview for Hidden Processes
#!/bin/bash # Security Note: These plugins scan for process structures that may be hidden # from normal enumeration, revealing rootkit activity # Scan physical memory for _EPROCESS structures (finds terminated/hidden processes) volatility -f memory_dump.raw --profile=Win7SP1x64 psscan # Cross-reference multiple process enumeration methods # Shows discrepancies that indicate hiding techniques volatility -f memory_dump.raw --profile=Win7SP1x64 psxview # List each process's loaded DLLs volatility -f memory_dump.raw --profile=Win7SP1x64 dlllistTimeline Reconstruction with Volatility
#!/bin/bash # Security Note: Timeline analysis reveals temporal patterns in system activity # Critical for understanding attack sequences and persistence mechanisms # Generate a body-file timeline (the plugin is timeliner, not timeline) volatility -f memory_dump.raw --profile=Win7SP1x64 timeliner --output=body --output-file=full_timeline.body # Focus on process-specific timeline volatility -f memory_dump.raw --profile=Win7SP1x64 timeliner --output=timeline_processes.csv # Convert to format suitable for timeline analysis tools # Use mactime for visualization (requires Sleuth Kit) mactime -d -z UTC -b full_timeline.body > timeline_visualization.csvScripting the timeline triage
Once you have a timeliner CSV, the triage is scriptable. Parse it, flag processes that lived only a few seconds, flag children of
svchost.exe,services.exe, orlsass.exethat have no business spawning anything, and grep the command lines for the usual openers (cmd.exe/powershell.exespawns, writes to autorun keys,.exefiles dropped to disk). None of this is conclusive on its own; it’s a way to sort thousands of events down to the dozen worth reading by hand.Cross-Timeline Correlation
#!/bin/bash # Security Note: Correlate multiple data sources for comprehensive analysis # Combine memory timeline with disk forensics and log analysis # Extract process timeline from memory volatility -f memory_dump.raw --profile=Win7SP1x64 timeliner > memory_timeline.csv # Extract file timeline from disk image # Requires disk image acquisition first fls -r -m / disk_image.dd > disk_timeline.txt # Combine timelines using custom correlation script python3 correlate_timelines.py memory_timeline.csv disk_timeline.txt > combined_timeline.jsonAnomaly detection, with a caveat
You can push this further with statistical anomaly detection, an isolation forest over features like execution hour, parent process, and network/file activity will happily surface outliers. Treat the output as triage, not a verdict. It tells you which events are unusual for this host, not which ones are malicious; you still confirm every hit by hand.
Timeline analysis and pattern recognition#
Timeline analysis goes beyond simple enumeration; it’s about understanding behavioral patterns and identifying deviations from normal system activity.
Statistical process behavior analysis#
The same baseline-and-deviate idea works at the process level. Build a baseline per process name, typical lifetime,
usual parent, the hours it normally runs, then alert when a new instance falls several standard deviations off: a
svchost.exe that lived four seconds, spawned from something other than services.exe, at 3 a.m. Each of those is a
weak signal alone. Stacked, they’re a lead.
Temporal attack reconstruction#
Reconstruction is mostly ordering and linking. Categorize each event into a rough stage (recon, initial access, execution, persistence, lateral movement, exfil), sort by timestamp, and connect events that fall within a short window of each other. Map the stages onto ATT&CK and you get a first-pass kill chain, enough to see the shape of the intrusion before you commit to the deep read. A directed graph is a natural fit if you want to visualize it, but the value is in the sequencing, not the drawing.
Behavioral pattern recognition#
Process Injection Indicators
- Sudden memory allocation spikes in legitimate processes
- Unusual thread creation patterns
- Modified entry points or image bases
- Presence of executable memory regions without file backing
Rootkit Detection Patterns
- Discrepancies between different process enumeration methods
- Missing processes in active process lists
- Hooked system calls or kernel functions
- Modified kernel data structures
Malware Persistence Markers
- Registry modifications in autorun keys
- Scheduled task creation with suspicious commands
- Service installation with unusual parameters
- DLL search order exploitation
Data Exfiltration Signals
- Unusual network connections to external IPs
- Large data transfers to unexpected destinations
- DNS queries with encoded data
- File compression followed by network activity
Anti-Forensic Activity
- Attempts to clear event logs
- Modification of system timestamps
- Deletion of forensic artifacts
- Encryption of memory regions
High-low level analysis#
High-low level analysis pairs the high-level view (processes, connections, modules) with the low-level one (raw process memory, file and registry structures). What one hides, the other tends to expose.
High-level data#
High-level data includes information such as network connections, running processes, and loaded modules. This information can be collected using tools such as Volatility or Rekall, which can analyze memory dumps and provide a snapshot of the system at the time the memory dump was taken.
To analyze high-level data, we can use Volatility’s netscan plugin (on Win7 x64; netstat is the Volatility 3 name) to list network
connections and identify suspicious ones.
volatility -f memory_dump.raw --profile=Win7SP1x64 netscanWe can also use Volatility’s pslist plugin to list all running processes and identify any suspicious processes.
volatility -f memory_dump.raw --profile=Win7SP1x64 pslistFinally, we can use Volatility’s dlllist plugin to list all loaded modules and identify any suspicious modules.
volatility -f memory_dump.raw --profile=Win7SP1x64 dlllistLow-level data#
Low-level data includes information such as process memory, file system activity, and registry activity. This information can be collected using tools such as Volatility or Rekall, as well as file system forensics tools such as Autopsy or The Sleuth Kit.
To analyze low-level data, we can use Volatility’s memdump plugin to dump the memory of a specific process and analyze it using a disassembler such as IDA Pro or Radare2.
volatility -f memory_dump.raw --profile=Win7SP1x64 memdump -p <pid> -D dump_dir/We can also use Volatility’s filescan plugin to search the memory dump for file system structures and identify any suspicious activity.
volatility -f memory_dump.raw --profile=Win7SP1x64 filescanFinally, we can use Volatility’s printkey plugin to list all registry keys that are present in the memory dump and identify any suspicious keys.
volatility -f memory_dump.raw --profile=Win7SP1x64 printkeyCombining the two#
By combining high-level and low-level analysis, we can identify suspicious activity that may be hidden from traditional process monitoring tools. For example, an attacker may use a rootkit to hide a malicious process from the process list, but this process may still be present in the memory dump and can be identified using low-level analysis.
Likewise, an attacker may use process hollowing to inject malicious code into a legitimate process, but this activity may be identified using high-level analysis by looking for unusual network connections or file system activity.
Walking the VAD tree#
Walking the VAD tree shows how a process laid out its memory, which is exactly where injected code and hollowed regions stand out.
What a VAD is#
A Virtual Address Descriptor (VAD) is a data structure that is used by the Windows operating system to manage the memory allocation of processes. Each process has its own VAD tree, which is a hierarchical structure that represents the memory space of the process.
By analyzing the VAD tree of a process, we can identify the memory regions that have been allocated by the process and the characteristics of each region, such as its protection level (read, write, execute) and its backing file on disk.
Walking the tree#
To walk the VAD tree of a process, we can use Volatility’s vadtree plugin. This plugin takes a process ID (PID) as input and generates a hierarchical representation of the VAD tree for the process.
volatility -f memory_dump.raw --profile=Win7SP1x64 vadtree -p <pid>The output of the vadtree plugin shows the VAD tree of the specified process, with each node representing a memory region that has been allocated by the process. The output also shows the protection level of each region and the backing file on disk, if one exists.
Reading the output#
Once we have generated the VAD tree of a process, the next step is to analyze the output and identify any suspicious activity. Some of the key things to look for when analyzing the VAD tree include:
Unusual Memory Regions
Memory regions that have unusual protection levels or are not backed by a file on disk may be indicative of malicious activity. For example, a memory region that is marked as executable and writable may be used by an attacker to inject malicious code into a process.
Memory Regions with Unusual Names
Memory regions that have unusual names may be indicative of malicious activity. For example, a memory region that is named “hollowed” may be part of a process hollowing attack.
Memory Regions with Unusual Sizes
Memory regions that have unusual sizes may be indicative of malicious activity. For example, a memory region that is much larger than it needs to be may be used by an attacker to store stolen data.
Unusual Backing Files
Memory regions that are backed by unusual files may be indicative of malicious activity. For example, a memory region that is backed by a file that is not normally used by the process may be part of a fileless malware attack.
By analyzing the VAD tree and looking for these indicators of malicious activity, we can identify memory regions that are unusual or suspicious and investigate them further.
Finding malice in memory#
Detecting malice in memory can be a challenging task, especially for advanced attackers who may use sophisticated techniques to hide their presence on a system. In this section, we will explore some of the techniques that can be used to identify malicious activity in memory, including detecting rogue, hidden, and injected processes, kernel-level rootkits, Dynamic Link Libraries (DLL) hijacking, process hollowing, and sophisticated persistence mechanisms.
Rogue, hidden, and injected processes#
One of the most common techniques used by attackers to hide their presence on a system is to inject malicious code into a legitimate process, creating what is known as a process injection attack. This technique can be used to bypass traditional process monitoring tools and evade detection.
To detect rogue, hidden, and injected processes, we can use Volatility’s psscan plugin to scan the memory dump for process structures and identify any suspicious activity.
volatility -f memory_dump.raw --profile=Win7SP1x64 psscanBy analyzing the output of the psscan plugin, we can identify any hidden or terminated processes, as well as processes that may have been injected with malicious code.
Kernel rootkits#
Kernel-level rootkits are a type of malware that operate at the kernel level of the operating system, allowing them to hide their presence and evade detection by traditional process monitoring tools. These rootkits can be extremely difficult to detect and remove.
To catch modules a rootkit has unlinked to hide, we can use Volatility’s ldrmodules plugin, which cross-references the three PEB module lists against the VAD and flags DLLs that are mapped but missing from one or more of them.
volatility -f memory_dump.raw --profile=Win7SP1x64 ldrmodulesldrmodules does no signature checking; what it gives you is the discrepancy, a module present in memory but absent from a list it should be on, which is exactly the footprint of DKOM-style hiding. We can also run malfind, which flags private, executable-and-writable memory regions containing PE headers or shellcode, a common sign of injected code.
volatility -f memory_dump.raw --profile=Win7SP1x64 malfindDLL hijacking#
Dynamic Link Libraries (DLL) hijacking is a technique used by attackers to replace legitimate DLL files with malicious versions. These malicious DLL files can be used to execute arbitrary code and evade detection.
To detect DLL hijacking, we can use Volatility’s dlllist plugin to list all loaded DLL files and identify any suspicious DLL files.
volatility -f memory_dump.raw --profile=Win7SP1x64 dlllistBy analyzing the output of the dlllist plugin, we can identify any DLL files that are not signed or are otherwise suspicious.
Process hollowing#
Process hollowing is a technique used by attackers to create a new process by hollowing out an existing, legitimate process and replacing its code with malicious code. This technique can be used to bypass traditional process monitoring tools and evade detection.
To detect process hollowing, malfind is a start, it catches the injected RWX regions, but true hollowing (where the image is swapped yet the VAD still names the legit module) is better caught by the hollowfind plugin or by cross-referencing dlllist and cmdline against what the process claims to be.
volatility -f memory_dump.raw --profile=Win7SP1x64 malfindRead those together and the hollowed process gives itself away: the on-disk identity and the in-memory reality no longer match.
Hunting persistence#
Sophisticated persistence mechanisms are techniques used by attackers to maintain their presence on a system even after it has been rebooted or reimaged. These persistence mechanisms can be extremely difficult to detect and remove.
To detect sophisticated persistence mechanisms, we can use Volatility’s hivelist plugin to list all registry hives and identify any suspicious hives.
volatility -f memory_dump.raw --profile=Win7SP1x64 hivelistBy analyzing the output of the hivelist plugin, we can identify any hives that are not part of the standard Windows configuration or are otherwise suspicious.
We can also use Volatility’s svcscan plugin to list all Windows services and identify any suspicious services.
volatility -f memory_dump.raw --profile=Win7SP1x64 svcscanBy analyzing the output of the svcscan plugin, we can identify any services that are not part of the standard Windows configuration or are otherwise suspicious.
Tools and frameworks#
Volatility#
Volatility is the gold standard for memory analysis, offering extensive plugin architecture for comprehensive investigations.
Writing your own plugin#
Volatility’s real strength is that the plugin API is open. When the built-ins don’t ask your exact question, you can
subclass AbstractWindowsCommand, walk the process list, and apply your own checks: flag a process whose image base
doesn’t start with a valid MZ header (a hollowing tell), an unbacked RWX VAD region, or a module loading out of
%TEMP%. In practice most of this already lives in malfind and ldrmodules, so read those first, they encode years
of refinement you’d otherwise be reinventing. Write a custom plugin when you have a detection idea the existing ones
genuinely don’t cover.
Other tools#
Rekall#
Rekall was Google’s fork of Volatility, and for a while it was the more ergonomic of the two. It’s effectively unmaintained now, so on a fresh setup reach for Volatility 3 rather than standing up Rekall. It’s worth knowing the name because you’ll still hit it in older writeups and tooling.
Automating the pipeline#
Nothing about the workflow above needs to be manual. A thin wrapper that runs pslist, psscan, psxview,
netscan, malfind, and hivelist over a dump, diffs the process listings to surface anything hidden, and writes the
output to per-plugin files gets you a repeatable first pass in one command. Keep the automation dumb: it collects and
flags, you judge. The moment a script starts deciding what’s malicious on its own, you’ve traded a reviewable process
for a black box.
Methodology and practice#
Investigation methodology#
Preparation Phase
- Understand the incident context
- Gather system information (OS version, architecture, installed software)
- Ensure proper chain of custody for evidence
- Prepare analysis environment (isolated, secure)
Acquisition Phase
- Choose appropriate acquisition method
- Validate acquisition integrity
- Document acquisition process
- Preserve original evidence
Analysis Phase
- Start with high-level overview (pslist, netscan)
- Identify suspicious processes and connections
- Deep dive into specific artifacts
- Correlate findings across data sources
Reporting Phase
- Document all findings with evidence
- Provide technical details and impact assessment
- Include remediation recommendations
- Preserve analysis artifacts
Quality assurance#
Validating findings#
Before you call anything malicious, corroborate it. One indicator is a lead, not a conclusion. A single RWX region
might be a JIT compiler; a process with an odd parent might be a legitimate installer. Require multiple independent
signals before you escalate, check destinations and paths against known-good baselines, and weight confidence
accordingly. The goal is to keep false positives from burying the real finding, which on a busy host they will.
Legal and ethical considerations#
Evidence handling#
- Chain of Custody: Maintain unbroken chain of evidence possession
- Documentation: Record all analysis steps and findings
- Integrity: Use cryptographic hashes to verify evidence integrity
- Privacy: Handle sensitive data according to privacy regulations
- Authorization: Ensure proper legal authorization for analysis
Ethical analysis#
- Authorized Access: Only analyze systems you own or have permission to analyze
- Data Protection: Protect sensitive information discovered during analysis
- Responsible Disclosure: Report findings to appropriate parties
- Professional Standards: Follow industry best practices and standards
Closing thoughts#
Memory forensics earns its place because it sees what disk forensics can’t: the code that only ever ran in RAM. Rootkits, hollowed processes, injected DLLs, the connections and keys that vanish on reboot, all of it lives in the image and nowhere else.
The tools do a lot of the work, but they don’t do the judgment. A plugin flags an RWX region; you decide whether it’s a JIT or a payload. malfind names a process; you confirm the injection by hand. That gap between “flagged” and “confirmed” is the whole job, and it’s why methodology matters more than any single plugin.
If you take one thing from this: work high-level to low-level, corroborate every finding with a second signal, and never let an automated verdict stand in for a look with your own eyes. The evidence is in the bytes. Reading it is still on you.