在第三节函数表示与搜索函数 提到block函数和普通的OC函数不同。
反汇编分析前需要理解block的实现原理,故推荐先看看这几篇文章及其所引用的参考资料:
Block介绍(一)基础
Block介绍(二)内存管理与其他特性
block介绍(三)揭开神秘面纱(上)
block介绍(四)揭开神秘面纱(下)
block函数的命名与上文提到类似。函数内部定义的block会以scope命名,如:
[cpp]
@implementationViewController
-(void)later
{
[selfpresentViewController:selfanimated:NOcompletion:^{
NSLog(@"woyun");
[selfdidReceiveMemoryWarning];
}];
[UIViewtransitionFromView:self.viewtoView:self.viewduration:1options:UIViewAnimationOptionTransitionCurlUpcompletion:^(BOOLfinished){
NSLog(@"%d",finished);
}];
}
在IDA中出现的名字分别为:
[cpp]
___23__ViewController_later__block_invoke
___23__ViewController_later__block_invoke6
全局型block:
[cpp]
int(^nimei)(int,id)=^(intp1,idp2){
p1++;
[p2release];
return0;
};
显示为:
[cpp]
_nimei_block_invoke
由于block的实质是用一些结构体来保存调用信息,而结构体信息在release版的C++编译结果中是无明文的,所以在反汇编中block的传参看起来就是直接传到一块内存区域中,需要自己理解其排放顺序是参照那些结构体的。
以下是上面的源码- [ViewController later]函数的反汇编(Mac IDA):
[cpp]
__text:00001F30;===============SUBROUTINE=======================================
__text:00001F30
__text:00001F30;ViewController-(void)later
__text:00001F30;Attributes:bp-basedframe
__text:00001F30
__text:00001F30;void__cdecl-[ViewControllerlater](structViewController*self,SEL)
__text:00001F30__ViewController_later_procnear;DATAXREF:__objc_const:00005590o
__text:00001F30
__text:00001F30var_30=dwordptr-30h
__text:00001F30var_2C=dwordptr-2Ch
__text:00001F30var_28=dwordptr-28h
__text:00001F30var_24=dwordptr-24h
__text:00001F30var_20=dwordptr-20h
__text:00001F30var_1C=dwordptr-1Ch
__text:00001F30var_18=dwordptr-18h
__text:00001F30var_14=dwordptr-14h
__text:00001F30self=dwordptr8
__text:00001F30
__text:00001F30pushebp
__text:00001F31movebp,esp
__text:00001F33pushebx
__text:00001F34pushedi
__text:00001F35pushesi
__text:00001F36subesp,4Ch
__text:00001F39call$+5
__text:00001F3Epopedi
__text:00001F3Fmoveax,ds:(__NSConcreteStackBlock_ptr-1F3Eh)[edi]
__text:00001F45mov[ebp+var_28],eax
__text:00001F48mov[ebp+var_24],42000000h
__text:00001F4Fmov[ebp+var_20],0
__text:00001F56leaeax,(___23__ViewController_later__block_invoke-1F3Eh)[edi]
__text:00001F5Cmov[ebp+var_1C],eax
__text:00001F5Fleaeax,(___block_descriptor_tmp-1F3Eh)[edi]
__text:00001F65mov[ebp+var_18],eax
__text:00001F68movebx,[ebp+self]
__text:00001F6Bmov[ebp+var_14],ebx
__text:00001F6Emoveax,ds:(selRef_presentViewController_animated_completion_-1F3Eh)[edi]
__text:00001F74leaecx,[ebp+var_28]
__text:00001F77mov[esp+10h],ecx
__text:00001F7Bmov[esp+8],ebx
__text:00001F7Fmov[esp+4],eax
__text:00001F83mov[esp],ebx
__text:00001F86movdwordptr[esp+0Ch],0
__text:00001F8Ecall_objc_msgSend
__text:00001F93moveax,ds:(classRef_UIView-1F3Eh)[edi]
__text:00001F99mov[ebp+var_2C],eax
__text:00001F9Cmovesi,ds:(selRef_view-1F3Eh)[edi]
__text:00001FA2mov[esp+4],esi
__text:00001FA6mov[esp],ebx
__text:00001FA9call_objc_msgSend
__text:00001FAEmov[ebp+var_30],eax
__text:00001FB1mov[esp+4],esi
__text:00001FB5mov[esp],ebx
__text:00001FB8call_objc_msgSend
__text:00001FBDmovecx,ds:(selRef_transitionFromView_toView_duration_options_completion_-1F3Eh)[edi]
__text:00001FC3leaedx,(___block_literal_global-1F3Eh)[edi]
__text:00001FC9mov[esp+1Ch],edx
__text:00001FCDmov[esp+0Ch],eax
__text:00001FD1moveax,[ebp+var_30]
__text:00001FD4mov[esp+8],eax
__text:00001FD8mov[esp+4],ecx
__text:00001FDCmoveax,[ebp+var_2C]
__text:00001FDFmov[esp],eax
__text:00001FE2movdwordptr[esp+14h],3FF00000h
__text:00001FEAmovdwordptr[esp+10h],0
__text:00001FF2movdwordptr[esp+18h],300000h
__text:00001FFAcall_objc_msgSend
__text:00001FFFaddesp,4Ch
__text:00002002popesi
__text:0000popedi
__text:0000popebx
__text:0000popebp
__text:0000retn
__text:0000__ViewController_later_endp
这两个block都是在栈上创建的,用到了_NSConcreteStackBlock来传参,在0x1F3F处开始的好几行代码是无法一下子看懂的,需要了解局部变量的空间里对应的意义。实际上,我还没碰到需要看懂这部分代码的实战情况,因为block函数也会得到传参,与普通的C/C++类似,所以还不如在xcode里加断点做动态分析的好。这里也就不深入了。
上面的代码是关于block创建和传递,下面的是调用block。
源码:
[cpp]
int(^nimei)(int,id)=^(intp1,idp2){
p1++;
[p2release];
return0;
};
[cpp]
-(void)setParam1:(CGRect)p1para2:(CGFloat)p2
{
nimei(3,nil);
}
其中调用block处的反汇编为:
[cpp]
__text:000023FAmoveax,ds:(_nimei-23F9h)[esi]
__text:00002400mov[esp],eax
__text:00002403movdwordptr[esp+8],0
__text:0000240Bmovdwordptr[esp+4],3
__text:00002413calldwordptr[eax+0Ch]
可见block是直接call相对地址的,这个相对地址就是block结构体
[cpp]
struct__block_impl{
void*isa;
intFlags;
intReserved;
void*FuncPtr;
};
中的FuncPtr,偏移就是0Ch。
对含有block的函数进行反编译是没意义的(至少在windows版IDA是这样),因为既然没有表示block结构体的信息,IDA就不能分析出调用的意义。
因为对block反汇编静态分析的场景不多(欢迎留下评论来举例),这里没再做更完全的阐述。如果想自行研究,可以自己写一些block例子来让IDA分析,就能知道各种block的创建、传递和调用方法是怎样被编译出来的了。
上一篇:IDA反汇编/反编译静态分析iOS模拟器程序(八)IDA for Mac
转载请注明出处:/hursing