[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所占的字节+要正向跳转的字节数
    }

 

posted on 2015-08-02 18:33  凌晨的搜索者  阅读(1271)  评论(0编辑  收藏  举报

导航