PEtools
Posted zhuh102
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PEtools相关的知识,希望对你有一定的参考价值。
// PETools.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <malloc.h>
DWORD len=0; //记录文件读取时的大小 作为还原内存镜像缓冲区时的长度
//=======================================================================================================================================
/*将文件从硬盘读取到缓冲区中
参数1 :文件路径 参数2:接受读取数据的缓冲区的地址的指针【指针的指针】
读取成功返回文件的长度 读取失败则返回0
文件缓冲区用于存储读入的文件,这里需要注意malloc申请的空间即使是在函数内部,其申请的空间在函数返回时,也不会被销毁,而是什么时候调用free函数什么时候被销毁
*/
DWORD ReadFileToBuffer(IN LPSTR FilePath,OUT LPVOID* PFileBuffer);
//========================================================================================================================================
//将文件从文件缓冲区拷贝到镜像缓冲区中
//读取成功则返回镜像的大小,如果读取事变则返回0
//虽然第二个参数是二级指针,但是,取一级指针的地址便可
DWORD CopyFromFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer);
//==========================================================================================================================================
//从镜像缓冲区还原到文件缓冲区中
//参数1:内存镜像缓冲区地址
//参数2:文件缓冲区地址的地址 是个二级指针
//返回值 还原成功则返回新文件缓冲区的大小 还原失败则返回0
DWORD CopyFromImageBufferToFileBuffer(IN PVOID pImageBuffer,OUT LPVOID* pNewFileBuffer );
//========================================================================================================================================
//将内存总的虚拟地址转化为文件中的偏移地址
//参数1 文件缓冲区地址
//参数2 内存偏移地址RVA
//Rva地址转文件偏移地址
DWORD RvaToOffset(LPVOID pFileBuffer,DWORD dwRva);
//====================================================================================================================================
//手动修复IAT表 根据倒入表修复IAT表
//参数 文件读入缓冲区地址
//返回值 修复成功则返回TRUE 修复失败则返回FALSE
BOOL ReparIATTable(LPVOID pFileBuffer);
//==================================================================================================================================
//打印DLL文件的导入表内容
BOOL DLLExPortTable(LPVOID pFileBuffer);
//=====================================================================================================================================
//测试将文件读取到文件缓冲区
//参数无
void TestReadFileToBuffer();
//=======================================================================================================================================
//测试将PE拉伸到镜像缓冲区中
void TestCopyFromFileBufferToImageBuffer();
//=======================================================================================================================================
//测试将内存镜像缓冲区还原到新的文件缓冲区并写出到磁盘文件中测试是够能够成功运行
void TestCopyFromImageBufferToFileBuffer();
//=======================================================================================================================================
//测试将RVA转化为FileOffset
void TestRvaToOffset();
//=====================================================================================================================================
//测试修复IAT表
void TestReparIATTable();
//=========================================================================================================================================
//测试打印DLL输出表
void TestDLLExPortTable();
DWORD main(int argc, char* argv[])
{
//TestReadFileToBuffer(); //当从镜像缓冲区拷贝到文件缓冲区的时候需要运行TestReadFileToBuffer()获取len
//TestCopyFromFileBufferToImageBuffer();
//TestCopyFromImageBufferToFileBuffer();
//TestRvaToOffset();
//TestReparIATTable();
TestDLLExPortTable();
getchar();
return 0;
}
//将文件读取到文件缓冲区中
DWORD ReadFileToBuffer(IN LPSTR FilePath,OUT LPVOID* pFileBuffer){
FILE* pFile=NULL;
DWORD fileSize=0;
LPVOID pTempFileBuffer=NULL;
pFile=fopen(FilePath,"rb");
if(!pFile){
printf("无法打开该文件\n");
return 0;
}
fseek(pFile,0,SEEK_END);
fileSize=ftell(pFile);
len=fileSize;
fseek(pFile,0,SEEK_SET);
//分配内存空间
pTempFileBuffer=malloc(fileSize);
//强申请的空间初始化为0
memset(pTempFileBuffer,0,fileSize);
if(!pTempFileBuffer){
printf("申请空间失败\n");
fclose(pFile);
return 0;
}
int n=fread(pTempFileBuffer,fileSize,1,pFile);
if(!n){
printf("读取文件失败\n");
fclose(pFile);
free(pTempFileBuffer);
return 0;
}
*pFileBuffer=pTempFileBuffer;
pTempFileBuffer=NULL;
/* fclose(pFile);
FILE* outputStream=NULL;
outputStream=fopen("E:/miaobijing.exe","w+");
if(!outputStream){
printf("无法创建写入文件,请重新打开一个文件\n");
return 0;
}
else{
fwrite(pTempFileBuffer,fileSize,1,outputStream);
}
*/
return fileSize;
}
DWORD CopyFromFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer){
PIMAGE_DOS_HEADER pDosHeader=NULL;
PIMAGE_NT_HEADERS pNTHeaders=NULL;
PIMAGE_FILE_HEADER pPEHeader=NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader=NULL;
PIMAGE_SECTION_HEADER pSectionHeader=NULL;
DWORD ImageSize=0;
//判断文件缓冲区是否有效
if(pFileBuffer==NULL){
printf("文件缓冲区指针无效\n");
return 0;
}
//判断该文件是否是PE文件
if(*((PWORD)pFileBuffer)!=IMAGE_DOS_SIGNATURE){
printf("不是有效的DOS文件\n");
return 0;
}
pDosHeader=(PIMAGE_DOS_HEADER)(pFileBuffer);
if(*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew))!=IMAGE_NT_SIGNATURE){ //这里注意:FileBuffer是一个指针,也就是一个地址,所以转型为DWROD与pDosHeader->e_lfanew相加
printf("该文件不是有效的PE文件");
return 0;
}
// printf("DOS的开始地址是:%x\n",pDosHeader);
//NT头指针
pNTHeaders=(PIMAGE_NT_HEADERS)((DWORD)pDosHeader+pDosHeader->e_lfanew);
// printf("NT的开始地址是:%x\n",pNTHeaders);
//PE头指针等于NT头指针加四
pPEHeader=(PIMAGE_FILE_HEADER)(((DWORD)pFileBuffer+pDosHeader->e_lfanew)+4);
// printf("PE的开始地址是:%x\n",pPEHeader);
//血的教训,一个指针加上一个整数,加上的实际的大小是该指针表示的数据类型【去掉一个*】乘以整数
pOptionalHeader=(PIMAGE_OPTIONAL_HEADER)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);//指针在加数时务必将其转化为整形
// printf("optional的开始地址是:%x\n",pOptionalHeader);
pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pPEHeader->SizeOfOptionalHeader);
// printf("section表的开始地址是:%x\n",pSectionHeader);
//根据SIZE_OF_IMAGE来分配内存缓冲区的大小,虽然每一个应用程序在理论上都拥有独立的4GB虚拟内存,但是还是根据SIZE FOF IMAGE来分配内存大小
LPVOID pTempImageBuffer=NULL;
pTempImageBuffer=malloc(pOptionalHeader->SizeOfImage);
printf("文件的sizeofImage为%x\n",pOptionalHeader->SizeOfImage);
if(pTempImageBuffer==NULL){
printf("分配内存镜像文件失败\n");
}
memset(pTempImageBuffer,0,pOptionalHeader->SizeOfImage);
//开始从文件缓冲区拷贝到镜像缓冲区中 1:第一步:将所有的头拷贝到镜像缓冲区中 DosHeader+NTHeader+SectionHeader
memcpy(pTempImageBuffer,pFileBuffer,pOptionalHeader->SizeOfHeaders);
int i;
PIMAGE_SECTION_HEADER pTempSectionHeader=pSectionHeader;
for(i=0;i<pPEHeader->NumberOfSections;i++,pTempSectionHeader++){
memcpy((void*)((DWORD)pTempImageBuffer+pTempSectionHeader->VirtualAddress),(void*)((DWORD)pDosHeader+pTempSectionHeader->PointerToRawData),pTempSectionHeader->SizeOfRawData);
}
//临时打印测试代码
/* FILE* testStream=NULL;
testStream=fopen("E:/tempImageprint.exe","w+");
if(!testStream){
printf("文件打开失败\n");
}
fwrite(pTempImageBuffer,pOptionalHeader->SizeOfImage,1,testStream);*/
// printf("ImageBuffer的大小是:%d\n",pOptionalHeader->SizeOfImage);
// printf("malloc申请到的空间的大小是:%d\n");
*pImageBuffer=pTempImageBuffer;
pTempImageBuffer=NULL;
return pOptionalHeader->SizeOfImage;
}
void TestReadFileToBuffer(){
LPVOID pFileBuffer=NULL;
DWORD len= ReadFileToBuffer("E:/ReverseMe.exe",&pFileBuffer);
if(len!=0){
printf("文件读取成功,文件的长度为:%xh\n",len);
}
else{
printf("文件读取失败\n");
return;
}
}
void TestCopyFromFileBufferToImageBuffer(){
LPVOID pImageBuffer=NULL;
LPVOID pFileBuffer=NULL;
DWORD FileLen=0;
DWORD ImageLen=0;
FileLen= ReadFileToBuffer("E:/ReverseMe.exe",&pFileBuffer);
if(FileLen!=0){
printf("文件读取成功,文件的长度为:%xh\n",FileLen);
}
else{
printf("文件读取失败\n");
return;
}
ImageLen=CopyFromFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
if(!ImageLen){
printf("从文件缓冲区拷贝到镜像缓冲区失败\n");
return;
}
else{
printf("从文件缓冲区拷贝到镜像缓冲区成功\r\n镜像缓冲区的长度为%x\n",ImageLen);
}
}
DWORD CopyFromImageBufferToFileBuffer(IN PVOID pImageBuffer,OUT LPVOID* pNewFileBuffer ){
PIMAGE_DOS_HEADER pDosHeader=NULL;
PIMAGE_NT_HEADERS pNTHeaders=NULL;
PIMAGE_FILE_HEADER pPEHeader=NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader=NULL;
PIMAGE_SECTION_HEADER pSectionHeader=NULL;
// DWORD ImageSize=0;
//判断文件缓冲区是否有效
if(pImageBuffer==NULL){
printf("内存镜像缓冲区指针无效\n");
return 0;
}
//判断该文件是否是PE文件
if(*((PWORD)pImageBuffer)!=IMAGE_DOS_SIGNATURE){
printf("不是有效的DOS内存镜像缓冲区\n");
return 0;
}
pDosHeader=(PIMAGE_DOS_HEADER)(pImageBuffer);
if(*((PDWORD)((DWORD)pImageBuffer+pDosHeader->e_lfanew))!=IMAGE_NT_SIGNATURE){ //这里注意:FileBuffer是一个指针,也就是一个地址,所以转型为DWROD与pDosHeader->e_lfanew相加
printf("该文件不是有效的PE文件");
return 0;
}
// printf("DOS的开始地址是:%x\n",pDosHeader);
//NT头指针
pNTHeaders=(PIMAGE_NT_HEADERS)((DWORD)pDosHeader+pDosHeader->e_lfanew);
// printf("NT的开始地址是:%x\n",pNTHeaders);
//PE头指针等于NT头指针加四
pPEHeader=(PIMAGE_FILE_HEADER)(((DWORD)pDosHeader+pDosHeader->e_lfanew)+4); // pPEHeader=(PIMAGE_FILE_HEADER)(((DWORD)pFileBuffer+pDosHeader->e_lfanew)+4);
// printf("PE的开始地址是:%x\n",pPEHeader);
//血的教训,一个指针加上一个整数,加上的实际的大小是该指针表示的数据类型【去掉一个*】乘以整数
pOptionalHeader=(PIMAGE_OPTIONAL_HEADER)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);//指针在加数时务必将其转化为整形
// printf("optional的开始地址是:%x\n",pOptionalHeader);
pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pPEHeader->SizeOfOptionalHeader);
// printf("section表的开始地址是:%x\n",pSectionHeader);
//根据SIZE_OF_IMAGE来分配内存缓冲区的大小,虽然每一个应用程序在理论上都拥有独立的4GB虚拟内存,但是还是根据SIZE FOF IMAGE来分配内存大小
PVOID pTempFileBuffer=NULL;
pTempFileBuffer=malloc(len);
printf("文件的大小为%x\n\r",len);
if(pTempFileBuffer==NULL){
printf("新的文件缓冲区申请失败\r\n");
free(pTempFileBuffer);
return 0;
}
memset(pTempFileBuffer,0,len);
//开始从文件缓冲区拷贝到镜像缓冲区中 1:第一步:将所有的头拷贝到镜像缓冲区中 DosHeader+NTHeader+SectionHeader
memcpy(pTempFileBuffer,pImageBuffer,pOptionalHeader->SizeOfHeaders);
int i;
PIMAGE_SECTION_HEADER pTempSectionHeader=pSectionHeader;
for(i=0;i<pPEHeader->NumberOfSections;i++,pTempSectionHeader++){
memcpy((void*)((DWORD)pTempFileBuffer+pTempSectionHeader->PointerToRawData),(void*)((DWORD)pDosHeader+pTempSectionHeader->VirtualAddress),pTempSectionHeader->SizeOfRawData);
}
//临时打印测试代码
/* FILE* testStream=NULL;
testStream=fopen("E:/tempImageprint.exe","w+");
if(!testStream){
printf("文件打开失败\n");
}
fwrite(pTempImageBuffer,pOptionalHeader->SizeOfImage,1,testStream);*/
// printf("ImageBuffer的大小是:%d\n",pOptionalHeader->SizeOfImage);
// printf("malloc申请到的空间的大小是:%d\n");
*pNewFileBuffer=pTempFileBuffer;
pTempFileBuffer=NULL;
return len;
}
void TestCopyFromImageBufferToFileBuffer(){
LPVOID pImageBuffer=NULL;
LPVOID pFileBuffer=NULL;
LPVOID pNewFileBuffer=NULL;
DWORD FileLen=0;
DWORD ImageLen=0;
DWORD NewFileLen=0;
FileLen= ReadFileToBuffer("E:/ReverseMe.exe",&pFileBuffer);
if(FileLen!=0){
printf("文件读取成功,文件的长度为:%xh\n",FileLen);
}
else{
printf("文件读取失败\n");
return;
}
ImageLen=CopyFromFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
if(!ImageLen){
printf("从文件缓冲区拷贝到镜像缓冲区失败\n");
return;
}
else{
printf("从文件缓冲区拷贝到镜像缓冲区成功\r\n镜像缓冲区的长度为%x\n",ImageLen);
}
NewFileLen=CopyFromImageBufferToFileBuffer(pImageBuffer,&pNewFileBuffer);
if(!NewFileLen){
printf("内存镜像还原失败\n\r");
return;
}
FILE* OutputStream=NULL;
OutputStream=fopen("E:/hah.exe","w+");
if(!OutputStream){
printf("写出文件打开失败\n\r");
return;
}
fwrite(pNewFileBuffer,NewFileLen,1,OutputStream);
}
//=====================================================================================================================================
DWORD RvaToOffset(LPVOID pFileBuffer,DWORD dwRva)
{
int i;
DWORD Offset;
int NumberOfSection;
PIMAGE_NT_HEADERS lpPeHeader;
PIMAGE_SECTION_HEADER lpSection;
Offset=NULL;
lpPeHeader=(PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+PIMAGE_DOS_HEADER(pFileBuffer)->e_lfanew);
NumberOfSection=lpPeHeader->FileHeader.NumberOfSections;
lpSection=(PIMAGE_SECTION_HEADER) ((DWORD)lpPeHeader + sizeof(IMAGE_NT_HEADERS));
//首先判断该RVA是位于Section中还是位于HEADERS中,也就是说,如果RVA是小于第一个区块的VirtualAddress的那么它在文件中的偏移和在内存镜像中的偏移是一样的,都是应该小于SizeOfHeaders
if(dwRva<lpSection->VirtualAddress){
return dwRva;
}
for(i=0;i<NumberOfSection;i++){
if((dwRva>=lpSection->VirtualAddress)&&(dwRva<(lpSection->VirtualAddress+lpSection->SizeOfRawData))){//if((dwRva>=lpSection->VirtualAddress)&&(dwRva<(lpSection->VirtualAddress+lpSection->SizeOfRawData))){
Offset=lpSection->PointerToRawData+dwRva-lpSection->VirtualAddress;
return Offset;
}
lpSection++;
}
return Offset;
}
void TestRvaToOffset(){
LPSTR FilePath="C:\\Users\\。\\Desktop\\ReverseMe.exe";
LPVOID FileBuffer=NULL;
LPVOID pImageBuffer=NULL;
DWORD ReadLen=ReadFileToBuffer(FilePath,&FileBuffer);
if(!ReadLen){
printf("文件读入失败\n\r");
return;
}
// DWORD ImageLen=CopyFromFileBufferToImageBuffer(FileBuffer,&pImageBuffer);
DWORD FileOffset=RvaToOffset(FileBuffer,0x1030);
printf("1030 RVA 在文件中的偏移地址为:%x\r\n",FileOffset);
}
BOOL ReparIATTable(LPVOID pFileBuffer){
PIMAGE_NT_HEADERS lpNTHeader;
PIMAGE_FILE_HEADER lpFileHeader;
PIMAGE_OPTIONAL_HEADER lpOptionHeader;
PIMAGE_SECTION_HEADER lpSectionHeader;
PIMAGE_DATA_DIRECTORY lpDataDirectory;//这里使用数组指针去访问数组元素 而数组元素也是一个结构体
PIMAGE_IMPORT_DESCRIPTOR lpImportDescriptor;
//PIMAGE_THUNK_DATA lpThunkData;
lpNTHeader=(PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+PIMAGE_DOS_HEADER(pFileBuffer)->e_lfanew);
lpFileHeader=(PIMAGE_FILE_HEADER)&lpNTHeader->FileHeader;
lpOptionHeader=(PIMAGE_OPTIONAL_HEADER)&lpNTHeader->OptionalHeader;
lpDataDirectory=(PIMAGE_DATA_DIRECTORY)lpOptionHeader->DataDirectory;
lpSectionHeader=(PIMAGE_SECTION_HEADER) ((DWORD)lpNTHeader + sizeof(IMAGE_NT_HEADERS));
lpImportDescriptor=(PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer+RvaToOffset(pFileBuffer,lpDataDirectory[1].VirtualAddress));//数据目录表中第二项描述的是导入表
DWORD i=0;
//先循环打印出导入表所中OriginalFirstTHUNK和FirstTHUNK两个表中地址所指向的API函数名,因为在程序加载到内存之前这两项的数据是完全一样的
//导入表是一个接着一个的最后会用相同大小空白大小来表示结束,所以只要判断倒入白中的OriginalFirstTHUNK和FirstTHUNK为0则表示导入表结束
while(!((lpImportDescriptor->FirstThunk==0)&&(lpImportDescriptor->OriginalFirstThunk==0))){
//打印每个导入模块的地址 需要将RVA转化为FileOffset
printf("=======第%d个模块为======%s=============\n",i,(LPVOID)((DWORD)pFileBuffer+(RvaToOffset(pFileBuffer,lpImportDescriptor->Name))));
//获取该模块的地址 也就是传说中每个.exe或者是每个DLL的IMAGEBASE
HMODULE hModule=LoadLibrary((CHAR*)((DWORD)pFileBuffer+(RvaToOffset(pFileBuffer,lpImportDescriptor->Name))));
//指向IMAGE_THUNK_DATA表的指针
PDWORD pOriginalThunk=(PDWORD)((DWORD)pFileBuffer+RvaToOffset(pFileBuffer,lpImportDescriptor->OriginalFirstThunk));//直接转化为在文件中的地址
printf("ORIGINAL THUNK 00000000000000000000000000000000000000\n");
while(*pOriginalThunk){
//先判断该函数市按照名字导出的还是按照序号导出的//判断第32位是0还是1 如果是1按照名称导出的,该数值为指向名称的一个指针 如果是0则是按照序号导出的 该数值的低31位为序号
if(*pOriginalThunk & IMAGE_ORDINAL_FLAG32){
printf("导出序号为:%d====================>>",*pOriginalThunk & 0x0fff);
printf("函数地址为%6x\n\r",GetProcAddress(hModule,(CHAR*)(*pOriginalThunk & 0x0fff)));
}
else{
PIMAGE_IMPORT_BY_NAME lpImportByName=(PIMAGE_IMPORT_BY_NAME)((DWORD)pFileBuffer+RvaToOffset(pFileBuffer,*pOriginalThunk));
printf("函数名称为%s==================>>",lpImportByName->Name);
printf("函数地址为%6x\n\r",GetProcAddress(hModule,(CHAR*)lpImportByName->Name));
//Sleep(100);
}
pOriginalThunk++;
}
PDWORD pFirstlThunk=(PDWORD)((DWORD)pFileBuffer+RvaToOffset(pFileBuffer,lpImportDescriptor->FirstThunk));//直接转化为在文件中的地址
printf("FIRST THUNK fffffffffffffffffffffffffffffffffffffff\n");
while(*pFirstlThunk){
//先判断该函数市按照名字导出的还是按照序号导出的
if(*pFirstlThunk & IMAGE_ORDINAL_FLAG32){//判断第32位是0还是1 如果是1按照名称导出的 如果是0则是按照序号导出的低31位为序号
printf("导出序号为:%d\n\r",*pFirstlThunk & 0x0fff);
}
else{
PIMAGE_IMPORT_BY_NAME lpImportByName=(PIMAGE_IMPORT_BY_NAME)((DWORD)pFileBuffer+RvaToOffset(pFileBuffer,*pFirstlThunk));
printf("%s\n",lpImportByName->Name);
//Sleep(100);
}
pFirstlThunk++;
}
i++;
lpImportDescriptor++;
}
return TRUE;
}
void TestReparIATTable(){
LPSTR FilePath="C:\\Users\\。\\Desktop\\shutdown_10.0.6.0_setup_5.exe";
LPVOID FileBuffer=NULL;
DWORD ReadLen=ReadFileToBuffer(FilePath,&FileBuffer);
if(!ReadLen){
printf("文件读入失败\n\r");
return;
}
ReparIATTable(FileBuffer);
}
BOOL DLLExPortTable(LPVOID pFileBuffer){
if(pFileBuffer==NULL){
printf("文件为空\n");
return FALSE;
}
PIMAGE_NT_HEADERS lpNTHeader;
PIMAGE_FILE_HEADER lpFileHeader;
PIMAGE_OPTIONAL_HEADER lpOptionHeader;
PIMAGE_DATA_DIRECTORY lpDataDirectory;//这里使用数组指针去访问数组元素 而数组元素也是一个结构体
PIMAGE_EXPORT_DIRECTORY lpExportDirectory;
lpNTHeader=(PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+PIMAGE_DOS_HEADER(pFileBuffer)->e_lfanew);
lpFileHeader=(PIMAGE_FILE_HEADER)&lpNTHeader->FileHeader;
lpOptionHeader=(PIMAGE_OPTIONAL_HEADER)&lpNTHeader->OptionalHeader;
lpDataDirectory=(PIMAGE_DATA_DIRECTORY)lpOptionHeader->DataDirectory;//数组名就是一个地址,所以这里不需要再像上面一样区地址
lpExportDirectory=(PIMAGE_EXPORT_DIRECTORY)((DWORD)pFileBuffer+RvaToOffset(pFileBuffer,lpDataDirectory[0].VirtualAddress));
//获取函数名称表的地址并将其转化为一个指针类型
PDWORD pAddressOfNames=(PDWORD)((DWORD)pFileBuffer+RvaToOffset(pFileBuffer,lpExportDirectory->AddressOfNames));
printf("下列为函数名称表为:==========================NAME=============================\n");
while(*pAddressOfNames){
CHAR* pStrName=(CHAR*)((DWORD)pFileBuffer+RvaToOffset(pFileBuffer,*pAddressOfNames));
printf("%s\n",pStrName);
pAddressOfNames++;
}
PDWORD pAddressOFOrdianl=(PDWORD)((DWORD)pFileBuffer+RvaToOffset(pFileBuffer,lpExportDirectory->AddressOfNameOrdinals));
printf("函数到处序号表为============Ordianls===================:\n");
while(*pAddressOFOrdianl){
printf("%8x\n",*pAddressOFOrdianl);
pAddressOFOrdianl++;
}
PDWORD pAddressOfFunctionTable=(PDWORD)((DWORD)pFileBuffer+RvaToOffset(pFileBuffer,lpExportDirectory->AddressOfFunctions));
printf("导出函数地址表为:================================\n");
while(*pAddressOfFunctionTable){
printf("%d\n",*pAddressOfFunctionTable);
pAddressOfFunctionTable++;
}
printf("导出函数的起始序号为==============:%x",lpExportDirectory->Base);
printf("到处函数的数目为:=============%d",lpExportDirectory->NumberOfFunctions);
printf("按名字到处的函数数目为:================%d",lpExportDirectory->NumberOfNames);
return TRUE;
}
void TestDLLExPortTable(){
LPSTR FilePath="C:\\Users\\。\\Desktop\\wiadss.dll";
LPVOID FileBuffer=NULL;
DWORD ReadLen=ReadFileToBuffer(FilePath,&FileBuffer);
if(!ReadLen){
printf("文件读入失败\n\r");
return ;
}
BOOL Result=DLLExPortTable(FileBuffer);
if(!Result){
return;
}
}
以上是关于PEtools的主要内容,如果未能解决你的问题,请参考以下文章