PE文件格式详解(下)
2006-07-20 11:43:35 来源:WEB开发网导出数据段,.edata
.edata段包含了应用程序或DLL的导出数据。在这个段出现的时候,它会包含一个到达导出信息的导出目录。 // WINNT.H
导出目录中的Name域标识了可执行模块的名称。NumberOfFunctions域和NumberOfNames域表示模块中有多少导出的函数以及这些函数的名称。
typedef struct _IMAGE_EXPORT_DIRECTORY {
ULONG Characteristics;
ULONG TimeDateStamp;
USHORT MajorVersion;
USHORT MinorVersion;
ULONG Name;
ULONG Base;
ULONG NumberOfFunctions;
ULONG NumberOfNames;
PULONG *AddressOfFunctions;
PULONG *AddressOfNames;
PUSHORT *AddressOfNameOrdinals;
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
AddressOfFunctions域是一个到导出函数入口列表的偏移量。AddressOfNames域是到一个导出函数名称列表起始处偏移量的地址,这个列表是由null分隔的。AddressOfNameOrdinals是一个到相同导出函数顺序值(每个值2字节长)列表的偏移量。
三个AddressOf...域是当模块装载时进程地址空间中的相对虚拟地址。一旦模块被装载,那么要获得进程地质空间中的确切地址的话,就应该在相对虚拟地址上加上模块的基地址。可是,在文件被装载前,仍然可以决定这一地址:只要从给定的域地址中减去段头部的虚拟地址(VirtualAddress),再加上段实体的偏移量(PointerToRawData),这个结果就是映像文件中的偏移量了。以下的例子解说了这一技术:
// PEFILE.C
请注意,在这个函数之中,变量pNames是由决定偏移量地址和当前偏移量位置的方法来赋值的。偏移量的地址和偏移量本身都是相对虚拟地址,因此在使用之前必须进行转换——函数之中体现了这一点。虽然你可以编写一个类似的函数来决定顺序值或函数入口点,但是我为什么不为你做好呢?——GetNumberOfExportedFunctions、GetExportFunctionEntryPoints和GetExportFunctionOrdinals已经存在于PEFILE.DLL之中了。
int WINAPI GetExportFunctionNames(LPVOID lpFile, HANDLE hHeap, char **pszFunctions)
{
IMAGE_SECTION_HEADER sh;
PIMAGE_EXPORT_DIRECTORY ped;
char *pNames, *pCnt;
int i, nCnt;
/* 获得.edata域中的段头部和指向数据目录的指针 */
if ((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset
(lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)) == NULL)
return 0;
GetSectionHdrByName (lpFile, &sh, ".edata");
/* 决定导出函数名称的偏移量 */
pNames = (char *)(*(int *)((int)ped->AddressOfNames -
(int)sh.VirtualAddress + (int)sh.PointerToRawData +
(int)lpFile) - (int)sh.VirtualAddress +
(int)sh.PointerToRawData + (int)lpFile);
/* 计算出要为所有的字符串分配多少内存 */
pCnt = pNames;
for (i = 0; i < (int)ped->NumberOfNames; i++)
while (*pCnt++);
nCnt = (int)(pCnt.pNames);
/* 在堆上为函数名称分配内存 */
*pszFunctions = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nCnt);
/* 将所有字符串复制到缓冲区 */
CopyMemory((LPVOID)*pszFunctions, (LPVOID)pNames, nCnt);
return nCnt;
}
更多精彩
赞助商链接