Getting Kernel Version from The Compressed Kernel Image

Getting kernel version from the compressed kernel image

Check kernel compression algorithm

Most likely your zImage was compressed using LZMA compressor. You can check it in next files:

  • in .config file (if you built kernel by yourself)
  • in /boot/config-`uname -r` file (if you are using your distribution)
  • in /proc/config.gz file (if CONFIG_IKCONFIG_PROC is enabled)

Look for CONFIG_KERNEL_* param:

$ cat .config | grep '^CONFIG_KERNEL_[^_]\+='

If you have CONFIG_KERNEL_LZMA=y set, it means LZMA compressor is used.

Unpack zImage

LZMA format has 5d 00 00 header signature. So one can find position of compressed Image file in zImage file this way:

$ grep -P -a -b -m 1 --only-matching '\x5D\x00\x00' zImage | cut -f 1 -d :

To extract compressed Image:

$ pos=$(grep -P -a -b -m 1 --only-matching '\x5D\x00\x00' zImage | cut -f 1 -d :)
$ dd if=arch/arm/boot/zImage of=piggy.lzma bs=1 skip=$pos

Now make sure that piggy.lzma is actually LZMA archive:

$ file piggy.lzma 

piggy.lzma: LZMA compressed data, streamed

Decompress piggy.lzma:

$ unlzma -c piggy.lzma > Image

Find the Linux version

Now that you have unpacked Image, you can find the Linux version using strings tool:

$ strings Image | grep 'Linux version'

which should give you something like this:

Linux version 4.4.11-188843-g94c4bf5-dirty (joe@joe-laptop) (gcc version 4.8 (GCC) ) #1 SMP PREEMPT Thu May 26 20:55:27 EEST 2016

Getting uname information from a compressed kernel image

For Linux image compressed with gzip, use this:

dd if=arch/arm/boot/zImage bs=1 skip=$(LC_ALL=C grep -a -b -o $'\x1f\x8b\x08\x00\x00\x00\x00\x00' arch/arm/boot/zImage | head -n 1 | cut -d ':' -f 1) | zcat | grep -a 'Linux version'

For Linux image compressed with xz, use this:

dd if=arch/arm/boot/zImage bs=1 skip=$(LC_ALL=C grep -a -b -o $'\xFD\x37\x7A\x58\x5A\x00' arch/arm/boot/zImage | head -n 1 | cut -d ':' -f 1) | xzcat | grep -a 'Linux version'

Because the image file contains data after the end of the compressed stream, you'll get an error you can ignore.

The string constant appears to be part of the frozen userspace visible kernel API:

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=init/version.c;hb=HEAD#l40

Is it possible to get kernel version from ELF image file without disassemble or using grep or strings?

As previously mentioned, the version number is hardcoded into the compressed image file. First it depends on the compression algorithm used to compress the content, how to decompress it.
Decompressing files in linux could be challenging due to the combination of compression algorithms and the correlated tool options (not to forget a newer version of tar for newer algorithms).
For files with

file extension tar.gz, tgz use e.g. $ tar -xzv -f vmlinuz.tgz
file extension tar.xz, use e.g. $ tar -xJv -f vmlinuz.tar.xz
file extension tar.bz2, use e.g. $ tar -xjv -f vmlinuz.tar.bz2

So if you have access to the file utility (should also run on windows), run the following to receive the version string and additional information of your file named e.g. vmlinuz-4.x.y-z-a.

file vmlinuz-4.x.y-z-a

Another possibility to reverse-engineer would be to read all strings of the binary file vmlinuz-4.x.y-z-a and grep for a part of the possible solution.

strings vmlinuz-4.x.y-z-a | grep 'linked,'

How can I determine the build/version of Linux kernel 'uImage'?

I just realized, the kernels I have immediate access to do have the version string stored uncompressed amongst the headers. strings uImage | grep 2.6 ought to be good enough for any 2.6 kernel which covers pretty much everything in the last 5+ years).

(original answer follows)


It's theoretically possible, but not entirely trivial.

Modern Linux kernel versions use a format called bzImage (for x86/x86_64, YMMV on other platforms). It actually consists of an ELF header and some other minutia (like a bit of decompression code) followed by, yes, a compressed image of the actual kernel.

Traditionally, the compression algorithm was zlib (contrary to popular misconception, 'bzImage' did not stand for "bzipped image", but for "big zImage" -- the original zImage format not being able to handle large kernels), though versions after 2.6.30 also support bzip2 and LZMA.

What you'll probably have to do is determine exactly where the compressed data starts (sorry, can't help you there, but trial and error might work), and write a bit of code to run it through the library for whichever compression algorithm is in use.

