欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

iOS

程序员文章站 2022-04-11 15:17:38
...

身为iOS程序员的你还在为如何解决定位而烦恼吗?

前言

如果Crash堆栈,如果是在自己的工程源码中,问题都比较好解决。但如果最后落到了系统库的方法里,并且系统库还没开源,这时候要定位原因就非常困难了。那么我们只能读汇编代码,或反汇编分析伪代码。下面介绍Hopper Disassembler,它是较常用的的反汇编工具。

下载方法

可以通过官网下载Hopper工具: www.hopperapp.com/ 。我们可以先使用试用版,每次可以打开30分钟,可以根据试用期观察工具是否符合自己的使用习惯,然后在做判断。

使用步骤

方法1 顶部导航栏,选择File - Read Executable to Disassemble…, 选择要分析的二进制文件。

方法2 直接将可执行文件/动态库/静态库/archive拖到Hopper里 如图
iOS
默认的是AArch64(Arm64),直接确认即可。

通过案例看下一般应该如何分析

Crash Log基本信息

Date/Time:           2020-11-27 06:37:36 +0000
OS Version:          iPhone OS 14.2 (18B92)
Report Version:      104
Exception Type:  SIGSEGV
Exception Codes: SEGV_ACCERR at 0x0
Triggered by Thread:  63

Crash发生在63号线程,最后的栈桢是_objc_msgSend,它第44行指令出现非法内存访问SEGV_ACCERR,访问了一个内存地址为0x0的指针,0x0明显是一个非法内存地址。下面我们通过查看libobjc的汇编,尝试分析一下0x0到底是从哪里来的。
iOS

导入目标文件

打开iOS DeviceSupport路径,在目标系统14.2 (18B92)文件夹里,找到libobjc动态库,将libobjc拖到反编译工具Hopper Disassembler。

libobjc所在路径
/Users/xxx/Library/Developer/Xcode/iOS DeviceSupport/14.2 (18B92) arm64e/Symbols/usr/lib/libobjc.A.dylib

定位到Crash指令行

iOS
搜索_objc_msgSend,定位到_objc_msgSend的arm汇编代码。方法的首地址是00000001949a60e0,偏移量+44是00000001949a610c,这行就是发生Crash的指令。

反向寻找异常的根源

00000001949a610c add x13, x10, x12, lsl #4
报错的日志显示,访问了非法内存0x0。简单可以理解为某个寄存器的地址是0x0,执行了某一个指令,读取了这个寄存器的值。所以这是一个推理游戏,我们找到0x0地址是从哪里来的。

lsl是逻辑左移指令,add是加法指令。这一行表示将x12左移4位,相当于乘以16,然后加上x10的值,最后赋值给x13寄存器。

x13 <= x10 + (x12 * 16)

这里读取了两个内存地址的值x10和x12,因为发生了非法内存读取,所以x10或x12其中一个的地址是0x0。

LSL是逻辑左移
逻辑左移,右边统一添0。逻辑左移一位:010101010[0]

LSR是逻辑右移
逻辑右移,左边统一添0。逻辑右移一位:[0]101010101

00000001949a6104 eor x12, x1, x1, lsr #7

先看一下x12的来源,看它是否可能是0x0

这里表示x1右移7位,相当于除以128,然后和x1进行异或,结果赋值给x12寄存器,推论x12不太可能为0,那么就是x10为0。

EOR 逻辑异或
如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。

00000001949a6100 and x10, x11, #0xffffffffffff

再看一下x10的来源。x10等于0,x11与上0xffffffffffff结果为0,那x11就是0.

00000001949a60ec and x16, x13, #0x7ffffffffffff8

结合反编译结果 struct objc_class *cls = (struct objc_class *)(isa & 0x7ffffffffffff8);

将isa与上0xffffffff8才能得到对象所属的Class对象,这里x13是isa指针,x16是class对象

00000001949a60f8 ldr x11, [x16, #0x10]

struct objc_class : objc_object {
    struct objc_class * superclass;   //基类信息结构体。
    cache_t cache;    //方法缓存哈希表
    //... 其他数据成员忽略。
};

struct cache_t {
    struct bucket_t *buckets;    //缓存方法的哈希桶数组指针,桶的数量 = mask + 1
    int  mask;        //桶的数量 - 1
    int  occupied;   //桶中已经缓存的方法数量。
};

读取x16里的地址偏移16个字节(0x10),取出来的值是0。取偏移16个字节的值,通常是取某个对象或结构体的成员变量。从上面一行得出,x16是class对象,偏移16个字节应该是cache对象,那么应该是cache对象为空。

总结

使用反汇编工具是分析疑难问题的基础,今天介绍了Hopper Disassembler工具的使用。有空可以找一些疑难问题来分析,慢慢地就会熟悉反汇编工具和arm64汇编

作者:Blacktea
链接:https://juejin.cn/post/6900725204054605838

相关标签: iOS ios 定位