How to extract and disassemble a Linux kernel
Extracting and examining the disassembled assembly code for your Linux kernel can be really helpful if you want to look for some malfunctioning piece of code or want to examine entry points for various functions. The process is fairly intuitive once you know the necessary tools that are required.
The process below is described for Ubuntu 20.04 but should work for other GNU/Linux based operating systems as well. We will be using the objdump command-line utility that comes pre-installed with all Ubuntu distributions. To check if it is installed and working, type the following on your terminal and you should see the version and license information about the program.
Attention reader! Don’t stop learning now. Get hold of all the important CS Theory concepts for SDE interviews with the CS Theory Course at a student-friendly price and become industry ready.
The Linux kernel executable is called vmlinuz . This is the executable file that is first loaded into the memory when we boot up our computer and this is what we will be disassembling. The file is located under /boot/ directory. It is, however, compressed. We will have to first extract it before disassembly using the extract-vmlinux script that comes with the Linux-headers.
STEP 1: Copying the compressed kernel executable to a different location :
First, we will create a copy of our kernel to a location of our choice and cd into that directory. Superuser privileges are necessary for this step.
mkdir ~/kernel-tmp sudo cp /boot/vmlinuz-$(uname -r) ~/kernel-tmp cd kernel-tmp
STEP 2: Extracting the kernel :
Now we will extract the compressed kernel that we have copied into our directory. we will use the extract-vmlinux script that comes with our Linux-headers.
sudo /usr/src/linux-headers-$(uname -r)/scripts/extract-vmlinux vmlinuz-$(uname -r) > decomp-vmlinuz
The above command will run the extract-vmlinux script for our copy of the kernel and output it into a file with the name decomp-vmlinuz that will be located under our current working directory.
STEP 3: Disassembly :
We are now ready to disassemble our decompressed executable. Simply run the following command
objdump -D decomp-vmlinuz > disassembled-vmlinuz.asm
The disassembled kernel code can now be found in dissassembled-vmlinuz.asm file.
STEP 4: Finding symbols :
The disassembled kernel file has no symbols, hence we cannot find the starting point of functions very easily. Linux stores all symbol names and their starting address in a separate file. We will copy that file as well for our ease of access.
sudo cp /boot/System.map-$(uname -r) ./
Now, we can easily grep for our symbol name in the System.map-x.x.x-xx-generic file to get the starting address, then we can look for that address in the dissassembled-vmlinuz.asm file.
For e.g. we could grep for register_keyboard_notifier
sudo cat System.map-$(uname -r) | grep register_keyboard_notifier
which will give an output somewhat like:
ffffffff816ec720 T register_keyboard_notifier
We can copy the starting address and search for it in the disassembled kernel code to find something like this :
ffffffff816ec720: e8 4b 13 98 ff callq 0xffffffff8106da70 ffffffff816ec725: 55 push %rbp ffffffff816ec726: 48 89 fe mov %rdi,%rsi ffffffff816ec729: 48 c7 c7 a0 f7 d8 82 mov $0xffffffff82d8f7a0,%rdi ffffffff816ec730: 48 89 e5 mov %rsp,%rbp ffffffff816ec733: e8 18 bb 9d ff callq 0xffffffff810c8250 ...