[vc] 获取函数名称真实地址
首先写一个很简单的main函数:
int main(){ printf("main的地址(?):%08x",main); }
单步调试,可得知 main函数的真实入口地址是:00be91a0
然而我们控制台输出的值是
为什么会出现这样的差别呢?院子里有一篇大牛写的有关注入的文章:http://www.cnblogs.com/fanzhidongyzby/archive/2012/08/30/2664287.html,里面就提到了这个问题。
其中提到一个解析真实地址的算法:
//将函数地址转换为真实地址 unsigned int getFunRealAddr(LPVOID fun) { unsigned int realaddr = (unsigned int)fun;//虚拟函数地址 // 计算函数真实地址 unsigned char* funaddr = (unsigned char*)fun; if (funaddr[0] == 0xE9)// 判断是否为虚拟函数地址,E9为jmp指令 { int disp = *(int*)(funaddr + 1);//获取跳转指令的偏移量 realaddr += 5 + disp;//修正为真实函数地址 } return realaddr; }
相信新手朋友都和我一样为这段代码怎么来的摸不着头脑。特此我单步调试研究了一番,才大致明白原理:
main函数名的地址其实就是一个 Jmp xxx的指令,
从vs的反汇编调试代码可以看出,第一个参数main入栈,对应汇编代码就是 push 0be135Ch ,这个入栈的数字,其实就是刚刚控制台输出的那个地址。所以很显然这个地址就是函数main的“函数名”所在的地址(其实在汇编里应该是不存在 “main”这样的字符串的,之所以可能可以在vs或在od这样的调试器里看到,是这些调试器通过经验推断出来的结果。)。然后 我们在地址栏里输入 0be135Ch这个地址,就可以跳到 相对的位置处。
jmp 对应的汇编码为 E9, 而后面的4个字节"3F 7E 00 00",实际上是倒序的相对地址 0x00007e3f.也就是我们看到是main。当然这个地址只是代码的相对位置,如果运行之后,就要加上当前模块的基址才是绝对地址。
那么既然,这个“main”的位置只是一个跳转指令(JMP),肯定是跳转到了jmp后面跟的这个地址的位置了,也就是说这个地址就是真正的main函数的地址了。
当然,0be135Ch是从e9 3F 7E 00 00这条指令开始算的。也就是说,从e9 3F 7E 00 00的位置开始算,跳过去0x00007e3f个字节,就到了真正的main函数入口处。
所以真正的地址就是
0be135Ch+5(指令占的字节数 JMP main)+0x00007e3f=00be91a0.
所以我们再回到函数部分来。
UINT realaddr = (UINT)main;// 拆箱转换成 unsigned int 数据。代表main函数名所代表的地址 unsigned char* funcaddr = (UCHAR*)main; //这里是获取main地址所在的字节内容,其内容为“e9 3F 7E 00 00”(JMP main),所以只要判断前面的字节指令是否是e9就知道是不是真实地址了,如果是Jmp(e9)的话就不是真正的地址。 if (funcaddr[0] == 0xE9){ //因为 UCHAR* fa = funcaddr + 1;//指针移后一位,从e9到 3f. int* as = (int*)(fa); //取指针=处的int数据(共4个字节),实际上这里就是一个跳转地址。 int disp = *as; //取指针的内容 realaddr += 5 + disp;//在main地址的基础上+JMP main所占的字节+要正向跳转的字节数 }
///******************************************************
///本文作者:凌晨的搜索者
///博客地址:http://www.cnblogs.com/uu102
///本文属于原创,如果有您需要的内容想要转载,请保留此段签名注释,否则作者将保留追究法律责任的权利。
///******************************************************