一个模块的导入段包含一组DLL。为了让模块能够运行,这些DLL是必须的。导入段还包含一个符号表。它列出了该模块从各DLL中导入的符号。当模块调用这些导入符号的时候,系统实际上会调用转换函数,获得导入函数在导入表的地址,然后再跳到相应的位置。如果我们能将导入段中相应导入函数的地址替换成自定义的函数的地址,即可实现对该函数的拦截。在自定义的函数中,我们既可以调用拦截的函数,也可以执行其他工作。
要实现修改导入段来拦截API必须对PE文件格式有很好的了解。网上关于它的资料铺天盖地,自己搜吧。此处不打算介绍。
为了修改要拦截的函数在导入段的地址,首先要获得PE文件导入段的地址。这可以调用ImageDirectoryEntryToData.函数。
PVOID WINAPI ImageDirectoryEntryToData( __in PVOID Base, __in BOOLEAN MappedAsImage, __in USHORT DirectoryEntry, __out PULONG Size ); |
Base为要获得导入段所在模块的基地址。它一般是GetModuleHandle的返回值。
MappedAsImage,它为true时,系统将该模块以映像文件的形式映射,否则以数据文件的形式映射。
DirectoryEntry,要获得的段的索引。此函数不仅仅能够获得导入段的地址,根据此索引的不同,该函数返回对应段的地址。此处我们使用 IMAGE_DIRECTORY_ENTRY_IMPORT表示我们要获得导入段的地址。
Size返回表项的大小。注意其类型。
看代码:
ULONG size; HMODULE hModule=GetModuleHandle(NULL); PIMAGE_IMPORT_DESCRIPTOR pImport= ImageDirectoryEntryToData(hModule,true,IMAGE_DIRECTORY_ENTRY_IMPORT,&size); while(pImport->FirstThunk) { int i=0; char *ModuleName=(char*)((BYTE*)hModule+pImport->Name); PIMAGE_THUNK_DATA pThunk=(PIMAGE_THUNK_DATA) ((BYTE*)hModule+pImport->FirstThunk); while(pThunk->u1.Function) { char*Func=(char*)((BYTE*)hModule+pThunk->u1.AddressOfData+2); If(Func=="MessageBoxA") { MessageBox("找到函数"); } } } |