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;


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值