美文网首页
Radare2-Android静态调试so

Radare2-Android静态调试so

作者: 无情剑客Burning | 来源:发表于2020-12-06 13:17 被阅读0次

使用Radare2静态分析apk(2)末尾通过Radare2分析出一段ARM64汇编代码,这篇文通过分析这段汇编代码来来了解下ARM64汇编。

完整的代码

            ; UNKNOWN XREF from unk @ 
┌ 156: sym.Java_com_example_myapplication_MainActivity_stringFromJNI (int64_t arg1, int64_t arg2);
│           ; var int64_t var_28h @ x29-0x28
│           ; var int64_t var_bp_8h @ x29-0x8
│           ; var int64_t var_0h @ sp+0x0
│           ; var int64_t var_8h @ sp+0x8
│           ; var int64_t var_10h @ sp+0x10
│           ; var char *var_18h @ sp+0x18
│           ; var int64_t var_0h_2 @ sp+0x30
│           ; var int64_t var_20h @ sp+0x40
│           ; var int64_t var_60h @ sp+0x60
│           ; var int64_t var_60h_2 @ sp+0x68
│           ; arg int64_t arg1 @ x0
│           ; arg int64_t arg2 @ x1
│           0x0000f08c      ffc301d1       sub sp, sp, 0x70
│           0x0000f090      fd7b06a9       stp x29, x30, [var_60h]
│           0x0000f094      fd830191       add x29, var_60h
│           0x0000f098      48d03bd5       mrs x8, tpidr_el0
│           0x0000f09c      081540f9       ldr x8, [x8, 0x28]          ; aav.0x00000028
│                                                                      ; [0x28:4]=0x341f8
│           0x0000f0a0      a8831ff8       stur x8, [var_bp_8h]
│           0x0000f0a4      a0831df8       stur x0, [var_28h]          ; arg1
│           0x0000f0a8      e11b00f9       str x1, [var_0h_2]          ; arg2
│           0x0000f0ac      c10000b0       adrp x1, 0x28000
│           0x0000f0b0      21201191       add x1, x1, 0x448           ; 0x28448 ; "Hello from C++" ; section..rodata
│           0x0000f0b4      a88300d1       sub x8, var_20h
│           0x0000f0b8      e00308aa       mov x0, x8
│           0x0000f0bc      e80f00f9       str x8, [var_18h]
│           0x0000f0c0      94ffff97       bl fcn.0000ef10
│           0x0000f0c4      a0835df8       ldur x0, [var_28h]
│           0x0000f0c8      e80f40f9       ldr x8, [var_18h]           ; aav.0x00000018
│                                                                      ; [0x18:4]=0xf050 pc ; "P\xf0"
│           0x0000f0cc      e00b00f9       str x0, [var_10h]
│           0x0000f0d0      e00308aa       mov x0, x8                  ; int64_t arg1
│           0x0000f0d4      40000094       bl fcn.0000f1d4             ; fcn.0000f1d4(0x0)
│           0x0000f0d8      e80b40f9       ldr x8, [var_10h]           ; aav.0x00000010
│                                                                      ; [0x10:4]=0xb70003
│           0x0000f0dc      e00700f9       str x0, [var_8h]
│           0x0000f0e0      e00308aa       mov x0, x8
│           0x0000f0e4      e10740f9       ldr x1, [var_8h]            ; aav.0x00000008
│                                                                      ; [0x8:4]=0
│           0x0000f0e8      e6feff97       bl fcn.0000ec80
│           0x0000f0ec      e00300f9       str x0, [sp]
│       ┌─< 0x0000f0f0      01000014       b 0xf0f4
│       │   ; CODE XREF from sym.Java_com_example_myapplication_MainActivity_stringFromJNI @ 0xf0f0
│       └─> 0x0000f0f4      a08300d1       sub x0, var_20h
│           0x0000f0f8      2affff97       bl fcn.0000eda0
│           0x0000f0fc      48d03bd5       mrs x8, tpidr_el0
│           0x0000f100      081540f9       ldr x8, [x8, 0x28]          ; aav.0x00000028
│                                                                      ; [0x28:4]=0x341f8
│           0x0000f104      a9835ff8       ldur x9, [var_bp_8h]
│           0x0000f108      080109eb       subs x8, x8, x9
│       ┌─< 0x0000f10c      a1010054       b.ne 0xf140                 ; likely
│      ┌──< 0x0000f110      01000014       b 0xf114
│      ││   ; CODE XREF from sym.Java_com_example_myapplication_MainActivity_stringFromJNI @ 0xf110
│      └──> 0x0000f114      e00340f9       ldr x0, [sp]
│       │   0x0000f118      fd7b46a9       ldp x29, x30, [var_60h]
│       │   0x0000f11c      ffc30191       add sp, sp, 0x70            ; 0x178000
│       │   0x0000f120      c0035fd6       ret
..
       ││   ; CODE XREF from unk @ 
