当前位置: 首页 > 科技观察

【iOS内功】使用Hopper定位疑难问题

时间:2023-03-16 00:48:37 科技观察

前言如果Crash栈,最后一个方法是使用自己项目的源码,问题更容易解决。但是如果最后落到系统库的方法上,而系统库还没有开源,这个时候就很难定位原因了。所以我们只能看汇编代码,或者反汇编分析伪代码。下面介绍一下HopperDisassembler,这是一款比较常用的反汇编工具。下载从官网下载Hopper工具:www.hopperapp.com/。可以先用试用版,每次可以打开30分钟。导入方法1在顶部导航栏中,选择File-ReadExecutabletoDisassemble...,选择要分析的二进制文件。方法二直接将可执行文件/动态库/静态库/归档拖入Hopper,默认为AArch64(Arm64),直接确认即可。下面通过一个案例来看看如何分析CrashLog的基本信息。Date/Time:2020-11-2706:37:36+0000OSVersion:iPhoneOS14.2(18B92)ReportVersion:104ExceptionType:SIGSEGVExceptionCodes:SEGV_ACCERRat0x0TriggeredbyThread:63Crashoccurredinthread63,最后栈帧是_objc_msgSend,它的第44行指令有非法内存访问SEGV_ACCERR,访问内存地址为0x0的指针,0x0显然是非法内存地址。接下来,我们尝试通过查看libobjc的汇编来分析0x0是从哪里来的。导入目标文件打开iOSDeviceSupport路径,在目标系统14.2(18B92)文件夹中找到libobjc动态库,将libobjc拖到反编译工具HopperDisassembler中。libobjc所在路径/Users/xxx/Library/Developer/Xcode/iOSDeviceSupport/14.2(18B92)arm64e/Symbols/usr/lib/libobjc.A.dylib定位Crash指令行搜索_objc_msgSend,定位arm程序集_objc_msgSend的代码。该方法的首地址为00000001949a60e0,偏移量+44为00000001949a610c。这一行是崩溃的指令。反向查找异常源00000001949a610caddx13,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]10101010100000001949a6104eorx12,x1,x1,lsr#7首先看x12的来源,看有没有可能是0x0这里的意思是x1右移了7位,相当于除以128,然后sumx1异或,结果赋值给x12寄存器。推断x12不可能为0,则x10为0。EOR逻辑异或如果a和b的两个值不相同,则异或结果为1。如果a的两个值和b一样,异或结果为0。00000001949a6100andx10,x11,#0xffffffffffff再看看x10的出处。x10等于0,x11和0xffffffffffff结果为0,则x11为0.00000001949a60ec和x16,x13,#0x7ffffffffffff8结合反编译结果structobjc_class*cls=(structobjc_class*)(isa&0x7ffffffffffff8);获取对象所属的Class对象,其中x13为isa指针,x16为类对象structobjc_class:objc_object{structobjc_class*superclass;//基类信息结构。cache_tcache;//方法缓存哈希表//...其他数据成员被忽略。};structcache_t{structbucket_t*buckets;//缓存方法的hash桶数组指针,buckets个数=mask+1intmask;//桶个数-1intoccupied;//桶中缓存方法个数。};读取x16中16字节(0x10)的地址偏移量,取到的值为0。取偏移量16字节的值,通常取一个对象或结构体的成员变量。从上面这行可以得出x16是一个类对象,16字节的偏移量应该是缓存对象,所以缓存对象应该是空的。小结反汇编工具的使用是分析疑难问题的基础。今天我们介绍一下HopperDisassembler工具的使用。有时间可以找一些比较难的问题分析,慢慢熟悉反汇编工具和arm64汇编。