Buildroot doesn't generate compressed Kernel image

On arm64, Linux does not support self-extracting compression. It relies on the boot loader to do that.

The Linux build system does have an Image.gz (and Image.bz2 etc.) target, but it does nothing more than calling gzip on Image (compare this with zImage, which adds a self-extractor).

Since it is easy to do the compression outside of the kernel build system, and since there are so many different compressors possible, Buildroot doesn't provide options for them. However, it is possible to select a custom image name (BR2_LINUX_KERNEL_IMAGE_TARGET_CUSTOM) and then set BR2_LINUX_KERNEL_IMAGE_TARGET_NAME to Image.gz. Alternatively, you can do the compression in a post-build script.

Remember to make sure that the bootloader is able to decompress with that algorithm.

Find linux kernel version of a router firmware from the filesystem

Along side the squashfs-root folder there was a A0 file.

binwalk A0 revealed:

 DECIMAL    HEX         DESCRIPTION
-------------------------------------------------------------------------------------------------------------------
0 0x0 ELF 64-bit MSB MIPS32 rel2 executable, MIPS, version 1 (SYSV)
2969600 0x2D5000 Linux kernel version "2.6.16.26-Cavium-Octeon (william@J10) (gcc version 4.1.1 (Cavium@J10) (gcc version 4.1.1 (Cavium Networks Development Build)) "
2991185 0x2DA451 LZMA compressed data, properties: 0x40, dictionary size: 2097152 bytes, uncompressed size: 2097216 bytes
3329399 0x32CD77 LZMA compressed data, properties: 0x40, dictionary size: 16777216 bytes, uncompressed size: 1073741824 bytes
3429479 0x345467 LZMA compressed data, properties: 0x40, dictionary size: 33554432 bytes, uncompressed size: 131072 bytes
3429503 0x34547F LZMA compressed data, properties: 0x40, dictionary size: 33554432 bytes, uncompressed size: 131072 bytes
3429527 0x345497 LZMA compressed data, properties: 0x40, dictionary size: 33554432 bytes, uncompressed size: 131072 bytes
3504750 0x357A6E LZMA compressed data, properties: 0x5B, dictionary size: 16777216 bytes, uncompressed size: 88 bytes
3915776 0x3BC000 gzip compressed data, from Unix, last modified: Thu Mar 11 16:11:03 2010, max compression

why compressed kernel image is used in linux?

Generally the processor can decompress faster than the I/O system can read. By having less for the I/O system to read, you reduce the time needed for boot.

This assumption doesn't hold for all hardware combinations, of course. But it frequently does.

An additional benefit for embedded systems is that the kernel image takes up less space on the non-volatile storage, which may allow using a smaller (and cheaper) flash chip. Many of these systems have ~ 32MB of system RAM and only ~ 4MB of flash.

u-boot hangs at Uncompressing/Loading Kernel Image

I have limited experience in using FIT, so my observation below could be wrong. Anyhow, it looks to me like the first image of your ftb is being used, which in turn has a configuration which does not include a device tree. You are basically loading a kernel without any information about the hardware (such as where and how to access the uart for the serial console), right? More specifically, I think the kernel needs the "chosen" node (e.g. stdout-path) as described here https://www.kernel.org/doc/Documentation/devicetree/bindings/chosen.txt

I'm in a similar situation (developing a board based on a similar "luton" SoC from Vitesse->Microsemi->Microchip, VSC7425). I'm not having any problems booting linux 5.9 with u-boot 2021.07. Then again, it's not exactly the same hardware nor software.

You could try to move your device tree sub-image into the first image, and replace the first configuration with what is found in the second one.

Extract vmlinux from vmlinuz or bzImage

To extract the uncompressed kernel from the kernel image, you can use the extract-vmlinux script from the scripts directory in the kernel tree (available at least in kernel version 3.5) (if you get an error like

mktemp: Cannot create temp file /tmp/vmlinux-XXX: Invalid argument

you need to replace $(mktemp /tmp/vmlinux-XXX) by $(mktemp /tmp/vmlinux-XXXXXX) in the script). The command is /path/to/kernel/tree/scripts/extract-vmlinux <kernel image> >vmlinux.

If the extracted kernel binary contains symbol information, you should¹ be able to create the System.map file using the mksysmap script from the same subdirectory. The command here is NM=nm /path/to/kernel/tree/scripts/mksysmap vmlinux System.map.

¹ The kernel images shipped with my distribution seem to be stripped, so the script was not able to get the symbols.



Related Topics



Leave a reply



Submit