这题刚开始漏看了一个条件……导致花了很多时间……虽然感觉没有那个条件也能做出来……但是想了很长时间没有找到非常好的方法……
漏看的条件就是mmap的区域是rwx的……所以可以直接上shellcode
程序主要实现了一个小探险游戏,而且数据的空间的动态分配由作者自己的malloc和"free"管理
userheap_init 讲 作者写的堆初始化,具体做的事情就是mmap出一块内存,然后将其地址存入一个全局变量top中,并将该地址+4096存入一个全局变量max中,之后每次分配(调用user_malloc)的时候从mmap的内存中划分一块出来,然后更新top,同时检查是否超过max,如果超过max既分配失败
那个malloc(0x50)不知道干嘛使得……
然后是第一层的"游戏登录"界面
banner,getint,getn都没什么好说的……分别是打印出banner,输入一个数,并atoi转成int,和输入n个字符,invalid_choice就输出invalid choice
这里程序用到了status这个结构,定义如下
其中username和password即为我们前面注册的时候所输入的,每个限制16字符,character是game中用到的另外一个结构体,存储当前玩家的各种状态
user_malloc的代码如下
先根据想要分配的大小,round到一个固定的大小,16,48,40,400中的一个,然后调用alloc_from_mmap这个函数来从之前mmap中的内存中分配
这里可以看到我们之前所提的根据max的检测,同时这里用到了一个Bin的结构体,类似malloc中的bin,存储该区块大小和引用计数(这里有点不是很一样),ptr存储我们实际的数据
之后还会有个free_list的结构来track所有被free过的块……然而malloc并没有用到它……非常迷……
insert这个函数就很有意思了……也是bug的所在
get_chunk会从我们给定的ptr中找到Bin这个结构所在的位置,即倒着找16个字节
allocated会增加ptr2,我们要插入的这个chunk的引用计数
user_free中含有我们需要触发的bug
find_valid_pointer_addr 从v3这个值开始,检测a1的每个指针是不是一个有效地址(这个操作非常迷……我至今还是没有弄懂为什么要这样做……),可以注意到的一点是这里检测的有效地址是包括ptr这个区域的……所以我们可以伪造一个指针,来让他假如free_list中(之后我们可以用它来伪造各种指针)
检测到有效地址后,我们把它插入到我们的freelist的头上,并把free_list的地址移到下一个指针(这里也是个没有非常明白的操作……这不是会和之后的东西有重叠的可能性吗……)
可看出insert的算法是这样的,先检测我们要插入的那个地址有没有指针,有的话把他"free“掉再插入新的指针,同时增加新指针的引用计数,free的时候会找到所有的有效地址,对于每个地址更新当前free_list所指的地方的值,并将free_list + 1,同时将free后的指针的ptr更改为所对应的free_list地址
这里有个很有趣的事情就是假如我们输入的数据中有有效地址并且当前区块被free掉的话,那么会发生以下事情
1. find_valid_pointer_addr找到我们数据中有效地址所存储的地址并返回
2. get_chunk返回我们有效地址-0x10
3. insert_freelist 会将我们有效地址-0x10+0x10变成free_list,同时会将我们有效地址的值存入free_list中,然后free_list++
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)