在第三节 函数表示与搜索函数 提到block函数和普通的OC函数不同。
反汇编分析前需要理解block的实现原理,故推荐先看看这几篇文章及其所引用的参考资料:
Block介绍(一)基础
Block介绍(二)内存管理与其他特性
block介绍(三)揭开神秘面纱(上)
block介绍(四)揭开神秘面纱(下)
block函数的命名与上文提到类似。函数内部定义的block会以scope命名,如:
@implementation ViewController
- (void)later
{
[self presentViewController:self animated:NO completion:^{
NSLog(@"wo yun");
[self didReceiveMemoryWarning];
}];
[UIView transitionFromView:self.view toView:self.view duration:1 options:UIViewAnimationOptionTransitionCurlUp completion:^(BOOL finished) {
NSLog(@"%d", finished);
}];
}
在IDA中出现的名字分别为:
___23__ViewController_later__block_invoke
___23__ViewController_later__block_invoke6
全局型block:
int (^nimei)(int, id) = ^(int p1, id p2) {
p1++;
[p2 release];
return 0;
};
显示为:
_nimei_block_invoke
以下是上面的源码- [ViewController later]函数的反汇编(Mac IDA):
__text:00001F30 ; =============== S U B R O U T I N E =======================================
__text:00001F30
__text:00001F30 ; ViewController - (void)later
__text:00001F30 ; Attributes: bp-based frame
__text:00001F30
__text:00001F30 ; void __cdecl -[ViewController later](struct ViewController *self, SEL)
__text:00001F30 __ViewController_later_ proc near ; DATA XREF: __objc_const:00005590o
__text:00001F30
__text:00001F30 var_30 = dword ptr -30h
__text:00001F30 var_2C = dword ptr -2Ch
__text:00001F30 var_28 = dword ptr -28h
__text:00001F30 var_24 = dword ptr -24h
__text:00001F30 var_20 = dword ptr -20h
__text:00001F30 var_1C = dword ptr -1Ch
__text:00001F30 var_18 = dword ptr -18h
__text:00001F30 var_14 = dword ptr -14h
__text:00001F30 self = dword ptr 8
__text:00001F30
__text:00001F30 push ebp
__text:00001F31 mov ebp, esp
__text:00001F33 push ebx
__text:00001F34 push edi
__text:00001F35 push esi
__text:00001F36 sub esp, 4Ch
__text:00001F39 call $+5
__text:00001F3E pop edi
__text:00001F3F mov eax, ds:(__NSConcreteStackBlock_ptr - 1F3Eh)[edi]
__text:00001F45 mov [ebp+var_28], eax
__text:00001F48 mov [ebp+var_24], 42000000h
__text:00001F4F mov [ebp+var_20], 0
__text:00001F56 lea eax, (___23__ViewController_later__block_invoke - 1F3Eh)[edi]
__text:00001F5C mov [ebp+var_1C], eax
__text:00001F5F lea eax, (___block_descriptor_tmp - 1F3Eh)[edi]
__text:00001F65 mov [ebp+var_18], eax
__text:00001F68 mov ebx, [ebp+self]
__text:00001F6B mov [ebp+var_14], ebx
__text:00001F6E mov eax, ds:(selRef_presentViewController_animated_completion_ - 1F3Eh)[edi]
__text:00001F74 lea ecx, [ebp+var_28]
__text:00001F77 mov [esp+10h], ecx
__text:00001F7B mov [esp+8], ebx
__text:00001F7F mov [esp+4], eax
__text:00001F83 mov [esp], ebx
__text:00001F86 mov dword ptr [esp+0Ch], 0
__text:00001F8E call _objc_msgSend
__text:00001F93 mov eax, ds:(classRef_UIView - 1F3Eh)[edi]
__text:00001F99 mov [ebp+var_2C], eax
__text:00001F9C mov esi, ds:(selRef_view - 1F3Eh)[edi]
__text:00001FA2 mov [esp+4], esi
__text:00001FA6 mov [esp], ebx
__text:00001FA9 call _objc_msgSend
__text:00001FAE mov [ebp+var_30], eax
__text:00001FB1 mov [esp+4], esi
__text:00001FB5 mov [esp], ebx
__text:00001FB8 call _objc_msgSend
__text:00001FBD mov ecx, ds:(selRef_transitionFromView_toView_duration_options_completion_ - 1F3Eh)[edi]
__text:00001FC3 lea edx, (___block_literal_global - 1F3Eh)[edi]
__text:00001FC9 mov [esp+1Ch], edx
__text:00001FCD mov [esp+0Ch], eax
__text:00001FD1 mov eax, [ebp+var_30]
__text:00001FD4 mov [esp+8], eax
__text:00001FD8 mov [esp+4], ecx
__text:00001FDC mov eax, [ebp+var_2C]
__text:00001FDF mov [esp], eax
__text:00001FE2 mov dword ptr [esp+14h], 3FF00000h
__text:00001FEA mov dword ptr [esp+10h], 0
__text:00001FF2 mov dword ptr [esp+18h], 300000h
__text:00001FFA call _objc_msgSend
__text:00001FFF add esp, 4Ch
__text:00002002 pop esi
__text:00002003 pop edi
__text:00002004 pop ebx
__text:00002005 pop ebp
__text:00002006 retn
__text:00002006 __ViewController_later_ endp
这两个block都是在栈上创建的,用到了_NSConcreteStackBlock来传参,在0x1F3F处开始的好几行代码是无法一下子看懂的,需要了解局部变量的空间里对应的意义。实际上,我还没碰到需要看懂这部分代码的实战情况,因为block函数也会得到传参,与普通的C/C++类似,所以还不如在xcode里加断点做动态分析的好。这里也就不深入了。
上面的代码是关于block创建和传递,下面的是调用block。
源码:
int (^nimei)(int, id) = ^(int p1, id p2) {
p1++;
[p2 release];
return 0;
};
- (void)setParam1:(CGRect)p1 para2:(CGFloat)p2
{
nimei(3, nil);
}
其中调用block处的反汇编为:
__text:000023FA mov eax, ds:(_nimei - 23F9h)[esi]
__text:00002400 mov [esp], eax
__text:00002403 mov dword ptr [esp+8], 0
__text:0000240B mov dword ptr [esp+4], 3
__text:00002413 call dword ptr [eax+0Ch]
可见block是直接call相对地址的,这个相对地址就是block结构体
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
中的FuncPtr,偏移就是0Ch。
对含有block的函数进行反编译是没意义的(至少在windows版IDA是这样),因为既然没有表示block结构体的信息,IDA就不能分析出调用的意义。
因为对block反汇编静态分析的场景不多(欢迎留下评论来举例),这里没再做更完全的阐述。如果想自行研究,可以自己写一些block例子来让IDA分析,就能知道各种block的创建、传递和调用方法是怎样被编译出来的了。
上一篇:IDA反汇编/反编译静态分析iOS模拟器程序(八)IDA for Mac
转载请注明出处:http://blog.csdn.net/hursing