IDA反汇编/反编译静态分析iOS模拟器程序

转载自:http://blog.csdn.net/hursing

(一)利用IDA和LLDB探索WebCore的C++类的继承关系

开刀的类名叫 PluginWidgetIOS,利用lldb可以得到:

[plain]  view plain  copy
  1. (lldb) image lookup -r -s PluginWidgetIOS  
  2. 7 symbols match the regular expression 'PluginWidgetIOS' in /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk/System/Library/PrivateFrameworks/WebKit.framework/WebKit:  
  3.         Address: WebKit[0x0003a5a0] (WebKit.__TEXT.__text + 231680)  
  4.         Summary: WebKit`PluginWidgetIOS::~PluginWidgetIOS()        Address: WebKit[0x0003a5b0] (WebKit.__TEXT.__text + 231696)  
  5.         Summary: WebKit`PluginWidgetIOS::~PluginWidgetIOS()        Address: WebKit[0x0003a6f0] (WebKit.__TEXT.__text + 232016)  
  6.         Summary: WebKit`PluginWidgetIOS::platformLayer() const        Address: WebKit[0x0003a750] (WebKit.__TEXT.__text + 232112)  
  7.         Summary: WebKit`PluginWidgetIOS::willProvidePluginLayer() const        Address: WebKit[0x0003a7b0] (WebKit.__TEXT.__text + 232208)  
  8.         Summary: WebKit`PluginWidgetIOS::attachPluginLayer()        Address: WebKit[0x0003a810] (WebKit.__TEXT.__text + 232304)  
  9.         Summary: WebKit`PluginWidgetIOS::detachPluginLayer()        Address: WebKit[0x001335e0] (WebKit.__DATA.__data + 560)  
  10.         Summary: vtable for PluginWidgetIOS  
其中有用的信息是:
[cpp]  view plain  copy
  1. Address: WebKit[0x001335e0] (WebKit.__DATA.__data + 560)  
  2.         Summary: vtable for PluginWidgetIOS  
