// 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的更多相关文章

  1. PEtools PE操作工具类C++

    源码来自各大网友并非原创修改了部分函数 仅供参考(PE没源码参考应该是很吃力的) 暂未更新完持续更新中....... PETools.h //函数头 int GetFileLength(FILE *p ...

  2. WIM镜像添加多语言支持

    起初的想法: intel 600p虽然速度一般,但pcie还是值得一试的.购买后发现原来的win7版本无法识别就找了KB2990941和KB3087873两个补丁,成功识别出了硬盘.期间通过dezor ...

  3. 使用 Windows AIK 创建自定的客户端系统WIM文件

    Windows 7/2008 的AIK 3.0下载页面:地址链接 1.8G [3.1补充包为1.4G] 安装3.0后,升级为3.1方法: xcopy E:\ "C:\Program File ...

  4. DIY_hlstudio_WIN7PE【69M】网络版【89M】

    DIY_hlstudio_WIN7PE[69M]网络版[89M] hlstudio的骨头版PE非常精简,由于启动方式和用法不同,个人进行了如下修改:1.原来的合盘修改为bootmgr直接起动ISO镜像 ...

  5. 通用 PE 工具箱1.9.6(XP内核)by Uepon(李培聪)

    通用 PE 工具箱1.9.6(XP内核)by Uepon(李培聪)官网:http://hi.baidu.com/uepon?page=21.8版论坛帖子:http://bbs.wuyou.net/fo ...

  6. 制作Win7(x86)PE ISO文件

    WinPE3.1     —Win7 x86 PE V3.1: waik_supplement_zh-cn.isoDVD: cn_windows_7_professional_with_sp1_x86 ...

  7. PE格式的理解(待补充)

    PE文件格式 一.基本结构 1.DOS头一般到节区头成为PE头部分,其下称为PE体.文件的内容一般可分为代码(.text).数据(.data).资源(.rsrc),分别保存. 2.PE头与各节区的尾部 ...

  8. 手动修复IAT

    现在我们已经了解了IAT的的工作原理,现在我们来一起学习手动修复IAT,一方面是深入了解运行过程一方面是为了避免遇到有些阻碍自动修复IAT的壳时不知所措. 首先我们用ESP定律找到加了UPX壳后的OE ...

  9. 动手制作属于你自己的WIN PE3.0

    最近想要更新公司的网Ghost系统,所以小研究一下win pe ,在网上看见一个很不错的教程,在这里分享给大家! 并非原创,纯属转载!!O(∩_∩)O~天缘的作品,很是佩服这个哥们啊..... 一.W ...

随机推荐

  1. 小猪cms微信二次开发之怎样分页

    $db=D('Classify'); $zid=$db->where(array('id'=>$this->_GET('fid'),'token'=>$this->tok ...

  2. bash的管道符与重定向

    管道符"|"可以用来将前面的程序的标准输出stdout(=1)重定向到后一个程序的stdin(=0),但是忽略了stderr. 在bash中使用2>&1 可以表示将s ...

  3. 5分钟部署ELK+filebeat5.1.1

    标题有点噱头,不过网络环境好的情况下也差不多了^_^   1. 首先保证安装了jdk.   elasticsearch, logstash, kibana,filebeat都可以通过yum安装,这里前 ...

  4. JavaScript中让Html页面中循环播放文字

    JavaScript中让Html页面中循环播放文字 <html> <head> <meta http-equiv="Content-Type" con ...

  5. centos 6.4 getmail 收取163 邮件

    #CentOS 6.6 64bit 默认yum 源没有getmail rpm包#首先安装EPEL yum 源EPEL(Extra Packages for Enterprise Linux):http ...

  6. IRequiresSessionState接口控制

    刚刚接触.net web端的朋友都会被Session坑过,莫名其妙的不能读取Session数据,后来知道原来有IRequiresSessionState这个接口,不继承的就不能读取Session里面的 ...

  7. sql 注入问题

    1. 关于使用intval强制转换成数字的问题.数字大于2147483647会出现溢出出现负数.使用个方法来替代这个吧$n="\n";$a=2147483648.05555;ech ...

  8. 关于MySQL存储过程中遇到的一个错误

    执行结果: 查询:)) comment '操作变量' begin set var='MySQL%Orcle%DeLL%IBM'; select replace(var,'%'... 共 行受到影响 执 ...

  9. 【转】MySQL索引背后的数据结构及算法原理

    摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...

  10. Android之下拉刷新的ListView

    不废话,代码里面注释很详细,直接上代码: 自定义的RefreshableListView代码: public class RefreshableListView extends ListView im ...