此处略去无数句自己,感谢,兴奋,苦逼,茫然,空白,疑问,不解,焦躁,凌乱…,的开场白~
但愿以下内容能给后来的新手一个参考:分析不当之处,还请高手指正!
第一次写,排版,布局,解说可能很次,请多多包含~~~
XCode6.0.1+自己的一个测试Demo,断点在main函数!用lldb命令行(XCode集成的:titter:)一步步分析笔记:
设置XCode ==> Debug->Debug Workflow->Allows Show Disassembly!
步骤一:运行demo,真机调试(直接分析arm汇编);
<XCode汇编代码>
MITest`main at main.mm:475:
<分析位置一>
0xdfdf4: push {r4, r5, r7, lr}
0xdfdf6: add r7, sp, #0x8 ==> r7 = 0x27d31ca8 sp = 0x27d31ca0
0xdfdf8: sub sp, #0x30 ==> sp = 0x27d31c70 在栈上分配0x30个直接存放局部变量(参数)?
0xdfdfa: movs r2, #0x1
0xdfdfc: movt r2, #0x0
0xdfe00: movs r3, #0x2
0xdfe02: movt r3, #0x0
0xdfe06: movw r9, #0x3
0xdfe0a: movt r9, #0x0
0xdfe0e: movw r12, #0x4
0xdfe12: movt r12, #0x0
0xdfe16: movw lr, #0x5
0xdfe1a: movt lr, #0x0
0xdfe1e: movs r4, #0x6
0xdfe20: movt r4, #0x0
0xdfe24: movs r5, #0x0
0xdfe26: movt r5, #0x0
<分析位置二>
0xdfe2a: str r5, [sp, #0x2c] ==> r5 → mem32[sp + 0x2c] 0x27d31c70+0x2c=0x27d31c9c ← 0
0xdfe2c: str r0, [sp, #0x28] ==> r0 → mem32[sp + 0x28] 0x27d31c70+0x28=0x27d31c98 ← *argc
0xdfe2e: str r1, [sp, #0x24] ==> r1 → mem32[sp + 0x24] 0x27d31c70+0x24=0x27d31c94 ← &argv
这三步是保存caller(main函数)的入参数地址到内存中(为什么要保存?因为有函数调用!), r5???不明白!!!
验证绿色注释:
**(lldb) **print argv
(char **) $10 = 0x27d31cb8
**(lldb) ***print argv
(char *) $11 = 0x27d31d5c “/var/mobile/Applications/C61CAD4C-BB92-437D-936E-C313A262F38B/MITest.app/MITest”
**(lldb) **memory read 0x27d31c98 0x27d31c9c
0x27d31c98: 01 00 00 00 … //0x00000001 <–r0
**(lldb) **memory read 0x27d31c94 0x27d31c98
0x27d31c94: b8 1c d3 27 …’ //0x27d31cb8 <–r1
<分析位置三>
断点停留位置
0xdfe30: mov r0, r2 ####pc 当前位置(指令尚未执行) Thread1:breakpoint1.1
0xdfe32: mov r1, r3
0xdfe34: mov r2, r9
0xdfe36: mov r3, r12
0xdfe38: str.w lr, [sp]
0xdfe3c: str r4, [sp, #0x4]
0xdfe3e: bl 0xdfdbc ; func_test(int, int, int, int, int, int) at main.mm:324
0xdfe42: str r0, [sp, #0x1c] ####pc 当前位置(指令尚未执行) Thread1:breakpoint2.1
0xdfe44: blx 0xe5f24 ; symbol stub for: objc_autoreleasePoolPush
0xdfe48: str r0, [sp, #0x18]
0xdfe4a: bl 0xdfeb4 ; logDeviceInfo() at main.mm:330
0xdfe4e: movw r0, #0x6306
0xdfe52: movt r0, #0x0
0xdfe56: add r0, pc
0xdfe58: ldr r0, [r0]
0xdfe5a: movw r1, #0x7d76
0xdfe5e: movt r1, #0x0
0xdfe62: add r1, pc
0xdfe64: movw r2, #0x7e1c
0xdfe68: movt r2, #0x0
0xdfe6c: add r2, pc
0xdfe6e: ldr r3, [sp, #0x28]
0xdfe70: ldr.w r9, [sp, #36]
0xdfe74: ldr r2, [r2]
0xdfe76: ldr r1, [r1]
0xdfe78: str r0, [sp, #0x14]
0xdfe7a: mov r0, r2
0xdfe7c: ldr r2, [sp, #0x14]
0xdfe7e: str r3, [sp, #0x10]
0xdfe80: str.w r9, [sp, #12]
0xdfe84: blx r2
0xdfe86: blx 0xe5edc ; symbol stub for: NSStringFromClass
0xdfe8a: movs r2, #0x0
0xdfe8c: movt r2, #0x0
0xdfe90: ldr r1, [sp, #0x10]
0xdfe92: str r0, [sp, #0x8]
0xdfe94: mov r0, r1
0xdfe96: ldr r1, [sp, #0xc]
0xdfe98: ldr r3, [sp, #0x8]
0xdfe9a: blx 0xe5ed0 ; symbol stub for: UIApplicationMain
0xdfe9e: movs r1, #0x1
0xdfea0: movt r1, #0x0
0xdfea4: str r0, [sp, #0x2c]
0xdfea6: str r1, [sp, #0x20]
0xdfea8: ldr r0, [sp, #0x18]
0xdfeaa: blx 0xe5f20 ; symbol stub for: objc_autoreleasePoolPop
0xdfeae: ldr r0, [sp, #0x2c]
0xdfeb0: add sp, #0x30
0xdfeb2: pop {r4, r5, r7, pc}
<ida反汇编代码>
__text:00011DF4 ; =============== S U B R O U T I N E =======================================
__text:00011DF4
__text:00011DF4 ; Attributes: bp-based frame
__text:00011DF4
__text:00011DF4 ; int __cdecl main(int argc, const char **argv, const char **envp)
__text:00011DF4 EXPORT _main
__text:00011DF4 _main ; CODE XREF: start+24p
__text:00011DF4
__text:00011DF4 var_38 = -0x38
__text:00011DF4 var_34 = -0x34
__text:00011DF4 var_30 = -0x30
__text:00011DF4 var_2C = -0x2C
__text:00011DF4 var_28 = -0x28
__text:00011DF4 var_24 = -0x24
__text:00011DF4 var_20 = -0x20
__text:00011DF4 var_1C = -0x1C
__text:00011DF4 var_18 = -0x18
__text:00011DF4 var_14 = -0x14
__text:00011DF4 var_10 = -0x10
__text:00011DF4 var_C = -0xC
__text:00011DF4
__text:00011DF4 PUSH {R4,R5,R7,LR}
__text:00011DF6 ADD R7, SP, #8
__text:00011DF8 SUB SP, SP, #0x30
__text:00011DFA MOVS R2, #1
__text:00011E00 MOVS R3, #2
__text:00011E06 MOV R9, #3
__text:00011E0E MOV R12, #4
__text:00011E16 MOV LR, #5
__text:00011E1E MOVS R4, #6
__text:00011E24 MOVS R5, #0
__text:00011E2A STR R5, [SP,#0x38+var_C]
__text:00011E2C STR R0, [SP,#0x38+var_10]
__text:00011E2E STR R1, [SP,#0x38+var_14]
__text:00011E30 MOV R0, R2 ; int####pc 当前位置(指令尚未执行) 断点停留位置
__text:00011E32 MOV R1, R3 ; int
__text:00011E34 MOV R2, R9 ; int
__text:00011E36 MOV R3, R12 ; int
__text:00011E38 STR.W LR, [SP,#0x38+var_38] ; int
__text:00011E3C STR R4, [SP,#0x38+var_34] ; int
__text:00011E3E BL __Z9func_testiiiiii ; func_test(int,int,int,int,int,int)
__text:00011E42 STR R0, [SP,#0x38+var_1C]
__text:00011E44 BLX _objc_autoreleasePoolPush
__text:00011E48 STR R0, [SP,#0x38+var_20]
__text:00011E4A BL __ZL13logDeviceInfov ; logDeviceInfo(void)
__text:00011E4E MOV R0, #(_objc_msgSend_ptr_0 - 0x11E5A)
__text:00011E56 ADD R0, PC ; _objc_msgSend_ptr_0
__text:00011E58 LDR R0, [R0] ; __imp__objc_msgSend
__text:00011E5A MOV R1, #(selRef_class - 0x11E66)
__text:00011E62 ADD R1, PC ; selRef_class
__text:00011E64 MOV R2, #(classRef_MIAppDelegate - 0x11E70)
__text:00011E6C ADD R2, PC ; classRef_MIAppDelegate
__text:00011E6E LDR R3, [SP,#0x38+var_10]
__text:00011E70 LDR.W R9, [SP,#0x38+var_14]
__text:00011E74 LDR R2, [R2] ; OBJC_CLASS$_MIAppDelegate
__text:00011E76 LDR R1, [R1] ; “class”
__text:00011E78 STR R0, [SP,#0x38+var_24]
__text:00011E7A MOV R0, R2
__text:00011E7C LDR R2, [SP,#0x38+var_24]
__text:00011E7E STR R3, [SP,#0x38+var_28]
__text:00011E80 STR.W R9, [SP,#0x38+var_2C]
__text:00011E84 BLX R2
__text:00011E86 BLX _NSStringFromClass
__text:00011E8A MOVS R2, #0
__text:00011E90 LDR R1, [SP,#0x38+var_28]
__text:00011E92 STR R0, [SP,#0x38+var_30]
__text:00011E94 MOV R0, R1
__text:00011E96 LDR R1, [SP,#0x38+var_2C]
__text:00011E98 LDR R3, [SP,#0x38+var_30]
__text:00011E9A BLX _UIApplicationMain
__text:00011E9E MOVS R1, #1
__text:00011EA4 STR R0, [SP,#0x38+var_C]
__text:00011EA6 STR R1, [SP,#0x38+var_18]
__text:00011EA8 LDR R0, [SP,#0x38+var_20]
__text:00011EAA BLX _objc_autoreleasePoolPop
__text:00011EAE LDR R0, [SP,#0x38+var_C]
__text:00011EB0 ADD SP, SP, #0x30
__text:00011EB2 POP {R4,R5,R7,PC}
__text:00011EB2 ; End of function _main
步骤二:在xcode右下角的console窗口执行lldb命令
(lldb) register read
General Purpose Registers:
r0 = 0x00000001 #### *argc = 1
r1 = 0x27d31cb8 #### *argv = /var/mobile/Applications/C61CAD4C-BB92-437D-936E-C313A262F38B/MITest.app/MITest
r2 = 0x00000001
r3 = 0x00000002
r4 = 0x00000006
r5 = 0x00000000
r6 = 0x00000000
r7 = 0x27d31ca8
r8 = 0x27d31cb0
r9 = 0x00000003
r10 = 0x00000000
r11 = 0x00000000
r12 = 0x00000004
sp = 0x27d31c70 ####
lr = 0x00000005
pc = 0x000dfe30 MITest`main + 60 at main.mm:476
cpsr = 0x60000030
新手的各种疑问(我的真实感受):
1:断点在main函数开头在,为何停止在0xdfe30这条指令上?之前的指令是干什么的?做了什么操作?
2:听说过r0~r3保存的是函数参数,汇编指令中没有对r0,r1的赋值操作,他们的值怎么来的?
3:sp寄存器的初始值是多少?该怎么计算出来?
4:这些寄存器的值哪些是真实操作数,哪些是地址?
5:各个寄存器都是干什么的?都有什么独特的功能?
在解决这些问题之前,需要先恶补一些知识点:
arm指令(了解常用的),arm寻址方式,arm工作模式,编译原理,程序加载,函数调用,栈帧,调用约定等等!
介绍arm寄存器的一些简单知识:
问题1:
对这个的理解是,调用函数开始所要处理的事情:序言(prologs)!可能是用来处理函数参数,返回值的东东?
问题2:
根据调用约定(如_cdecl,_stdcall, _fastcall,_thiscall等)的简单了解,main函数的参数是系统处理的,
_cdecl调用约定:
规定调用方按从右到左的顺序将函数参数放入栈中!在被调用的函数完成操作时,调用方(而不是被调用方)
负责从栈中清除参数!
从右到左在栈中放入参数的一个结果是:左边第一个参数将始终位于栈顶!无论有多少个参数都可以轻易找到第一个参数!(iOS是向下增长的)
ARM使用一个栈来来维护函数的调用及返回。ARM中栈是向下生长(由高地址向低地址生长的)。
问题3:
根据断点位置时寄存器的值,和执行的有限条简单的指令来反向分析
MITest`main at main.mm:475:
0xdfdf4: push {r4, r5, r7, lr}
0xdfdf6: add r7, sp, #0x8 ==> r7 = 0x27d31ca8 sp = 0x27d31ca0
0xdfdf8: sub sp, #0x30 ==> sp = 0x27d31c70 在栈上分配30个直接存放局部变量(参数)?
这几条指令对r7,sp的值有修改,后面的指令(到断点前)没有修改:
而执行执行到0xdfe2e后寄存器的值:如下
sp = 0x27d31c70,
r7 = 0x27d31ca8,
也就是sp-#0x30=0x27d31c70(sp的最终值,也就是执行0xdfdf8执行后的值) ==>sp = 0x27d31ca0
sp(0x27d31ca0)+0x8 = r7 ==> r7 = 0x27d31ca8
问题4:
**(lldb) **thread list
Process 3231 stopped
-
thread #1: tid = 0x2c4af,
0x000dfe30 MITest`main(argc=1, argv=0x27d31cb8) + 60 at main.mm:476,
queue = ‘com.apple.main-thread’,
stop reason = breakpoint 1.1thread #2: tid = 0x2c4c3,
0x3a2f0808 libsystem_kernel.dylib`kevent64 + 24,
queue = ‘com.apple.libdispatch-manager’thread #3: tid = 0x2c4c4, 0x3a303c70 libsystem_kernel.dylib`__workq_kernreturn + 8
r0 = argc(main入参) -->保存的是值(操作数)0x1
r1 = &argv(main入参) -->保存的是argv在内存的地址0x27d31cb8
验证:
**(lldb) **po * argv
“/var/mobile/Applications/C61CAD4C-BB92-437D-936E-C313A262F38B/MITest.app/MITest”
**(lldb) **po argv
0x27d31cb8
**(lldb) ***po argv
“/var/mobile/Applications/C61CAD4C-BB92-437D-936E-C313A262F38B/MITest.app/MITest”
**(lldb) **print argv
(char **) $10 = 0x27d31cb8
**(lldb) ***print argv
(char *) $11 = 0x27d31d5c “/var/mobile/Applications/C61CAD4C-BB92-437D-936E-C313A262F38B/MITest.app/MITest”
**(lldb) ****memory read 0x27d31cb8 0x27d31d5c **####打印内存的值,验证猜测
0x27d31c58:
0x27d31c68:
0x27d31c78:
0x27d31c88:
0x27d31c98:
0x27d31ca8:
0x27d31cb8: 5c 1d d3 27 00 00 00 00 ac 1d d3 27 cf 1d d3 27 …’…’…’
0x27d31cc8: 20 1e d3 27 2e 1e d3 27 79 1e d3 27 85 1e d3 27 …’…‘y…’…’
0x27d31cd8: 94 1e d3 27 b6 1e d3 27 cd 1e d3 27 e0 1e d3 27 …’…’…’…’
0x27d31ce8: ee 1e d3 27 46 1f d3 27 00 00 00 00 0c 1d d3 27 …‘F…’…’
0x27d31cf8: 8c 1f d3 27 9b 1f d3 27 ac 1f d3 27 cb 1f d3 27 …’…’…’…’
0x27d31d08: 00 00 00 00 2f 76 61 72 2f 6d 6f 62 69 6c 65 2f …/var/mobile/
0x27d31d18: 41 70 70 6c 69 63 61 74 69 6f 6e 73 2f 43 36 31 Applications/C61
0x27d31d28: 43 41 44 34 43 2d 42 42 39 32 2d 34 33 37 44 2d CAD4C-BB92-437D-
0x27d31d38: 39 33 36 45 2d 43 33 31 33 41 32 36 32 46 33 38 936E-C313A262F38
0x27d31d48: 42 2f 4d 49 54 65 73 74 2e 61 70 70 2f 4d 49 54 B/MITest.app/MIT
0x27d31d58: 65 73 74 00 est. ==> 0x27d31d58 + #4 = 0x27d31d5c:
在mac os x终端中vi 输入/var/mobile/Applications/C61CAD4C-BB92-437D-936E-C313A262F38B/MITest.app/MITest (argv的值)
执行:%!xxd命令:
0000000: 2f76 6172 2f6d 6f62 696c 652f 4170 706c /var/mobile/Appl
0000010: 6963 6174 696f 6e73 2f43 3631 4341 4434 ications/C61CAD4
0000020: 432d 4242 3932 2d34 3337 442d 3933 3645 C-BB92-437D-936E
0000030: 2d43 3331 3341 3236 3246 3338 422f 4d49 -C313A262F38B/MI
0000040: 5465 7374 2e61 7070 2f4d 4954 6573 740a Test.app/MITest.
在vi中的0x0a == 0x00??
0x27d31cb8 argv地址
0x27d31d5c argv结束地址
灰色部分的作用不明白!
r2=1,r3=2,r9=3,r12=4,lr=5,r4=6 难道是保存的局部变量? main.mm :: 476: func_test(1, 2, 3, 4, 5, 6);
问题5:
查资料google,baidu吧.
如果对上面mian函数序言部分的汇编代码分析有所感悟,那么在(lldb)next后的操作后的汇编代码部分应该可以有所把握了,至少在看ida中某个函数的代码不那么无从下手了吧!
至此,亲自调试自己写的代码吧,把源代码,汇编代码,寄存器,内存,栈帧,ida逆向代码…等等知识点结合起来,拼成一个完整的图吧!
要看的懂别人的代码,就想看懂自己的代码吧!
也可以接着分析吧:
<XCode汇编代码>
323 int func_test(int a, int b, int c, int d, int e, int f)
324 {
325 int g = a + b + c + d + e + f;
326 return g;
327 }
(lldb)next
main.m中:
0xdfe30: mov r0, r2 r0<- r2 = 1 ####pc 当前位置(指令尚未执行) Thread1:breakpoint1.1
0xdfe32: mov r1, r3 r1<- r3 = 2
0xdfe34: mov r2, r9 r2<- r9 = 3
0xdfe36: mov r3, r12 r3<- r12=4
0xdfe38: str.w lr, [sp] lr->[sp(0x27d31c70)] = 0x5
0xdfe3c: str r4, [sp, #0x4] r4->[sp(0x27d31c70+0x4)] = 0x6
0xdfe3e: bl 0xdfdbc ; func_test(int, int, int, int, int, int) at main.mm:324
0xdfe42: str r0, [sp, #0x1c] ####pc 当前位置(指令尚未执行) Thread1:breakpoint2.1
MITest`func_test(int, int, int, int, int, int) at main.mm:324:
0xdfdbc: sub sp, #0x1c sp=sp(0x27d31c70-0x1c)= 0x27d31c54
0xdfdbe: ldr.w r9, [sp, #32] r9=sp(0x27d31c54+32)=(0x27d31c74)= 0x06
0xdfdc2: ldr.w r12, [sp, #28] r12=sp(0x27d31c54+28)=(0x27d31c70)= 0x05
0xdfdc6: str r0, [sp, #0x18] r0->sp(0x27d31c54 + 0x18)=(0x27d31c6c)= 0x1 (a)
0xdfdc8: str r1, [sp, #0x14] r1->sp(0x27d31c54 + 0x14)=(0x27d31c68)= 0x2 (b)
0xdfdca: str r2, [sp, #0x10] r2->sp(0x27d31c54 + 0x10)=(0x27d31c64)= 0x3 (c)
0xdfdcc: str r3, [sp, #0xc] r3->sp(0x27d31c54 + 0xc) =(0x27d31c60)= 0x4 (d)
0xdfdce: str.w r12, [sp, #8] r12->sp(0x27d31c54 + 8)= (0x27d31c5c)= 0x5 (e)
0xdfdd2: str.w r9, [sp, #4] r9->sp(0x27d31c54 + 4)=(0x27d31c58)= 0x6 (f)
0xdfdd6: ldr r0, [sp, #0x18]
0xdfdd8: ldr r1, [sp, #0x14]
0xdfdda: add r0, r1
0xdfddc: ldr r1, [sp, #0x10]
0xdfdde: add r0, r1
0xdfde0: ldr r1, [sp, #0xc]
0xdfde2: add r0, r1
0xdfde4: ldr r1, [sp, #0x8]
0xdfde6: add r0, r1
0xdfde8: ldr r1, [sp, #0x4]
0xdfdea: add r0, r1
0xdfdec: str r0, [sp]
0xdfdee: ldr r0, [sp]
0xdfdf0: add sp, #0x1c
0xdfdf2: bx lr
**(lldb) **register read
General Purpose Registers:
r0 = 0x00000001
r1 = 0x00000002
r2 = 0x00000003
r3 = 0x00000004
r4 = 0x00000006
r5 = 0x00000000
r6 = 0x00000000
r7 = 0x27d31ca8
r8 = 0x27d31cb0
r9 = 0x00000006
r10 = 0x00000000
r11 = 0x00000000
r12 = 0x00000005
sp = 0x27d31c54
lr = 0x000dfe43 MITestmain + 79 at main.mm:479 pc = 0x000dfdd6 MITest
func_test(int, int, int, int, int, int) + 26 at main.mm:325
cpsr = 0x60000030
**(lldb) **print &a
(int *) $15 = 0x27d31c6c
**(lldb) **print &b
(int *) $16 = 0x27d31c68
**(lldb) **print &c
(int *) $17 = 0x27d31c64
**(lldb) **print &d
(int *) $18 = 0x27d31c60
**(lldb) **print &e
(int *) $19 = 0x27d31c5c
**(lldb) **print &f
(int *) $20 = 0x27d31c58
(lldb) **memory read 0x27d31c54 0x27d31c58
0x27d31c54: 15 00 00 00 … func_test的返回值位置0x27d31c54**