│       │   ; CODE XREF from sym.Java_com_example_myapplication_MainActivity_stringFromJNI @ 0xf10c
└       └─> 0x0000f140      14ffff97       bl sym.imp.__stack_chk_fail ; void __stack_chk_fail(void) ; sym.std::__ndk1::basic_string_char__std::__ndk1::char_traits_char___std::__ndk1::allocator_char___::basic_string_decltype_nullptr___char_const
└                                                                      ; void __stack_chk_fail(void)

ARM处理器用到的指令集分为 ARM 和 THUMB 两种。ARM指令长度固定为32bit,THUMB指令长度固定为16bit。上面代码的所有指令都是32位的,所以都是ARM指令。

代码分析

1. 开辟堆栈空间`sub sp, sp, 0x70`
2. 存在一对数据 `stp x29, x30, [var_60h]`
3. x29与[var_60h]相加 `add x29, var_60h`
4. 保存状态tpidr_el0到x8寄存器  `mrs x8, tpidr_el0`
5. 将x8+0x28内存中的值加载到x8寄存器 `ldr x8, [x8, 0x28] `
6. 将x8寄存器保存起来,保存到var_bp_8h指向的内存中
7. 将第一个参数x0保存到var_bp_8h指向的内存中
8. 将第二个参数x1保存到var_0h_2指向的内存中
9. 将x1寄存器指向只读字符串"Hello from C++" 
10. 将x8寄存器与var_20h相减法,把结果赋值给x8寄存器
11. 将x8赋值给x0
12. 将x8寄存器保存到var_18h指向的内存中
13. 调用函数fcn.0000ef10,没有处理返回值,暂时不用关注
14. 将第一个参数给x0寄存器,上面函数的返回值没有什么实际的用途呀,这里直接把x0寄存器覆盖了
15. 恢复x8寄存器的值
16. 将x0寄存器的值保存起来,放到var_10h指向的内存中
17. 将x8寄存器赋值给x0
18. 调用fcn.0000f1d4
19. 恢复x8寄存器的值
20. 将上述函数的返回值x0保存到var_8h指向的内存中
21. 将x8赋值给x0
22. 将var_8h中的值赋值给x1寄存器
23. 调用函数fcn.0000ec80
24. 将返回值x0保存到sp指向的内存中
25. 跳转到0xf0f4,也就是下一条指令
26. 将x0与var_20h相减,结果赋值给x0
27. 调用fcn.0000eda0
28. 读取tpidr_el0状态到x8寄存器
29. 将x8+0x28内存中的值加载到x8寄存器 `ldr x8, [x8, 0x28] `
30. 加载var_bp_8h中的值到x9寄存器
31. 判断x8的值是否发生变化,如果发生变化,走失败流程,这个应该是使用cookie技术防止堆栈攻击的技术
32. 如果没有发生变化,跳转到0xf114
33. 将sp内存中的值加载到x0寄存器中,用作返回值
34. 恢复x29,x30的值
35. 恢复堆栈
36. ret返回

