我在写DLL的时候,发现DEBUG模式下调用某个自己的函数时总是会跳到一个jmp指令处,再由jmp转到函数入口。
举例说,有如下函数:
void func1()
{
...
}int dllmain(...)
{
   func1();
   ...
}运行到func1时,查看汇编模式,单步进入,发现到了一个jmp指令处,然后再由jmp跳转到函数真正的入口。
而Release下编译就不会有这样的情况,直接转到函数入口执行。看起来确实没什么大碍,可是如果要读取func1函数的指令码就麻烦了,DEBUG模式下func1得到的是jmp指令的地址,
而非实际入口,这样也就读不到函数的指令码了。请问有没有办法在DEBUG模式下不产生jmp跳转的编译开关或是其它设置?或者有没有办法在DEBUG模式下取到函数的真正入口地址?

解决方案 »

  1.   

    如果你能有访问代码的权限,你在debug模式下就能读jmp的地址了,那地址想必就是真正地址。
      

  2.   

    to Mackz:我就是在DEBUG模式下调试的时候才发现不是实际地址的。编译成Release模式再用OD调试发现没有了jmp跳转,而是直接到函数入口。举例说,函数func1()的编码为:10001150                      /$  6A FF              push -1
    10001152                      |.  68 98A30330        push mmdll.1003A398 
    10001157                      |.  64:A1 00000000     mov eax,dword ptr fs:[0]
    1000115D                      |.  50                 push eax
    1000115E                      |.  64:8925 00000000   mov dword ptr fs:[0],esp
    ....而我调用func1()的时候,会来到
    10001035                       . /E9 16010000        jmp rxwg.10001150
     
    jmp指令跳转到真正的入口10001150但如果是Release模式下,则调用func1()时直接跳到10001150
    to jennyvenus:jmp后面的地址确实是真正的地址。如果去读jmp后面的地址会有两个问题,
    1.读取指令码的函数需要有两个版本,一个是DEBUG版本(从jmp指令读),另一个是Release版本(直接读)
    2.我不确定在DEBUG模式下是不是每个函数都会产生jmp跳转。调用DLL模块的导出函数时会有一个跳转,但我测试的这些函数都是没有导出的。我想应该是和某个编译开关有关系,可是我不熟悉那些开关。如果实在没办法,我只能从读取函数指令码的函数入手了。
      

  3.   

    // test8.cpp : Defines the entry point for the console application.
    //#include "stdafx.h"int fun1()
    {
    return 0;
    }int getaddr( void *f )
    {
    // 计算函数真实地址
    unsigned char* funaddr = ( unsigned char* )f;//void f(){}
    unsigned long realaddr = 0;
    if( 0xe9 == funaddr[ 0 ] )// 判断是否为虚拟函数地址,E9为jmp指令
    {
    realaddr = ( unsigned long )f;
    realaddr += funaddr[ 2 ] * 0x100 + funaddr[ 1 ] + 5;
    }
    else
    {
    realaddr = ( unsigned long )f;
    }
    return realaddr;

    int main(int argc, char* argv[])
    {
    printf( "%X", getaddr( fun1 ) );
    return 0;
    }看看这管用吗
      

  4.   

    搞得太复杂了吧,修改一下Release的配置,选上调试信息选项,然后用Release来调试。
      

  5.   

    project->setting->c/C++修改一个选项.link中打上两个勾。
      

  6.   

    Debug模式有jmp是为了将调试信息写在jmp,使其得到执行。
    用5楼的方法应该可以得到真正的函数地址
      

  7.   

    jennyvenus 的方法可以得到地址,不过似乎程序有点问题:
    realaddr += funaddr[ 2 ] * 0x100 + funaddr[ 1 ] + 5;
    为什么只加了2个字节?jmp后面的参数是一个4字节的整数.
      

  8.   

    5楼的方法可以解决,不过好像有点问题:
    realaddr += funaddr[ 2 ] * 0x100 + funaddr[ 1 ] + 5
    只读了两个字节。E9指令后面是4字节操作数吧?总之谢谢了!
      

  9.   

    这是个很好的问题。我今天也遇到了,用了一天来测试,发觉只需要对你的工程进行一些设置,就不会有这个问题,跟是否调试无关。选择1:
    在工程的链接器选项里,选上“使用链接时间代码生成(/ltcg)”,或者“Use Link Time Code Generation (/ltcg)”。
    选择2:
    在链接器选项的“高级”选项卡里,对“设置校验和”或者“Set Checksum”选上“是(/RELEASE)”。这2种方法都是有效的,避免一些指向函数的指针指到了JMP跳转指令上。