用IDA打开WebCore的静态库,goto(快捷键g) vtable所在的地址 0x1335e0,可以看到:
[cpp]  view plain  copy
  1. __data:001335E0 ; `vtable for'PluginWidgetIOS  
  2. __data:001335E0 __ZTV15PluginWidgetIOS db    0          ; DATA XREF: __nl_symbol_ptr:__ZTV15PluginWidgetIOS_ptro  
  3. __data:001335E1                 db    0  
  4. __data:001335E2                 db    0  
  5. __data:001335E3                 db    0  
  6. __data:001335E4                 db    0  
  7. __data:001335E5                 db    0  
  8. __data:001335E6                 db    0  
  9. __data:001335E7                 db    0  
  10. __data:001335E8                 dd offset __ZN15PluginWidgetIOSD1Ev ; PluginWidgetIOS::~PluginWidgetIOS()  
  11. __data:001335EC                 dd offset __ZN15PluginWidgetIOSD0Ev ; PluginWidgetIOS::~PluginWidgetIOS()  
  12. __data:001335F0                 dd offset __ZN7WebCore6Widget12setFrameRectERKNS_7IntRectE ; WebCore::Widget::setFrameRect(WebCore::IntRect  const&)  
  13. __data:001335F4                 dd offset __ZN7WebCore6Widget5paintEPNS_15GraphicsContextERKNS_7IntRectE ; WebCore::Widget::paint(WebCore::GraphicsContext *,WebCore::IntRect  const&)  
  14. __data:001335F8                 dd offset __ZN12PluginWidget14invalidateRectERKN7WebCore7IntRectE ; PluginWidget::invalidateRect(WebCore::IntRect  const&)  
  15. __data:001335FC                 dd offset __ZN7WebCore6Widget8setFocusEb ; WebCore::Widget::setFocus(bool)  
  16. __data:00133600                 dd offset __ZN7WebCore6Widget4showEv ; WebCore::Widget::show(void)  
  17. __data:00133604                 dd offset __ZN7WebCore6Widget4hideEv ; WebCore::Widget::hide(void)  
  18. __data:00133608                 dd offset __ZN7WebCore6Widget16setParentVisibleEb ; WebCore::Widget::setParentVisible(bool)  
  19. __data:0013360C                 dd offset __ZNK7WebCore6Widget11isFrameViewEv ; WebCore::Widget::isFrameView(void)  
  20. __data:00133610                 dd offset __ZNK7WebCore6Widget12isPluginViewEv ; WebCore::Widget::isPluginView(void)  
  21. __data:00133614                 dd offset __ZNK7WebCore14PluginViewBase16isPluginViewBaseEv ; WebCore::PluginViewBase::isPluginViewBase(void)  
  22. __data:00133618                 dd offset __ZNK7WebCore6Widget11isScrollbarEv ; WebCore::Widget::isScrollbar(void)  
  23. __data:0013361C                 dd offset __ZN7WebCore6Widget9setParentEPNS_10ScrollViewE ; WebCore::Widget::setParent(WebCore::ScrollView *)  
  24. __data:00133620                 dd offset __ZN7WebCore6Widget11handleEventEPNS_5EventE ; WebCore::Widget::handleEvent(WebCore::Event *)  
  25. __data:00133624                 dd offset __ZN7WebCore6Widget12notifyWidgetENS_18WidgetNotificationE ; WebCore::Widget::notifyWidget(WebCore::WidgetNotification)  
  26. __data:00133628                 dd offset __ZN7WebCore6Widget17frameRectsChangedEv ; WebCore::Widget::frameRectsChanged(void)  
  27. __data:0013362C                 dd offset __ZN7WebCore6Widget22widgetPositionsUpdatedEv ; WebCore::Widget::widgetPositionsUpdated(void)  
  28. __data:00133630                 dd offset __ZN7WebCore6Widget25transformsAffectFrameRectEv ; WebCore::Widget::transformsAffectFrameRect(void)  
  29. __data:00133634                 dd offset __ZNK7WebCore6Widget23convertToContainingViewERKNS_7IntRectE ; WebCore::Widget::convertToContainingView(WebCore::IntRect  const&)  
  30. __data:00133638                 dd offset __ZNK7WebCore6Widget25convertFromContainingViewERKNS_7IntRectE ; WebCore::Widget::convertFromContainingView(WebCore::IntRect  const&)  
  31. __data:0013363C                 dd offset __ZNK7WebCore6Widget23convertToContainingViewERKNS_8IntPointE ; WebCore::Widget::convertToContainingView(WebCore::IntPoint  const&)  
  32. __data:00133640                 dd offset __ZNK7WebCore6Widget25convertFromContainingViewERKNS_8IntPointE ; WebCore::Widget::convertFromContainingView(WebCore::IntPoint  const&)  
  33. __data:00133644                 dd offset __ZNK7WebCore6Widget13axObjectCacheEv ; WebCore::Widget::axObjectCache(void)  
  34. __data:00133648                 dd offset __ZNK15PluginWidgetIOS13platformLayerEv ; PluginWidgetIOS::platformLayer(void)  
  35. __data:0013364C                 dd offset __ZNK15PluginWidgetIOS22willProvidePluginLayerEv ; PluginWidgetIOS::willProvidePluginLayer(void)  
  36. __data:00133650                 dd offset __ZN15PluginWidgetIOS17attachPluginLayerEv ; PluginWidgetIOS::attachPluginLayer(void)  
  37. __data:00133654                 dd offset __ZN15PluginWidgetIOS17detachPluginLayerEv ; PluginWidgetIOS::detachPluginLayer(void)  
  38. __data:00133658                 dd offset __ZN7WebCore14PluginViewBase12scriptObjectEPN3JSC14JSGlobalObjectE ; WebCore::PluginViewBase::scriptObject(JSC::JSGlobalObject *)  
  39. __data:0013365C                 dd offset __ZN7WebCore14PluginViewBase27privateBrowsingStateChangedEb ; WebCore::PluginViewBase::privateBrowsingStateChanged(bool)  
  40. __data:00133660                 dd offset __ZN7WebCore14PluginViewBase12getFormValueERN3WTF6StringE ; WebCore::PluginViewBase::getFormValue(WTF::String &)  
  41. __data:00133664                 dd offset __ZN7WebCore14PluginViewBase6scrollENS_15ScrollDirectionENS_17ScrollGranularityE ; WebCore::PluginViewBase::scroll(WebCore::ScrollDirection,WebCore::ScrollGranularity)  
  42. __data:00133668                 dd offset __ZN7WebCore14PluginViewBase19horizontalScrollbarEv ; WebCore::PluginViewBase::horizontalScrollbar(void)  
  43. __data:0013366C                 dd offset __ZN7WebCore14PluginViewBase17verticalScrollbarEv ; WebCore::PluginViewBase::verticalScrollbar(void)  
  44. __data:00133670                 dd offset __ZN7WebCore14PluginViewBase16wantsWheelEventsEv ; WebCore::PluginViewBase::wantsWheelEvents(void)  
  45. __data:00133674                 align 10h  

这是PluginWidgetIOS的虚函数表。从分号后的注释可以看到函数直接的执行地址,分别有指向Widget、PluginWidget、PluginViewBase的函数,可以知道PluginWidgetIOS是他们的直接或间接子类。

再利用lldb分别image lookup这三个类,就可以看出继承链为:

PluginWidgetIOS->PluginViewBase->PluginWidget->Widget

因为PluginWidget的虚表里不会出现PluginViewBase, Widget的虚表里不会出现PluginWidget和PluginViewBase。当然,这三个类在开源码中也能找到继承关系。

(二)加载文件与保存数据库

启动windows版的IDA,在Quickstart界面点击New,弹出一个对话框选择文件。也可以按取消后再把文件拖进IDA。由于Mac版的IDA没注册,没有save功能,所以只好先把Mac上的东西拷贝到windows再打开了。

能拖进IDA的文件可以是静态库、动态库、可执行程序等。对ios而言,可执行程序通常是build出来的.app包里的同名文件,当然,也可以是系统自带的程序。库文件主要是SDK中各个framework,以UIKit为例,它的iOS6.1模拟器版静态链接库的路径为:

[plain]  view plain  copy
  1. /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk/System/Library/Frameworks/UIKit.framework/UIKit  

把UIKit拖进IDA,会弹出下图所示界面:

IDA反汇编/反编译静态分析iOS模拟器程序_第1张图片

IDA已识别出这是内含i386指令的mach-o动态库,所以点击ok就行了。然后IDA左下角会显示正在继续分析文件:

(左下角的信息会一直变动,表示分析至文件的某个偏移处)

最后等到显示为idle

就表示分析完毕了。

此时,库文件所在的目录会多出5个文件:

IDA反汇编/反编译静态分析iOS模拟器程序_第2张图片

这是IDA的数据库文件。当退出IDA时,选择Pack database后点击ok

IDA反汇编/反编译静态分析iOS模拟器程序_第3张图片

这5个文件就会被打包成idb文件

下次启动IDA时,在quickstart选择这个文件,或直接双击让IDA打开这个文件,就能直接得到分析完成后的数据了,不用再分析一遍。(demo版IDA没有save database功能)
后面提到的自己修改分析结果的操作,也会保存在idb数据库文件里。


Mac版的IDA操作是类似的,稍微注意的是,要把库文件拷贝到一个能让IDA自由创建文件的目录下再进行分析,否则IDA创建不了临时数据库就会打开失败。

(三)函数表示与搜索函数

打开IDA一般都是去搜索函数,可以说函数是IDA工程的基本单位吧,数据结构什么的都是为函数服务而已。函数列表在界面左侧的Functions Window:


可以看到,UIKit有27789个函数呢。在搜索前要先知道函数的表示方式。

Objective-C函数的表示:

拿UIView来做例子吧。在xcode documentation中,UIView的函数会有这样的表示:

[plain]  view plain  copy
  1. + (void)beginAnimations:(NSString *)animationID context:(void *)context  
  2. - (void)drawRect:(CGRect)rect  
  3. - (id)initWithFrame:(CGRect)aRect  
  4. - (void)removeFromSuperview  
  5. @property(nonatomic) CGRect frame  

在gdb/lldb中的表示(没有debugging symbols的函数):

[plain]  view plain  copy
  1. +[UIView(Animation) beginAnimations:context:]  
  2. -[UIView(Rendering) drawRect:]  
  3. -[UIView initWithFrame:]  
  4. -[UIView(Hierarchy) removeFromSuperview]  
  5. -[UIView(Geometry) frame]  
  6. -[UIView(Geometry) setFrame:]  
可以看到,xdb表示的特点是:

  • 省略返回值
  • 省略参数类型声明与形参
  • 函数名与类名之间有一个空格,多参数之间不含空格,直接是冒号分割
  • 类名后紧跟着category名
  • property被展开,readwrite属性的property会等于两个函数,set函数会有set前缀和第一个字母大写(@property时显式声明函数名的话也许不同)

在IDA中的表示是:

[plain]  view plain  copy
  1. __UIView_Animation__beginAnimations_context__  
  2. __UIView_Rendering__drawRect__  
  3. __UIView_initWithFrame__  
  4. __UIView_Hierarchy__removeFromSuperview_  
  5. __UIView_Geometry__frame_  
  6. __UIView_Geometry__setFrame__  
其特点就是把xdb表示法中除字母数字外的字符都用下划线代替。

(block型的函数会较复杂,后面的章节再讲)

C++函数的表示:

和xdb的格式差不多,不单独列了。基本格式为:

命名空间名::类名::函数名(参数类型,参数类型...)

默认命名空间的话就会没有前面的名字和两个冒号。C函数没有类名,有的C函数实际有参数,但在IDA中不显示。

尽量列我所看到的规则吧:

  • 省略返回值,省略形参
  • 空参数时会表示为 函数名(void)
  • 指针型参数是 类型+空格+* ,引用型参数是 类型+空格+&
  • const型参数的const声明在后,有空格隔开,在*和&之前
  • const型函数的const省略
  • 参数的typedef会展开,例如CFDictionaryRef会变成__CFDictionary const*
  • 参数类型也要加命名空间名

一些函数示例如下:

[cpp]  view plain  copy
  1. WebCore::loaderRunLoop(void)  
  2. WebCore::runLoaderThread(void *)  
  3. WebCore::CustomEvent::~CustomEvent()  
  4. WebCore::CustomEvent::initCustomEvent(WTF::AtomicString  const&, boolbool, WebCore::ScriptValue)  
  5. WebCore::LegacyWebArchive::createResource(__CFDictionary  const*)  
  6. _WKViewAddSubview  

好了,知道函数名的表示规则之后,就可以搜索你想看的函数了。

激活Functions Window(随便点击一行令本窗口处于焦点状态),顶部菜单Search->Search...->输入函数名->OK。IDA的是模糊搜索,可以不填全名,只要你能确保输入的字符会令搜索结果唯一就行,匹配中的话就会跳到那个函数处,双击这条函数,就能在右边窗口看到此函数的反汇编代码了。如果搜索结果有多个,可以在顶部菜单->Search->Search again跳到下一个。

Search快捷键为Alt+T,Search again的快捷键为Ctrl+T。


一般来说,看着xcode文档也难以确定其实际函数名的,先用xdb搜索一遍再对照规则在IDA里查找会便捷些。

(四)反汇编的符号信息与改名

首先看看windows IDA和xcode的反汇编有什么不同。因为不确定直接分析UIKit的代码会不会有法律问题,还是自己写个例子吧。分析UIKit的时候因为没有完整的debugging symbols,所以得到的反汇编信息会比自己写的代码较少。

一个在命名空间ANameSpace的类DataInternal,一个DataModel的C++类,一个继承自UIButton的TestButton。演示的是TestButton的printLog函数。

这是源码:

[cpp]  view plain  copy
  1. namespace ANameSpace  
  2. {  
  3.     class DataInternal  
  4.     {  
  5.         int m_sample;  
  6.     public:  
  7.         void add();  
  8.     };  
  9. }  
  10.   
  11. class DataModel {  
  12.     int m_count;  
  13.     int m_index;  
  14.     float m_number;  
  15.     std::vector<long> m_longData;  
  16.     double m_value;  
  17.     char m_name[10];  
  18.     ANameSpace::DataInternal m_internal;  
  19.     static DataModel* s_sharedInstance;  
  20.     DataModel();  
  21. public:  
  22.     int count();  
  23.     int index() { return m_index; }  
  24.     float number();  
  25.     static DataModel *sharedInstance();  
  26.     double getValueAfterAddedNumber(double number);  
  27.     void addLongData(long data);  
  28. };  

[cpp]  view plain  copy
  1. class DataModel;  
  2.   
  3. @interface TestButton : UIButton  
  4. {  
  5.     DataModel *m_model;  
  6.     NSString *m_printLog;  
  7. }  
  8.   
  9. - (bool)inWindow;  
  10. @property (nonatomic, assign) DataModel *model;  
  11.   
  12. @end  
  13.   
  14. @interface TestButton (Construct)  
  15.   
  16. + (TestButton*)createAButton;  
  17. - (id)initWithNothing:(id)nilPointer;  
  18.   
  19. @end  
  20.   
  21. @interface TestButton (Test)  
  22.   
  23. - (void)setParam1:(CGRect)p1 para2:(CGFloat)p2;  
  24. - (NSString*)printLog;  
  25.   
  26. @end  

[cpp]  view plain  copy
  1. - (NSString*)printLog  
  2. {  
  3.     if (m_model->count() == 0)  
  4.     {  
  5.         if (m_printLog)  
  6.             return m_printLog;  
  7.         else  
  8.             return @"ok";  
  9.     }  
  10.     else if (m_model->count() == 1)  
  11.     {  
  12.         if ([self model])  
  13.             return @"fine";  
  14.         else  
  15.             return @"error";  
  16.     }  
  17.     else  
  18.         return m_printLog;  
  19. }  

这是IDA得到的反汇编:

[cpp]  view plain  copy
  1. __text:000026B5 ; =============== S U B R O U T I N E =======================================  
  2. __text:000026B5  
  3. __text:000026B5 ; Attributes: bp-based frame  
  4. __text:000026B5  
  5. __text:000026B5 __TestButton_Test__printLog_ proc near  
  6. __text:000026B5  
  7. __text:000026B5 arg_0           = dword ptr  8  
  8. __text:000026B5  
  9. __text:000026B5                 push    ebp  
  10. __text:000026B6                 mov     ebp, esp  
  11. __text:000026B8                 push    ebx  
  12. __text:000026B9                 push    edi  
  13. __text:000026BA                 push    esi  
  14. __text:000026BB                 sub     esp, 0Ch  
  15. __text:000026BE                 call    $+5  
  16. __text:000026C3                 pop     esi  
  17. __text:000026C4                 mov     ebx, ds:(_OBJC_IVAR_$_TestButton_m_model - 26C3h)[esi]  
  18. __text:000026CA                 mov     edi, [ebp+arg_0]  
  19. __text:000026CD                 mov     eax, [edi+ebx]  
  20. __text:000026D0                 mov     [esp], eax  
  21. __text:000026D3                 call    __ZN9DataModel5countEv ; DataModel::count(void)  
  22. __text:000026D8                 test    eax, eax  
  23. __text:000026DA                 jz      short loc_2713  
  24. __text:000026DC                 mov     eax, [edi+ebx]  
  25. __text:000026DF                 mov     [esp], eax  
  26. __text:000026E2                 call    __ZN9DataModel5countEv ; DataModel::count(void)  
  27. __text:000026E7                 cmp     eax, 1  
  28. __text:000026EA                 jnz     short loc_2729  
  29. __text:000026EC                 mov     eax, ds:(off_57FC - 26C3h)[esi]  
  30. __text:000026F2                 mov     [esp+4], eax  
  31. __text:000026F6                 mov     [esp], edi  
  32. __text:000026F9                 call    _objc_msgSend  
  33. __text:000026FE                 mov     ecx, eax  
  34. __text:00002700                 lea     edx, (cfstr_Error.isa - 26C3h)[esi] ; "error"  
  35. __text:00002706                 lea     eax, (cfstr_Fine.isa - 26C3h)[esi] ; "fine"  
  36. __text:0000270C                 test    ecx, ecx  
  37. __text:0000270E                 cmovz   eax, edx  
  38. __text:00002711                 jmp     short loc_2732  
  39. __text:00002713 ; ---------------------------------------------------------------------------  
  40. __text:00002713  
  41. __text:00002713 loc_2713:                               ; CODE XREF: __TestButton_Test__printLog_+25j  
  42. __text:00002713                 mov     eax, ds:(_OBJC_IVAR_$_TestButton_m_printLog - 26C3h)[esi]  
  43. __text:00002719                 mov     ecx, [edi+eax]  
  44. __text:0000271C                 lea     eax, (cfstr_Ok.isa - 26C3h)[esi] ; "ok"  
  45. __text:00002722                 test    ecx, ecx  
  46. __text:00002724                 cmovnz  eax, ecx  
  47. __text:00002727                 jmp     short loc_2732  
  48. __text:00002729 ; ---------------------------------------------------------------------------  
  49. __text:00002729  
  50. __text:00002729 loc_2729:                               ; CODE XREF: __TestButton_Test__printLog_+35j  
  51. __text:00002729                 mov     eax, ds:(_OBJC_IVAR_$_TestButton_m_printLog - 26C3h)[esi]  
  52. __text:0000272F                 mov     eax, [edi+eax]  
  53. __text:00002732  
  54. __text:00002732 loc_2732:                               ; CODE XREF: __TestButton_Test__printLog_+5Cj  
  55. __text:00002732                                         ; __TestButton_Test__printLog_+72j  
  56. __text:00002732                 add     esp, 0Ch  
  57. __text:00002735                 pop     esi  
  58. __text:00002736                 pop     edi  
  59. __text:00002737                 pop     ebx  
  60. __text:00002738                 pop     ebp  
  61. __text:00002739                 retn  
  62. __text:00002739 __TestButton_Test__printLog_ endp  

这是lldb的:

[cpp]  view plain  copy
  1. HursingTest`-[TestButton(Test) printLog] at TestButton.mm:51:  
  2. 0x26b3:  pushl  %ebp  
  3. 0x26b4:  movl   %esp, %ebp  
  4. 0x26b6:  pushl  %ebx  
  5. 0x26b7:  pushl  %edi  
  6. 0x26b8:  pushl  %esi  
  7. 0x26b9:  subl   $12, %esp  
  8. 0x26bc:  calll  0x26c1                    ; -[TestButton(Test) printLog] + 14 at TestButton.mm:53  
  9. 0x26c1:  popl   %esi  
  10. 0x26c2:  movl   13207(%esi), %ebx  
  11. 0x26c8:  movl   8(%ebp), %edi  
  12. 0x26cb:  movl   (%edi,%ebx), %eax  
  13. 0x26ce:  movl   %eax, (%esp)  
  14. 0x26d1:  calll  0x2742                    ; DataModel::count() at DataModel.cpp:22  
  15. 0x26d6:  testl  %eax, %eax  
  16. 0x26d8:  je     0x2711                    ; -[TestButton(Test) printLog] + 94 at TestButton.mm:55  
  17. 0x26da:  movl   (%edi,%ebx), %eax  
  18. 0x26dd:  movl   %eax, (%esp)  
  19. 0x26e0:  calll  0x2742                    ; DataModel::count() at DataModel.cpp:22  
  20. 0x26e5:  cmpl   $1, %eax  
  21. 0x26e8:  jne    0x2727                    ; -[TestButton(Test) printLog] + 116 at TestButton.mm:68  
  22. 0x26ea:  movl   12607(%esi), %eax  
  23. 0x26f0:  movl   %eax, 4(%esp)  
  24. 0x26f4:  movl   %edi, (%esp)  
  25. 0x26f7:  calll  0x352c                    ; symbol stub for: objc_msgSend  
  26. 0x26fc:  movl   %eax, %ecx  
  27. 0x26fe:  leal   13279(%esi), %edx  
  28. 0x2704:  leal   13263(%esi), %eax  
  29. 0x270a:  testl  %ecx, %ecx  
  30. 0x270c:  cmovel %edx, %eax  
  31. 0x270f:  jmp    0x2730                    ; -[TestButton(Test) printLog] + 125 at TestButton.mm:69  
  32. 0x2711:  movl   13211(%esi), %eax  
  33. 0x2717:  movl   (%edi,%eax), %ecx  
  34. 0x271a:  leal   13247(%esi), %eax  
  35. 0x2720:  testl  %ecx, %ecx  
  36. 0x2722:  cmovnel%ecx, %eax  
  37. 0x2725:  jmp    0x2730                    ; -[TestButton(Test) printLog] + 125 at TestButton.mm:69  
  38. 0x2727:  movl   13211(%esi), %eax  
  39. 0x272d:  movl   (%edi,%eax), %eax  
  40. 0x2730:  addl   $12, %esp  
  41. 0x2733:  popl   %esi  
  42. 0x2734:  popl   %edi  
  43. 0x2735:  popl   %ebx  
  44. 0x2736:  popl   %ebp  
  45. 0x2737:  ret      

