Igor posted a great answer previously on SO about the format of the Linux kernel image on ARM.
Assuming I can't boot my kernel image, can someone give me pointers on finding this compressed symbol table in the binary?
Reverse Engineering Stack Exchange is a question and answer site for researchers and developers who explore the principles of a system through analysis of its structure, function, and operation. It only takes a minute to sign up.Sign up to join this community
After decompressing and loading the kernel, you need to find a couple of tables that encode the compressed symbol table. These are (in the usual order they are placed in binary):
kallsyms_addresses- a table of addresses to all public symbols in the kernel
kallsyms_num_syms- not a table but just an integer with total number of symbols (should match previous table)
kallsyms_names- a list of length-prefixed byte arrays that encode indexes into the token table
kallsyms_token_table- a list of 256 zero-terminated tokens from which symbol names are built
kallsyms_token_index- 256 shorts pointing to the corresponding entry in
They're not hard to find with some experience. A good way to find the first one is to look for several 0xC0008000 values in a row, because a typical kernel symbol table starts like this:
C0008000 T __init_begin C0008000 T _sinittext C0008000 T _stext C0008000 T stext
After locating the tables the symbol recovery is trivial. I made a script for IDA that does it automatically, you can find it here (
kallsyms.py in the tools zip).
For more the details of how it's implemented in the kernel, see
You mentioned that you do have a running kernel available. It is possible to obtain symbol information from a running kernel by reading
/proc/kallsyms. On newer distributions, this information is disabled by default for security reasons (all symbols will be displayed as 0x0 addresses), but you can manually enable it by running the following command as root:
echo 0 > /proc/sys/kernel/kptr_restrict
Once you've obtained the list of kernel symbols/address pairs, it should be easy to convert to any format desired, e.g. an IDA
.idc script for import.
This is a bit tricky to answer without getting my hands on the file and verifying a few assumptions based on the question and the linked answer. However, let me try, perhaps we can extend it further if you elaborate more on some aspects of the file.
We know it's an ARM file and from your description this pretty much sounds like an ARM kernel image for U-Boot. Now the problem is that I cannot know whether that's true, but you could run the oft mentioned
firmware-mod-kit on the file to see what that gives you.
dd if=<image> of=<recovered file> bs=64 skip=1
This skips 1 block of 64 bytes and otherwise writes the data from
<recovered file>. Essentially it reverses - in part - the effects of the
mkimage tool, which is part of U-Boot.
Now, assuming everything so far works - and that is a huge assumption - you should be able to decompress (
gzip -d) the resulting file and end up with something you can hopefully
grep. If I was you I'd then use
file to check what kind of file it is and process it further if I happened to get anything meaningful out of it. If not, I would treat the file with
binwalk again and failing that run
strings on it.
Okay, tried the process myself. Downloaded this Debian package, unpacked it, got a
zImage-126.96.36.199-power51 which I then looked at in 010 Editor and it's true, this is an ARM kernel image according to the marker (see reading section below):
After that I tried to skip the first 64 Byte and then decompress the rest, to no avail. Investigating a bit more.
If you manage to get more information using this incomplete answer, please edit your question and I'll amend my answer once I notice your edit, to add more (hopefully useful) information.
Okay, for the zImage in question it turns out
binwalk, mentioned in my original answer, can at least handle the file and outputs:
12900 0x3264 gzip compressed data, from Unix, last modified: Mon Jul 23 13:41:37 2012, max compression
Lovely. Do let's run
dd to extract the
gzip stuff and then extract it:
dd if=zImage-188.8.131.52-power51 of=extract.gz bs=12900 skip=1 && gunzip extract.gz && ls -l extract
Once I extracted it, I ran
binwalk again after noticing that
file didn't yield a result:
DECIMAL HEX DESCRIPTION ------------------------------------------------------------------------------------------------------- 135456 0x21120 gzip compressed data, from Unix, last modified: Mon Jul 23 13:38:47 2012, max compression 973460 0xEDA94 ELF 1070320 0x1054F0 CramFS filesystem, big endian size 2126262976 CRC 0xdc0a0e1, edition 4040895977, 78662882 blocks, 271618533 files
However, I don't want to proceed now without further input from you. Just an example how it could be investigated. One more thing
strings does produce a list of symbols, but since I presume you want symbols and their addresses, I reckon there is more to be investigated.
0x016F2818can be found at offset
this forum entry, in particular the post by user fattire, which mentions
There's a 64 byte header you have to cut off of uRamdisk/uRecRam:
dd if=uRamdisk of=uRamdisk.cpio.gz bs=64 skip=1
cpio -i -F uRamdisk.cpio
which essentially implies that you have to expect an
initrd (hence the CPIO format) at offset 64. That is, the "kernel image" would actually turn out to be the old kernel format which embedded the
initrd (also see
mkimage man page under "Create old legacy image").