32位汇编没有基址跟
偏移地址
的概念
你没发现call后面是DWORD PTR吗?这说明什么?
这说明call能寻址所有4GB地址空间
楼下的那个回答更是扯谈
32位的PE文件根本就不能用debug调试
楼主给出的明显是32位汇编代码
别拿你的16位汇编过来了!
楼主我想告诉你的是32位汇编没有段地址 偏移地址的概念
如果真的要跟16位汇编联系起来
那么你可以这么认为所有段地址寄存器在程序中都是0(实际上 段寄存器 保存的是段描述符)
所有在程序中给出的地址都是32位偏移地址,也就是程序地址空间的 绝对地址
call dword ptr [408030];这条指令我估计你是在OD这些调试工具下面看到的
对于408030这个问题
如果不是API函数而是程序自身函数
一般在程序中是直接call 函数首地址的
但是对于API函数因为是在把程序运行的时候才装入内存的
编译的时候根本不知道函数会被装入内存的哪个地方
所以不能call 绝对地址 来寻址
InitCommonControls是comctl32.dll在程序运行的时候被加载到程序地址空间之后
API函数InitCommonControls所在的首地址
如果 源代码 使用类似:
MessageBox(NULL,"Hello","Hello",MB_OK)
那么得到的 反汇编 代码不是你这样的而是这样的:
call 0040101A
........
:0040101A jmp dword [00402008]指向MessageBox函数
为什么要用效率这么低的方式呢?
因为编译器无法区别输入函数的调用和普通函数的调用
这里的call 0040101A指令从实际源代码中来而并非来自输入表的 函数指针
接下去会call到一个jmp指令,jmp指令来自于为输入函数准备的输入库(lib)
所以call以后的代码 都不是你能控制的了,因为这由输入库决定了
你给出的那种调用方式
源代码中是这样定义函数的(这些都在头文件中,有兴趣自己去找下):
void __declspec(dllimport) InitCommonControls(void);
这样就会产生call dword ptr [408030]; 而不是call XXXXXXXX
此外编译器讲给函数加上_imp_前缀,然后送给 连接器 ,这样可以直接把_imp_XXX送给输入表这样就不要jmp指令了
对于你的问题
我自己先写一段:
#include<windows.h>
#include<commctrl.h>
#pragma comment(lib,"comctl32.lib")
//_declspec(dllimport) void InitCommonControls(void);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int iCmdShow)
{
InitCommonControls();
MessageBox(NULL,"Hello","Hello",MB_OK);
return 0;
}
对initCommonControls函数的调用我得到的反汇编代码是call dword ptr ds:[42A1D0](不同操作系统,编译器编译出来地址不一样的)
由于这个函数怎么也不做编译器在编译的时候直接给出自己的代码mov eax,eax而并没有真正调用Windows API 所以你在PE文件中找不到这个函数
下面来说明MessageBox地址是怎么找到的:
在反汇编中 这个函数地址是
0042A320H
我们现在要知道的就是在exe没有被装入内存之前PE文件内部0042A320里面放的究竟是什么
先分析下 文件
由于建议装入地址是00400000
所以0042A320实际上处于相对 虚拟地址 (RVA)2A320处
正好处于idata节区内
因为2A000对应文件偏移28000
所以2A320对应文件便宜281D0
所以2A320对应文件便宜28320处
用WinHex查看文件28320结果是
0002A350这显然不会是MessageBox的内存地址
但是这也还是个RVA,处在idata中减去节首地址0002A000H是350H
相对节首28000H偏移350
查看文件偏移00028350H处发现过去两个字节就是MessageBox函数名了
有了函数名就能在内存中找到函数地址
有了函数地址就能调用了
楼主还有问题吗?看不懂的话仔细研究下PE文件的输入表和仔细分析下lib库文件就懂了
你没发现call后面是DWORD PTR吗?这说明什么?
这说明call能寻址所有4GB地址空间
楼下的那个回答更是扯谈
32位的PE文件根本就不能用debug调试
楼主给出的明显是32位汇编代码
别拿你的16位汇编过来了!
楼主我想告诉你的是32位汇编没有段地址 偏移地址的概念
如果真的要跟16位汇编联系起来
那么你可以这么认为所有段地址寄存器在程序中都是0(实际上 段寄存器 保存的是段描述符)
所有在程序中给出的地址都是32位偏移地址,也就是程序地址空间的 绝对地址
call dword ptr [408030];这条指令我估计你是在OD这些调试工具下面看到的
对于408030这个问题
如果不是API函数而是程序自身函数
一般在程序中是直接call 函数首地址的
但是对于API函数因为是在把程序运行的时候才装入内存的
编译的时候根本不知道函数会被装入内存的哪个地方
所以不能call 绝对地址 来寻址
InitCommonControls是comctl32.dll在程序运行的时候被加载到程序地址空间之后
API函数InitCommonControls所在的首地址
如果 源代码 使用类似:
MessageBox(NULL,"Hello","Hello",MB_OK)
那么得到的 反汇编 代码不是你这样的而是这样的:
call 0040101A
........
:0040101A jmp dword [00402008]指向MessageBox函数
为什么要用效率这么低的方式呢?
因为编译器无法区别输入函数的调用和普通函数的调用
这里的call 0040101A指令从实际源代码中来而并非来自输入表的 函数指针
接下去会call到一个jmp指令,jmp指令来自于为输入函数准备的输入库(lib)
所以call以后的代码 都不是你能控制的了,因为这由输入库决定了
你给出的那种调用方式
源代码中是这样定义函数的(这些都在头文件中,有兴趣自己去找下):
void __declspec(dllimport) InitCommonControls(void);
这样就会产生call dword ptr [408030]; 而不是call XXXXXXXX
此外编译器讲给函数加上_imp_前缀,然后送给 连接器 ,这样可以直接把_imp_XXX送给输入表这样就不要jmp指令了
对于你的问题
我自己先写一段:
#include<windows.h>
#include<commctrl.h>
#pragma comment(lib,"comctl32.lib")
//_declspec(dllimport) void InitCommonControls(void);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int iCmdShow)
{
InitCommonControls();
MessageBox(NULL,"Hello","Hello",MB_OK);
return 0;
}
对initCommonControls函数的调用我得到的反汇编代码是call dword ptr ds:[42A1D0](不同操作系统,编译器编译出来地址不一样的)
由于这个函数怎么也不做编译器在编译的时候直接给出自己的代码mov eax,eax而并没有真正调用Windows API 所以你在PE文件中找不到这个函数
下面来说明MessageBox地址是怎么找到的:
在反汇编中 这个函数地址是
0042A320H
我们现在要知道的就是在exe没有被装入内存之前PE文件内部0042A320里面放的究竟是什么
先分析下 文件
由于建议装入地址是00400000
所以0042A320实际上处于相对 虚拟地址 (RVA)2A320处
正好处于idata节区内
因为2A000对应文件偏移28000
所以2A320对应文件便宜281D0
所以2A320对应文件便宜28320处
用WinHex查看文件28320结果是
0002A350这显然不会是MessageBox的内存地址
但是这也还是个RVA,处在idata中减去节首地址0002A000H是350H
相对节首28000H偏移350
查看文件偏移00028350H处发现过去两个字节就是MessageBox函数名了
有了函数名就能在内存中找到函数地址
有了函数地址就能调用了
楼主还有问题吗?看不懂的话仔细研究下PE文件的输入表和仔细分析下lib库文件就懂了