windows导出表的函数转发
函数转发
PE文件的导出表主要由三部分组成:导出名称表ENT,导出序号表和导出地址表EAT。导出名称表中存放的是导出函数对应的名称字符串的RVA,导出地址表中存放的是导出函数的函数地址的RVA,而导出序号表中就是用来连接导出名称表和导出地址表的。导出名称表和序号表一一对应,而序号表中存放了对应的导出地址表的索引。
如果DLL中导出的函数存在函数转发,那么导出地址表中存放的就是转发的函数名称的RVA。利用dumpbin查看user32.dll中的转发函数,发现导出函数中有四个函数被转发DefDlgProcA/W, DefWindowProcA/W. 转发到ntdll模块的NtdllDefDlgProc_A/W, NtdllDefWindowProc_A/W.
windows加载器在加载此dll时如果发现其导出函数含有转发函数的话就会将转发的目标dll也加载到内存中,并且会修改对应导出地址表中的值为转发的目标函数的RVA(此RVA横跨了两个不同的模块)。
这就产生了一个有趣的现象,如果我们的程序中调用了一个dll中的导出函数是一个转发函数,windows在进行IAT表填充时是根据查询对应dll的导出地址表获取到实际的函数地址。因为windows加载在加载此dll时已经将此转发函数的导出地址表项改为了目标转发函数,所以实际填充进IAT的地址也就是目标转发函数的地址。同理通过GetProcAddress调用函数也是通过查询dll的导出地址表,因此返回的也是目标转发函数的地址
在dll中导出转发的函数
只要使用这条语句就可以将本DLL的导出函数转发到其他DLL的函数中。
#pragma comment(linker, "/export:本DLL导出函数=其他DLL.函数名")
可以利用windows的函数转发机制注入dll(也就是dll劫持),只需要将待劫持的dll的导出函数在自己的dll中也导出同名的,然后进行转发到待劫持的dll对应的函数中。最后将自己的dll更改为被劫持dll的名称(被劫持dll也需要改名),这样就可以在不影响原程序运行的情况下执行自己的操作。