导入函数的疑问

fangkmjo 2009-08-28 08:52:01
Windows的API都是导入函数,程序调用API首先要从导入表中取得函数的地址,继而转向函数的执行代码,我有几个疑问:
1. PROC pfn = (PROC)::MessageBoxA, 这取得的地址是函数的真实地址还是其在导入表中的地址(我想应该是真实地址)?
2. 程序调用API是怎么区别和普通函数的调用的?
...全文
144 21 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
fangkmjo 2009-08-29
  • 打赏
  • 举报
回复
自己写程序测试了,
PMessageBox pfn1 = (PMessageBox)::MessageBoxA;
PMessageBox pfn = (PMessageBox)::GetProcAddress( ::GetModuleHandle(_T("User32")), "MessageBoxA");
这两种方法取得的都是函数在DLL中的实际地址,也就是函数在IAT中保存的地址,而不是IAT的地址
fangkmjo 2009-08-29
  • 打赏
  • 举报
回复
PMessageBox pfn1 = (PMessageBox)::MessageBoxA;
PMessageBox pfn = (PMessageBox)::GetProcAddress( ::GetModuleHandle(_T("User32")), "MessageBoxA");
我获取到的pfn1 和pfn 地址相同啊,难道都是IAT的地址?
野男孩 2009-08-29
  • 打赏
  • 举报
回复
1.  PROC pfn = (PROC)::MessageBoxA, 这取得的地址是函数的真实地址还是其在导入表中的地址(我想应该是真实地址)?

IAT中的地址,不是真实的地址

2.  程序调用API是怎么区别和普通函数的调用的?

调用的API肯定有include头文件,里面有声明,但是所有cpp中没有定义。在对应lib里面才有link信息。
一般函数的话,编译器会在cpp中找到函数的定义直接调用的。
jingzhongrong 2009-08-29
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 fangkmjo 的回复:]
自己写程序测试了,
PMessageBox pfn1 = (PMessageBox)::MessageBoxA;
PMessageBox  pfn  = (PMessageBox)::GetProcAddress( ::GetModuleHandle(_T("User32")), "MessageBoxA");
这两种方法取得的都是函数在DLL中的实际地址,也就是函数在IAT中保存的地址,而不是IAT的地址
[/Quote]

取得得地址肯定是一样的,IAT表中的地址是程序加载过程中由系统填写的,程序加载完毕后通过IAT表就能获取对应dll导入的函数的地址。
这个地址和使用GetProcAddress取得的地址肯定是一样的。
而GetProcAddress是通过读取dll的导出表查找函数名称(或序号)来获得函数相对于dll基地址的偏移,并加上基地址得到函数地址。(详细流程可反汇编ntdll.dll中的LdrGetProcedureAddress)
MoXiaoRab 2009-08-28
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 jingzhongrong 的回复:]
引用 14 楼 wltg2001 的回复:
看样子,我以前的理解有错啊!我以前觉得用LIB文件时,在链接过程中用到到导入表,不过仔细想想,大家的说法了对,在用GetProcAddress得到址时,这个函数内部还是会用到导入表的.


GetProcAddress应该是查找对应dll的导出表来获取偏移得到函数地址的吧。
[/Quote]
同意
jingzhongrong 2009-08-28
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 wltg2001 的回复:]
看样子,我以前的理解有错啊!我以前觉得用LIB文件时,在链接过程中用到到导入表,不过仔细想想,大家的说法了对,在用GetProcAddress得到址时,这个函数内部还是会用到导入表的.
[/Quote]

GetProcAddress应该是查找对应dll的导出表来获取偏移得到函数地址的吧。
MoXiaoRab 2009-08-28
  • 打赏
  • 举报
回复
对啊,我就说嘛。当初我们搞IAT Hook的时候....都是去IAT中找API的地址,然后进行替换实现Hook的
wltg2001 2009-08-28
  • 打赏
  • 举报
回复
看样子,我以前的理解有错啊!我以前觉得用LIB文件时,在链接过程中用到到导入表,不过仔细想想,大家的说法了对,在用GetProcAddress得到址时,这个函数内部还是会用到导入表的.
jingzhongrong 2009-08-28
  • 打赏
  • 举报
