Updated: expand initramfs ramdisc from zImage kernel, supports gzip, lzma, bzip2 (?)

daniel.weck

Senior Member
Nov 2, 2010
574
95
0
daniel.weck.free.fr
If you are interested in building your own kernels (from the Samsung-released open-source code, or any other source), you may need to extract initramfs ramdiscs from existing kernels.

There is a well-known script to achieve that goal, but it only supports uncompressed and gzip'ed kernels, and it doesn't unpack the CPIO archive for further inspection of the actual initramfs "source code" (the output trace is also not easy to debug when working with "weird" zImages). The original script is explained in the XDA wiki: http://forum.xda-developers.com/wiki/index.php?title=Extract_initramfs_from_zImage.

For my personal convenience, I tweaked the original bash script so I thought I'd share it with the XDA devs. I added support for lzma-compressed initramfs ramdiscs (thanks to koxudaxi for reminding me of the lzma "magic string"), please let me know if you know the "magic string" for bzip2 archives (EDIT: "0x314159265359" 6 bytes "start of block", 4 bytes header at the beginning...experimental untested support is now available in the script below).

Note that the latest Samfirmware ROMs include encrypted boot.bin and Sbl.bin bootloaders, but I'm not sure how the zImage kernels are encoded...so this script may not work.

Also note that zImage files patched with z4mod require further decoding work, see the XDA wiki page mentioned above for instructions.

Code:
#!/bin/bash
zImage=$1

read -rp "Enter any text to skip extraction (assumes /tmp/kernel2.img already exists): " input

if [ ${input}" " = " " ]; then

echo "==> deleting /tmp/kernel1.img"
rm /tmp/kernel1.img

echo "==> deleting /tmp/kernel2.img"
rm /tmp/kernel2.img

echo "==> searching for gzip header in $zImage"
skip=`grep -P -a -b -m 1 --only-matching $'\x1F\x8B\x08' $zImage | cut -f 1 -d :`
echo "==> found gzip header at $skip"

echo "==> unzipping $zImage to /tmp/kernel1.img"
dd if=$zImage bs=1 skip=$skip | gunzip > /tmp/kernel1.img

echo "==> searching for gzip header in /tmp/kernel1.img"
poszip=`grep -P -a -b -m 1 --only-matching $'\x1F\x8B\x08' /tmp/kernel1.img | cut -f 1 -d :`
if [ ! $poszip = "" ]; then
    echo "==> gzip header at $poszip in /tmp/kernel1.img"

    echo "==> extracting /tmp/kernel2.img from /tmp/kernel1.img using gunzip"
    dd if=/tmp/kernel1.img bs=1 skip=$poszip | gunzip > /tmp/kernel2.img
else
    echo "==> no gzip header in /tmp/kernel1.img"

    echo "==> searching for lzma header in /tmp/kernel1.img"
    poslzma=`grep -P -a -b -m 1 --only-matching '\x{5D}\x{00}\x..\x{FF}\x{FF}\x{FF}\x{FF}\x{FF}\x{FF}' /tmp/kernel1.img | cut -f 1 -d :`
    if [ ! $poslzma = "" ]; then
        echo "==> lzma header at $poslzma in /tmp/kernel1.img"

        echo "==> extracting /tmp/kernel2.img from /tmp/kernel1.img using lzma"
        dd if=/tmp/kernel1.img bs=1 skip=$poslzma | unlzma > /tmp/kernel2.img
    else
        echo "==> no lzma header in /tmp/kernel1.img"

        echo "==> searching for bzip2 header in /tmp/kernel1.img"
        posbzip2=`grep -P -a -b -m 1 --only-matching $'\x{42}\x{5A}\x{68}\x{39}\x{31}\x{41}\x{59}\x{26}\ x{53}\x{59}' /tmp/kernel1.img | cut -f 1 -d :`
        if [ ! $posbzip2 = "" ]; then
            echo "==> bzip2 header at $posbzip2 in /tmp/kernel1.img"
            
            posbzip2=$((posbzip2 - 4))
            echo "==> adjusted bzip2 header with -4 bytes offset: $posbzip2"
            
            echo "==> extracting /tmp/kernel2.img from /tmp/kernel1.img using bzip2"
            dd if=/tmp/kernel1.img bs=1 skip=$posbzip2 | bunzip2 > /tmp/kernel2.img
        else
            echo "==> no bzip2 header in /tmp/kernel1.img"

            echo "==> assuming no compression for /tmp/kernel1.img, copying to /tmp/kernel2.img"
            cp /tmp/kernel1.img /tmp/kernel2.img
        fi
    fi
fi

fi

#    '070701'  ==  $'\x30\x37\x30'  ==  '\x{30}\x{37}\x{30}'

echo "==> searching for cpio header in /tmp/kernel2.img"
start=`grep -a -b -m 1 --only-matching '070701' /tmp/kernel2.img | head -1 | cut -f 1 -d :`
echo "==> cpio header at $start in /tmp/kernel2.img"

echo "==> searching for cpio footer in /tmp/kernel2.img"
end=`grep -a -b -m 1 --only-matching 'TRAILER!!!' /tmp/kernel2.img | head -1 | cut -f 1 -d :`
echo "==> cpio footer at $end in /tmp/kernel2.img"

# 14 bytes = length of "TRAILER!!!" (zero-terminated string) + padding => fixes premature end of file warning in CPIO
end=$((end + 14))
echo "==> adjusted cpio footer with 14 bytes offset: $end"

count=$((end - start))
echo "==> cpio size is $count bytes ($end - $start)"

if (($count < 0)); then
    echo "==> error in cpio positions, aborting"
    exit
fi

cpio_file="initramfs.cpio"
cpio_dir=`echo "${cpio_file}.expanded"`
cpio_ls=`echo "${cpio_file}.ls"`

echo "==> deleting ${zImage}_${cpio_file}"
rm ${zImage}_${cpio_file}

echo "==> deleting ${zImage}_${cpio_dir}"
rm -r ${zImage}_${cpio_dir}

echo "==> deleting ${zImage}_${cpio_ls}"
rm -r ${zImage}_${cpio_ls}

echo "==> extracting initramfs ramdisc from /tmp/kernel2.img to ${zImage}_${cpio_file}"
dd if=/tmp/kernel2.img bs=1 skip=$start count=$count > ${zImage}_${cpio_file}

echo "==> expanding ${zImage}_${cpio_file} into ${zImage}_${cpio_dir} directory"
mkdir ${zImage}_${cpio_dir}
curdir=`pwd`
(cd ${zImage}_${cpio_dir} && cpio --quiet -id --no-absolute-filenames < ${curdir}/${zImage}_${cpio_file})

echo "==> generating ls-like file list in ${zImage}_${cpio_ls}"
cpio --quiet -tvnF ${zImage}_${cpio_file} > ${zImage}_${cpio_ls}

echo "==> DONE."
 
Last edited: