一 Mach-O文件内存分布
二 ASLR详解
三 实例演示ASLR的应用
一 Mach-O文件内存分布
我们平时开发调试应用程序很简单,就是利用Xcode进行断点
但是在逆向工程中,你是不能这样调试别人的应用的,我们无法拿到别人的源代码,无法通过Xcode来调试.但是不要担心,我们可以通过LLDB这个工具来进行调试
breakpoint set -n "test"
我们通过breakpoint命令来断点我们要调试的代码,但是这里我们要注意的是在调试别人的代码时我们无法通过方法名来进行断点的,我们只能通过方法地址来进行断点,如下:
breakpoint set -a 0x102227859
在这里方法的地址值我们通过逆向Mach-O文件就能看到,下面我就拿自己写的这个应用来演示一下,因为是自己的应用,我不用砸壳了,要是别人的应用你需要砸壳.
第一步 拿到我们应用的可执行文件
第二步 把我们的可执行文件拖到hopper disassember里面去
我们可以看到我们的函数地址是
0x0000000100000dc0
,那么是不是我们断点到这个地址就能断点到我们的test函数呢
breakpoint set -a 0000000100000dc0
执行断点的话不管成功还是不成功,我可以直接告诉你断点的位置都是不对的,因为我们的应用程序在载进内存的时候,系统都会添加一个偏移地址,这个偏移地址每次运行程序都是不一样的.你想一下如果地址都是死的,那还有什么安全可言,别人只要把可执行文件网Hopper一拖,就能看到你所有的函数地址,那不是想干什么就干什么了.具体这个偏移具体详情我们下小节讲,我们先来了解下mach-o文件的内存分布情况,把我们刚才的可执行文件拖到MachOView里面
我们先来讲解下红框四个字段的基本概念
VM Address:Virtual Memory Address,内存地址,在内存中的位置
VM size:Virtual Memory Size,内存大小,占多少内存
File Offset:在Mach-O文件中的位置
File Size:在Mach-O文件中占用的大小
__PAGEZERO
VM Address: 0
VM size:4294967296
File Offset:0
File Size:0
__PAGEZERO在Mach-O文件中占用的大小为零,但是在载进内存后,它的大小就不是为零了.
__TEXT
VM Address: 4294967296
VM size:12288
__DATA
VM Address: 4294979584
VM size:12288
Mach-O已经描述好我们的代码段,数据段的内存地址以及内存大小,函数代码存放在
__TEXT
段中,我们函数存放地址都在__TEXT段中的
我们在来熟悉下Mach-O文件的整体结构
好了我们通过Mach-O文件已经知道我们写的函数存放的大致位置,那么在运行程序的时候载进内存时候,函数地址有什么变化呢,我们接下来看一下.
二 ASLR详解
ASLR (Address Space Layout Randomization)地址空间布局随机化
是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的的一种技术
iOS4.3开始引入了ASLR技术
2.1 未使用ASLR之前Mach-O文件内存分布情况
函数代码存放在
__TEXT
段中
全局变量存放在
__DATA
段中
可执行文件的内存地址是
0x0
__PAGEZERO
大小:0
代码段(__TEXT)的内存地址就是
LC_SEGMENT(__TEXT)
中VM Address arm64:
0x100000000(8个0)
非arm64:
0x4000(3个0)
2.2 使用ASLR之后Mach-O文件内存分布情况
LC_SEGMENT(__TEXT)
的VM Address
0x100000000
ASLR随机产生的Offset(偏移)
0x5000
__PAGEZERO
大小:100000000
原先Mach-O文件在装载进内存后各数据位置都发生了偏移,那我们函数内存地址就是(VM Address) = File Offset + ASLR Offset + __PAGEZERO Size
所以我们在断点别人的函数时,它的地址要通过(
File Offset + ASLR Offset + __PAGEZERO Size
)这三个地址相加来计算,这三个地址每次程序装载进内存,都要重新获取.
Hopper中显示的的地址都是未使用ASLR的VM Address 也就是说Hopper中显示的地址是:
File Offset + __PAGEZERO Size
,那么我们要断点一个函数的地址就简单了:
1 先看该函数在Hopper中的地址
2 查看该应用的ASLR Offset
3 两者相加
下面我们来演示一下.
三 实例演示ASLR的应用
为了方便我直接拿自己Xcode写的应用来演示,如果是调试别人的应用,你只要进入动态调试,就可以和我一样的操作了,首先我先进入调试模式
这里我打算给test函数打个断点
把我们的可执行文件拖放到Hopper中我们先看下test函数的地址
我们看到test函数地址是:
0x0000000100000dc0
接下来我们再看ASLR Offset.
使用LLDB命令
image list -o -f | grep runloop
runloop是你应用的名字
这个打印出来的就是偏移地址:
0x00000000082bd000
最后我们执行断点命令
breakpoint set -a 0x0000000100000dc0+0x00000000082bd000
我们可以看到断点打成功了.
我们过掉Xcode断点,发现代码会断点到test函数处了.
OK 今天就是我要讲的全部内容.动态调试别人的代码,总得知道别人的代码具体在内存中什么位置吧,学了今天的内容,相信对于你定位代码位置不再是难事了.