PE文件格式详解(下)
2006-07-20 11:43:35 来源:WEB开发网导入数据段,.idata
.idata段是导入数据,包括导入库和导入地址名称表。虽然定义了IMAGE_DIRECTORY_ENTRY_IMPORT,但是WINNT.H之中并无相应的导入目录结构。作为代替,其中有若干其它的结构,名为IMAGE_IMPORT_BY_NAME、IMAGE_THUNK_DATA与IMAGE_IMPORT_DESCRIPTOR。在我个人看来,我实在不知道这些结构是如何和.idata段发生关联的,所以我花了若干个小时来破译.idata段实体并且得到了一个更简单的结构,我名之为IMAGE_IMPORT_MODULE_DIRECTORY。 // PEFILE.H
和其它段的数据目录不同的是,这个是作为文件中的每个导入模块重复出现的。你可以将它看作模块数据目录列表中的一个入口,而不是一个整个数据段的数据目录。每个入口都是一个指向特定模块导入信息的目录。
typedef struct tagImportDirectory
{
DWORD dwRVAFunctionNameList;
DWORD dwUseless1;
DWORD dwUseless2;
DWORD dwRVAModuleName;
DWORD dwRVAFunctionAddressList;
} IMAGE_IMPORT_MODULE_DIRECTORY, *PIMAGE_IMPORT_MODULE_DIRECTORY;
IMAGE_IMPORT_MODULE_DIRECTORY结构中的一个域dwRVAModuleName是一个相对虚拟地址,它指向模块的名称。结构中还有两个dwUseless参数,它们是为了保持段的对齐。PE文件格式规范提到了一些东西,关于导入标记、时间/日期标志以及主/次版本,但是在我的实验中,这两个域自始而终都是空的,所以我仍然认为它们没有什么用处。
基于这个结构的定义,你便可以获得可执行文件中导入的所有模块和函数名称了。以下的函数示范了如何获得特定的PE文件中的所有导入函数名称: //PEFILE.C
这个函数非常好懂,然而有一点值得指出——注意while循环。这个循环当pid->dwRVAModuleName为0的时候终止,这就暗示了在IMAGE_IMPORT_MODULE_DIRECTORY结构列表的末尾有一个空的结构,这个结构拥有一个0值,至少dwRVAModuleName域为0。这便是我在对文件的实验中以及之后在PE文件格式中研究的行为。
int WINAPI GetImportModuleNames(LPVOID lpFile, HANDLE hHeap, char **pszModules)
{
PIMAGE_IMPORT_MODULE_DIRECTORY pid;
IMAGE_SECTION_HEADER idsh;
BYTE *pData;
int nCnt = 0, nSize = 0, i;
char *pModule[1024];
char *psz;
pid = (PIMAGE_IMPORT_MODULE_DIRECTORY)ImageDirectoryOffset
(lpFile, IMAGE_DIRECTORY_ENTRY_IMPORT);
pData = (BYTE *)pid;
/* 定位.idata段头部 */
if (!GetSectionHdrByName(lpFile, &idsh, ".idata"))
return 0;
/* 提取所有导入模块 */
while (pid->dwRVAModuleName)
{
/* 为绝对字符串偏移量分配缓冲区 */
pModule[nCnt] = (char *)(pData +
(pid->dwRVAModuleName-idsh.VirtualAddress));
nSize += strlen(pModule[nCnt]) + 1;
/* 增至下一个导入目录入口 */
pid++;
nCnt++;
}
/* 将所有字符串赋值到一大块的堆内存中 */
*pszModules = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, nSize);
psz = *pszModules;
for (i = 0; i < nCnt; i++)
{
strcpy(psz, pModule[i]);
psz += strlen (psz) + 1;
}
return nCnt;
}
更多精彩
赞助商链接