首先看看windows IDA和xcode的反汇编有什么不同。因为不确定直接分析UIKit的代码会不会有法律问题,还是自己写个例子吧。分析UIKit的时候因为没有完整的debugging symbols,所以得到的反汇编信息会比自己写的代码较少。
一个在命名空间ANameSpace的类DataInternal,一个DataModel的C++类,一个继承自UIButton的TestButton。演示的是TestButton的printLog函数。
这是源码:
namespace ANameSpace { class DataInternal { int m_sample; public: void add(); }; } class DataModel { int m_count; int m_index; float m_number; std::vector<long> m_longData; double m_value; char m_name[10]; ANameSpace::DataInternal m_internal; static DataModel* s_sharedInstance; DataModel(); public: int count(); int index() { return m_index; } float number(); static DataModel *sharedInstance(); double getValueAfterAddedNumber(double number); void addLongData(long data); };
class DataModel; @interface TestButton : UIButton { DataModel *m_model; NSString *m_printLog; } - (bool)inWindow; @property (nonatomic, assign) DataModel *model; @end @interface TestButton (Construct) + (TestButton*)createAButton; - (id)initWithNothing:(id)nilPointer; @end @interface TestButton (Test) - (void)setParam1:(CGRect)p1 para2:(CGFloat)p2; - (NSString*)printLog; @end
- (NSString*)printLog { if (m_model->count() == 0) { if (m_printLog) return m_printLog; else return @"ok"; } else if (m_model->count() == 1) { if ([self model]) return @"fine"; else return @"error"; } else return m_printLog; }
这是IDA得到的反汇编:
__text:000026B5 ; =============== S U B R O U T I N E ======================================= __text:000026B5 __text:000026B5 ; Attributes: bp-based frame __text:000026B5 __text:000026B5 __TestButton_Test__printLog_ proc near __text:000026B5 __text:000026B5 arg_0 = dword ptr 8 __text:000026B5 __text:000026B5 push ebp __text:000026B6 mov ebp, esp __text:000026B8 push ebx __text:000026B9 push edi __text:000026BA push esi __text:000026BB sub esp, 0Ch __text:000026BE call $+5 __text:000026C3 pop esi __text:000026C4 mov ebx, ds:(_OBJC_IVAR_$_TestButton_m_model - 26C3h)[esi] __text:000026CA mov edi, [ebp+arg_0] __text:000026CD mov eax, [edi+ebx] __text:000026D0 mov [esp], eax __text:000026D3 call __ZN9DataModel5countEv ; DataModel::count(void) __text:000026D8 test eax, eax __text:000026DA jz short loc_2713 __text:000026DC mov eax, [edi+ebx] __text:000026DF mov [esp], eax __text:000026E2 call __ZN9DataModel5countEv ; DataModel::count(void) __text:000026E7 cmp eax, 1 __text:000026EA jnz short loc_2729 __text:000026EC mov eax, ds:(off_57FC - 26C3h)[esi] __text:000026F2 mov [esp+4], eax __text:000026F6 mov [esp], edi __text:000026F9 call _objc_msgSend __text:000026FE mov ecx, eax __text:00002700 lea edx, (cfstr_Error.isa - 26C3h)[esi] ; "error" __text:00002706 lea eax, (cfstr_Fine.isa - 26C3h)[esi] ; "fine" __text:0000270C test ecx, ecx __text:0000270E cmovz eax, edx __text:00002711 jmp short loc_2732 __text:00002713 ; --------------------------------------------------------------------------- __text:00002713 __text:00002713 loc_2713: ; CODE XREF: __TestButton_Test__printLog_+25j __text:00002713 mov eax, ds:(_OBJC_IVAR_$_TestButton_m_printLog - 26C3h)[esi] __text:00002719 mov ecx, [edi+eax] __text:0000271C lea eax, (cfstr_Ok.isa - 26C3h)[esi] ; "ok" __text:00002722 test ecx, ecx __text:00002724 cmovnz eax, ecx __text:00002727 jmp short loc_2732 __text:00002729 ; --------------------------------------------------------------------------- __text:00002729 __text:00002729 loc_2729: ; CODE XREF: __TestButton_Test__printLog_+35j __text:00002729 mov eax, ds:(_OBJC_IVAR_$_TestButton_m_printLog - 26C3h)[esi] __text:0000272F mov eax, [edi+eax] __text:00002732 __text:00002732 loc_2732: ; CODE XREF: __TestButton_Test__printLog_+5Cj __text:00002732 ; __TestButton_Test__printLog_+72j __text:00002732 add esp, 0Ch __text:00002735 pop esi __text:00002736 pop edi __text:00002737 pop ebx __text:00002738 pop ebp __text:00002739 retn __text:00002739 __TestButton_Test__printLog_ endp
这是lldb的:
HursingTest`-[TestButton(Test) printLog] at TestButton.mm:51: 0x26b3: pushl %ebp 0x26b4: movl %esp, %ebp 0x26b6: pushl %ebx 0x26b7: pushl %edi 0x26b8: pushl %esi 0x26b9: subl $12, %esp 0x26bc: calll 0x26c1 ; -[TestButton(Test) printLog] + 14 at TestButton.mm:53 0x26c1: popl %esi 0x26c2: movl 13207(%esi), %ebx 0x26c8: movl 8(%ebp), %edi 0x26cb: movl (%edi,%ebx), %eax 0x26ce: movl %eax, (%esp) 0x26d1: calll 0x2742 ; DataModel::count() at DataModel.cpp:22 0x26d6: testl %eax, %eax 0x26d8: je 0x2711 ; -[TestButton(Test) printLog] + 94 at TestButton.mm:55 0x26da: movl (%edi,%ebx), %eax 0x26dd: movl %eax, (%esp) 0x26e0: calll 0x2742 ; DataModel::count() at DataModel.cpp:22 0x26e5: cmpl $1, %eax 0x26e8: jne 0x2727 ; -[TestButton(Test) printLog] + 116 at TestButton.mm:68 0x26ea: movl 12607(%esi), %eax 0x26f0: movl %eax, 4(%esp) 0x26f4: movl %edi, (%esp) 0x26f7: calll 0x352c ; symbol stub for: objc_msgSend 0x26fc: movl %eax, %ecx 0x26fe: leal 13279(%esi), %edx 0x2704: leal 13263(%esi), %eax 0x270a: testl %ecx, %ecx 0x270c: cmovel %edx, %eax 0x270f: jmp 0x2730 ; -[TestButton(Test) printLog] + 125 at TestButton.mm:69 0x2711: movl 13211(%esi), %eax 0x2717: movl (%edi,%eax), %ecx 0x271a: leal 13247(%esi), %eax 0x2720: testl %ecx, %ecx 0x2722: cmovnel%ecx, %eax 0x2725: jmp 0x2730 ; -[TestButton(Test) printLog] + 125 at TestButton.mm:69 0x2727: movl 13211(%esi), %eax 0x272d: movl (%edi,%eax), %eax 0x2730: addl $12, %esp 0x2733: popl %esi 0x2734: popl %edi 0x2735: popl %ebx 0x2736: popl %ebp 0x2737: ret
两者会有以下区别:
1.IDA计算出了成员变量的偏移地址并把symbol直接显示出来
IDA:__text:000026C4 mov ebx, ds:(_OBJC_IVAR_$_TestButton_m_model - 26C3h)[esi]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), %edi3.常数值型偏移地址被赋予名称,以loc_为前缀。
IDA:jmp short loc_2732
xcode:0x270f: jmp 0x2730 ; -[TestButton(Test) printLog] + 125 at TestButton.mm:694.IDA是intel汇编,xcode是AT&T汇编。
另外,IDA在00002713处有一个全减号的注释,这是表示上面的代码不会顺序执行到下面,只可能是有跳转指令才会执行到这里。
在分析UIKit时,代码偏移地址在IDA和xcode间是相差很远的,因为IDA中的地址是相对于库文件的,xcode中的地址是相对于运行中的程序的。不过偏移地址的后三位会相同,因为linker会令部分地址对齐。
这个例子没用到局部变量,如果用到:
__text:0004F0AF __UIView_Geometry__convertSize_toView__ proc near __text:0004F0AF ; DATA XREF: __objc_const:0075E28Co __text:0004F0AF __text:0004F0AF var_18 = dword ptr -18h __text:0004F0AF var_14 = dword ptr -14h __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)
即可为off_7E4960这个自动生成的名字改名,方便以后查看。因为它代表的是selector,所以直接改成selector的名字就最直观了。
修改完毕后就会显示为:
__text:000026EC mov eax, ds:(model - 26C3h)[esi]各种IDA自动生成的名字都可以改名,怎么易理解就怎么改。为了免除输入麻烦,可以双击off_7E4960跳转到那个地址,然后复制model这个字符串,再回到刚才的界面,rename,粘贴~~~
如果是带参数的selector,粘贴后,冒号会自动变成下划线的。
退出IDA的时候保存到idb文件,下次启动的时候,改名仍然有效。
上一篇:IDA反汇编/反编译静态分析iOS模拟器程序(三)函数表示与搜索函数
下一篇:IDA反汇编/反编译静态分析iOS模拟器程序(五)F5反编译
本文请勿转载。