热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

iosBlock参数和返回值类型获取

原博客:http:www.swiftyper.com20161216debuging-objective-c-blocks-in-lldb注:本篇文章都是在64位系统下进行分析,如

原博客:http://www.swiftyper.com/2016/12/16/debuging-objective-c-blocks-in-lldb/

注:本篇文章都是在 64 位系统下进行分析,如果是 32 位系统,整型与指针类型的大小都是与 64 位不一致的,请自行进行修改。

Block 的内存结构

在 LLVM 文档中,可以看到 Block 的实现规范,其中最关键的地方是对于 Block 内存结构的定义:

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
};

可以看到第一个成员是 isa,说明了 Block 在 Objective-C 当中也是一个对象。我们重点要关注的就是 void (*invode)(void *, ...); 和 descriptor 中的 const char *signature,前者指向了 Block 具体实现的地址,后者是表示 Block 函数签名的字符串。

 

 通过分析界面以及 class-dump 出来头文件就能分析出某个函数的参数为block类型,主要对block中返回值和入参进行分析,方便后期的hook,例:

- (void)requestCorpse:(CDUnknownBlockType)arg1;

   

 通过hook 该函数debug可以看到block函数的具体地址

 

在 64 位系统上,指针类型的大小是 8 个字节,而 int 是 4 个字节,long int 8个字节

因此,invoke 函数指针的地址就是在第 16 个字节之后。我们可以通过 lldb 的 memory 命令来打印出指定地址的内存,我们上面已经得到了 block 的地址,现在就打印出它的内存内容:

(lldb) memory read --size 8 --format x 0x16db93bb8
0x16db93bb8: 0x00000001f81c4870 0x00000000c0000000
0x16db93bc8: 0x000000010497cc34 0x0000000109f49750
0x16db93bd8: 0x4277c7d786884399 0x0000000000000000
0x16db93be8: 0x40ea4cd7c8a9a6a0 0x0000000281eecc60

如前所述,函数指针的地址是在第 16 个字节之后,并占用 8 个字节,所以可以得到函数的地址是0x000000010497cc34

void *isa; 指针8个字节:0x00000001f81c4870
int flags; int reserved; int4个字节,2个int8个:0x00000000c0000000
(
*invoke)(void *, ...); 指针8个所以该地址:0x000000010497cc34
struct Block_descriptor_1{...}*descriptor 0x0000000109f49750

 


找出 Block 的函数签名

         要找出 Block 的函数签名,需要通过 descriptor 结构体中的 signature 成员,然后通过它得到一个 NSMethodSignature 对象。

首先,需要找到 descriptor 结构体。这个结构体在 Block 中是通过指针持有的,它的位置正好在 invoke 成员后面,占用 8 个字节。可以从上面的内存打印中看到 descriptor 指针的地址是 0x0000000109f49750

找到地址,并打印出它的字符串内容:       ios中第9位大部分时候为1,第8位为0,其他的容易超出内存

(lldb) memory read --size 8 --format x 0x0000000109f49750
0x109f49750: 0x0000000000000000 0x0000000000000028
0x109f49760: 0x000000010ce7a034 0x000000010d9cad29
0x109f49770: 0x00000001f81c49b0 0x0000000050000000
0x109f49780: 0x00000001022d1498 0x0000000109eee450
(lldb) p (
char *)0x000000010ce7a034 //一般来说为第二行第一个,或第三行第一个,具体可看下文扩展知识
(
char *) $2 = 0x000000010ce7a034 "v16@?0@\"NSDictionary\"8"

拿到函数签名后,只是我们需要通过 NSMethodSignature 找出它的参数和返回类型:

(lldb) po [NSMethodSignature signatureWithObjCTypes:"v16@?0@\"NSDictionary\"8"]
0x8ce27f0dea645e47>
number of arguments
= 2
frame size
= 224
is special struct return? NO
return value: -------- -------- -------- --------
type encoding (v)
'v'
flags {}
modifiers {}
frame {offset
= 0, offset adjust = 0, size = 0, size adjust = 0}
memory {offset
= 0, size = 0}
argument
0: -------- -------- -------- --------
type encoding (@)
'@?'
flags {isObject, isBlock}
modifiers {}
frame {offset
= 0, offset adjust = 0, size = 8, size adjust = 0}
memory {offset
= 0, size = 8}
argument
1: -------- -------- -------- --------
type encoding (@)
'@"NSDictionary"'
flags {isObject}
modifiers {}
frame {offset
= 8, offset adjust = 0, size = 8, size adjust = 0}
memory {offset
= 0, size = 8}
class 'NSDictionary'

注意,字符串中的双引号需要对其进行转义。


 对我们最有用的 type encoding 字段,这些符号对应的解释可以参考 Type Encoding 官方文档。

 

所以,总结来讲就是:这个方法没有返回值 void类型,它接受2个参数,第一个是 block (即我们自己的 block 的引用)"@?" 代表本身所以hook中不需要写,第二个是一个 NSDictionary 对象。

callBack:(void (^)(NSDictionary *)arg1;

 

本文章仅供学习参考,如有版权侵犯,请联系作者修改,转载请注明出处!



推荐阅读
author-avatar
菜蕻的薇笑2602929033
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有