两者会有以下区别:

1.IDA计算出了成员变量的偏移地址并把symbol直接显示出来

IDA:__text:000026C4                 mov     ebx, ds:(_OBJC_IVAR_$_TestButton_m_model - 26C3h)[esi]
xcode:0x26c2:  movl   13207(%esi), %ebx

TestButton的成员变量DataModel* m_model以_OBJC_IVAR_$_TestButton_m_model 为名显示。(其中IVAR是Objective-C运行时的类型,其概念请参考xcode文档)
2.函数参数在IDA中被赋予名称,ebp+8为arg_0,ebp+12为arg_1。 arg即为argument的缩写,第n个参数在+号后面的偏移量不是绝对的,请参考《xcode反汇编调试iOS模拟器程序(三)查看Objective-C函数与参数》。在函数开头和代码中,名称都会直接替换掉实际偏移量。对于Objective-C函数,arg_0都是self。

IDA:__text:000026CA                 mov     edi, [ebp+arg_0]

xcode:0x26c8:  movl   8(%ebp), %edi

3.常数值型偏移地址被赋予名称,以loc_为前缀。

IDA:jmp     short loc_2732

xcode:0x270f:  jmp    0x2730                    ; -[TestButton(Test) printLog] + 125 at TestButton.mm:69

4.IDA是intel汇编,xcode是AT&T汇编。

