PE文件格式详解(下)

来源: 作者: 2007-10-24 出处:pcdog.com

dos  ssl  操作系统  虚拟内存  
上一页 1 2 3 4 5 6 7 8 9 下一页 

  这个结构中的第一个域dwRVAFunctionNameList是一个相对虚拟地址,这个地址指向一个相对虚拟地址的列表,这些地址是文件中的一些文件名。

如下面的数据所示,所有导入模块的模块和函数名称都列于.idata段数据中了: E6A7 0000 F6A7 0000 08A8 0000 1AA8 0000 ................
28A8 0000 3CA8 0000 4CA8 0000 0000 0000 (...<...L.......
0000 4765 744F 7065 6E46 696C 654E 616D ..GetOpenFileNam
6541 0000 636F 6D64 6C67 3332 2E64 6C6C eA..comdlg32.dll
0000 2500 4372 6561 7465 466F 6E74 496E ..%.CreateFontIn
6469 7265 6374 4100 4744 4933 322E 646C directA.GDI32.dl
6C00 A000 4765 7444 6576 6963 6543 6170 l...GetDeviceCap
7300 C600 4765 7453 746F 636B 4F62 6A65 s...GetStockObje
6374 0000 D500 4765 7454 6578 744D 6574 ct....GetTextMet
7269 6373 4100 1001 5365 6C65 6374 4F62 ricsA...SelectOb
6A65 6374 0000 1601 5365 7442 6B43 6F6C ject....SetBkCol
6F72 0000 3501 5365 7454 6578 7443 6F6C or..5.SetTextCol
6F72 0000 4501 5465 7874 4F75 7441 0000 or..E.TextOutA..
以上的数据是EXEVIEW.EXE示例程序.idata段的一部分。这个特别的段表示了导入模块列表和函数名称列表的起始处。如果你开始检查数据中的这个段,你应该认出一些熟悉的Win32 API函数以及模块名称。从上往下读的话,你可以找到GetOpenFileNameA,紧接着是COMDLG32.DLL。然后你能发现CreateFontIndirectA,紧接着是模块GDI32.DLL,以及之后的GetDeviceCaps、GetStockObject、GetTextMetrics等等。

  这样的式样会在.idata段中重复出现。第一个模块是COMDLG32.DLL,第二个是GDI32.DLL。请注意第一个模块只导出了一个函数,而第二个模块导出了很多函数。在这两种情况下,函数和模块的排列的方法是首先出现一个函数名,之后是模块名,然后是其它的函数名(如果有的话)。

  以下的函数示范了如何获得指定模块的所有函数名。 // PEFILE.C
int WINAPI GetImportFunctionNamesByModule(LPVOID lpFile, HANDLE hHeap,
  char *pszModule, char **pszFunctions)
{
 PIMAGE_IMPORT_MODULE_DIRECTORY pid;
 IMAGE_SECTION_HEADER idsh;
 DWORD dwBase;
 int nCnt = 0, nSize = 0;
 DWORD dwFunction;
 char *psz;
 /* 定位.idata段的头部 */
 if (!GetSectionHdrByName(lpFile, &idsh, ".idata"))
  return 0;
 pid = (PIMAGE_IMPORT_MODULE_DIRECTORY)ImageDirectoryOffset
   (lpFile, IMAGE_DIRECTORY_ENTRY_IMPORT);
 dwBase = ((DWORD)pid. idsh.VirtualAddress);
 /* 查找模块的pid */
 while (pid->dwRVAModuleName && strcmp (pszModule,
   (char *)(pid->dwRVAModuleName+dwBase)))
  pid++;
 /* 如果模块未找到,就退出 */
 if (!pid->dwRVAModuleName)
  return 0;
 /* 函数的总数和字符串长度 */
 dwFunction = pid->dwRVAFunctionNameList;
 while (dwFunction && *(DWORD *)(dwFunction + dwBase) &&
   *(char *)((*(DWORD *)(dwFunction + dwBase)) + dwBase+2))
 {
  nSize += strlen ((char *)((*(DWORD *)(dwFunction +
   dwBase)) + dwBase+2)) + 1;
  dwFunction += 4;
  nCnt++;
 }
 /* 在堆上分配函数名称的空间 */
 *pszFunctions = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nSize);
 psz = *pszFunctions;
 /* 向内存指针复制函数名称 */
 dwFunction = pid->dwRVAFunctionNameList;
 while (dwFunction && *(DWORD *)(dwFunction + dwBase) &&
  *((char *)((*(DWORD *)(dwFunction + dwBase)) + dwBase+2)))
 {
  strcpy (psz, (char *)((*(DWORD *)(dwFunction + dwBase)) +
    dwBase+2));
  psz += strlen((char *)((*(DWORD *)(dwFunction + dwBase))+
    dwBase+2)) + 1;
  dwFunction += 4;
 }
 return nCnt;
}
  
就像GetImportModuleNames函数一样,这一函数依靠每个信息列表的末端来获得一个置零的入口。这在种情况下,函数名称列表就是以零结尾的。



上一页 1 2 3 4 5 6 7 8 9 下一页 
上一篇:PE文件格式详解(上)
下一篇:PE文件格式文档