用C写的一个PE分析工具(含源码)
程序功能概述:可以显示DOS头,PE头,区块表,输入表,输出表
欢迎兄弟们反馈BUG,多多提意见
代码:
//**************************************************************
//Name:PE Info Detector
//Code:by 鹭影依凌
//**************************************************************
#include "stdio.h"
#include "windows.h"
//**************************************************************
//全局变量声明
//**************************************************************
FILE *p; //文件对象
UINT myCurFileOffset; //当前指针
UINT myCurVirtOffset; //虚拟地址
UINT i; //循环计数器
//**************************************************************
//全局函数声明
//**************************************************************
//@ChgRvaToFileOffset: 功能:虚拟地址转化为文件的物理地址
//VirtualOffset: 虚拟地址
//sectionVirtOffset: 当前节的虚拟地址
//sectionFileOffset: 当前节的物理地址
//@NumOfFunc: 区段的数目
UINT ChgRvaToFileOffset(UINT VirtualOffset,UINT sectionVirtOffset[],UINT sectionFileOffset[],UINT NumOfFunc);
//**************************************************************
//主函数Main
//**************************************************************
int main()
{
//---------------------------
//PE头变量
//---------------------------
IMAGE_DOS_HEADER myDosHeader; //DOS头
IMAGE_FILE_HEADER myFileHeader; //PE头
IMAGE_OPTIONAL_HEADER32 myOptionalHeader; //PE头
//区块表和区块
IMAGE_SECTION_HEADER mySectionHeader; //区块表
//数据目录树
IMAGE_EXPORT_DIRECTORY myExportTable; //[00]输出表
IMAGE_IMPORT_DESCRIPTOR myImportTable; //[01]输入表
//***********************************************************
//打开文件,获取文件对象指针
//***********************************************************
char filename[20] = ""; //文件名
printf("请输入文件名:");
gets(filename);
printf("\n");
p = fopen(filename,"r+b"); //打开文件
if(p==NULL)
{
MessageBox(NULL,"没有找到目标文件","提示",MB_OK);
return 0;
}
//***********************************************************
//监测Dos Signature
//***********************************************************
WORD myDosSignature;
fseek(p,0,SEEK_SET);
fread(&myDosSignature,sizeof(WORD),1,p);
if(myDosSignature != IMAGE_DOS_SIGNATURE)
{
MessageBox(NULL,"DOS头错误","提示",MB_OK);
return 0;
}
//***********************************************************
//读取Dos Header
//***********************************************************
fseek(p,0,SEEK_SET);
fread(&myDosHeader,sizeof(myDosHeader),1,p);
//***********************************************************
printf(";===================================================;\n");
printf("DOS头结构:\n");
printf(";---------------------------------------------------;\n");
printf("e_mageic : %04X\n",myDosHeader.e_magic);
printf("e_cblp : %04X\n",myDosHeader.e_cblp);
printf("e_cp : %04X\n",myDosHeader.e_cp);
printf("e_crlc : %04X\n",myDosHeader.e_crlc);
printf("e_cparhdr : %04X\n",myDosHeader.e_cparhdr);
printf("e_minalloc : %04X\n",myDosHeader.e_minalloc);
printf("e_maxalloc : %04X\n",myDosHeader.e_maxalloc);
printf("e_ss : %04X\n",myDosHeader.e_ss);
printf("e_sp : %04X\n",myDosHeader.e_sp);
printf("e_csum : %04X\n",myDosHeader.e_csum);
printf("e_ip : %04X\n",myDosHeader.e_ip);
printf("e_cs : %04X\n",myDosHeader.e_cs);
printf("e_lfarlc : %04X\n",myDosHeader.e_lfarlc);
printf("e_ovno : %04X\n",myDosHeader.e_ovno);
printf("e_res : %04X\n",myDosHeader.e_res);
printf("e_oemid : %04X\n",myDosHeader.e_oemid);
printf("e_oeminfo : %04X\n",myDosHeader.e_oeminfo);
printf("e_res2 : %04X\n",myDosHeader.e_res2);
printf("e_lfanew : %04X\n",myDosHeader.e_lfanew);
//***********************************************************
//读取NT SignNature
//***********************************************************
DWORD myNtSignature;
myCurFileOffset = myDosHeader.e_lfanew; //修改指针,指向NtHeader.
fseek(p,myCurFileOffset,SEEK_SET);
fread(&myNtSignature,sizeof(DWORD),1,p);
if(myNtSignature != IMAGE_NT_SIGNATURE)
{
MessageBox(NULL,"不是有效PE文件","提示",MB_OK);
return 0;
}
//***********************************************************
//读取File Header
//***********************************************************
myCurFileOffset = myDosHeader.e_lfanew + sizeof(DWORD); //修改指针,指向FileHeader.
fseek(p,myCurFileOffset,SEEK_SET);
fread(&myFileHeader,sizeof(IMAGE_FILE_HEADER),1,p);
printf(";===================================================;\n");
printf("IMAGE_File_HEADER 结构:\n");
printf(";---------------------------------------------------;\n");
printf("Machine :%04X \n",myFileHeader.Machine);
printf("NumberOfSections :%04X \n",myFileHeader.NumberOfSections);
printf("TimeDateStamp :%08X \n",myFileHeader.TimeDateStamp);
printf("PointerToSymbolTable:%08X \n",myFileHeader.PointerToSymbolTable);
printf("NumberOfSymbols :%08X \n",myFileHeader.NumberOfSymbols);
printf("SizeOfOptionalHeader:%04X \n",myFileHeader.SizeOfOptionalHeader);
printf("Characteristics :%04X \n",myFileHeader.Characteristics);
//***********************************************************
//读取Optional Header
//***********************************************************
myCurFileOffset += sizeof(IMAGE_FILE_HEADER); //修改指针,指向optional header
fseek(p,myCurFileOffset,SEEK_SET);
fread(&myOptionalHeader,sizeof(myOptionalHeader),1,p);
printf(";===================================================;\n");
printf("IMAGE_OPTIONAL_HEADER 结构:\n");
printf(";---------------------------------------------------;\n");
printf("Magic :%04X\n",myOptionalHeader.Magic);
printf("MajorLinkerVersion :%04X\n",myOptionalHeader.MajorLinkerVersion);
printf("MinorLinkerVersion :%04X\n",myOptionalHeader.MinorLinkerVersion);
printf("SizeOfCode :%04X\n",myOptionalHeader.SizeOfCode);
printf("SizeOfInitializedData :%04X\n",myOptionalHeader.SizeOfInitializedData);
printf("SizeOfUninitializedData :%04X\n",myOptionalHeader.SizeOfUninitializedData);
printf("AddressOfEntryPoint :%04X\n",myOptionalHeader.AddressOfEntryPoint);
printf("BaseOfCode :%04X\n",myOptionalHeader.BaseOfCode);
printf("BaseOfData :%04X\n",myOptionalHeader.BaseOfData);
// NT additional fields.
printf("ImageBase :%04X\n",myOptionalHeader.ImageBase);
printf("SectionAlignment :%04X\n",myOptionalHeader.SectionAlignment);//内存对齐尺寸
printf("FileAlignment :%04X\n",myOptionalHeader.FileAlignment);//文件对齐尺寸
printf("MajorOperatingSystemVersion :%04X\n",myOptionalHeader.MajorOperatingSystemVersion);
printf("MinorOperatingSystemVersion :%04X\n",myOptionalHeader.MinorOperatingSystemVersion);
printf("MajorImageVersion :%04X\n",myOptionalHeader.MajorImageVersion);
printf("MinorImageVersion :%04X\n",myOptionalHeader.MinorImageVersion);
printf("MajorSubsystemVersion :%04X\n",myOptionalHeader.MajorSubsystemVersion);
printf("MinorSubsystemVersion :%04X\n",myOptionalHeader.MinorSubsystemVersion);
printf("Win32VersionValue :%04X\n",myOptionalHeader.Win32VersionValue);
printf("MinorLinkerVersion :%04X\n",myOptionalHeader.SizeOfImage);
printf("SizeOfImage :%04X\n",myOptionalHeader.SizeOfHeaders);
printf("CheckSum :%04X\n",myOptionalHeader.CheckSum);
printf("Subsystem :%04X\n",myOptionalHeader.Subsystem);
printf("DllCharacteristics :%04X\n",myOptionalHeader.DllCharacteristics);
printf("SizeOfStackReserve :%04X\n",myOptionalHeader.SizeOfStackReserve);
printf("SizeOfStackCommit :%04X\n",myOptionalHeader.SizeOfStackCommit);
printf("MinorLinkerVersion :%04X\n",myOptionalHeader.SizeOfHeapReserve);
printf("SizeOfHeapReserve :%04X\n",myOptionalHeader.SizeOfHeapCommit);
printf("LoaderFlags :%04X\n",myOptionalHeader.LoaderFlags);
printf("NumberOfRvaAndSizes :%04X\n",myOptionalHeader.NumberOfRvaAndSizes);
//***********************************************************
//读取Data Directory
//***********************************************************
printf(";===================================================;\n");
printf("数据目录树结构:\n");
printf(";---------------------------------------------------;\n");
for( i=0;i<16;i++) //循环输出数据目录树
{
printf("DataDirectory[%x]->",i);
printf("VirtualAddress: %08X ",myOptionalHeader.DataDirectory[i].VirtualAddress);
printf("Size:%04X ",myOptionalHeader.DataDirectory[i].Size);
printf("\n");
}
//***********************************************************
//读取Section Header
//***********************************************************
UINT sectionVirtOffset[20] = {0,0,0,0,0,0,0,0,0,0}; //虚拟地址
UINT sectionFileOffset[20] = {0,0,0,0,0,0,0,0,0,0}; //文件地址
UINT NumOfFunc = myFileHeader.NumberOfSections;
myCurFileOffset += myFileHeader.SizeOfOptionalHeader; //修改指针,指向第一个Section Table;
fseek(p,myCurFileOffset,SEEK_SET);
fread(&mySectionHeader,sizeof(IMAGE_SECTION_HEADER),1,p);
printf(";============================================================;\n");
printf("区段信息:\n");
printf(";------------------------------------------------------------;\n");
printf(" name |VOffset |VSize |ROffset |RSize |Flags \n");
for(i = 0; i < myFileHeader.NumberOfSections; i++)
{
printf("%-6s ",mySectionHeader.Name); //区段名字
printf("%08X ",mySectionHeader.VirtualAddress); //虚拟偏移
printf("%08X ",mySectionHeader.Misc.VirtualSize); //虚拟大小
printf("%08X ",mySectionHeader.PointerToRawData); //文件偏移
printf("%08X ",mySectionHeader.SizeOfRawData); //文件大小
printf("%08X ",mySectionHeader.Characteristics);
sectionVirtOffset[i] = mySectionHeader.VirtualAddress;
sectionFileOffset[i] = mySectionHeader.PointerToRawData;
printf("\n");
fseek(p,myCurFileOffset + (i+1)*sizeof(IMAGE_SECTION_HEADER),SEEK_SET);
fread(&mySectionHeader,sizeof(IMAGE_SECTION_HEADER),1,p);
}
//***********************************************************
//读取“[0]输出表”
//***********************************************************
myCurVirtOffset = myOptionalHeader.DataDirectory[0].VirtualAddress;//修改指针,指向输出表
myCurFileOffset = ChgRvaToFileOffset(myCurVirtOffset,sectionVirtOffset,sectionFileOffset,NumOfFunc);
//若存在输入表,则输出
if(myCurVirtOffset > 0)
{
fseek(p,myCurFileOffset,SEEK_SET);
fread(&myExportTable,sizeof(IMAGE_EXPORT_DIRECTORY),1,p);
printf(";============================================================;\n");
printf("输出表结构:\n");
printf(";------------------------------------------------------------;\n");
printf("Characteristics %08X\n",myExportTable.Characteristics);
printf("TimeDateStamp %08X\n",myExportTable.TimeDateStamp);
printf("MajorVersion %08X\n",myExportTable.MajorVersion);
printf("MinorVersion %08X\n",myExportTable.MinorVersion);
printf("Name %08X\n",myExportTable.Name);
printf("Base %08X\n",myExportTable.Base);
printf("NumberOfFunctions %08X\n",myExportTable.NumberOfFunctions);
printf("NumberOfNames %08X\n",myExportTable.NumberOfNames);
printf("AddressOfFunctions %08X\n",myExportTable.AddressOfFunctions);
printf("AddressOfNameOrdinals %08X\n",myExportTable.AddressOfNameOrdinals);
printf("AddressOfNames %08X\n",myExportTable.AddressOfNames);
printf(";************************************************************;\n");
printf("输出函数:\n");
printf(";------------------------------------------------------------;\n");
printf("Ordinal RVA Offset Name \n");
printf(";------------------------------------------------------------;\n");
for(i = 0;i < myExportTable.NumberOfNames;i++)
{
//一些壳对PE做了修改,做下校验(32 lite)
if(myExportTable.AddressOfNames == 0)
break;
//-------------------------------------------------------|
printf("number[%d] ",i+1); //序号
//-------------------------------------------------------|
UINT arrayVirtOffset = myExportTable.AddressOfFunctions + i * sizeof(DWORD);//数组地址的RVA
UINT arrayFileOffset = ChgRvaToFileOffset(arrayVirtOffset,sectionVirtOffset,sectionFileOffset,NumOfFunc);
fseek(p,arrayFileOffset,SEEK_SET);
UINT arrayData =0;
fread(&arrayData,sizeof(DWORD),1,p);
printf("%08X ",arrayData); //RVA
//-------------------------------------------------------|
UINT OffsetExpFuc = ChgRvaToFileOffset(arrayData,sectionVirtOffset,sectionFileOffset,NumOfFunc);
printf("%08X ",OffsetExpFuc); //Offset
//-------------------------------------------------------|
char myExportDll[40];
UINT virtOffsetExpName = myExportTable.AddressOfNames + i * sizeof(DWORD);//数组地址的RVA
UINT fileOffsetExpName = ChgRvaToFileOffset(virtOffsetExpName,sectionVirtOffset,sectionFileOffset,NumOfFunc);//数组在文件中地址
fseek(p,fileOffsetExpName,SEEK_SET);
UINT expTemp =0;
fread(&expTemp,40,1,p);
UINT addresAnother = ChgRvaToFileOffset(expTemp,sectionVirtOffset,sectionFileOffset,NumOfFunc);
fseek(p,addresAnother,SEEK_SET);
fread(&myExportDll,40,1,p);
printf("%s\n",myExportDll); //API Name
//-------------------------------------------------------|
}
printf("\n");
}
//************************************************************
//读取“[1]输入表”
//************************************************************
myCurVirtOffset = myOptionalHeader.DataDirectory[1].VirtualAddress;//修改指针,指向输出入表
myCurFileOffset = ChgRvaToFileOffset(myCurVirtOffset,sectionVirtOffset,sectionFileOffset,NumOfFunc);
//读取输入表
fseek(p,myCurFileOffset,SEEK_SET);
fread(&myImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p);
printf(";=======================================================================================;\n");
printf("输入表结构\n");
printf(";---------------------------------------------------------------------------------------;\n");
printf("DllName |OriginalFirstThunk |TimeDateStamp |ForwarderChain |Name |FirstThunk\n");
printf(";---------------------------------------------------------------------------------------;\n");
i = 0;
//循环输出
while(myImportTable.FirstThunk != NULL)
{
char mydllname[20];
UINT mychar = ChgRvaToFileOffset(myImportTable.Name,sectionVirtOffset,sectionFileOffset,NumOfFunc);
fseek(p,mychar,SEEK_SET);
fread(&mydllname,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p);
printf("%-12s ", mydllname);
printf("%08X ",myImportTable.OriginalFirstThunk);
printf("%08X ", myImportTable.TimeDateStamp);
printf("%08X ", myImportTable.ForwarderChain);
printf("%08X ", myImportTable.Name);
printf("%08X \n", myImportTable.FirstThunk);
fseek(p,myCurFileOffset+(i+1) * sizeof(IMAGE_IMPORT_DESCRIPTOR),SEEK_SET);
fread(&myImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p);
i++;
}
printf("\n");
//***********************************************************
//IAT函数
//***********************************************************
myCurVirtOffset = myOptionalHeader.DataDirectory[1].VirtualAddress;//修改指针,指向输出入表
myCurFileOffset = ChgRvaToFileOffset(myCurVirtOffset,sectionVirtOffset,sectionFileOffset,NumOfFunc);
printf(";=======================================================================================;\n");
printf("IAT相关函数\n");
printf(";***************************************************************************************;\n");
i = 0;
//读取输入表
fseek(p,myCurFileOffset,SEEK_SET);
fread(&myImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p);
while(myImportTable.FirstThunk != NULL)
{
char mydllname[20];
UINT fileOffsetImpName = ChgRvaToFileOffset(myImportTable.Name,sectionVirtOffset,sectionFileOffset,NumOfFunc);
fseek(p,fileOffsetImpName,SEEK_SET);
fread(&mydllname,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p);
//printf("DllName |OriginalFirstThunk |TimeDateStamp |ForwarderChain |Name |FirstThunk\n");
printf("%-12s ", mydllname);
printf("%08X ",myImportTable.OriginalFirstThunk);
printf("%08X ", myImportTable.TimeDateStamp);
printf("%08X ", myImportTable.ForwarderChain);
printf("%08X ", myImportTable.Name);
printf("%08X \n", myImportTable.FirstThunk);
printf(";---------------------------------------------------------------------------------------;\n");
UINT fileOffsetIAT = ChgRvaToFileOffset(myImportTable.FirstThunk,sectionVirtOffset,sectionFileOffset,NumOfFunc);
printf("@Thunk RVA @Thunk Offset @Tank Value @hint/OrDinal @API NAME\n");
unsigned int k = 0;
while(true)
{
//判断是否终结
UINT myTankValue = 0;
fseek(p,fileOffsetIAT + k*sizeof(DWORD),SEEK_SET);
fread(&myTankValue,sizeof(DWORD),1,p);
if(myTankValue == 0)
break;
//----------------------------------------------------------------|
printf(" %08X ", myImportTable.FirstThunk + k * sizeof(DWORD));//虚拟地址
printf("%08X ",fileOffsetIAT + k * sizeof(WORD)); //文件地址
printf("%08X ",myTankValue); //ThankVALUE
//----------------------------------------------------------------|
UINT impTemp =0;
UINT myTankWordVale = ChgRvaToFileOffset(myTankValue,sectionVirtOffset,sectionFileOffset,NumOfFunc);
fseek(p,myTankWordVale,SEEK_SET);
fread(&impTemp,sizeof(WORD),1,p);
printf(" %04X ",impTemp); //OrDinal
//----------------------------------------------------------------|
UINT myFucOffset = ChgRvaToFileOffset(myTankValue,sectionVirtOffset,sectionFileOffset,NumOfFunc);
char myFucName[40];
int m = 0;
for(m=0;m<100;m++)
{
BYTE myByte = 0;
fseek(p,myFucOffset,SEEK_SET);
fread(&myByte,sizeof(BYTE),1,p);
if(myByte>=0x20 && myByte <= 0x7F)
{
fseek(p,myFucOffset+1,SEEK_SET);
fread(&myByte,sizeof(BYTE),1,p);
if(myByte<0x20)
myFucOffset++;
else
break;
}
else
myFucOffset++;
}
fseek(p,myFucOffset,SEEK_SET);
fread(&myFucName,40,1,p);
printf(" %-s \n",myFucName); //API NAME
k++;
}
printf(" \n");
printf(";***************************************************************************************;\n");
fseek(p,myCurFileOffset+(i+1) * sizeof(IMAGE_IMPORT_DESCRIPTOR),SEEK_SET);
fread(&myImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR),1,p);
i++;
}
fclose(p);
system("pause");
return 0;
}
UINT ChgRvaToFileOffset(UINT VirtualOffset,UINT sectionVirtOffset[],UINT sectionFileOffset[],UINT NumOfFunc)
{
int temp = 0;
UINT counter;
for(counter =0;counter < NumOfFunc-1;counter++)
{
//依次排查
if((VirtualOffset >= sectionVirtOffset[counter]) && (VirtualOffset < sectionVirtOffset[counter+1]))
{
if(sectionFileOffset[counter] == 0)
return 0;
else
{
temp = sectionVirtOffset[counter] - sectionFileOffset[counter];
break;
}
}
}
//落在最后一个区段的情形
if(counter == (NumOfFunc-1))
temp = sectionVirtOffset[counter] - sectionFileOffset[counter];
return (VirtualOffset - temp);
}