iOS-逆向04-判断&循环&选择

2021-04-01  本文已影响0人  一亩三分甜

《iOS底层原理文章汇总》

1.cmp(Compare)比较指令

   CMP 把一个寄存器的内容和另一个寄存器的内容或立即数进行比较。但不存储结果,只是正确的更改标志。
   一般CMP做完判断后会进行跳转,后面通常会跟上B指令!

2.内存分区

1.代码区:存放代码,可读,可执行,MachO文件只有一部分是代码,还有一部分是数据,还有一部分是MachO文件描述信息
2.栈区:参数,局部变量,临时数据
3.堆区:动态申请,可读,可写
4.全局变量:可读可写
5.常量区:只读

I.全局变量和常量

图片.png 图片.png

68 61 68 61
h a h a 前面四个字节表示haha

0x104c93f9f: 68 61 68 61 00 01 00 00 00 1c 00 00 00 02 00 00 haha............
0x104c93faf: 00 24 00 00 00 00 00 00 00 24 00 00 00 02 00 00 ..............

以上两个十六个字节分别对应字符,x0获取到的内存地址属于字符串常量区,

image
0x104c9218c <+20>: adrp   x0, 1
0x104c92190 <+24>: add    x0, x0, #0xf9f            ; =0xf9f 

上面两句代码是如何得到字符串常量区的内存地址0x0000000104c93f9f并存放到x0寄存器中的呢?adrp表示以页来寻址(address page),将1的值左移12位,十六进制左移0x1000,相当于二进制左移12位,将当前pc寄存器的地址加上1左移12位的值,且将原来的地址最后3位(低12位)清零

0x104c9218c --- > 0x104c9218c
0x1000 0x1000

0x104c93000得到尾数是000,则地址值是16的倍数,也是4的倍数,iOS中一页数据的大小PAGESIZE是16K,也就是会偏移0x4000,Mac中一页数据PAGESIZE的大小是4K,0x104c93000是一页数据的开头,加上偏移地址f9f得到存放字符串常量“haha”的内存地址0x104c93f9f

image

页号是在编译器编译时候确定的,以PC寄存器作为参照相当于以当前代码段的地址作为参照

为什么不能直接加这个地址,需要偏移呢?
我们不能得到一个确定的内存地址,但是我们能得到一个参照

程序在内存中的地址通常会通过ASLR,即实际地址+ASLR = 偏移地址,ASLR -> 0x0000000102e18000,
实际地址 + ASLR -> 0x0000000102e18000 = 偏移地址 0x0000000102e1e18c

偏移值作为参照会有两种参照方式:从文件的起始位置偏移或从当前代码的地址偏移,常量区的内存地址的计算是从当前代码的地址偏移

同理,取全局变量g的内存地址 0x104f16194 ---> 0x104f19648


image 图片.png image

通过汇编拿到地址-aspr 得到MachO文件中的地址
0x f9f
0x104c93f9f
0xf9f的值是编译器给的

image

若是0x1002bf888 <+20>: adrp x0,2
01002c1000
最后结果是将“haha”字符串出放入x0寄存器中传入printf函数

通过内存地址无法判断是字符串常量还是全局变量

3.通过汇编代码还原高级语言

1.编译当前工程

2.在product目录下.app中显示包内容,将app同名的MachO文件拖入hopper disassembler v4中

image 图片.png image

直接adrp的地址已经算好,是没有aslr的地址0x100007000+0xf9f
在MachOView烂苹果中查找0x100007f9f的地址,得到字符串常量haha的值,字符串常量存在String区

image image

同理查找全局变量g的值0x100009000 + 0x648
在MachOView烂苹果中查找0x100009648的地址,得到全局变量g的值12,字符串常量存在String区,全局变量存在于section64,data部分

图片.png 图片.png

精简代码

image

得到原来高级代码

image

3.代码的执行流程并不关心,只关心执行的结果和原始的一样

4.if

image

两者相减,若小于0,跳入loc_1000061c0
若大于0,直接往下走

image

还原高级语言代码

图片.png image

5.循环(loop)

do{}while();循环

图片.png image

while(){};循环

image image

for循环 和 while循环一模一样

image 图片.png

5.Switch

1、假设switch语句的分支比较少的时候(例如3,少于4的时候没有意义)没有必要使用此结构,相当于if。
2、各个分支常量的差值较大的时候,编译器会在效率还是内存进行取舍,这个时候编译器还是会编译成类似于if,else的结构。
3、在分支比较多的时候:在编译的时候会生成一个表(跳转表每个地址四个字节)。

switch三个case情况

image image

switch四个case情况:建立一张数据表8字节、8字节、8字节,将每一个条件要做的事情放到不同的连续地址8字节,得到index到数据表中去查找地址,找到后直接执行地址中保存的代码,通过一次运算,直接查表,找到要执行的地址,不需要多次if else判断

switch判断条件比较多,一直if else会浪费时间比较多

image image

switch若判断条件无规则呢?没有查表,进行多次比较

图片.png image

条件有规律的情况下,如何建表,查表的呢?且看下文分析。

上一篇下一篇

猜你喜欢

热点阅读