首先看看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 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反编译
本文请勿转载。