0%

逆向获取Block对应函数入口和函数签名

逆向获取block对应函数入口和函数签名

在逆向分析App的时候,有时会遇到某个关键方法中传入一个block参数来做回调,class-dump无法解析出block的类型以及函数签名。了解过block本质及其内存模型后,就可以通过lldb动态调试来获取目标信息

block的内存结构

在LLVM文档中,找到block的实现规范Block Implementation Specification,找到block内存结构的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct Block_literal_1 {
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor_1 {
unsigned long int reserved; // NULL
unsigned long int size; // sizeof(struct Block_literal_1)
// optional helper functions
void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
void (*dispose_helper)(void *src); // IFF (1<<25)
// required ABI.2010.3.16
const char *signature; // IFF (1<<30)
} *descriptor;
// imported variables
};

其中block对应的实现函数地址入口和函数签名分别在void (*invoke)(void *, ...);descriptor中的const char *signature;中保存

实例

某app中的某个带block参数的方法

- (void)parseRequest:(id)arg1 result:(id)arg2 completion:(id)arg3;

祭出debugserver和lldb


debugserver启动

LLDB connect

定位目标方法内存地址

断点并触发

获取block参数对象

block内存实例

检查block是否有函数签名

检查block是否有copy和dispose函数指针

descriptor布局

函数签名信息

最后得到的函数签名字符编码,可在官方Type Encoding中找到

从图中可以看出,block参数个数为3,block 的返回值为void,第一个参数为block自身,通常在block语法参数列表省略,第二个参数为NSArray类型,第三个参数为BOOL类型

参考

通过逆向深入理解 Block 的内存模型