摘要
最近在使用vs2010编写shellcode的时候,在将编写好的shellcode保存为二进制格式的。那么引出一个问题,我刚开始的时候直接: 取地址符 + 函数名 的方式来获取函数的首地址。当时在使用shellcode的时候,程序一直崩溃,经过分析发现shellcode前面的一些代码并不是我们所需要的代码,而是一条jmp指令+一系列的CC指令,再经过对原本编写shellcode的程序进行逆向,对比分析后得出结论:&取地址符 获取的函数地址并非真正的起始地址。
分析过程
下面我将会使用一个最简单的例子来记录和说明。
环境:win7 64位操作系统 + vs2010.
代码如下:
void function(){ MessageBox(0, "", "", 0); return ; } int main(){ void *p = (void *)&function; printf("function的ì?地ì?址?¤:êo%x", p); getchar(); return 0; } |
打开od对我们生成的程序, 定位到main函数:
当执行完:lea rax, qword ptr ds:[function]这条汇编指令(相当于执行完:void *p = (void *)&function;)后,此时rax = 0x000000013F7F100A。
接下来我们在定位到rax执向的地址:000000013F7F100A。
可以看出,rax指向的是一条跳转指令的地址,并非是function函数的真正执行地址。
获取函数真正地址
那么问题来了,我们要怎么获取我们需要的函数的真正的地址呢?我们进行进一步的分析。首先明确跳转指令jmp是由:E9 + 4字节的偏移(相对本条指令结束),那么接下来我们就可以很容易地确定函数的真正执行地址了。其代码如下:
void *p = (void *)&function; int offset = *(unsigned int *)((char*)p + 1); void *rfadr = (void*)((char*)p + 5 + offset); |
其结果如下:
运行完 lea rax,qword ptr ds:[rcx+rax+5] | ;rax:function 这条指令后,rax = 0x000000013F501020,我们转移到rax指向的地址:
这次获取的地址是我们真正想要的函数地址。
总结
经过对这个小例子的分析,我不仅仅知道了所谓的对函数名取地址的操作并非直接获取函数的真正的起始地址,更是让我在从发现shellcode执行崩溃,到逆向分析shellcode,再到找出、确认问题产生的原因,最后到给出真正的解决方法,这整个过程中收获良多。
2018-04-04 21:02:02