hook read_chk 導致dex2oat進程 abort

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如下:

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]
可以看到 eba9b000 - ebaf8fff 段是 r-x 屬性,即可執行代碼段;

在 main log中有如下log:

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是不會有這種參數的,看起來是第三方 APP 自行調用的 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
可以看出來,dex2oat(23898)進程確實是由 23710 進程 fork出來的,那麼 dex2oat的參數也應該是其組織的;

抓到  core file後,進行分析:

直觀的看 backtrace, frame8中的可執行代碼,調用了 __read_chk函數,出發了abort,導致進程終止。

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);
}
據此,我們分析參數 count 和 buf_size 在調用過程的傳遞。

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:

#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:

#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;:
#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
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:
#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>
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:
#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;


發佈了34 篇原創文章 · 獲贊 13 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章