Generate custom profile using btf2json
How to use btf2json to generate a kernel profile for Volatility 3, without using a virtual machine and entirely within WSL.
Last updated
Was this helpful?
How to use btf2json to generate a kernel profile for Volatility 3, without using a virtual machine and entirely within WSL.
Last updated
Was this helpful?
My previous guides (and ) have used dwarf2json, fresh virtual machines, and full debugging kernels. This is a somewhat time intensive process and doesn't scale that well - you have to generate multiple fresh virtual machines (depending on flavour/variant), install multiple debugging profiles from slow Canonical debugging repositories, to generate multiple profiles. This assumes you have access to an environment you can (or are allowed to) generate new virtual machines, and doing this in an enterprise environments (with considerations like TLS/SSL inspection, EDR registration, host management, etc etc) becomes an incredibly long winded process.
A few days ago, I saw an announcement from Volatility regarding their plugin contest and btf2json caught my eye.
"Valentin Obst: btf2json
The btf2json project is a very promising effort to ease the burden of large-scale Linux memory analysis. By incorporating information in the readily available vmlinuz file, analysts can create Volatility 3 symbol tables without the need for a full debug kernel. Through acquisition techniques that incorporate filesystem data, it appears that the final version of this project will enable analysis with only information stored within the memory sample – a large shift from the currently difficult method to gather this information across Linux systems and distributions.
Related References: Source:
The tool is great and it works as expected, however the guide/instructions on GitHub are perhaps a little unclear, so I thought I'd write a guide here on how to practically generate a custom profile using btf2json and without access to a virtual machine.
At a high level, this is the process;
Obtain/generate memory sample (DumpIt for Linux, AVML, etc)
Identify full kernel banner (this is important, don't skip this step)
Identify & obtain kernel image and linux modules from relevant repository.
Extract kernel image from package
Decompress kernel image (decompress vmlinuz to vmlinux)
Extract system map from linux modules package
Bring it all together with btf2json
Modify volatility3 schema
Test profile
Let's get started.
Obtain/generate memory sample (DumpIt for Linux, AVML, etc)
Identify full kernel banner (this is important, don't skip this step)
We can use the volatility3 plugin 'banners' to identify banner information. Be mindful that volatility sometimes outputs raw/escape characters in its output. Although the output below is the full value, make sure you remove any prepended/trailing values (like \b for backspace) are removed. Depending on how messy the output is, this may require some trial and error.
Identify & obtain kernel image and Linux modules from relevant repository.
From the above, we can see we have an Ubuntu host with 6.5.0-41-generic.
Extract kernel image from package
We have the kernel package, but it's inside a .deb file (which is an Ubuntu package). We don't want to install it, we want to extract a file from within it. We want to extract vmlinuz-6.5.0-41-generic, but how can we do that? Packages contain data streams and controls streams. If we were to use 7zip (as shown below), you'd be presented with 2 additional zst files (these are compressed with zstd and can't be uncompressed with 7zip)
We can use the dpkg -c command to identify which files we want.
We can then use dpkg with the fsystarfile option to inspect and ultimately extract the file.
This is the syntax;
Using the package above, this would result in the following command (one liner, code block is wrapped)
Decompress kernel image (decompress vmlinuz to vmlinux)
Decompress vmlinuz into vmlinux
Extract system map from linux modules package
Download our corresponding kernel modules package
Perform the same steps as 4, just targeting the System.Map file
Extract System.map-6.5.0-41-generic (one liner, code block is wrapped)
Bring it all together with btf2json
In the same directory, download btf2json
Remember how we identified the banners in step 1? You'll need the full value here.
The final command;
You can see we end up with the profile "13cubed-btfs2json.json" which you'll need to place in volatility3 symbols folder.
Modify volatility3 schema
Test Profile
Move your new profile (13cubed-btf2json.json) to your symbols folder.
Check it's registered.
Test the profile
For this step, we'll use a publicly available sample. recently released an analysis challenge on which involved examination of a memory sample from an Ubuntu machine. The sample is available to .
You'll see that this is important later as btf2json requires you to input this value so it can generate a compatible profile. The variable you provide is going to be converted/encoded in base64, and stored in the profile (as I here)
A quick search gives us a download location; and a direct link;
btf2json doesn't handle compressed linux kernels/images. vmlinuz is the compressed version of vmlinux. The bash script used to extract/decompress the compressed image should be included in your kernel tree (usually /usr/src/kernels/your-kernel-version/scripts/extract-vmlinux). If not, you can .
In \volatility3-2.5.21\volatility3\schemas you'll see a file named 'schema-6.2.0.json'. Open that in your favourite text editor, and here.