另外,IDA在00002713处有一个全减号的注释,这是表示上面的代码不会顺序执行到下面,只可能是有跳转指令才会执行到这里。

在分析UIKit时,代码偏移地址在IDA和xcode间是相差很远的,因为IDA中的地址是相对于库文件的,xcode中的地址是相对于运行中的程序的。不过偏移地址的后三位会相同,因为linker会令部分地址对齐。


这个例子没用到局部变量,如果用到:

[cpp]  view plain  copy
  1. __text:0004F0AF __UIView_Geometry__convertSize_toView__ proc near  
  2. __text:0004F0AF                                         ; DATA XREF: __objc_const:0075E28Co  
  3. __text:0004F0AF  
  4. __text:0004F0AF var_18          = dword ptr -18h  
  5. __text:0004F0AF var_14          = dword ptr -14h  
  6. __text:0004F0AF var_10          = dword ptr -10h  
局部变量,即 ebp-xxx 会被命名为 var_xxx。关于局部变量请参考《 xcode反汇编调试iOS模拟器程序(六)函数出入口处的处理与局部变量

下面这个IDA特性也许比较激动人心:把鼠标悬停在000026EC行的off_57FC上,会有悬浮框显示这个名字的意义。


000026F9处是objc_msgSend函数,所以000026EC这里是在传递selector,悬浮框显示的是selector的字符串。其中aModel的a表示off_57FC处的是字符串。后边的分号注释中,第一行是交叉引用的信息(后面的章节再讲),第二行是symbol信息,所以000026EC行是表示把"model"这个selector字符串的起始地址传到edx。悬停鼠标就能看到,相比于xcode方便多了。