回复
我想问下lz的“真实地址”指的是?
jingzhongrong 2009-08-28
  • 打赏
  • 举报
回复
IAT得到的地址。
fangkmjo 2009-08-28
  • 打赏
  • 举报
回复
汇编码
00449413 mov eax,dword ptr [__imp__MessageBoxA@16 (4DE8C0h)]
00449418 mov dword ptr [pfn],eax
.....
.....
00449430 call dword ptr [pfn]
貌似还是通过IAT调用的啊
jingzhongrong 2009-08-28
  • 打赏
  • 举报
回复
VC得到的汇编代码是
mov ebx,dword ptr [__imp__MessageBoxA@16 (10D20B8h)]
fangkmjo 2009-08-28
  • 打赏
  • 举报
回复
通过GetProcAddress获取的是函数的真实地址,不需要通过导入表调用,但我就想知道PROC pfn = (PROC)::MessageBoxA获得的是不是真实地址
jingzhongrong 2009-08-28
  • 打赏
  • 举报
回复
至于这句话,PROC pfn = (PROC)::MessageBoxA
应该还是从IAT获得的地址
jingzhongrong 2009-08-28
  • 打赏
  • 举报
回复
程序加载完毕后IAT中的值不就是对应函数的地址?
GetProcAddress是查找dll导出表获得的地址。
wltg2001 2009-08-28
  • 打赏
  • 举报
回复
我觉得您的第一点有点....讨论下?我怎么感觉API的调用都是从IAT中找到后,去相应的DLL中调用的?
==========================
这个我觉得用LoadLibrary方式调用API是用不到导入表的,以前我做基于导入表的API HOOK时,对于这种方法调用API是无效的,必须还要先HOOK LoadLibrary才成功
wltg2001 2009-08-28
  • 打赏
  • 举报
回复
自己的函数则是一个以push ebp开始,ret结束的过程,不过函数的调用都是call来调用罢了,方式很相似,都是先将参数按调用约定压栈
============
同意,一般API的调用约定都是_stdcall,函数采用从右到左的压栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。 int f(void *p) -->> _f@4
而一般C++的函数默认用_cdecl方式,按从右至左的顺序压参数入栈,由调用者把参数弹出栈。
MoXiaoRab 2009-08-28
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 wltg2001 的回复:]
PROC pfn = (PROC)::MessageBoxA, 这取得的地址是函数的真实地址还是其在导入表中的地址
=========
这种动态调用API的方法和导入表无关的,只有用LIB文件的静态调用API时才用到导入表.所以上面得到的地址是真实地址.

程序调用API是怎么区别和普通函数的调用的?
=================================
这个没有多大的区别,或者说这两者没有根本上的区别,程序在编译时并不分你调用的是API还是自已写的函数,它都当作一个函数来处理,对于API,因为你自己的程序没有实现它,所以链接时会在LIB文件中找导入表,然后链接.普通函数因为是自己实现的,没有这一步.
[/Quote]
我觉得您的第一点有点....讨论下?我怎么感觉API的调用都是从IAT中找到后,去相应的DLL中调用的?比如MessageBox,在自己的程序调用的时候,其实调用的是User32.dll中那个。以前常用OD调程序,发现的。
MoXiaoRab 2009-08-28
  • 打赏
  • 举报
回复
自己的函数则是一个以push ebp开始,ret结束的过程,不过函数的调用都是call来调用罢了,方式很相似,都是先将参数按调用约定压栈
wltg2001 2009-08-28
  • 打赏
  • 举报
回复
PROC pfn = (PROC)::MessageBoxA, 这取得的地址是函数的真实地址还是其在导入表中的地址
=========
这种动态调用API的方法和导入表无关的,只有用LIB文件的静态调用API时才用到导入表.所以上面得到的地址是真实地址.

程序调用API是怎么区别和普通函数的调用的?
=================================
这个没有多大的区别,或者说这两者没有根本上的区别,程序在编译时并不分你调用的是API还是自已写的函数,它都当作一个函数来处理,对于API,因为你自己的程序没有实现它,所以链接时会在LIB文件中找导入表,然后链接.普通函数因为是自己实现的,没有这一步.
加载更多回复(1)

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