ios逆向获取Block的参数和返回值

先贴个图

1.原理,Block的内存结构,出自Clang编译器的官方文档

参考了https://blog.csdn.net/u013378438/article/details/87167133

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

在 64 位系统上,指针类型的大小是 8 个字节,而 int 是 4 个字节,
因此,invoke 函数指针的地址就是在第 16 个字节之后。我们可以通过 lldb 的 memory 命令来打印出指定地址的内存,我们上面已经得到了 block 的地址,现在就打印出它的内存内容
 memory read --size 8 --format x 0x16d1a6050

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

找出 Block 的函数签名

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

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

为了找出 signature 的地址,我们还需要确认这个 Block 是否拥有 copy_helper 和 disponse_helper 这两个可选的函数指针。由于 ((0xc2000000 & (1 << 25)) != 0),因此我们可以确认这个 Block 拥有刚刚提到的两个函数指针。

现在可以总结下:signature 的地址是在 descriptor 下偏移两个 unsiged long 和两个指针后的地址,即 32 个字节后。现在让我们找出它的地址,并打印出它的字符串内容:

memory read --size 8 --format x 0x00000001075496c2

看到这一串乱码是不是觉得有点崩溃,折腾了半天,怎么打印出这么一串鬼东西,虽然里面有一个熟悉的 NSDictionary,但是其它的东西完全看不懂啊。

不要慌,这确实就是一个函数签名,只是我们需要通过 NSMethodSignature 找出它的参数类型:

po [NSMethodSignature signatureWithObjCTypes:"v16@?0@\"XSearchService\"8"]

注意在双引号”前加转义\

(lldb) memory read --size 8 --format x 0x16d1a6050
0x16d1a6050: 0x00000001b6ca1e88 0x00000000c2000000
0x16d1a6060: 0x0000000105e014a8 0x0000000106336398
0x16d1a6070: 0x00000001c4329ba0 0x00000001c4329ba0
0x16d1a6080: 0x4094615555555555 0x0000000000000000
(lldb) memory read --size 8 --format x 0x0000000106336398
0x106336398: 0x0000000000000000 0x0000000000000028
0x1063363a8: 0x0000000105e014dc 0x0000000105e014e8
0x1063363b8: 0x00000001075496c2 0x0000000000000001
0x1063363c8: 0x0000000000000000 0x0000000000000028
(lldb) p (char *)0x00000001075496c2
(char *) $0 = 0x00000001075496c2 "v16@?0@"XSearchService"8"
(lldb) po [NSMethodSignature signatureWithObjCTypes:"v16@?0@\"XSearchService\"8"]
<NSMethodSignature: 0x1c1a71100>
    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 (@) '@"XSearchService"'
        flags {isObject}
        modifiers {}
        frame {offset = 8, offset adjust = 0, size = 8, size adjust = 0}
        memory {offset = 0, size = 8}
            class 'XSearchService'

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

这里还有个方法签名的相关原理

最终可还原的参数为

%hook TBSRPXSearchService
- (void)doSearchStart:(id)arg1 Success:(void (^)(id response))completionHandler Fail:(id)arg3 isMore:(_Bool)arg4{
    NSLog(@"gouzhule3333");
    NSLog(@"%@",[NSThread callStackSymbols]);
    //或者在这里加个断点,运行时看调用栈吧
    void (^interception)(XSearchService *response) = ^(XSearchService *response){
        NSLog(@"%@", response);
        completionHandler(response);
    };
    
    %orig(arg1,completionHandler,arg3,arg4);
}
%end
发布了96 篇原创文章 · 获赞 10 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/feifeiwuxian/article/details/90296668
今日推荐