通过上面的分析,可知最终的返回值是通过调用函数fcn.0000ec80。这个函数其中的一个参数是字符串处理函数fcn.0000f1d4的返回值。另一个参数是x8的值,通过分析可知x8寄存器正是函数Java_com_example_myapplication_MainActivity_stringFromJNI的第一个参数,类型是JNIEnv。由此推断fcn.0000ec80很可能是JNIEnv相关函数。


burning_gzh.png

查看fcn.0000ec80

            ; CALL XREF from sym.Java_com_example_myapplication_MainActivity_stringFromJNI @ 0xf0e8
┌ 16: fcn.0000ec80 ();
│           0x0000ec80      300100d0       adrp x16, obj.typeinfo_for_decltype_nullptr__const ; 0x34000
│           0x0000ec84      119a46f9       ldr x17, [x16, 0xd30]       ; [0x34d30:4]=0xeb50 fcn.0000eb50 ; "P\xeb"
│           0x0000ec88      10c23491       add x16, x16, 0xd30         ; 0x34d30 ; "P\xeb"
└           0x0000ec8c      20021fd6       br x17

跳转到0x34d30,通过pd命令查看相应的内容。很显然这个函数就是NewStringUTF。这涉及到got表和plt表,在深入理解GOT覆写技术 中对GOT表进行了介绍。在后续文章中还会重点讲解android got表。

在这里插入图片描述 使用pdg命令decompiler一下更加直观。
在这里插入图片描述

查看fcn.0000ef10

            ; CALL XREF from sym.Java_com_example_myapplication_MainActivity_stringFromJNI @ 0xf0c0
┌ 16: fcn.0000ef10 ();
│           0x0000ef10      300100d0       adrp x16, obj.typeinfo_for_decltype_nullptr__const ; 0x34000
│           0x0000ef14      113e47f9       ldr x17, [x16, 0xe78]       ; [0x34e78:4]=0xeb50 fcn.0000eb50 ; "P\xeb"
│           0x0000ef18      10e23991       add x16, x16, 0xe78         ; 0x34e78 ; "P\xeb"
└           0x0000ef1c      20021fd6       br x17

最终定位到basic_string<decltype(nullptr)>(char const)。

在这里插入图片描述 查看basic_string函数信息,可知有2个参数,其中x0也就是参数1是x8寄存器的值,x1指向字符串"Hello from C++"*。这个函数的功能相当于string.c_str()。c_str()函数返回一个指向正规C字符串的指针常量, 内容与本string串相同。
[0x0000eb50]> pdf @ 0x0000f144
            ; UNKNOWN XREF from aav.0x00001f0c @ +0x664
