我在写DLL的时候,发现DEBUG模式下调用某个自己的函数时总是会跳到一个jmp指令处,再由jmp转到函数入口。
举例说,有如下函数:
void func1()
{
...
}int dllmain(...)
{
func1();
...
}运行到func1时,查看汇编模式,单步进入,发现到了一个jmp指令处,然后再由jmp跳转到函数真正的入口。
而Release下编译就不会有这样的情况,直接转到函数入口执行。看起来确实没什么大碍,可是如果要读取func1函数的指令码就麻烦了,DEBUG模式下func1得到的是jmp指令的地址,
而非实际入口,这样也就读不到函数的指令码了。请问有没有办法在DEBUG模式下不产生jmp跳转的编译开关或是其它设置?或者有没有办法在DEBUG模式下取到函数的真正入口地址?
举例说,有如下函数:
void func1()
{
...
}int dllmain(...)
{
func1();
...
}运行到func1时,查看汇编模式,单步进入,发现到了一个jmp指令处,然后再由jmp跳转到函数真正的入口。
而Release下编译就不会有这样的情况,直接转到函数入口执行。看起来确实没什么大碍,可是如果要读取func1函数的指令码就麻烦了,DEBUG模式下func1得到的是jmp指令的地址,
而非实际入口,这样也就读不到函数的指令码了。请问有没有办法在DEBUG模式下不产生jmp跳转的编译开关或是其它设置?或者有没有办法在DEBUG模式下取到函数的真正入口地址?
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模块的导出函数时会有一个跳转,但我测试的这些函数都是没有导出的。我想应该是和某个编译开关有关系,可是我不熟悉那些开关。如果实在没办法,我只能从读取函数指令码的函数入手了。
//#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;
}看看这管用吗
用5楼的方法应该可以得到真正的函数地址
realaddr += funaddr[ 2 ] * 0x100 + funaddr[ 1 ] + 5;
为什么只加了2个字节?jmp后面的参数是一个4字节的整数.
realaddr += funaddr[ 2 ] * 0x100 + funaddr[ 1 ] + 5
只读了两个字节。E9指令后面是4字节操作数吧?总之谢谢了!
在工程的链接器选项里,选上“使用链接时间代码生成(/ltcg)”,或者“Use Link Time Code Generation (/ltcg)”。
选择2:
在链接器选项的“高级”选项卡里,对“设置校验和”或者“Set Checksum”选上“是(/RELEASE)”。这2种方法都是有效的,避免一些指向函数的指针指到了JMP跳转指令上。