再方便一点,在off_57FC上右键单击,在菜单中选择Rename(或者按快捷键N)

IDA反汇编/反编译静态分析iOS模拟器程序_第4张图片

即可为off_7E4960这个自动生成的名字改名,方便以后查看。因为它代表的是selector,所以直接改成selector的名字就最直观了。

IDA反汇编/反编译静态分析iOS模拟器程序_第5张图片

修改完毕后就会显示为:

[cpp]  view plain  copy
  1. __text:000026EC                 mov     eax, ds:(model - 26C3h)[esi]  

各种IDA自动生成的名字都可以改名,怎么易理解就怎么改。为了免除输入麻烦,可以双击off_7E4960跳转到那个地址,然后复制model这个字符串,再回到刚才的界面,rename,粘贴~~~

如果是带参数的selector,粘贴后,冒号会自动变成下划线的。
退出IDA的时候保存到idb文件,下次启动的时候,改名仍然有效。

(五)F5反编译

反编译是IDA最让人振奋的功能,它的本质是IDA的一个插件,不过会被当做hex-rays的另一个产品。既然是产品,那当然就另外收费,demo版是没有的。反编译的快捷键是F5,菜单位置在 顶部菜单View->Open Subviews->Pseudocode。(有网友问到为什么按照第一篇的地址下载IDA后也没有F5,最终是发现他自己装了python,设了环境变量,这会令IDA工作不正常)

IDA反汇编/反编译静态分析iOS模拟器程序_第6张图片

在显示反汇编的窗口中按F5,经过分析后,会多了一个标签栏Pseudocode-A:

IDA反汇编/反编译静态分析iOS模拟器程序_第7张图片

继续上一节(可用两个浏览器窗口对比)的示例,以-[TestButton printLog]为例,可得到反编译代码:

[cpp]  view plain  copy
  1. __CFString *__cdecl _TestButton_Test__printLog_(void *a1)  
  2. {  
  3.   int v1; // ebx@1  
  4.   __CFString *result; // eax@3  
  5.   void *v3; // ecx@3  
  6.   
  7.   v1 = OBJC_IVAR___TestButton_m_model;  
  8.   if ( DataModel__count(*(_DWORD *)((char *)a1 + OBJC_IVAR___TestButton_m_model)) )  
  9.   {  
  10.     if ( DataModel__count(*(_DWORD *)((char *)a1 + v1)) == 1 )  
  11.     {  
  12.       v3 = objc_msgSend(a1, (const __seg *)model[0]);// 改名前显示为v3 = objc_msgSend(a1, (const __seg *)off_57FC[0]);  
  13.       result = &cfstr_Fine;  
  14.       if ( !v3 )  
  15.         result = &cfstr_Error;  
  16.     }  
  17.     else  
  18.     {  
  19.       result = *(__CFString **)((char *)a1 + OBJC_IVAR___TestButton_m_printLog);  
  20.     }  
  21.   }  
  22.   else  
  23.   {  
  24.     result = &cfstr_Ok;  
  25.     if ( *(_DWORD *)((char *)a1 + OBJC_IVAR___TestButton_m_printLog) )  
  26.       result = *(__CFString **)((char *)a1 + OBJC_IVAR___TestButton_m_printLog);  
  27.   }  
  28.   return result;  
  29. }  

改名的操作同样可在反编译代码中进行,只是界面稍有不同。在off_57FC处右键单击,选择Rename global item。无论在反汇编还是反编译改名,都会在另一方同步修改。

IDA反汇编/反编译静态分析iOS模拟器程序_第8张图片

IDA反汇编/反编译静态分析iOS模拟器程序_第9张图片


Objective-C和C++一样,每个类的函数实际都可用static的C函数表示,第一参数是self或this指针。所以反编译代码中,参数a1的类型显示为void*,实际也就是id,类的实例对象,即self指针。相比源码,反编译中有许多冗余代码,而且好多的类型转换和解引用,这是难免的,代码写法太多,总不能要求IDA这么智能。其实看多了也就习惯了,O(∩_∩)O

再看另一个函数:

源码中 @symthesize model 会得到 -[TestButton setModel:]函数,其反编译代码为:

[cpp]  view plain  copy
  1. int __cdecl _TestButton_setModel__(int a1, int a2, int a3)  
  2. {  
  3.   int result; // eax@1  
  4.   
  5.   result = OBJC_IVAR___TestButton_m_model;  
  6.   *(_DWORD *)(a1 + OBJC_IVAR___TestButton_m_model) = a3;  
  7.   return result;  
  8. }  
实际上这个函数返回值应该是void,但编译器是没有void返回值概念的,总会把一些东西返回,只是没用。a2是selector,实质为字符串的起始地址,IDA只能识别为int。a3是Objective-C语法的第一个参数,即被setModel的model,我们知道它是DataModel*,即传来的是一个地址,也被IDA当做int了,即32bit的数值。