┌ 88: sym.std::__ndk1::basic_string_char__std::__ndk1::char_traits_char___std::__ndk1::allocator_char___::basic_string_decltype_nullptr___char_const (int64_t arg1, int64_t arg2);
│           ; var int64_t var_10h @ x29-0x10
│           ; var int64_t var_8h @ x29-0x8
│           ; var int64_t var_sp_8h @ sp+0x8
│           ; var int64_t var_sp_10h @ sp+0x10
│           ; var char *var_18h @ sp+0x18
│           ; var int64_t var_30h @ sp+0x30
│           ; var int64_t var_30h_2 @ sp+0x38
│           ; arg int64_t arg1 @ x0
│           ; arg int64_t arg2 @ x1
│           0x0000f144      ff0301d1       sub sp, sp, 0x40            ; std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >::basic_string<decltype(nullptr)>(char const*)
│           0x0000f148      fd7b03a9       stp x29, x30, [var_30h]
│           0x0000f14c      fdc30091       add x29, var_30h
│           0x0000f150      a0831ff8       stur x0, [var_8h]           ; arg1
│           0x0000f154      a1031ff8       stur x1, [var_10h]          ; arg2
│           0x0000f158      a8835ff8       ldur x8, [var_8h]
│           0x0000f15c      e00308aa       mov x0, x8
│           0x0000f160      e80f00f9       str x8, [var_18h]
│           0x0000f164      cbfeff97       bl fcn.0000ec90
│           0x0000f168      a1035ff8       ldur x1, [var_10h]
│           0x0000f16c      a0035ff8       ldur x0, [var_10h]
│           0x0000f170      e10b00f9       str x1, [var_sp_10h]
│           0x0000f174      9fffff97       bl fcn.0000eff0
│           0x0000f178      e80f40f9       ldr x8, [var_18h]           ; aav.0x00000018
│                                                                      ; [0x18:4]=0xf050 pc ; "P\xf0"
│           0x0000f17c      e00700f9       str x0, [var_sp_8h]
│           0x0000f180      e00308aa       mov x0, x8
│           0x0000f184      e10b40f9       ldr x1, [var_sp_10h]        ; aav.0x00000010
│                                                                      ; [0x10:4]=0xb70003
│           0x0000f188      e20740f9       ldr x2, [var_sp_8h]         ; aav.0x00000008
│                                                                      ; [0x8:4]=0
│           0x0000f18c      a1ffff97       bl fcn.0000f010
│           0x0000f190      fd7b43a9       ldp x29, x30, [var_30h]
│           0x0000f194      ff030191       add sp, sp, 0x40            ; 0x178000
└           0x0000f198      c0035fd6       ret

查看fcn.0000f1d4

            ; CALL XREF from sym.Java_com_example_myapplication_MainActivity_stringFromJNI @ 0xf0d4
┌ 36: fcn.0000f1d4 (char *arg1);
│           ; var char *var_8h @ sp+0x8
│           ; var int64_t var_10h @ sp+0x10
│           ; var int64_t var_10h_2 @ sp+0x18
│           ; arg char *arg1 @ x0
│           0x0000f1d4      ff8300d1       sub sp, sp, 0x20
│           0x0000f1d8      fd7b01a9       stp x29, x30, [var_10h]
│           0x0000f1dc      fd430091       add x29, var_10h
│           0x0000f1e0      e00700f9       str x0, [var_8h]            ; arg1
│           0x0000f1e4      e00740f9       ldr x0, [var_8h]            ; aav.0x00000008
│                                                                      ; [0x8:4]=0 ; int64_t arg1
│           0x0000f1e8      d8020094       bl fcn.0000fd48
│           0x0000f1ec      fd7b41a9       ldp x29, x30, [var_10h]
│           0x0000f1f0      ff830091       add sp, sp, 0x20            ; 0x178000
└           0x0000f1f4      c0035fd6       ret

通过分析大概推测是混淆函数,没什么实际的作用,从上面的代码中可以能看出x0的值也就是返回值没有发生任何的改变

查看fcn.0000eda0

         ; CALL XREF from sym.Java_com_example_myapplication_MainActivity_stringFromJNI @ 0xf0f8
            ; CALL XREF from sym.Java_com_example_myapplication_MainActivity_stringFromJNI @ +0xa4
┌ 16: fcn.0000eda0 ();
│           0x0000eda0      300100d0       adrp x16, obj.typeinfo_for_decltype_nullptr__const ; 0x34000
│           0x0000eda4      11e246f9       ldr x17, [x16, 0xdc0]       ; [0x34dc0:4]=0xeb50 fcn.0000eb50 ; "P\xeb"
│           0x0000eda8      10023791       add x16, x16, 0xdc0         ; 0x34dc0 ; "P\xeb"
└           0x0000edac      20021fd6       br x17

最终定位到~basic_string()方法。


在这里插入图片描述

IDA查看

通过下图可知与上面的分析基本一致。


在这里插入图片描述

