呵呵 通宵了一晚上算是把这章看懂的 我觉得dword shoot这里可能有些人看的觉得吃力 所以贸然写一篇注解 不过鉴于水平有限 有错误请指出
虽然很多东西现在已经不实用了 原理还是相同的 没有谁可以一步登天 戒焦戒躁
感谢failwest和为软件安全做出贡献的前辈们
书上猜测卸载堆结点的代码可能是这个样子的
int remove(Listnode * node)
{
node -> blink -> flink = node -> flink;
node -> flink -> blank = node -> blank;
}
现在我们假设 node的结构是这样的
struct node{
struct node *flink;
struct node *blink;
int data;
};
我们这里先不考虑块首和大块的数据
然后在内存地址0x44444444存在node结构
0x44444444 flink (4byte) 0x55555555
blink (4byte) 0x33333333
data (4byte)
32位系统上 每个指针都有32位的大小 所以是4byte
node结构中blink被赋于0x33333333 flink被赋于0x55555555 data保存一个32位的数据
node -> blink -> flink
如果不知道->是什么意思 真的麻烦补一下C语言知识再看这本书 没有基础不可能达到巅峰
我们可以把node -> blink看成0x44444444偏移4byte位置保存的数据 我们这里保存的是0x33333333
偏移多少是当初定义数据结构时先后顺序决定的
得到0x33333333 我们把0x33333333代替node->blink->flink里面的node->blink 就成了0x33333333->flink 我们再根据数据结构的定义来算偏移 于是就得到了0x33333333+0的偏移 还是0x33333333
node->flink 一样按照上面的方法 node用0x44444444代替 根据数据结构定义 就是0x44444444偏移0byte就是要访问的地址 要访问的地址是0x44444444
所以node -> blink -> flink = node -> flink;
翻译成汇编就是 mov eax,[44444444h]
mov [33333333h],eax
就是这么简单的两条汇编语句-_-
node -> flink -> blink = node -> blink; 还是跟上面的方法一样
node -> flink -> blink 的 node->flink替换成0x55555555 然后0x55555555->blank 根据数据结构定义偏移4byte 就等于了0x55555559
node->blink就等于了0x44444444偏移4byte 就是0x44444448
翻译成汇编就是 mov eax,[44444448h]
mov [55555559h],eax
前面的内容虽说很基础 可是对理解后面的东西起到很重要的作用
现在 我们再看一下节点的数据结构
struct node{
struct node *flink;
struct node *blink;
int data;
};
假设在内存是这么分布的
0x33333333 flink (4byte) 0x44444444
blink (4byte) 0x55555555
data (4byte)
0x44444444 flink (4byte) 0x55555555
blink (4byte) 0x33333333
data (4byte)
0x55555555 flink (4byte) 0x33333333
blink (4byte) 0x44444444
data (4byte)
可能不太准确=_= 我的本意是一个双向循环链表 我数据结构老师死的早 错了勿喷
我们假设这个链表都像上面那样填写好数据了
这时候 我们修改了0x44444444处的flink和blink
将flink填为0x12345678 blink填为0x87654321
0x33333333 flink (4byte) 0x44444444
blink (4byte) 0x55555555
data (4byte)
0x44444444 flink (4byte) 0x12345678
blink (4byte) 0x87654321
data (4byte)
0x55555555 flink (4byte) 0x33333333
blink (4byte) 0x44444444
data (4byte)
然后我们释放0x44444444处的节点
释放会调用这个方法
int remove(Listnode * node)
{
node -> blink -> flink = node -> flink;
node -> flink -> blank = node -> blank;
}
我们就继续用汇编来解释 按照前面我所说的话 如果我们把0x44444444当做参数传送进去
那就会是这个样子
int remove(0x44444444)
{
0x44444444 -> blink -> flink = 0x44444444 -> flink;
0x44444444 -> flink -> blank = 0x44444444 -> blank;
}
按照之前算便宜的方法 我们把他翻译成汇编代码
mov eax,[44444444h]
mov [87654321h],eax
mov eax,[44444448h]
mov [1234567Ch],eax
大家应该明白了点什么 这尼玛就是一个能篡改内存任意位置数据的机会啊 如果用来改保存seh函数地址的指针 或者关键变量都行
试想一下 如果我们把这个节点的flink改成程序一个关键必须执行的函数指针的内存位置 然后再把blink改成我们shellcode的地址 那就咩哈哈了
我感觉理解了这个 看这一章应该没有什么问题了 如果有什么疑问可以回帖 我再补上
感谢各位看完 本人年龄比较小 就容许叫大家一声哥哥姐姐吧 也不知道有没有姐姐。。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)