这个结果很容易看出来实际操作是 m_model = a3;

第3个例子:

[cpp]  view plain  copy
  1. - (bool)inWindow  
  2. {  
  3.     return self.window != nil;  
  4. }  
[cpp]  view plain  copy
  1. bool __cdecl _TestButton_inWindow_(void *a1)  
  2. {  
  3.   return objc_msgSend(a1, (const __seg *)off_57C4[0]) != 0;  
  4. }  

其中off_57C4改名后就是window。如此简单的源码才可能和反编译代码形同。另外也可看出,0可能会代表实际代码中的 NO,false,NULL,nil等。1则可能会代表YES,true。

当没有debugging symbol时,bool会被显示为char,因为bool是语法类型,不是编译器类型,占1个字节,和char相同。


以上便是反编译最简单的应用。

(六)交叉引用

交叉引用cross reference是指 这个地址的 数据或代码 引用了哪个地址 以及 被哪些地址的代码所引用。引用了哪个地址,在反汇编就能看出来,一行汇编代码自然只会引用一个地址。但被引用是一对多的关系,正如一个函数可以被很多函数在内部调用。查看“被引用”是静态分析中得到堆栈的方法,当然,因为一对多的关系,还需要猜。这主要是看分析的目的是什么,与运行时动态分析相比各有好处,静态分析能得到完整的调用关系图。
在IDA里,cross reference也会缩写成XREF。

XREF主要是两种,数据引用和代码引用,只要看见有分号注释的 XREF 的地方,把鼠标悬停上去,都能看到部分交叉引用的代码。如果被引用的地方有很多,还可以通过快捷键Ctrl+X或菜单,得到更完整的交叉引用信息。例如在图中的Data XREF右键单击,弹出菜单:

选择Jump to cross reference,弹出对话框:


可以看到它被9个位置的代码引用。选中其中一条点击ok,即会跳转到那个地址。


由于Objective-C是一种弱类型语言,各种函数和成员变量都可以用字符串获取得到,开发者以实际为字符串的selector来调用函数,会令静态分析的引用分析变得复杂。下面做一个演示。

通过class-dump或xdb,可以知道UIView有这样一个私有API。

[cpp]  view plain  copy
  1. - (void)_addSubview:(id)arg1 positioned:(int)arg2 relativeTo:(id)arg3   
现在去IDA里搜索,由于category的可能存在,一般搜索一个类的具体某个函数时,关键字是不带类名的,这个函数在IDA中的表示是
__UIView_Internal___addSubview_positioned_relativeTo__
如果搜索
__UIView__addSubview_positioned_relativeTo__
那肯定搜不到,所以用关键字
addSubview_positioned_relativeTo

来搜索,有重复的就search again,直到找到是UIView的函数。它的反汇编代码头部信息为:

[cpp]  view plain  copy
  1. __text:00059DAC ; =============== S U B R O U T I N E =======================================  
  2. __text:00059DAC  
  3. __text:00059DAC ; Attributes: bp-based frame  
  4. __text:00059DAC  
  5. __text:00059DAC __UIView_Internal___addSubview_positioned_relativeTo__ proc near  
  6. __text:00059DAC                                         ; DATA XREF: __objc_const:0075DBE4o  

想知道哪些函数会调用这个函数,很自然想到在上面的DATA XREF处查看。可是,00059DAC这个位置实际只是Objective-C运行时实现中的IMP,即函数实现地址(具体请查看xcode文档)。开发者通过selector的方式调用函数,直接引用的是selector,而不会直接引用到IMP。 编译过程中,selector本身的字符串会被一个method对应,method再对应IMP,反编译的搜索过程就是它的反过程。

在00059DAC处查看XREF,得到:


跳转后,发现一堆的字符串:


这三行其实Method结构体的所有成员。

[cpp]  view plain  copy
  1. 00000000 __objc2_meth    struc ; (sizeof=0xC)    ; XREF: __objc_const:000050C0r  
  2. 00000000                                         ; __objc_const:000050CCr ...  
  3. 00000000 name            DCD ?                   ; offset  
  4. 00000004 types           DCD ?                   ; offset  
  5. 00000008 imp             DCD ?                   ; offset  
  6. 0000000C __objc2_meth    ends  

第一行是字符串的起始地址,name,即源码中以@selector()括起来的字符串。第二行是对selector中参数类型的描述,Type encode请参考《利用Objective-C运行时hook函数的三种方法》,class-dump估计就是靠这些types信息确定各个selector的参数类型。第三行是IMP,所以上面的XREF会jump到这里来。

因为是selector对应字符串,所以要在0075DBDC处继续查看XREF。这是个字符串指针,所以是操作数,与函数的交叉引用稍有不同,右键单击,弹出菜单:


选择Jump to xref to operand。这里也有提示,快捷键是X,不是函数交叉引用的Ctrl+X,他们的区别是后者弹出来的是非模态对话框,X弹出来的是模态的:


这里会发现有三个引用,前两个是普通的引用,最后一个,可以看到IDA分析出是 __objc_selrefs,即有selector对此字符串做引用,所以需要选择__objc_selrefs处的引用,跳转过去:


如果做重命名多了,会发现这个地方的代码格式很熟悉,因为这里就是程序selector的放置区域,双击反汇编代码中默认命名的selector如off_XXXX就会来到这。

在DATA XREF上查看:


会发现非常多的引用,这些引用才是会最终调用到00059DAC的函数。

从上表也可看出,UIView的addSubview:,insertSubview:atIndex:,insertSubview:aboveSubview:等许多公开接口实际都会调用这个私有API。

(七)识别类的信息

C++类的实质是个结构体。先举个例:

[cpp]  view plain  copy
  1. class TestClass  
  2. {  
  3.     int m_val1;  
  4.     int m_val2;  
  5. public:  
  6.     int getVal1();  
  7.     int getVal2();  
  8. };  
  9.   
  10. int TestClass::getVal1()  
  11. {  
  12.     return m_val1;  
  13. }  
  14. int TestClass::getVal2()  
  15. {  
  16.     return m_val2;  
  17. }  

反编译两个函数,得到的是

[cpp]  view plain  copy
  1. int __cdecl TestClass__getVal1(int a1)  
  2. {  
  3.   return *(_DWORD *)a1;  
  4. }  
  5. int __cdecl TestClass__getVal2(int a1)  
  6. {  
  7.   return *(_DWORD *)(a1 + 4);  
  8. }  
getVal1直接返回this指针的解引用,也就是m_val1的内存地址和实例对象是一致的,m_val2则是在m_val1的后一个int,所以是this指针+4字节。

