1.問題描述
Native Crash 如下:
Build fingerprint: 'XXX/ddddn:7.0/dddd/7.3.27:user/release-keys' Revision: '0' ABI: 'arm' pid: 23898, tid: 23898, name: dex2oat >>> /system/bin/dex2oat <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'FORTIFY: read: prevented write past end of buffer' backtrace: #00 pc 00049b38 /system/lib/libc.so (tgkill+12) #01 pc 000472b3 /system/lib/libc.so (pthread_kill+34) #02 pc 0001d555 /system/lib/libc.so (raise+10) #03 pc 000190a1 /system/lib/libc.so (__libc_android_abort+34) #04 pc 00017104 /system/lib/libc.so (abort+4) #05 pc 0001b54f /system/lib/libc.so (__libc_fatal+22) #06 pc 0001b52f /system/lib/libc.so (__fortify_chk_fail+26) #07 pc 0004f69d /system/lib/libc.so (__read_chk+36) #08 pc 00035987 <anonymous:eba9b000>
map如下:
可以看到 eba9b000 - ebaf8fff 段是 r-x 屬性,即可執行代碼段;eba96000-eba96fff — 0 1000 [anon:thread signal stack guard page] eba97000-eba98fff rw- 0 2000 [anon:thread signal stack] eba99000-eba99fff rw- 0 1000 [anon:linker_alloc_small_objects] eba9a000-eba9afff r-- 0 1000 [anon:atexit handlers] eba9b000-ebaf8fff r-x 0 5e000 ebaf9000-ebafdfff rw- 0 5000 ebafe000-ebb1dfff r-- 0 20000 /dev/_properties_/properties_serial ebb1e000-ebb1efff rw- 0 1000 [anon:linker_alloc_vector]
在 main log中有如下log:
系統調用的 dex2oat是不會有這種參數的,看起來是第三方 APP 自行調用的 dex2oat,看下當時的進程信息:03-28 05:10:51.629 23898 23898 I dex2oat : /system/bin/dex2oat --dex-file=/data/data/com.happyelements.AndroidAnimal.qq/.jiagu/classes.dex --dex-file=/data/data/com.happyelements.AndroidAnimal.qq/.jiagu/classes2.dex --dex-file=/data/data/com.happyelements.AndroidAnimal.qq/.jiagu/classes3.dex --oat-file=/data/data/com.happyelements.AndroidAnimal.qq/.jiagu/classes.oat
可以看出來,dex2oat(23898)進程確實是由 23710 進程 fork出來的,那麼 dex2oat的參數也應該是其組織的;u0_a297 23710 584 1969400 186196 SyS_epoll_ 00ea9041f8 S com.happyelements.AndroidAnimal.qq u0_a297 23898 23710 23324 4688 do_signal_ 00eb3ddb38 T /system/bin/dex2oat
抓到 core file後,進行分析:
直觀的看 backtrace, frame8中的可執行代碼,調用了 __read_chk函數,出發了abort,導致進程終止。
據此,我們分析參數 count 和 buf_size 在調用過程的傳遞。extern "C" ssize_t __read_chk(int fd, void* buf, size_t count, size_t buf_size) { if (__predict_false(count > buf_size)) { //此處 count > buf_size 會出發下一行調用 __fortify_chk_fail("read: prevented write past end of buffer", 0); } if (__predict_false(count > SSIZE_MAX)) { __fortify_chk_fail("read: count > SSIZE_MAX", 0); } return read(fd, buf, count); }
2.問題分析
(gdb) bt #0 tgkill () at bionic/libc/arch-arm/syscalls/tgkill.S:10 #1 0xeb3db2b6 in pthread_kill (t=<optimized out>, sig=6) at bionic/libc/bionic/pthread_kill.cpp:45 #2 0xeb3b1558 in raise (sig=23898) at bionic/libc/bionic/raise.cpp:34 #3 0xeb3ad0a4 in __libc_android_abort () at bionic/libc/bionic/abort.cpp:47 #4 0xeb3ab108 in abort () at bionic/libc/arch-arm/bionic/abort_arm.S:43 #5 0xeb3af552 in __libc_fatal (format=0x0) at bionic/libc/bionic/libc_logging.cpp:678 #6 0xeb3af532 in __fortify_chk_fail (msg=0xeb40b9ec "read: prevented write past end of buffer", tag=0) at bionic/libc/bionic/libc_logging.cpp:645 #7 0xeb3e36a0 in _read_chk (fd=<optimized out>, buf=<optimized out>, count=6, buf_size=114) at bionic/libc/bionic/_read_chk.cpp:35 #8 0xebad0988 in ?? ()
map對應的段:
eba9b000-ebaf8fff r-x 0 5e000 ebaf9000-ebafdfff rw- 0 5000
2.1 調用流程推倒
從backtrace看到 frame8是個匿名可執行段,可能是某個第三方設計出來的一些技術;
但總歸要有函數要跳轉到這個可執行段,才能執行到這段代碼,我們從 coredump中分析,進程中是怎麼跳轉到 frame8的;
這個推到的關鍵點就在於 LR寄存器和SP寄存器;
LR保存着上一層跳轉到當前函數的指令的下一條指令;SP保存着當前堆棧的棧頂位置,而當前堆棧的棧底就是上一層調用的堆棧的棧頂;
#00
#00 tgkill()
(gdb) disassemble
Dump of assembler code for function tgkill:
0xeb3ddb2c <+0>: mov r12, r7
0xeb3ddb30 <+4>: ldr r7, [pc, #20] ; 0xeb3ddb4c
0xeb3ddb34 <+8>: svc 0x00000000
=> 0xeb3ddb38 <+12>: mov r7, r12
0xeb3ddb3c <+16>: cmn r0, #4096 ; 0x1000
0xeb3ddb40 <+20>: bxls lr
0xeb3ddb44 <+24>: rsb r0, r0, #0
0xeb3ddb48 <+28>: b 0xeb404174
(gdb) info reg
r0 0x0 0
r1 0x5d5a 23898
r2 0x6 6
r3 0x8 8
r4 0xebb9658c 3954795916
r5 0x6 6
r6 0xebb96534 3954795828
r7 0x10c 268
r8 0x1 1
r9 0x61b738 6403896
r10 0xeb3e3679 3946722937
r11 0xffffffff 4294967295
r12 0x0 0
sp 0xffbe71e8 0xffbe71e8
lr 0xeb3db2b7 -348278089
pc 0xeb3ddb38 0xeb3ddb38 <tgkill+12>
cpsr 0x200e0010 537788432
(gdb) info frame
Stack level 0, frame at 0xffbe71e8:
pc = 0xeb3ddb38 in tgkill (bionic/libc/arch-arm/syscalls/tgkill.S:10); saved pc = 0xeb3db2b6
called by frame at 0xffbe7200
source language asm.
Arglist at 0xffbe71e8, args:
Locals at 0xffbe71e8, Previous frame's sp is 0xffbe71e8
(gdb) p $sp
$11 = (void *) 0xffbe71e8
所以:#00 tgkill()
pc:0xeb3ddb38
sp:0xffbe71e8
lr:0xeb3db2b7
stack: none (frame0 中沒有push操作和增長堆棧的操作)
#01 pthread_kill()
pc:0xeb3db2b7 //是#00對應的 lr
sp:0xffbe71e8 //是#00的棧底,由於#00沒有棧,所以還是 0xffbe71e8
(gdb) disassemble
Dump of assembler code for function pthread_kill(pthread_t, int):
0xeb3db290 <+0>: push {r4, r5, r6, r7, lr}
0xeb3db292 <+2>: sub sp, #4
0xeb3db294 <+4>: mov r5, r1
0xeb3db296 <+6>: mov r6, r0
0xeb3db298 <+8>: blx 0xeb3a85c8 <__errno@plt>
0xeb3db29c <+12>: mov r4, r0
0xeb3db29e <+14>: mov r0, r6
0xeb3db2a0 <+16>: ldr r7, [r4, #0]
0xeb3db2a2 <+18>: bl 0xeb3dafdc <__pthread_internal_find(long)>
0xeb3db2a6 <+22>: mov r6, r0
0xeb3db2a8 <+24>: cbz r6, 0xeb3db2c2 <pthread_kill(pthread_t, int)+50>
0xeb3db2aa <+26>: blx 0xeb3a8b74 <getpid@plt>
0xeb3db2ae <+30>: ldr r1, [r6, #8]
0xeb3db2b0 <+32>: mov r2, r5
0xeb3db2b2 <+34>: blx 0xeb3a9fc0 <tgkill@plt> // 這裏跳轉的位置不是 #00 的代碼開始位置,而是 plt
=> 0xeb3db2b6 <+38>: cmp.w r0, #4294967295 ; 0xffffffff
0xeb3db2ba <+42>: ite eq
0xeb3db2bc <+44>: ldreq r0, [r4, #0]
0xeb3db2be <+46>: movne r0, #0
0xeb3db2c0 <+48>: b.n 0xeb3db2c4 <pthread_kill(pthread_t, int)+52>
0xeb3db2c2 <+50>: movs r0, #3
0xeb3db2c4 <+52>: str r7, [r4, #0]
0xeb3db2c6 <+54>: add sp, #4
0xeb3db2c8 <+56>: pop {r4, r5, r6, r7, pc}
End of assembler dump.
stack存放 r4-r7,lr,以及另外4字節
stack:
addr value reg
0xffbe71e8 0x00001204
0xffbe71ec 0x00000006 r4
0xffbe71f0 0x00000000 r5
0xffbe71f4 0x00000008 r6
0xffbe71f8 0xeb3e3679 r7
0xffbe71fc 0xeb3b1559 lr
#02:
#02 raise()
pc:0xeb3b1559 //同樣的,是 #01的lr
sp:0xffbe71fc + 4 = 0xffbe7200 // 是#01的棧底,這裏+4是因爲,棧是從高地址向低地址擴展的
(gdb) disassemble 0xeb3b1559
Dump of assembler code for function raise(int):
0xeb3b154a <+0>: push {r4, lr}
0xeb3b154c <+2>: mov r4, r0
0xeb3b154e <+4>: blx 0xeb3a92d0 <pthread_self@plt>
0xeb3b1552 <+8>: mov r1, r4
0xeb3b1554 <+10>: blx 0xeb3a9204 <pthread_kill@plt>
=> 0xeb3b1558 <+14>: mov r4, r0
0xeb3b155a <+16>: cbz r4, 0xeb3b1568 <raise(int)+30>
0xeb3b155c <+18>: blx 0xeb3a85c8 <__errno@plt>
0xeb3b1560 <+22>: str r4, [r0, #0]
0xeb3b1562 <+24>: mov.w r0, #4294967295 ; 0xffffffff
0xeb3b1566 <+28>: pop {r4, pc}
0xeb3b1568 <+30>: movs r0, #0
0xeb3b156a <+32>: pop {r4, pc}
End of assembler dump.
stack:
addr value reg
0xffbe7200 0xffbe721c r4
0xffbe7204 0xeb3ad0a5 lr
#03:
#03 __libc_android_abort()
pc:0xeb3ad0a5
sp:0xffbe7204 + 4 = 0xffbe7208
(gdb) disassemble 0xeb3ad0a5
Dump of assembler code for function __libc_android_abort():
0xeb3ad07e <+0>: push {r4, r5, r7, lr}
0xeb3ad080 <+2>: sub sp, #24
0xeb3ad082 <+4>: add r4, sp, #20
0xeb3ad084 <+6>: mov r0, r4
0xeb3ad086 <+8>: blx 0xeb3a8ac0 <sigfillset@plt>
0xeb3ad08a <+12>: mov r0, r4
0xeb3ad08c <+14>: movs r1, #6
0xeb3ad08e <+16>: blx 0xeb3a8acc <sigdelset@plt>
0xeb3ad092 <+20>: movs r0, #2
0xeb3ad094 <+22>: mov r1, r4
0xeb3ad096 <+24>: movs r2, #0
0xeb3ad098 <+26>: movs r5, #0
0xeb3ad09a <+28>: blx 0xeb3a8658 <sigprocmask@plt>
0xeb3ad09e <+32>: movs r0, #6
0xeb3ad0a0 <+34>: blx 0xeb3a8ad8 <raise@plt>
=> 0xeb3ad0a4 <+38>: str r5, [sp, #4]
0xeb3ad0a6 <+40>: mov.w r0, #268435456 ; 0x10000000
0xeb3ad0aa <+44>: add r5, sp, #4
0xeb3ad0ac <+46>: str r0, [sp, #12]
0xeb3ad0ae <+48>: adds r0, r5, #4
0xeb3ad0b0 <+50>: blx 0xeb3a8ae4 <sigemptyset@plt>
0xeb3ad0b4 <+54>: movs r0, #6
0xeb3ad0b6 <+56>: mov r1, r5
0xeb3ad0b8 <+58>: mov r2, r5
0xeb3ad0ba <+60>: blx 0xeb3a8af0 <sigaction@plt>
0xeb3ad0be <+64>: movs r0, #2
0xeb3ad0c0 <+66>: mov r1, r4
0xeb3ad0c2 <+68>: movs r2, #0
0xeb3ad0c4 <+70>: blx 0xeb3a8658 <sigprocmask@plt>
0xeb3ad0c8 <+74>: movs r0, #6
0xeb3ad0ca <+76>: blx 0xeb3a8ad8 <raise@plt>
0xeb3ad0ce <+80>: movs r0, #1
0xeb3ad0d0 <+82>: blx 0xeb3a8afc <_exit@plt>
End of assembler dump.
stack:
addr value reg
0xffbe7208 0x0000004a
0xffbe720c 0x0061b737
0xffbe7210 0xeae0b000
0xffbe7214 0xeae0b008
0xffbe7218 0x00000001
0xffbe721c 0xffffffdf
0xffbe7220 0xeb40b9ec r4
0xffbe7224 0x00000000 r5
0xffbe7228 0xeb3e3679 r7
0xffbe722c 0xeb3ab108 lr
#04:
#04 abort()
pc:0xeb3ab108
sp:0xffbe722c + 4 = 0xffbe7230
(gdb) disassemble 0xeb3ab108-0x10,+0x20
Dump of assembler code from 0xeb3ab0f8 to 0xeb3ab118:
0xeb3ab0f8 <memcmp+640>: pop {r5, r6, r7}
0xeb3ab0fc <memcmp+644>: b 0xeb3aaf94 <memcmp+284>
0xeb3ab100 <abort+0>: push {r3, lr}
0xeb3ab104 <abort+4>: blx 0xeb3ad07e <__libc_android_abort()>
=> 0xeb3ab108 <__bionic_clone+0>: mov r12, sp
0xeb3ab10c <__bionic_clone+4>: push {r4, r5, r6, r7}
0xeb3ab110 <__bionic_clone+8>: ldm r12, {r4, r5, r6}
0xeb3ab114 <__bionic_clone+12>: stmdb r1!, {r5, r6}
stack:
addr value reg
0xffbe7230 0x00000072 r3
0xffbe7234 0xeb3af553 lr
#05 __libc_fatal()
pc:0xeb3af553
sp:0xffbe7234 + 4 = 0xffbe7238
(gdb) disassemble 0xeb3af553-0x20,+0x21
Dump of assembler code from 0xeb3af533 to 0xeb3af554:
0xeb3af533 <__fortify_chk_fail(char const*, uint32_t)+30>: nop
0xeb3af535 <__fortify_chk_fail(char const*, uint32_t)+32>: strh r4, [r4, #60] ; 0x3c
0xeb3af537 <__fortify_chk_fail(char const*, uint32_t)+34>: movs r5, r0
0xeb3af539 <__libc_fatal(char const*, ...)+0>: sub sp, #12
0xeb3af53b <__libc_fatal(char const*, ...)+2>: push {r7, lr}
0xeb3af53d <__libc_fatal(char const*, ...)+4>: sub sp, #4
0xeb3af53f <__libc_fatal(char const*, ...)+6>: add.w r12, sp, #12
0xeb3af543 <__libc_fatal(char const*, ...)+10>: stmia.w r12, {r1, r2, r3}
0xeb3af547 <__libc_fatal(char const*, ...)+14>: add r1, sp, #12
0xeb3af549 <__libc_fatal(char const*, ...)+16>: str r1, [sp, #0]
0xeb3af54b <__libc_fatal(char const*, ...)+18>: bl 0xeb3af554 <__libc_fatal(char const*, std::__va_list)>
0xeb3af54f <__libc_fatal(char const*, ...)+22>: blx 0xeb3a8f64 <abort@plt>
=> 0xeb3af553: movs r0, r0
End of assembler dump.
其中 sp 先減去 12,再push lr,r7,再減去 4
stack:
addr value reg
0xffbe7238 0xffbe7244
0xffbe723c 0xeb3e3679 r7
0xffbe7240 0xeb3af533 lr
0xffbe7244 0xeb40b9ec
0xffbe7248 0x0061b738
0xffbe724c 0x00000000
#06 __fortify_chk_fail()
pc:0xeb3af533
sp:0xffbe724c + 4 = 0xffbe7250
(gdb) disassemble 0xeb3af533
Dump of assembler code for function __fortify_chk_fail(char const*, uint32_t):
0xeb3af514 <+0>: push {r4, r5, r7, lr}
0xeb3af516 <+2>: mov r5, r1
0xeb3af518 <+4>: mov r4, r0
0xeb3af51a <+6>: cbz r5, 0xeb3af528 <__fortify_chk_fail(char const*, uint32_t)+20>
0xeb3af51c <+8>: blx 0xeb3a8f58 <getuid@plt>
0xeb3af520 <+12>: mov r1, r0
0xeb3af522 <+14>: mov r0, r5
0xeb3af524 <+16>: bl 0xeb3af44c <__libc_android_log_event_int(int32_t, int)>
0xeb3af528 <+20>: ldr r0, [pc, #8] ; (0xeb3af534 <__fortify_chk_fail(char const*, uint32_t)+32>)
0xeb3af52a <+22>: mov r1, r4
0xeb3af52c <+24>: add r0, pc
0xeb3af52e <+26>: bl 0xeb3af538 <__libc_fatal(char const*, ...)>
=> 0xeb3af532 <+30>: nop
0xeb3af534 <+32>: andeq r8, r5, r4, lsr #15
End of assembler dump.
stack:
addr value reg
0xffbe7250 0xeb41d008 r4
0xffbe7254 0xea480000 r5
0xffbe7258 0xeb3e3679 r7
0xffbe725c 0xeb3e36a1 lr
#07:
#07 __read_chk()
pc:0xeb3e36a1
sp:0xffbe725c + 4 = 0xffbe7260
(gdb) disassemble 0xeb3e36a1
Dump of assembler code for function __read_chk(int, void*, size_t, size_t):
0xeb3e3678 <+0>: push {r7, lr}
0xeb3e367a <+2>: cmp r2, r3
0xeb3e367c <+4>: bhi.n 0xeb3e3696 <__read_chk(int, void*, size_t, size_t)+30>
0xeb3e367e <+6>: cmp.w r2, #4294967295 ; 0xffffffff
0xeb3e3682 <+10>: itt gt
0xeb3e3684 <+12>: ldmiagt.w sp!, {r7, lr}
0xeb3e3688 <+16>: bgt.w 0xeb404b84
0xeb3e368c <+20>: ldr r0, [pc, #16] ; (0xeb3e36a0 <__read_chk(int, void*, size_t, size_t)+40>)
0xeb3e368e <+22>: movs r1, #0
0xeb3e3690 <+24>: add r0, pc
0xeb3e3692 <+26>: bl 0xeb3af514 <__fortify_chk_fail(char const*, uint32_t)>
0xeb3e3696 <+30>: ldr r0, [pc, #12] ; (0xeb3e36a4 <__read_chk(int, void*, size_t, size_t)+44>)
0xeb3e3698 <+32>: movs r1, #0
0xeb3e369a <+34>: add r0, pc
0xeb3e369c <+36>: bl 0xeb3af514 <__fortify_chk_fail(char const*, uint32_t)>
=> 0xeb3e36a0 <+40>: andeq r8, r2, r1, lsl #7
0xeb3e36a4 <+44>: andeq r8, r2, lr, asr #6
End of assembler dump.
stack:
addr value reg
0xffbe7260 0xeb3e3679 r7
0xffbe7264 0xebad0989 lr
實際上,從#00 - #07 GDB都能給解析出來了,我們這麼做,可以加深這個印象,對接下來的分析指向更明確#08:
#08 // 由於在匿名可執行段中,所以不知道這個函數的名字
pc:0xebad0989
sp:0xffbe7264 + 4 = 0xffbe7268
0xebad0894: push {r4, r5, r6, r7, lr}
0xebad0896: mov r7, r11
0xebad0898: mov r6, r10
0xebad089a: mov r5, r9
0xebad089c: mov r4, r8
-> 0xebad089e: push {r4, r5, r6, r7}
0xebad08a0: ldr r4, [pc, #528] ; (0xebad0ab4) // r4=0xffffef6c
0xebad08a2: ldr r2, [pc, #532] ; (0xebad0ab8) // r2=0x1084
0xebad08a4: adds r6, r0, #0 //
-> 0xebad08a6: add sp, r4 //
0xebad08a8: add r1, sp, #8
0xebad08aa: mov r12, r1
0xebad08ac: ldr r4, [pc, #524] ; (0xebad0abc) // r4=0x0002a46a
0xebad08ae: add r2, r12
0xebad08b0: add r5, sp, #140 ; 0x8c
0xebad08b2: add r4, pc // r4=0xebad08b6
0xebad08b4: ldr r4, [r4, #0] // r4=0x68232100
0xebad08b6: movs r1, #0 //
0xebad08b8: ldr r3, [r4, #0]
0xebad08ba: adds r0, r5, #0
0xebad08bc: str r3, [r2, #0]
0xebad08be: movs r2, #128 ; 0x80
0xebad08c0: ldr r3, [pc, #508] ; (0xebad0ac0)
0xebad08c2: lsls r2, r2, #5
0xebad08c4: add r3, pc
0xebad08c6: ldr r7, [r3, #0]
0xebad08c8: bl 0xebaea964
0xebad08cc: ldr r1, [pc, #500] ; (0xebad0ac4)
0xebad08ce: adds r0, r6, #0
0xebad08d0: add r1, pc
0xebad08d2: bl 0xebaeac04
0xebad08d6: cmp r6, r0
0xebad08d8: bls.n 0xebad08e2
0xebad08da: b.n 0xebad08ee
0xebad08dc: subs r0, #1
0xebad08de: cmp r6, r0
0xebad08e0: bhi.n 0xebad08ee
0xebad08e2: ldrb r3, [r0, #0]
0xebad08e4: subs r3, #48 ; 0x30
0xebad08e6: lsls r3, r3, #24
0xebad08e8: lsrs r3, r3, #24
0xebad08ea: cmp r3, #9
0xebad08ec: bls.n 0xebad08dc
0xebad08ee: subs r3, r0, r6
0xebad08f0: mov r8, r3
0xebad08f2: adds r2, r3, #0
0xebad08f4: adds r1, r6, #0
0xebad08f6: adds r0, r5, #0
0xebad08f8: bl 0xebaeb064
0xebad08fc: mov r3, r8
0xebad08fe: adds r0, r5, r3
0xebad0900: ldr r3, [pc, #452] ; (0xebad0ac8)
0xebad0902: movs r2, #4
0xebad0904: add r3, pc
0xebad0906: mov r8, r3
0xebad0908: adds r1, r3, #0
0xebad090a: bl 0xebaea944
0xebad090e: adds r0, r6, #0
0xebad0910: mov r1, r8
0xebad0912: bl 0xebaeac04
0xebad0916: cmp r0, #0
0xebad0918: beq.n 0xebad0942
0xebad091a: subs r0, #1
0xebad091c: cmp r6, r0
0xebad091e: bhi.n 0xebad0942
0xebad0920: ldrb r3, [r0, #0]
0xebad0922: subs r3, #48 ; 0x30
0xebad0924: lsls r3, r3, #24
0xebad0926: lsrs r3, r3, #24
0xebad0928: cmp r3, #9
0xebad092a: bhi.n 0xebad09b6
0xebad092c: subs r6, #1
0xebad092e: b.n 0xebad093c
0xebad0930: ldrb r3, [r0, #0]
0xebad0932: subs r3, #48 ; 0x30
0xebad0934: lsls r3, r3, #24
0xebad0936: lsrs r3, r3, #24
0xebad0938: cmp r3, #9
0xebad093a: bhi.n 0xebad09b6
0xebad093c: subs r0, #1
0xebad093e: cmp r0, r6
0xebad0940: bne.n 0xebad0930
0xebad0942: movs r3, #1
0xebad0944: mov r8, r3
0xebad0946: adds r0, r5, #0
0xebad0948: movs r1, #0
0xebad094a: bl 0xebaea9e4
0xebad094e: subs r6, r0, #0
0xebad0950: ble.n 0xebad09d2
0xebad0952: add r5, sp, #32
0xebad0954: movs r1, #0
0xebad0956: adds r0, r5, #0
0xebad0958: movs r2, #104 ; 0x68
0xebad095a: bl 0xebaea964
0xebad095e: adds r0, r6, #0
0xebad0960: adds r1, r5, #0
0xebad0962: bl 0xebaeadb4
0xebad0966: adds r3, r0, #1
0xebad0968: beq.n 0xebad098c
0xebad096a: ldr r3, [r5, #48] ; 0x30
0xebad096c: movs r0, #1
0xebad096e: adds r1, r3, #0
0xebad0970: mov r9, r3
0xebad0972: bl 0xebaea9b4
0xebad0976: subs r5, r0, #0
0xebad0978: beq.n 0xebad098c
0xebad097a: adds r0, r6, #0
0xebad097c: adds r1, r5, #0
0xebad097e: mov r2, r9
0xebad0980: cmp r7, #0
0xebad0982: bne.n 0xebad0986
0xebad0984: b.n 0xebad0aa4
0xebad0986: blx r7
=> 0xebad0988: cmp r0, r9
在這個 frame中,對sp做了以下操作,稍微複雜一點: 0xebad0894: push {r4, r5, r6, r7, lr} //先push r4-r7,lr
0xebad0896: mov r7, r11
0xebad0898: mov r6, r10
0xebad089a: mov r5, r9
0xebad089c: mov r4, r8
-> 0xebad089e: push {r4, r5, r6, r7} //,因爲把r8-r11放到了r4-r7,相當於保存r8-r11
0xebad08a0: ldr r4, [pc, #528] ; (0xebad0ab4) // r4=0xffffef6c
0xebad08a2: ldr r2, [pc, #532] ; (0xebad0ab8)
0xebad08a4: adds r6, r0, #0 //
-> 0xebad08a6: add sp, r4 //sp=sp+r4
我們已經知道了當前frame的sp棧頂是在 sp:0xffbe7264 + r4 = 0xffbe7268,
所以這裏 sp = sp+r4 = 0xffbe7268,也即在 0xebad08a6 之前的sp我們記爲 sp2 = 0xffbe7268 - r4
其中 r4 在0xebad08a0處賦值, r4 = [0xebad0ab4] = 0xffffef6c
所以 sp2 = 0xffbe7268 - 0xffffef6c = 0xffbe82fc
(gdb) p /x 0xffbe7268-0xffffef6c
$12 = 0xffbe82fc
所以 sp2至當前棧頂的距離等於 0xffbe82fc - 0xffbe7268 = 4244;
所以 0xebad08a6: add sp, r4 這條指令相當於 sp = sp - 4244,堆棧擴展了 4k+的一個空間;是的sp指向到 0xffbe7268;
這個棧的棧底我們標記爲 sp_start,
0xebad0894: push {r4, r5, r6, r7, lr}
0xebad089e: push {r4, r5, r6, r7}
由於這兩條push指令,
所以:
sp_start - 5*4 - 4*4 = sp2 = 0xffbe82fc
sp_start = 0xffbe8320
所以這個frame中,棧底位置是 0xffbe8320
#8 stack 如下:
stack:
addr value reg
0xffbe7268 0x00000000
...
...(4244 byte)
...
0xffbe82fc 0xffbe83f0 r8
0xffbe8300 0x00000001 r9
0xffbe8304 0xeb3e3679 r10
0xffbe8308 0xffffffff r11
0xffbe830c 0xeb41d008 r4
0xffbe8310 0xffbe8320 r5
0xffbe8314 0x00000007 r6
0xffbe8318 0x00000004 r7
0xffbe831c 0xebad1113 lr
#09:
#09 // 同樣在匿名可執行段中,不知道函數的名字
pc:0xebad1113
sp:0xffbe831c + 4 = 0xffbe8320
(gdb) disassemble 0xebad1069,0xebad1115
Dump of assembler code from 0xebad1069 to 0xebad1115:
0xebad1069: push {r4, r5, r6, r7, lr}
0xebad106b: mov r7, r11
0xebad106d: mov r6, r10
0xebad106f: mov r4, r8
0xebad1071: mov r5, r9
0xebad1073: push {r4, r5, r6, r7}
0xebad1075: adds r6, r0, #0
0xebad1077: sub sp, #20
0xebad1079: mov r5, sp
0xebad107b: ldr r4, [pc, #380] ; (0xebad11f8)
0xebad107d: mov r11, r3
0xebad107f: add r4, pc
0xebad1081: ldr r4, [r4, #0]
0xebad1083: mov r8, r1
0xebad1085: ldr r3, [r4, #0]
0xebad1087: mov r0, sp
0xebad1089: str r3, [sp, #12]
0xebad108b: ldr r3, [pc, #368] ; (0xebad11fc)
0xebad108d: adds r1, r6, #0
0xebad108f: add r3, pc
0xebad1091: ldr r3, [r3, #0]
0xebad1093: adds r7, r2, #0
0xebad1095: mov r10, r3
0xebad1097: bl 0xebacfd8c
0xebad109b: ldrb r3, [r5, #0]
0xebad109d: lsls r3, r3, #31
0xebad109f: bpl.n 0xebad111a
0xebad10a1: ldr r3, [sp, #8]
0xebad10a3: ldr r1, [pc, #348] ; (0xebad1200)
0xebad10a5: adds r0, r3, #0
0xebad10a7: add r1, pc
0xebad10a9: mov r9, r3
0xebad10ab: bl 0xebaeac04
0xebad10af: cmp r0, #0
0xebad10b1: beq.n 0xebad113c
0xebad10b3: ldr r1, [pc, #336] ; (0xebad1204)
0xebad10b5: mov r0, r9
0xebad10b7: add r1, pc
0xebad10b9: bl 0xebaeac04
0xebad10bd: cmp r0, #0
0xebad10bf: beq.n 0xebad113c
0xebad10c1: subs r2, r0, #1
0xebad10c3: cmp r9, r2
0xebad10c5: bhi.n 0xebad10ee
0xebad10c7: ldrb r3, [r2, #0]
0xebad10c9: subs r3, #48 ; 0x30
0xebad10cb: lsls r3, r3, #24
0xebad10cd: lsrs r3, r3, #24
0xebad10cf: cmp r3, #9
0xebad10d1: bls.n 0xebad10d4
0xebad10d3: b.n 0xebad11c2
0xebad10d5: mov r0, r9
0xebad10d7: subs r0, #1
0xebad10d9: b.n 0xebad10e8
0xebad10db: ldrb r3, [r2, #0]
0xebad10dd: subs r3, #48 ; 0x30
0xebad10df: lsls r3, r3, #24
0xebad10e1: lsrs r3, r3, #24
0xebad10e3: cmp r3, #9
0xebad10e5: bls.n 0xebad10e8
0xebad10e7: b.n 0xebad11c2
0xebad10e9: subs r2, #1
0xebad10eb: cmp r2, r0
0xebad10ed: bne.n 0xebad10da
0xebad10ef: movs r3, #1
0xebad10f1: movs r0, #1
0xebad10f3: mov r9, r3
0xebad10f5: ldr r3, [pc, #272] ; (0xebad1208)
0xebad10f7: add r3, pc
0xebad10f9: ldr r2, [r3, #0]
0xebad10fb: ldr r3, [r3, #4]
0xebad10fd: subs r3, r3, r2
0xebad10ff: asrs r3, r3, #2
0xebad1101: cmp r3, r0
0xebad1103: bcs.n 0xebad1178
0xebad1105: mov r2, sp
0xebad1107: ldrb r3, [r5, #0]
0xebad1109: adds r0, r2, #1
0xebad110b: lsls r3, r3, #31
0xebad110d: bmi.n 0xebad11d6
0xebad110f: bl 0xebad0894 // 可以看到這裏是 frame8函數的起始地址,說明沒有推倒錯
=> 0xebad1113: cmp r0, #0
End of assembler dump.
操作sp的指令:
0xebad1069: push {r4, r5, r6, r7, lr}
0xebad106b: mov r7, r11
0xebad106d: mov r6, r10
0xebad106f: mov r4, r8
0xebad1071: mov r5, r9
0xebad1073: push {r4, r5, r6, r7}
0xebad1075: adds r6, r0, #0
0xebad1077: sub sp, #20
stack:
addr value reg
0xffbe8320 0x00000051
0xffbe8324 0x00000040
0xffbe8328 0xeae35140
0xffbe832c 0xb53930d7
0xffbe8330 0xeae00000
0xffbe8334 0xffbe83dc r8
0xffbe8338 0xeae2d000 r9
0xffbe833c 0x00000006 r10
0xffbe8340 0xab08e004 r11
0xffbe8344 0xffbe83f0 r4
0xffbe8348 0xffbe83e0 r5
0xffbe834c 0xffbe8e4e r6
0xffbe8350 0x00000007 r7
0xffbe8354 0xeb4d0735 lr
#10:
#10 art::OpenAndReadMagic() //這裏可以看到函數名了
pc:0xeb4d0735
sp:0xffbe8354 + 4 = 0xffbe8358
當前pc在 libart.so的可執行段中:
eb428000-eb87afff r-x 0 453000 /system/lib/libart.so (BuildId: 05da207454e69ef76261022c1a78d6fe) (load base 0xb000)
可以看到 frame10 的 pc 已經在 libart.so中了,對應的函數是 art::OpenAndReadMagic。
(gdb) disassemble 0xeb4d0735
Dump of assembler code for function art::OpenAndReadMagic(char const*, unsigned int*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*):
0xeb4d06f8 <+0>: stmdb sp!, {r4, r5, r6, r7, r8, r9, r10, lr}
0xeb4d06fc <+4>: sub sp, #64 ; 0x40
0xeb4d06fe <+6>: mov r8, r0
0xeb4d0700 <+8>: ldr r0, [pc, #448] ; (0xeb4d08c4 <art::OpenAndReadMagic(char const*, unsigned int*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)+460>)
0xeb4d0702 <+10>: mov r4, r2
0xeb4d0704 <+12>: mov r5, r3
0xeb4d0706 <+14>: add r0, pc
0xeb4d0708 <+16>: mov r6, r1
0xeb4d070a <+18>: cmp r4, #0
0xeb4d070c <+20>: ldr r0, [r0, #0]
0xeb4d070e <+22>: ldr r0, [r0, #0]
0xeb4d0710 <+24>: str r0, [sp, #60] ; 0x3c
0xeb4d0712 <+26>: beq.n 0xeb4d0812 <art::OpenAndReadMagic(char const*, unsigned int*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)+282>
0xeb4d0714 <+28>: mov r0, r6
0xeb4d0716 <+30>: movs r1, #0
0xeb4d0718 <+32>: movs r2, #0
0xeb4d071a <+34>: blx 0xeb4b2ea4 <open@plt> //
0xeb4d071e <+38>: mov r7, r0 // open的返回值是 fd,放到 r7
0xeb4d0720 <+40>: cmp.w r7, #4294967295 ; 0xffffffff
0xeb4d0724 <+44>: beq.n 0xeb4d0746 <art::OpenAndReadMagic(char const*, unsigned int*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)+78>
0xeb4d0726 <+46>: mov r0, r7 // fd
0xeb4d0728 <+48>: mov r1, r4 // buf首地址
0xeb4d072a <+50>: movs r2, #4 // count 是4
0xeb4d072c <+52>: mov.w r3, #4294967295 ; 0xffffffff // buf_size
0xeb4d0730 <+56>: blx 0xeb4b2eb0 <__read_chk@plt>
=> 0xeb4d0734 <+60>: cmp.w r0, #4294967295 ; 0xffffffff
0xeb4d0738 <+64>: bne.n 0xeb4d076c <art::OpenAndReadMagic(char const*, unsigned int*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)+116>
0xeb4d073a <+66>: blx 0xeb4b2ebc <__errno@plt>
可以看到 該方法中調用 __read_chk:0xeb4d0730 <+56>: blx 0xeb4b2eb0 <__read_chk@plt>
即跳轉到 libart.so的 plt 表中 __read_chk對應的函數, 我們從 0xeb4b2eb0往下推推看:
(gdb) disassemble 0xeb4b2eb0-0x10,+0x20
Dump of assembler code from 0xeb4b2ea0 to 0xeb4b2ec0:
0xeb4b2ea0 <__aeabi_memmove@plt+8>: ldr pc, [r12, #3356]! ; 0xd1c
0xeb4b2ea4 <open@plt+0>: add r12, pc, #3145728 ; 0x300000
0xeb4b2ea8 <open@plt+4>: add r12, r12, #847872 ; 0xcf000
0xeb4b2eac <open@plt+8>: ldr pc, [r12, #3348]! ; 0xd14
-> 0xeb4b2eb0 <__read_chk@plt+0>: add r12, pc, #3145728 ; 0x300000
0xeb4b2eb4 <__read_chk@plt+4>: add r12, r12, #847872 ; 0xcf000
=>0xeb4b2eb8 <__read_chk@plt+8>: ldr pc, [r12, #3340]! ; 0xd0c
0xeb4b2ebc <__errno@plt+0>: add r12, pc, #3145728 ; 0x300000
End of assembler dump.
在 __read_chk的 plt 項中會通過 ldr pc, [r12, #3340]! 進行跳轉,這裏是沒有保存LR的,所以LR仍然是 OpenAndReadMagic 函數中, 0xeb4d0730 <+56>: blx 0xeb4b2eb0 的下一條指令地址:0xeb4d0735
看下此時跳轉到哪:
pc= [0xeb4b2eb0+8+0x300000+0xcf000+0xd0c] = 0xebad1069
(gdb) x /x 0xeb4b2eb0+8+0x300000+0xcf000+0xd0c
0xeb882bc4: 0xebad1069
這裏就 0xebad1069 就是frame9對應的函數地址了。
所以到這裏,調用關係梳理完了,如下:
#0 tgkill () at bionic/libc/arch-arm/syscalls/tgkill.S:10
#1 0xeb3db2b6 in pthread_kill (t=<optimized out>, sig=6) at bionic/libc/bionic/pthread_kill.cpp:45
#2 0xeb3b1558 in raise (sig=23898) at bionic/libc/bionic/raise.cpp:34
#3 0xeb3ad0a4 in __libc_android_abort () at bionic/libc/bionic/abort.cpp:47
#4 0xeb3ab108 in abort () at bionic/libc/arch-arm/bionic/abort_arm.S:43
#5 0xeb3af552 in __libc_fatal (format=0x0) at bionic/libc/bionic/libc_logging.cpp:678
#6 0xeb3af532 in __fortify_chk_fail (msg=0xeb40b9ec "read: prevented write past end of buffer", tag=0) at bionic/libc/bionic/libc_logging.cpp:645
#7 0xeb3e36a0 in _read_chk (fd=<optimized out>, buf=<optimized out>, count=6, buf_size=114) at bionic/libc/bionic/_read_chk.cpp:35
#8 <anonymous:eba9b000>:blx r7 (0xeb3e3679 r7)
#9 <anonymous:eba9b000>:bl 0xebad0894
<anonymous:eba9b000>:ldr pc, [r12, #3340]! ; 0xd0c// 相當於 b 0xebad1069 ,由於沒有堆棧且是直接跳轉,歸爲 frame10
liabrt.so: blx 0xeb4b2eb0 <__read_chk@plt>// 由於沒有堆棧且是直接跳轉,歸爲 frame10
#10 libart.so:: OpenAndReadMagic
2.2 業務邏輯推倒
查看 Art中OpenAndReadMagic函數:
1.ScopedFd OpenAndReadMagic(const char* filename, uint32_t* magic, std::string* error_msg) {
CHECK(magic != nullptr);
ScopedFd fd(open(filename, O_RDONLY, 0));
if (fd.get() == -1) {
*error_msg = StringPrintf("Unable to open '%s' : %s", filename, strerror(errno));
return ScopedFd();
}
int n = TEMP_FAILURE_RETRY(read(fd.get(), magic, sizeof(*magic)));
if (n != sizeof(*magic)) {
*error_msg = StringPrintf("Failed to find magic in '%s'", filename);
return ScopedFd();
}
if (lseek(fd.get(), 0, SEEK_SET) != 0) {
*error_msg = StringPrintf("Failed to seek to beginning of file '%s' : %s", filename,
strerror(errno));
return ScopedFd();
}
return fd;
}
其中是調用 read函數,讀取dex文件的 magic數據;
read是個inline函數:
__BIONIC_FORTIFY_INLINE
ssize_t read(int fd, void* buf, size_t count) {
size_t bos = __bos0(buf);
#if !defined(__clang__)
if (__builtin_constant_p(count) && (count > SSIZE_MAX)) {
__read_count_toobig_error();
}
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __read_real(fd, buf, count);
}
if (__builtin_constant_p(count) && (count > bos)) {
__read_dest_size_error();
}
if (__builtin_constant_p(count) && (count <= bos)) {
return __read_real(fd, buf, count);
}
#endif
return __read_chk(fd, buf, count, bos);
}
所以,正常流程下,ART的OpenAndReadMagic編譯後會直接調用系統的 read_chk;
而我們這裏看到,調用read_chk時,卻跳轉到了<anonymous:eba9b000>中的代碼中運行,這應該是當前進程中__read_chk函數被 hook了;
由於libjiagu是加固框架,其對dex文件加密,所以如果是正常流程讀取dex文件,是無法識別其加密過的dex文件的,這就需要其自己對加密的dex文件做解密處理;
這裏的邏輯應該就是:
libjiagu.so hook 當前進程的__read_chk函數,當執行到 jiagu.so中的 read_chk時,先進行解密等相關操作後,在調用系統的read_check把正確的數據交給ART去處理。
2.3 參數推倒
從目前分析來看是從 frame8中調用到 frame7的系統調用 __read_chk時,檢查參數錯誤導致的abort,所以從frame8的參數傳遞開始分析;
系統調用:
__read_chk(int fd, void* buf, size_t count, size_t buf_size)// __read_chk 共需要4個參數,ARM中就是 r0,r1,r2,r3
查看frame8中的參數準備:
(gdb) f 8
#8 0xecab842c in ?? ()
(gdb) disassemble 0xecab842c-0x50,+0x51
Dump of assembler code from 0xecab83dc to 0xecab842d:
0xecab83dc: cmp r3, #9
0xecab83de: bhi.n 0xecab845a
0xecab83e0: subs r0, #1
0xecab83e2: cmp r0, r6
0xecab83e4: bne.n 0xecab83d4
0xecab83e6: movs r3, #1
0xecab83e8: mov r8, r3
0xecab83ea: adds r0, r5, #0
0xecab83ec: movs r1, #0
0xecab83ee: bl 0xecad2e64 //調用函數open
0xecab83f2: subs r6, r0, #0 //將open函數的返回值r0(fd)放到 r6
0xecab83f4: ble.n 0xecab8476
0xecab83f6: add r5, sp, #32
0xecab83f8: movs r1, #0 // 準備第二個參數,即 memset 的內容 0
0xecab83fa: adds r0, r5, #0 //準備第一個參數,即memset的首地址
0xecab83fc: movs r2, #104 ; 0x68 // 準備地三個參數,即memset的大小 104
0xecab83fe: bl 0xecad2da4 //跳轉到函數 memset, buf對應的前 104字節設置爲 0
0xecab8402: adds r0, r6, #0 //準備 fstat函數第一個參數fd
0xecab8404: adds r1, r5, #0 //準備 fstat函數第二個參數 buf
0xecab8406: bl 0xecad3304 //跳轉到函數 fstat64
0xecab840a: adds r3, r0, #1
0xecab840c: beq.n 0xecab8430
0xecab840e: ldr r3, [r5, #48] ; 0x30 //從buf中取出要malloc的的內存大小 count
0xecab8410: movs r0, #1 //分配一組數據
0xecab8412: adds r1, r3, #0 //每組數據大小爲count
0xecab8414: mov r9, r3 //count保存到 r9 中
0xecab8416: bl 0xecad2df4 //跳轉到 calloc函數
0xecab841a: subs r5, r0, #0 // calloc函數返回值,即calloc的地址放到 r5
0xecab841c: beq.n 0xecab8430
0xecab841e: adds r0, r6, #0 // 準備第一個參數 r0(fd)
0xecab8420: adds r1, r5, #0 // 準備第二個參數 r1(buf),從上面 calloc的r5過來的,作爲 buffer起始地址
0xecab8422: mov r2, r9 // 準備第三個參數 r2(count),到這裏,可以看到沒有第四個參數 r3 的構造
0xecab8424: cmp r7, #0 // 判斷__read_chk函數(r7) 指針是否爲空
0xecab8426: bne.n 0xecab842a // __read_chk不爲空,跳轉到 0xecab842a
0xecab8428: b.n 0xecab8548
0xecab842a: blx r7 //跳轉到 libc 的 __read_chk函數
在這裏,我們看到,blx r7之前,也即調用libc __read_ chk之前只准備了 r0,r1,r2三個參數,沒有準備 r3,
看起來像是在函數調用時只傳遞了3個參數編譯出來的指令。
那麼 r2作爲 count, r3 作爲 buf_size,在 frame7中要做比較:
#07 __read_chk()
pc:0xeb3e36a1
sp:0xffbe725c + 4 = 0xffbe7260(gdb) disassemble 0xeb3e36a1
Dump of assembler code for function __read_chk(int, void*, size_t, size_t):
0xeb3e3678 <+0>: push {r7, lr}
0xeb3e367a <+2>: cmp r2, r3 // 比較 r2,r3大小
0xeb3e367c <+4>: bhi.n 0xeb3e3696 <__read_chk(int, void*, size_t, size_t)+30> // r2 比 r3大,跳轉到 0xeb3e3696
0xeb3e367e <+6>: cmp.w r2, #4294967295 ; 0xffffffff
0xeb3e3682 <+10>: itt gt
0xeb3e3684 <+12>: ldmiagt.w sp!, {r7, lr}
0xeb3e3688 <+16>: bgt.w 0xeb404b84
0xeb3e368c <+20>: ldr r0, [pc, #16] ; (0xeb3e36a0 <__read_chk(int, void*, size_t, size_t)+40>)
0xeb3e368e <+22>: movs r1, #0
0xeb3e3690 <+24>: add r0, pc
0xeb3e3692 <+26>: bl 0xeb3af514 <__fortify_chk_fail(char const*, uint32_t)>
0xeb3e3696 <+30>: ldr r0, [pc, #12] ; (0xeb3e36a4 <__read_chk(int, void*, size_t, size_t)+44>)
0xeb3e3698 <+32>: movs r1, #0
0xeb3e369a <+34>: add r0, pc
0xeb3e369c <+36>: bl 0xeb3af514 <__fortify_chk_fail(char const*, uint32_t)> // 跳轉到 __fortify_chk_fail函數進行Abort
=> 0xeb3e36a0 <+40>: andeq r8, r2, r1, lsl #7
0xeb3e36a4 <+44>: andeq r8, r2, lr, asr #6
End of assembler dump.
由於在frame8中,調用 __read_chk時沒有準備r3,那麼此時使用的 r3的值肯定不是正確的,它是不確定的,可能在之前的某一次函數調用修改過;
經過查看在 0xecab8416: bl 0xecad2df4 //跳轉到 calloc函數, calloc函數中就修改了r3;
從而就導致,概率性的 r2 的值大於r3的值,進程abort退出。
2.4 結論
所以,問題原因是:
應用啓動的dex2oat進程中 libjiagu hook了 libc的 __read_chk函數做解密操作,在解密完成後,重新調用libc的 __read_chk函數時,
少傳了第四個參數 buf_size.
3.擴展
其實到上面的分析,我們已經能夠得出問題的結論,但繼續推到調用棧應該能夠推到dex2oat的main函數,繼續推倒:
接着上面 frame10:
#10 pc:0xeb4d0735 sp:0xffbe8354 + 4 = 0xffbe8358
stack: addr value reg 0xffbe8358 0xeba00500 0xffbe835c 0x00000000 0xffbe8360 0xeae0b008 0xffbe8364 0xeb3e8d5f 0xffbe8368 0xeb421c88 0xffbe836c 0xeb3e7b19 0xffbe8370 0x00000000 0xffbe8374 0xeae0f6a0 0xffbe8378 0xeae0b040 0xffbe837c 0xeb3f8a29 0xffbe8380 0x0000000f 0xffbe8384 0xeae0f6a0 0xffbe8388 0xeae0b008 0xffbe838c 0xeae0b040 0xffbe8390 0xeae0b070 0xffbe8394 0xb53930d7 0xffbe8398 0xeae4d000 r4 0xffbe839c 0xffbe8e4e r5 0xffbe83a0 0xffbe8e4e r6 0xffbe83a4 0x00000000 r7 0xffbe83a8 0xffbe868c r8 0xffbe83ac 0xeae2d000 r9 0xffbe83b0 0x00000006 r10 0xffbe83b4 0xeb12523b lr
#11:#11 art::OatWriter::AddDexFileSource() pc:0xeb12523b sp:0xffbe83b4 + 4 = 0xffbe83b8
(gdb) disassemble 0xeb12523b Dump of assembler code for function art::OatWriter::AddDexFileSource(char const*, char const*, art::OatWriter::CreateTypeLookupTable): 0xeb12520c <+0>: stmdb sp!, {r4, r5, r6, r7, r8, r9, r10, lr} 0xeb125210 <+4>: sub sp, #72 ; 0x48 0xeb125212 <+6>: mov r4, r0 0xeb125214 <+8>: ldr r0, [pc, #588] ; (0xeb125464 <art::OatWriter::AddDexFileSource(char const*, char const*, art::OatWriter::CreateTypeLookupTable)+600>) 0xeb125216 <+10>: mov r7, r3 0xeb125218 <+12>: mov r6, r2 0xeb12521a <+14>: add r0, pc 0xeb12521c <+16>: add r2, sp, #56 ; 0x38 0xeb12521e <+18>: add r3, sp, #40 ; 0x28 0xeb125220 <+20>: mov r5, r1 0xeb125222 <+22>: ldr r0, [r0, #0] 0xeb125224 <+24>: ldr r0, [r0, #0] 0xeb125226 <+26>: str r0, [sp, #68] ; 0x44 0xeb125228 <+28>: movs r0, #0 0xeb12522a <+30>: strd r7, r6, [sp, #60] ; 0x3c 0xeb12522e <+34>: strd r0, r0, [sp, #40] ; 0x28 0xeb125232 <+38>: str r0, [sp, #48] ; 0x30 0xeb125234 <+40>: add r0, sp, #36 ; 0x24 0xeb125236 <+42>: blx 0xeb06ef5c <_ZN3art16OpenAndReadMagicEPKcPjPNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE@plt> => 0xeb12523a <+46>: ldr r0, [sp, #36] ; 0x24
#12:stack: addr value reg 0xffbe83b8 0xffbe868c ... 0xffbe8400 0xeae0e000 r4 0xffbe8404 0xeae2d000 r5 0xffbe8408 0x00000000 r6 0xffbe840c 0x00000001 r7 0xffbe8410 0xffbe868c r8 0xffbe8414 0xeae2d000 r9 0xffbe8418 0x00000006 r10 0xffbe841c 0xab08005f lr
#12 art::Dex2Oat::AddDexFileSources() pc:0xab08005f sp:0xffbe841c + 4 = 0xffbe8420
(gdb) disassemble 0xab08005f Dump of assembler code for function art::Dex2Oat::AddDexFileSources(): 0xab07ff88 <+0>: stmdb sp!, {r4, r5, r6, r7, r8, lr} 0xab07ff8c <+4>: sub sp, #8 0xab07ff8e <+6>: mov r5, r0 0xab07ff90 <+8>: ldr r0, [pc, #288] ; (0xab0800b4 <art::Dex2Oat::AddDexFileSources()+300>) 0xab07ff92 <+10>: ldr r1, [pc, #292] ; (0xab0800b8 <art::Dex2Oat::AddDexFileSources()+304>) 0xab07ff94 <+12>: add r0, pc 0xab07ff96 <+14>: add r1, pc 0xab07ff98 <+16>: ldr r0, [r0, #0] ... 0xab08004c <+196>: ldr.w r2, [r5, #196] ; 0xc4 0xab080050 <+200>: movs r3, #0 0xab080052 <+202>: ldr r1, [r1, #0] 0xab080054 <+204>: movs r6, #0 0xab080056 <+206>: ldr r0, [r0, #0] 0xab080058 <+208>: ldr r2, [r2, #0] 0xab08005a <+210>: blx 0xab075158 <_ZN3art9OatWriter16AddDexFileSourceEPKcS2_NS0_21CreateTypeLookupTableE@plt> => 0xab08005e <+214>: cbz r0, 0xab080092 <art::Dex2Oat::AddDexFileSources()+266>
#13:stack: addr value reg 0xffbe8420 0xeae0cd50 0xffbe8424 0xb53930d7 0xffbe8428 0xeae0e000 r4 0xffbe842c 0xeae0cd50 r5 0xffbe8430 0xeadfd060 r6 0xffbe8434 0x00000000 r7 0xffbe8438 0x00000004 r8 0xffbe843c 0xab078103 lr
#13 art::Dex2Oat::Setup() //到這裏已經到了 dex2oat的Setup函數,這個函數是 dex2oat.cc中的 pc:0xab078103 sp:0xffbe843c + 4 = 0xffbe8440
Dump of assembler code for function art::Dex2Oat::Setup(): 0xab078040 <+0>: stmdb sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr} 0xab078044 <+4>: sub sp, #284 ; 0x11c 0xab078046 <+6>: mov r9, r0 0xab078048 <+8>: ldr.w r0, [pc, #3728] ; 0xab078edc <art::Dex2Oat::Setup()+3740> 0xab07804c <+12>: ldr.w r1, [pc, #3728] ; 0xab078ee0 <art::Dex2Oat::Setup()+3744> 0xab078050 <+16>: add r0, pc 0xab078052 <+18>: add r1, pc 0xab078054 <+20>: ldr r0, [r0, #0] 0xab078056 <+22>: ldr r0, [r0, #0] 0xab078058 <+24>: str r0, [sp, #280] ; 0x118 ... 0xab0780d4 <+148>: ittt ne 0xab0780d6 <+150>: ldrne r1, [r0, #0] 0xab0780d8 <+152>: ldrne r1, [r1, #4] 0xab0780da <+154>: blxne r1 0xab0780dc <+156>: add r1, sp, #208 ; 0xd0 0xab0780de <+158>: movs r7, #0 0xab0780e0 <+160>: adds r0, r1, #4 0xab0780e2 <+162>: strd r7, r7, [sp, #212] ; 0xd4 0xab0780e6 <+166>: str r0, [sp, #56] ; 0x38 0xab0780e8 <+168>: str r0, [sp, #208] ; 0xd0 0xab0780ea <+170>: mov r0, r9 0xab0780ec <+172>: bl 0xab07f37c <art::Dex2Oat::PrepareRuntimeOptions(art::RuntimeArgumentMap*)> 0xab0780f0 <+176>: cmp r0, #1 0xab0780f2 <+178>: bne.w 0xab0790c6 <art::Dex2Oat::Setup()+4230> 0xab0780f6 <+182>: mov r0, r9 0xab0780f8 <+184>: bl 0xab07fe08 <art::Dex2Oat::CreateOatWriters()> 0xab0780fc <+188>: mov r0, r9 0xab0780fe <+190>: bl 0xab07ff88 <art::Dex2Oat::AddDexFileSources()> => 0xab078102 <+194>: cmp r0, #1
stack: addr value reg 0xffbe8440 0xb53930d7 ... 0xffbe855c 0xeae2d000 r4 0xffbe8560 0xeadfa510 r5 0xffbe8564 0xeadfd060 r6 0xffbe8568 0x00000001 r7 0xffbe856c 0x00000004 r8 0xffbe8570 0x00000000 r9 0xffbe8574 0x00000006 r10 0xffbe8578 0xab08e004 r11 0xffbe857c 0xab075869 lr
#14:#14 main(int, char**) pc:0xab075869 sp:0xffbe857c + 4 = 0xffbe8580 (gdb) disassemble 0xab075869 Dump of assembler code for function main(int, char**): 0xab075650 <+0>: stmdb sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr} 0xab075654 <+4>: sub sp, #4 0xab075656 <+6>: vpush {d8-d9} 0xab07565a <+10>: sub.w sp, sp, #664 ; 0x298 0xab07565e <+14>: mov r11, r0 0xab075660 <+16>: ldr.w r0, [pc, #3128] ; 0xab07629c <main(int, char**)+3148> 0xab075664 <+20>: add r7, sp, #268 ; 0x10c 0xab075666 <+22>: mov r10, r1 0xab075668 <+24>: add r0, pc 0xab07566a <+26>: ldr r0, [r0, #0] 0xab07566c <+28>: ldr r0, [r0, #0] 0xab07566e <+30>: str r0, [sp, #660] ; 0x294 0xab075670 <+32>: mov r0, r7 0xab075672 <+34>: blx 0xab074b94 <uname@plt> ... 0xab07584c <+508>: ldrb.w r0, [sp, #76] ; 0x4c 0xab075850 <+512>: tst.w r0, #1 0xab075854 <+516>: itt ne 0xab075856 <+518>: ldrne r0, [sp, #84] ; 0x54 0xab075858 <+520>: blxne 0xab074c3c <_ZdlPv@plt> 0xab07585c <+524>: add r0, sp, #88 ; 0x58 0xab07585e <+526>: blx 0xab074bdc <_ZN3art10LogMessageD1Ev@plt> 0xab075862 <+530>: mov r0, r4 0xab075864 <+532>: bl 0xab078040 <art::Dex2Oat::Setup()> 0xab075868 <+536>: cmp r0, #0
到了 main函數:int main(int argc, char** argv) { int result = art::dex2oat(argc, argv); ... }
(gdb) p 166+12 $13 = 178 (gdb) x /178wx 0xffbe8580 stack: addr value reg 0xffbe8580 0xffffffff ... 0xffbe8840 0x00000000 0xffbe8840 0x00000000 lr
main函數的 lr 是0x00000000,沒有上一層調用了。
此時sp=0xffbe8840+4 = 0xffbe8844
main函數是由exec執行 dex2oat可執行程序調用的,
exec時會傳遞參數,從此處的sp開始向前推,可以找到exec的參數如下:
0xffbe8e12: "" 0xffbe8e13: "" 0xffbe8e14: "" 0xffbe8e15: "" 0xffbe8e16: "" 0xffbe8e17: "" ---Type <return> to continue, or q <return> to quit--- 0xffbe8e18: "" 0xffbe8e19: "/system/bin/dex2oat" 0xffbe8e2d: "--instruction-set=arm" 0xffbe8e43: "--dex-file=/data/data/com.happyelements.AndroidAnimal.qq/.jiagu/classes.dex" 0xffbe8e8f: "--dex-file=/data/data/com.happyelements.AndroidAnimal.qq/.jiagu/classes2.dex" 0xffbe8edc: "--dex-file=/data/data/com.happyelements.AndroidAnimal.qq/.jiagu/classes3.dex" 0xffbe8f29: "--oat-file=/data/data/com.happyelements.AndroidAnimal.qq/.jiagu/classes.oat" 0xffbe8f75: "LD_PRELOAD=/data/data/com.happyelements.AndroidAnimal.qq/files/libjiagu.so" 0xffbe8fc0: "ANDROID_ROOT=/system" 0xffbe8fd5: "OAT_VERSION=79" 0xffbe8fe4: "/system/bin/dex2oat" 0xffbe8ff8: "" 0xffbe8ff9: "" 0xffbe8ffa: "" 0xffbe8ffb: "" 0xffbe8ffc: "" 0xffbe8ffd: "" 0xffbe8ffe: "" 0xffbe8fff: "" 0xffbe9000: <error: Cannot access memory at address 0xffbe9000>
從參數可以看到,應用調用dex2oat時傳遞的參數,3個dex文件,以及設置了
LD_PRELOAD=libjiagu.so
使用LD_PRELOAD環境變量是一種hook的方法,libjiagu看來是使用這個方法做的hook;