一般在VC中,只要包含了Windows.h就可以使用其中的API函数了,那么这些函数的地址是怎么得到的?预先就有的还是,我们的程序中动态得到的。如果是预先固定的那么请问,windows那么多版本,它怎么保证每一个版本的DLL中每一个函数的地址都是一样的呢?
如果不是那么请看我反汇编的一个简单的C代码
win2k+VC6
#include "stdafx.h"
#include "Windows.h"int main(int argc, char* argv[])
{
MessageBox(NULL,"Somebody Help!",NULL,MB_OK);
printf("Hello World!\n");
return 0;
}7:    int main(int argc, char* argv[])
8:    {
00401010   push        ebp
00401011   mov         ebp,esp
00401013   sub         esp,40h
00401016   push        ebx
00401017   push        esi
00401018   push        edi
00401019   lea         edi,[ebp-40h]
0040101C   mov         ecx,10h
00401021   mov         eax,0CCCCCCCCh
00401026   rep stos    dword ptr [edi]
9:        MessageBox(NULL,"Somebody Help!",NULL,MB_OK);
00401028   mov         esi,esp
0040102A   push        0
0040102C   push        0
0040102E   push        offset string "Somebody Help!" (0042002c)
00401033   push        0
00401035   call        dword ptr [__imp__MessageBoxA@16 (0042528c)]
0040103B   cmp         esi,esp
0040103D   call        __chkesp (00401100)
10:       printf("Hello World!\n");
00401042   push        offset string "Hello World!\n" (0042001c)
00401047   call        printf (00401080)
0040104C   add         esp,4
11:       return 0;
/***********************************************************************/
winxp+vc7
--- f:\vc70\test_del\test_del\main.cpp -----------------------------------------
#include "stdio.h"
#include "windows.h"
int main()
{
00411A40  push        ebp  
00411A41  mov         ebp,esp 
00411A43  sub         esp,0C0h 
00411A49  push        ebx  
00411A4A  push        esi  
00411A4B  push        edi  
00411A4C  lea         edi,[ebp-0C0h] 
00411A52  mov         ecx,30h 
00411A57  mov         eax,0CCCCCCCCh 
00411A5C  rep stos    dword ptr [edi] 
MessageBox(NULL,"123",NULL,MB_OK);
00411A5E  mov         esi,esp 
00411A60  push        0    
00411A62  push        0    
00411A64  push        offset string "123" (424024h) 
00411A69  push        0    
00411A6B  call        dword ptr [__imp__MessageBoxA@16 (42A314h)] 
00411A71  cmp         esi,esp 
00411A73  call        @ILT+935(__RTC_CheckEsp) (4113ACh) 
printf("OKKKKK");
00411A78  push        offset string "OKKKKK" (42401Ch) 
00411A7D  call        @ILT+1170(_printf) (411497h) 
00411A82  add         esp,4 
return 0;
00411A85  xor         eax,eax 
}
/***********************************************************************/
XP+VC6--- G:\test_del\test_del.cpp  ---------------------------------------------------------------------------------------------
1:    // test_del.cpp : Defines the entry point for the console application.
2:    //
3:
4:    #include "stdafx.h"
5:    #include "windows.h"
6:    int main(int argc, char* argv[])
7:    {
00401010   push        ebp
00401011   mov         ebp,esp
00401013   sub         esp,40h
00401016   push        ebx
00401017   push        esi
00401018   push        edi
00401019   lea         edi,[ebp-40h]
0040101C   mov         ecx,10h
00401021   mov         eax,0CCCCCCCCh
00401026   rep stos    dword ptr [edi]
8:        MessageBox(NULL,"123",NULL,MB_OK);
00401028   mov         esi,esp
0040102A   push        0
0040102C   push        0
0040102E   push        offset string "123" (0042002c)
00401033   push        0
00401035   call        dword ptr [__imp__MessageBoxA@16 (0042528c)]
0040103B   cmp         esi,esp
0040103D   call        __chkesp (00401100)
9:        printf("Hello World!\n");
00401042   push        offset string "Hello World!\n" (0042001c)
00401047   call        printf (00401080)
0040104C   add         esp,4
10:       return 0;
0040104F   xor         eax,eax
11:   }
00401051   pop         edi
00401052   pop         esi
00401053   pop         ebx
00401054   add         esp,40h
00401057   cmp         ebp,esp
00401059   call        __chkesp (00401100)
0040105E   mov         esp,ebp
00401060   pop         ebp
00401061   ret很奇怪吧,
vc7和vc6中MessageBox的地址是不一样的!!!!晕死了

解决方案 »

  1.   

    没有人会用入口地址来调API的吧:)
      

  2.   

    想要通过函数名称获得入口地址可以:g_hInstanceDll = LoadLibrary((LPCTSTR)"user32.dll"))GetProcAddress(g_hInstanceDll, "MessageBoxA");
      

  3.   

    你看看菜单中的:project--->settings--->link标签中的 “object/library module”
    中不是有一堆的例如:kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib
    入口的信息就在这些 .lib 的文件中
      

  4.   

    windows.h的主要模块有:kernel32、user32、gdi32
      

  5.   

    回复人: kuangjingbo(正在学习windows) ( ) 信誉:100  2004-05-04 21:29:00  得分:0 
     
     
      你看看菜单中的:project--->settings--->link标签中的 “object/library module”
    中不是有一堆的例如:kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib
    入口的信息就在这些 .lib 的文件中
      
     问题就出在这里,那些*.lib文件中它怎么知道某个API的入口地址的呢?莫非从Win95到windows2003这些API的位置就一直没有变动过,不会吧
      

  6.   

    纠正我短消息里的一个错误,的确,任何一个exe程序获得API的入口地址都是
    载入一个API所在的dll以后,使用GetProcAddress获得入口地址的,
    然后保存在IAT(Import Address Table)表里,你可以自由用OllyDbg或者SoftIce跟踪一下
      

  7.   

    好像不太对啊,我自己都觉得但是API的入口地址放在IAT(Import Address Table)是没有错的调用API都通过这个入口地址表,你不必担心入口地址不一样,只要函数名一致就可以了应该是从.lib文件里获得的,具体的如何取的我也说不清楚了
      

  8.   

    楼主帮忙顶一下这个贴:http://expert.csdn.net/Expert/topic/3027/3027142.xml?temp=.210232
      

  9.   

    取得api,的地址的事情是在load exe ,要开始运行之前,由PE Loader 来做的。而在exe 中,根本没有api 的地址,而仅仅是他的名字,或者是序号。pe loader 根据名字,或者是序号来得到api 的地址。这些名字,序号放在exe 的import table 中。
    还有call        dword ptr [__imp__MessageBoxA@16 (0042528c)]你如果看0042528c的内容就是一句 jmp 77xxxxxxx!转向真正的Messagebox的地址.
      

  10.   

    每一个exe都有一个Import Address Table
    在这个表里记载了引用了哪个dll的哪个函数(或使用名字,或使用序号)
    我上面已经修正了我的说法,这个Import Address Table里的入口地址
    是根据这些函数名字取得入口地址的,所有在不同的系统不用担心入口地址是多少例如:
    call dword ptr[0042528c]  // call MessageBoxA[0042528c]处的内容才是真正跳转到API的地方,为什么要这么call了以后再跳,我想就是为了适应不同的dll版本。至于如何获得的入口地址,正如由 fbmsf(FBM) 说的是由 PE Loader 来做的(之前我说的是不对的,我更正了)