如果类有虚函数,则与this指针同地址的是一个虚函数表,各个成员变量的偏移会+4。虚表的应用可看看《利用IDA和LLDB探索WebCore的C++类的继承关系》

明白以上这个原理,在反编译C++类的代码时,看见a1+x的地方就能猜出是在访问成员变量。

关于C++的反编译很多资料都有提及了,这里不赘述。除了《IDA Pro权威指南》那本书,推荐两篇文章:

逆向 C++-- 识别类及其构造函数

逆向 C++-- 2 识别类

下面说说Objective-C的。

在反汇编的窗口搜索(Alt+T)关键字 _objc_ivar

IDA反汇编/反编译静态分析iOS模拟器程序_第10张图片

随意找到哪个,双击它,便会跳转到Objective-C类保存成员变量信息的区域,以__objc_ivar:开头的偏移段。

IDA反汇编/反编译静态分析iOS模拟器程序_第11张图片

OC(Objective-C)这样做,主要是为了Key-Value Coding,方便了开发者,却也方便了逆向工程者,多了一些C++类没有的信息。

图中绿色的字符是代表相对偏移,即对于self指针的地址加上多少就是访问此成员变量,与上面C++类的概念相同。

对一些复杂类型的变量,还可以查找到它的类型信息。

例如在_OBJC_IVAR_$_UIView._gestureRecognizers上查看引用

IDA反汇编/反编译静态分析iOS模拟器程序_第12张图片

选择以__objc_const开头的引用来跳转

IDA反汇编/反编译静态分析iOS模拟器程序_第13张图片

这几行是ivar结构体的保存区域。

[cpp]  view plain  copy
  1. 00000000 __objc2_ivar    struc ; (sizeof=0x14)   ; XREF: __objc_const:000054E8r  
  2. 00000000                                         ; __objc_const:000054FCr ...  
  3. 00000000 ptr             dd ?                    ; offset  
  4. 00000004 name            dd ?                    ; offset  
  5. 00000008 type            dd ?                    ; offset  
  6. 0000000C align           dd ?  
  7. 00000010 size            dd ?  
  8. 00000014 __objc2_ivar    ends  
第一行0x0075EE18处是变量偏移指针,第2行是变量的名字,第3行是type信息,可以看出UIView的成员变量_gestureRecognizers的类型是NSMutableArray*。第4到7行其实应该合起来占用4个字节,是align信息,这里的2表示以2字节对齐保存。第8到11行同属一个int,表示这个成员变量占4字节。

看到这,也就大概能明白class-dump的原理了吧。

(八)IDA for Mac

iOS多用OC(Objective-C)编程,Mac也类似,所以IDA for Mac对OC的支持似乎强些。Windows的IDA在反汇编某些SDK库文件时会识别不出OC的函数名,而且对OC运行时的结构体也没识别出来。当然,因为我用的是6.1版的windows IDA, Mac上用的是6.4版,不知道是不是windows IDA 6.1的bug了。

总之在界面操作流程上,感觉Mac IDA是对OC有做优化的。当加载一个app时,


会询问是否解析和重命名OC的函数:


如果选择No,所有OC函数都会识别成sub_开头的名字。它的识别原理估计和上一节提到的相同

一个例子是用IDA打开这个库文件时(关于这个库,可参考《iOS的QuickTime Plugin》)

[plain]  view plain  copy
  1. /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk/System/Library/Internet Plug-Ins/QuickTime Plugin.webplugin/QuickTime Plugin  

windows版识别不出函数名:


Mac版可以识别出部分:



因为是反汇编同一个文件,所以得到的代码的偏移地址是一致的,如果windows版没识别好OC函数,可以用Mac版同时打开,知道偏移地址后,在windows版goto address即可。


Mac IDA还识别出一些OC运行时的结构体信息。点开Structures栏,

按照提示,在其中一行同时按下control键和加号键就会展开详细信息:


这也就是前两节列出IVAR结构体和METHOD结构体的方法。

(在Structures栏还可以自定义结构体来标识C++类,具体方法请查阅《IDA Pro权威指南》等资料。)


以上就是未注册版的IDA for Mac的辅助作用

(九)block

在第三节 函数表示与搜索函数 提到block函数和普通的OC函数不同。

反汇编分析前需要理解block的实现原理,故推荐先看看这几篇文章及其所引用的参考资料:

Block介绍(一)基础
Block介绍(二)内存管理与其他特性
block介绍(三)揭开神秘面纱(上)
block介绍(四)揭开神秘面纱(下)


block函数的命名与上文提到类似。函数内部定义的block会以scope命名,如:

[cpp]  view plain  copy
  1. @implementation ViewController  
  2.   
  3. - (void)later  
  4. {  
  5.     [self presentViewController:self animated:NO completion:^{  
  6.         NSLog(@"wo yun");  
  7.         [self didReceiveMemoryWarning];  
  8.     }];  
  9.       
  10.     [UIView transitionFromView:self.view toView:self.view duration:1 options:UIViewAnimationOptionTransitionCurlUp completion:^(BOOL finished) {  
  11.         NSLog(@"%d", finished);  
  12.     }];  
  13. }  
在IDA中出现的名字分别为:

[cpp]  view plain  copy
  1. ___23__ViewController_later__block_invoke  
  2. ___23__ViewController_later__block_invoke6  
全局型block:

[cpp]  view plain  copy
  1. int (^nimei)(int, id) = ^(int p1, id p2) {  
  2.     p1++;  
  3.     [p2 release];  
  4.     return 0;  
  5. };  
显示为:

[cpp]  view plain  copy
  1. _nimei_block_invoke  


由于block的实质是用一些结构体来保存调用信息,而结构体信息在release版的C++编译结果中是无明文的,所以在反汇编中block的传参看起来就是直接传到一块内存区域中,需要自己理解其排放顺序是参照那些结构体的。

以下是上面的源码- [ViewController later]函数的反汇编(Mac IDA):

