zImage文件提取及逆向分析

//weibo: @少仲

技術背景:

Android手機獲得Root權限,可以讓/system和/data分區獲得讀寫的權限.這兩個分區的權限配置,一般在根分區的init.rc文件中,修改這個文件可永久獲得root權限.衆所周知,市面上絕大部分的Android手機文件系統有三個分區,分別是/,/system,/data.根分區(/)是打包爲ramdisk.img後,再與kernel的zImage打包爲boot.img. boot.img在EMMC/NAND中以RAW DATA的形式存在,且除使用燒寫工具外,無法讀寫.正因如此,根分區(/)在每次開機時都會從存儲器中加載到RAM, 所以根分區(/)是難以不被刷機破解的.

那麼如何破解?

獲得boot.img,解壓boot.img得到ramdisk.img, 再由ramdisk.img解壓得到root目錄(/),修改其中的init.rc文件,再打包,最終得到新的boot.img.最後利用燒寫工具boot.img燒寫到手機即可.(具體可參考AOSP/mkbootimg)

淺析boot分區結構




具體分析:

一.  提取kernel文件

(1)boot在哪裏?通過下載官方的rom包,解壓縮後可以看到裏面的boot.img文件然後分解

關於rom,簡單介紹下里面的文件:

boot.img  Linux內核和基本文件系統的內核包

system.img  系統的/system目錄

recovery.img系統恢復程序所用的鏡像

userdata.img  系統的/data目錄

 

/data/app  用戶應用程序

/system/app系統應用

/system/fonts  字體

/system/media  開關機動畫

/system/media/audio其他音頻,鬧鈴,提示音等

META-INF 刷機腳本信息和簽名

/system/etc系統配置文件夾,恢復出廠設置後都從這裏和build.prop調用配置來覆蓋出錯的配置,裏面init.d文件夾可以放入腳本,腳本名字前加數字表示優先級

build.prop手機信息

(2.1)boot在哪裏?真機中提取(這裏以Samsung Galaxy S4 爲例)

adb shell進入真機, ls -l/dev/block/platform/msm_sdcc.1/by-name

msm 代表高通的芯片

這個msm_sdcc.1是外接的SD卡掛載的目錄,by-name指的是這個sd卡分區的名稱


現在可以通過dd命令將boot.img提取出來

dd if=/dev/block/mmcblk0p20 of=/sdcard/boot.img




(2.2)boot在哪裏?真機中提取(這裏以Lenovo A300t爲例) 另一種查找boot.img的方法

首先介紹下手機分區信息:

主要有mtd分區和emmc分區

一般刷機包簽名文件夾裏的刷機腳本那裏有updater-script文件.

例如:

format("ext4","EMMC", "/dev/block/platform/xxxx", "0","/system")是EMMC分區的,

format("yaffs2","MTD","/dev/block/platform/xxxx", "0", "/system")是MTD分區的

MTD是用於訪問memory設備(ROM、flash)的Linux的子系統.MTD的主要目的是爲了使新的memory設備的驅動更加簡單

EMMC 結構由一個嵌入式存儲解決方案組成,帶有MMC (多媒體卡)接口、快閃存儲器設備及主控制器—— 所有都在一個小型的BGA 封裝.接口速度高達每秒52MB,EMMC具有快速、可升級的性能


cat /proc/mtd


可以通過同樣的方式,使用dd命令,將boot.img文件提取出來.之後我們可以通過adb pull的方式把從真機中提取的boot.img文件提取到本地.之後用split_boogimg.pl 將提取的boot.img分解出來,可以得到boot.img-kernel


二.  逆向分析kernel文件:

一般來說,這個kernel內核文件都是一個gzip的壓縮格式,偶爾也會有其他的壓縮算法.比如三星S5和MX4的內核壓縮算法是lzop

爲什麼是這樣的情況呢?簡要說下:

Kernel被載入內存後是以壓縮的狀態存放在磁盤之上的,他頭上的一段代碼就是爲了初始化並且解壓縮的一段代碼.這段代碼把自身壓縮的一部分代碼解壓出來.放到真正內核所在的位置上.所以他所用的壓縮算法要從他頭上那段來指定的.所以如果今後廠商使用一些自己的壓縮算法,那麼需要更多逆向分析的.


我們可以通過binwalk工具來判斷是gzip的壓縮格式還是lzop.

如果是lzop可以直接從第二段的地址dd出來然後使用命令解壓縮.

如果是gzip的壓縮格式則使用下面的腳本文件解壓.


#!/bin/bash
pos=`grep -P -a -b -m 1 --only-matching '\x1F\x8B\x08' zImage | cut -f 1 -d :`
echo "Extracting gzip'd kernel image from file: zImage (start = $pos)"

if [ ! -z $pos ]; then
echo "Dumping compressed image"
dd if=zImage of=zImage_unpacked.gz bs=1 skip=$pos 2>/dev/null >/dev/null
echo "Unzipping compressed image"
gunzip -qf zImage_unpacked.gz
fi


現在可以將它導入到IDA中分析,但是導入IDA後發現效果很不理想


這是因爲我們需要符號表.但是android的linux內核是一個平面結構,它沒有符號表.如果大家編譯過linux內核可以發現編譯好的zImage被打包到boot.img文件中去,下面有個巨大的vmlinux,它放到gdb裏面去調試可以看到完整的符號表和調試信息.刷入手機的版本是沒有的.

但是在/proc/kallsyms可以提供所有的kernel symbol


cat /proc/kallsyms 會發現地址都是0


爲什麼地址都是0呢?

因爲有一個patch 在/proc/sys/kernel/kptr_restrict默認爲1,就隱藏了symbol

只要我們將其置0就可以正常打印


如果我們之前在刷機的過程中放進去一個su授權文件,那麼我們就可以

echo 0 > /proc/sys/kernel/kptr_restrict
cat /proc/kallsyms > /data/local/tmp/syms.txt

但是我們目的是爲了root,這裏如果沒有su文件呢?

我們還有其他的方法.kallsyms既然可以打印symbol,那麼說明symbol肯定在內核之中的.它就在__ksymtab裏面.我們肯定可以知道一些常見的內核函數,比如kallsyms_lookup_name.我們可以在這個內核的二進制文件中找它的字符串.找到它的相對位置後,然後拿它的地址去搜索


我們可以搜到一個結構


從0xC0008000開始暴力搜索連續若干個具有上面的特徵的內存,就可以找到內核的導出符號表,有了符號地址後,手動在ida中添加地址,就可以分析了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章