ARM指令和寄存器

ARM指令

MRS指令的格式为:
MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR)
MRS指令用亍将程序状态寄存器的内容传送到通用寄存器中。

STUR (SIMD&FP):
Store SIMD&FP register (unscaled offset).

跳转指令:
B ;跳转指令,可带条件跳转与cmp配合使用
BL ;带返回的跳转指令, 返回地址保存到LR(X30)
BLR ; 带返回的跳转指令,跳转到指令后边跟随寄存器中保存的地址(例:blr x8 ;跳转到x8保存的地址中去执行),并且把当前PC+4回写到X30。
BR: 与BLR差别在于有无回写。
RET ;子程序返回指令,返回地址默认保存在LR(X30)

ADRP Xd, lable(Address Page)
符号扩展一个21位的offset, 向左移动12位
PC的值的低12位 清零, 然后 把 这两者相加, 结果写入到Xd寄存器
用来得到一块含有 lable的4KB对齐 内存区域的base地址 (也就是说lable所在的地址,一定落在这个4KB的内存区域里, 指令助记符里Page也就是这个意思), 可用来寻址 +/- 4GB的范围。

ARM寄存器

ARM64 有34个寄存器,包括31个通用寄存器、SP、PC、CPSR。

寄存器 位数 描述
x0-x30 64 通用寄存器,如果有需要可以当做32bit使用:W0-W30
FP(X29) 64 保存栈帧地址(栈底指针)
LR(x30) 64 通常称X30为程序链接寄存器,保存子程序结束后需要执行的下一条指令
SP 64 保存栈指针,使用 SP/WSP来进行对SP寄存器的访问。
PC 64 程序计数器,俗称PC指针,总是指向即将要执行的下一条指令,在arm64中,软件是不能改写PC寄存器的。
CPSR 64 状态寄存器
程序状态寄存器

CPSR (Current Program Status Register),各个bit的含义如下图:


在这里插入图片描述

SPSR (Saved Program Status Register),在异常状态下使用,当发生异常时,会把CPSR的内容写入SPSR, 等异常恢复之后,又会把SPSR写到CPSR中。

相关文章

  • Radare2-Android静态调试so

    在使用Radare2静态分析apk(2)[https://mp.weixin.qq.com/s?__biz=MzI...

  • 常用的gcc选项

    调试相关 警告相关 改变隐藏的链接行为 链接静态库 or 链接动态库 so相关选项 exe相关选项

  • ida pro动态调试步骤

    在上篇文章中,我简单介绍了使用IDA Pro静态分析so文件。今天,我将介绍一下如何使用IDA Pro动态调试so...

  • vscode调试 调试so

    背景 编译flutter和cronet(chromium分离)在android --AS 环境中使用会导致调试困难...

  • Android逆向之以调试方式启动App

    在逆向时有时不可避免需要调试app,比如调试so。 一般调试so有两种方式: 方式1:app已经启动运行了,使用调...

  • linux下静态库和动态库创建和使用

    linux静态库 .a ===== win 静态库 .lib linux动态库 .so ==== win动态库 ....

  • IDA调试so

    IDA调试so 环境配置 一台 root 的手机,与电脑在同一局域网IDA 7.0Android 环境 准备工作 ...

  • Android逆向 之 IDA动态调试so(二)

    概述 上一章进行了so的静态分析,很多时候由于加密逻辑非常复杂我们要依靠动态调试进行逻辑的判断,得到更有用的信息。...

  • 加载so分为动态加载和静态加载

    加载so分为动态加载和静态加载。 静态加载:System.loadLibrary(String libname),...

  • IDA 调试android

    使用IDA进行动态调试so,有两种方式进行调试,一种是调试启动方式,调试启动可以调试jni_onload ,ini...

网友评论

      本文标题:Radare2-Android静态调试so

      本文链接:https://www.haomeiwen.com/subject/kzsowktx.html