[cpp]  view plain  copy
  1. __text:00001F30 ; =============== S U B R O U T I N E =======================================  
  2. __text:00001F30  
  3. __text:00001F30 ; ViewController - (void)later  
  4. __text:00001F30 ; Attributes: bp-based frame  
  5. __text:00001F30  
  6. __text:00001F30 ; void __cdecl -[ViewController later](struct ViewController *self, SEL)  
  7. __text:00001F30 __ViewController_later_ proc near       ; DATA XREF: __objc_const:00005590o  
  8. __text:00001F30  
  9. __text:00001F30 var_30          = dword ptr -30h  
  10. __text:00001F30 var_2C          = dword ptr -2Ch  
  11. __text:00001F30 var_28          = dword ptr -28h  
  12. __text:00001F30 var_24          = dword ptr -24h  
  13. __text:00001F30 var_20          = dword ptr -20h  
  14. __text:00001F30 var_1C          = dword ptr -1Ch  
  15. __text:00001F30 var_18          = dword ptr -18h  
  16. __text:00001F30 var_14          = dword ptr -14h  
  17. __text:00001F30 self            = dword ptr  8  
  18. __text:00001F30  
  19. __text:00001F30                 push    ebp  
  20. __text:00001F31                 mov     ebp, esp  
  21. __text:00001F33                 push    ebx  
  22. __text:00001F34                 push    edi  
  23. __text:00001F35                 push    esi  
  24. __text:00001F36                 sub     esp, 4Ch  
  25. __text:00001F39                 call    $+5  
  26. __text:00001F3E                 pop     edi  
  27. __text:00001F3F                 mov     eax, ds:(__NSConcreteStackBlock_ptr - 1F3Eh)[edi]  
  28. __text:00001F45                 mov     [ebp+var_28], eax  
  29. __text:00001F48                 mov     [ebp+var_24], 42000000h  
  30. __text:00001F4F                 mov     [ebp+var_20], 0  
  31. __text:00001F56                 lea     eax, (___23__ViewController_later__block_invoke - 1F3Eh)[edi]  
  32. __text:00001F5C                 mov     [ebp+var_1C], eax  
  33. __text:00001F5F                 lea     eax, (___block_descriptor_tmp - 1F3Eh)[edi]  
  34. __text:00001F65                 mov     [ebp+var_18], eax  
  35. __text:00001F68                 mov     ebx, [ebp+self]  
  36. __text:00001F6B                 mov     [ebp+var_14], ebx  
  37. __text:00001F6E                 mov     eax, ds:(selRef_presentViewController_animated_completion_ - 1F3Eh)[edi]  
  38. __text:00001F74                 lea     ecx, [ebp+var_28]  
  39. __text:00001F77                 mov     [esp+10h], ecx  
  40. __text:00001F7B                 mov     [esp+8], ebx  
  41. __text:00001F7F                 mov     [esp+4], eax  
  42. __text:00001F83                 mov     [esp], ebx  
  43. __text:00001F86                 mov     dword ptr [esp+0Ch], 0  
  44. __text:00001F8E                 call    _objc_msgSend  
  45. __text:00001F93                 mov     eax, ds:(classRef_UIView - 1F3Eh)[edi]  
  46. __text:00001F99                 mov     [ebp+var_2C], eax  
  47. __text:00001F9C                 mov     esi, ds:(selRef_view - 1F3Eh)[edi]  
  48. __text:00001FA2                 mov     [esp+4], esi  
  49. __text:00001FA6                 mov     [esp], ebx  
  50. __text:00001FA9                 call    _objc_msgSend  
  51. __text:00001FAE                 mov     [ebp+var_30], eax  
  52. __text:00001FB1                 mov     [esp+4], esi  
  53. __text:00001FB5                 mov     [esp], ebx  
  54. __text:00001FB8                 call    _objc_msgSend  
  55. __text:00001FBD                 mov     ecx, ds:(selRef_transitionFromView_toView_duration_options_completion_ - 1F3Eh)[edi]  
  56. __text:00001FC3                 lea     edx, (___block_literal_global - 1F3Eh)[edi]  
  57. __text:00001FC9                 mov     [esp+1Ch], edx  
  58. __text:00001FCD                 mov     [esp+0Ch], eax  
  59. __text:00001FD1                 mov     eax, [ebp+var_30]  
  60. __text:00001FD4                 mov     [esp+8], eax  
  61. __text:00001FD8                 mov     [esp+4], ecx  
  62. __text:00001FDC                 mov     eax, [ebp+var_2C]  
  63. __text:00001FDF                 mov     [esp], eax  
  64. __text:00001FE2                 mov     dword ptr [esp+14h], 3FF00000h  
  65. __text:00001FEA                 mov     dword ptr [esp+10h], 0  
  66. __text:00001FF2                 mov     dword ptr [esp+18h], 300000h  
  67. __text:00001FFA                 call    _objc_msgSend  
  68. __text:00001FFF                 add     esp, 4Ch  
  69. __text:00002002                 pop     esi  
  70. __text:00002003                 pop     edi  
  71. __text:00002004                 pop     ebx  
  72. __text:00002005                 pop     ebp  
  73. __text:00002006                 retn  
  74. __text:00002006 __ViewController_later_ endp  
这两个block都是在栈上创建的,用到了_NSConcreteStackBlock来传参,在0x1F3F处开始的好几行代码是无法一下子看懂的,需要了解局部变量的空间里对应的意义。实际上,我还没碰到需要看懂这部分代码的实战情况,因为block函数也会得到传参,与普通的C/C++类似,所以还不如在xcode里加断点做动态分析的好。这里也就不深入了。


上面的代码是关于block创建和传递,下面的是调用block。

源码:

[cpp]  view plain  copy
  1. int (^nimei)(int, id) = ^(int p1, id p2) {  
  2.     p1++;  
  3.     [p2 release];  
  4.     return 0;  
  5. };  
[cpp]  view plain  copy
  1. - (void)setParam1:(CGRect)p1 para2:(CGFloat)p2  
  2. {  
  3.     nimei(3, nil);   
  4. }  
其中调用block处的反汇编为:
[cpp]  view plain  copy
  1. __text:000023FA                 mov     eax, ds:(_nimei - 23F9h)[esi]  
  2. __text:00002400                 mov     [esp], eax  
  3. __text:00002403                 mov     dword ptr [esp+8], 0  
  4. __text:0000240B                 mov     dword ptr [esp+4], 3  
  5. __text:00002413                 call    dword ptr [eax+0Ch]  
可见block是直接call相对地址的,这个相对地址就是block结构体

[cpp]  view plain  copy
  1. struct __block_impl {  
  2.   void *isa;  
  3.   int Flags;  
  4.   int Reserved;  
  5.   void *FuncPtr;  
  6. };  

中的FuncPtr,偏移就是0Ch。


对含有block的函数进行反编译是没意义的(至少在windows版IDA是这样),因为既然没有表示block结构体的信息,IDA就不能分析出调用的意义。

因为对block反汇编静态分析的场景不多(欢迎留下评论来举例),这里没再做更完全的阐述。如果想自行研究,可以自己写一些block例子来让IDA分析,就能知道各种block的创建、传递和调用方法是怎样被编译出来的了。

转载自:http://blog.csdn.net/hursing

你可能感兴趣的:(IDA反汇编/反编译静态分析iOS模拟器程序)