首先先看看PE文件大体的样子:
还有几个主要的结构体:
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER;
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
//
// NT additional fields.
//
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics; // 0 for terminating null import descriptor
DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
};
DWORD TimeDateStamp; // 0 if not bound,
// -1 if bound, and real date\time stamp
// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
// O.W. date/time stamp of DLL bound to (Old BIND)
DWORD ForwarderChain; // -1 if no forwarders
DWORD Name;
DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA;
typedef struct _IMAGE_THUNK_DATA32 {
union {
PBYTE ForwarderString;
PDWORD Function;
DWORD Ordinal;
PIMAGE_IMPORT_BY_NAME AddressOfData;
} u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
它们之间的联系:
信息看到这么多,开始实现:
#include <stdio.h>
#include <windows.h>
// define区
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (addValue) )
#define MAX_NAME_LEN 256
// 全局变量区
FILE *hFile = NULL;
IMAGE_DOS_HEADER dos_header;
IMAGE_NT_HEADERS nt_header;
IMAGE_SECTION_HEADER *psection_header;
IMAGE_IMPORT_DESCRIPTOR *pimport_descriptor; // 输入表描述符
int numOfImportDescriptor; // 输入表项数
bool openFile(char * filename)
{
hFile = fopen(filename, "rb ");
if(!hFile)
{
printf( "open file error\n ");
return false;
}
return true;
}
void closeFile()
{
fclose(hFile);
}
bool readDosHeader()
{
size_t num = fread(&dos_header, sizeof(dos_header), 1, hFile);
if(num!=1)
{
printf( "open dos header error\n ");
return false;
}
else
return true;
}
bool readNtHeader()
{
int offset = dos_header.e_lfanew;
if(fseek(hFile, offset, SEEK_SET)!=0)
return false;
size_t num = fread(&nt_header, sizeof(IMAGE_NT_HEADERS), 1, hFile);
if(num != 1)
{
printf( "read nt header error\n ");
return false;
}
return true;
}
bool readSectionHeaders()
{
// 没有重定位,所以必须在readNtHeader()之后调用
int sectionNum = nt_header.FileHeader.NumberOfSections;
psection_header = new IMAGE_SECTION_HEADER[sectionNum];
size_t num = fread(psection_header, sizeof(IMAGE_SECTION_HEADER), sectionNum, hFile);
if(num != sectionNum)
{
printf( "read section header error\n ");
return false;
}
return true;
}
bool readImportDescriptor()
{
// 读取输入描述符
int offset = nt_header.OptionalHeader.DataDirectory[1].VirtualAddress;
int size = nt_header.OptionalHeader.DataDirectory[1].Size;
pimport_descriptor = (IMAGE_IMPORT_DESCRIPTOR *)new char[size];
if(fseek(hFile, offset, SEEK_SET)!=0)
return false;
size_t num = fread(pimport_descriptor, size, 1, hFile);
if(num != 1)
{
printf( "read import descriptor header error\n ");
return false;
}
numOfImportDescriptor = size/sizeof(IMAGE_IMPORT_DESCRIPTOR)-1;
return true;
}
void displayImportFunction(IMAGE_IMPORT_DESCRIPTOR &import_descriptor)
{
int offset = import_descriptor.OriginalFirstThunk;
if(fseek(hFile, offset, SEEK_SET)!=0)
return;
IMAGE_THUNK_DATA imageThunkData;
for(;;)
{
size_t iRead = fread(&imageThunkData, sizeof(IMAGE_THUNK_DATA), 1, hFile);
if(iRead != 1)
{
printf( "read thunk data error\n ");
return;
}
if(*((DWORD *)(&imageThunkData)) == 0)
break;
// 最高位如果为1,表示函数以序号方式输入
if(*((DWORD *)(&imageThunkData)) & 0x80000000)
{
DWORD ordinal = *((DWORD *)(&imageThunkData)) & 0x7fffffff;
printf( " Ordinal %d\n ",ordinal);
}
else
{
// 最高位不为1,表示函数以字符串方式输入
long current = ftell(hFile);
DWORD offset = *((DWORD *)(&imageThunkData));
WORD Hint;
char FunctionName[MAX_NAME_LEN];
if(fseek(hFile, offset, SEEK_SET)!=0)
return;
fread(&Hint, sizeof(WORD), 1, hFile);
int position=0;
for(;;)
{
int ch = fgetc(hFile);
FunctionName[position++] = ch;
if(!ch)
break;
}
printf( " %8X %s\n ", Hint, FunctionName);
fseek(hFile, current, SEEK_SET);
}
}
}
void displayImportDescriptor()
{
printf( " Section contains the following imports:\n\n ");
for(int num = 0 ; num < numOfImportDescriptor ; num ++)
{
// 首先获取输入表名称
char import_descriptor_name[MAX_NAME_LEN];
int offset = pimport_descriptor[num].Name;
if(fseek(hFile, offset, SEEK_SET)!=0)
return;
int position=0;
for(;;)
{
int ch = fgetc(hFile);
import_descriptor_name[position++] = ch;
if(!ch)
break;
}
printf( " %s\n ",import_descriptor_name);
printf( " %X Import Address Table\n ", pimport_descriptor[num].FirstThunk+nt_header.OptionalHeader.ImageBase);
printf( " %X Import Name Table\n ", pimport_descriptor[num].OriginalFirstThunk+nt_header.OptionalHeader.ImageBase);
printf( " %X time date stamp\n ", pimport_descriptor[num].TimeDateStamp);
printf( " %X Index of first forwarder reference\n ", pimport_descriptor[num].ForwarderChain);
printf( "\n ");
displayImportFunction(pimport_descriptor[num]);
printf( "\n ");
}
}
void displaySectionTable()
{
printf( " Summary:\n\n ");
for(int num = 0 ; num < nt_header.FileHeader.NumberOfSections ; num++)
{
printf( " %6X %s\n ", psection_header[num].SizeOfRawData, psection_header[num].Name);
}
}
int main(int argc, char* argv[])
{
printf("请输入文件路径:\n");
fflush(stdin);
char buf[200]={0};
gets(buf);
if(!openFile(buf))
//if(!openFile(argv[1]))
return -1;
if(!readDosHeader())
return -1;
if(!readNtHeader())
return -1;
if(!readSectionHeaders())
return -1;
if(!readImportDescriptor())
return -1;
displayImportDescriptor();
displaySectionTable();
closeFile();
return 0;
}
或者另外一种:
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#include <stdio.h>
#include <windows.h>
#include <iostream>
#include <string>
using namespace std;
LPVOID LpAddr;
IMAGE_DOS_HEADER *m_DosHeader;
IMAGE_NT_HEADERS *m_NT_Header;
IMAGE_FILE_HEADER *m_Image_File_Head;
IMAGE_OPTIONAL_HEADER32 *m_Image_Optional_Header;
int GetDosHeader(string scFilePath); //得到了DOSHeader的起始地址 m_DosHeader
void OutputDosHeaderInfo();
void Get_Image_NT_Header_Info();
typedef PVOID
(WINAPI *IMAGERVATOVA)(
IN PIMAGE_NT_HEADERS NtHeaders,
IN PVOID Base,
IN ULONG Rva,
IN OUT PIMAGE_SECTION_HEADER *LastRvaSection
);
IMAGERVATOVA ImageRvaToVa;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int main(int argc, char *argv[])
{
HMODULE hMod = LoadLibrary("imagehlp.dll");
ImageRvaToVa = (IMAGERVATOVA)GetProcAddress(hMod,"ImageRvaToVa");
char strPath[260]="test.exe";
gets(strPath);
GetDosHeader(strPath);
OutputDosHeaderInfo();
Get_Image_NT_Header_Info();
return 1;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int GetDosHeader(string scFilePath)
{
HANDLE m_Handle = CreateFile(scFilePath.c_str(),GENERIC_READ,0,0,OPEN_EXISTING,0,0);
if (m_Handle==INVALID_HANDLE_VALUE)
{
MessageBox(NULL,"ERROR:","CreateFile Error !",0);
CloseHandle(m_Handle);
return 0;
}
HANDLE m_hMmap = CreateFileMapping(m_Handle,0,PAGE_READONLY,0,0,NULL);
if(m_hMmap==NULL)
{
string err="CreateFileMapping ERROR!";
MessageBox(NULL,"ERROR:",err.c_str(),0);
CloseHandle(m_Handle);
CloseHandle(m_hMmap);
return 0;
}
LpAddr = MapViewOfFile(m_hMmap,FILE_MAP_READ,0,0,0);
if (LpAddr==NULL) //映像基址
{
MessageBox(NULL,"ERROR:","MapViewOfFile Error !",0);
CloseHandle(m_Handle);
CloseHandle(m_hMmap);
return 0;
}
CloseHandle(m_Handle);
CloseHandle(m_hMmap);
m_DosHeader = (IMAGE_DOS_HEADER *)LpAddr;
return 1;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void OutputDosHeaderInfo()
{
cout<<"==========================================================================\n";
cout<<"Dos Header:\n\n";
cout<<"Magic number :"<<(char *)&m_DosHeader->e_magic<<endl;
cout<<"Magic number :--------------------"<<hex<<m_DosHeader->e_magic<<endl; // Magic number
cout<<"Bytes on last page of file:-------"<<hex<<m_DosHeader->e_cblp<<endl; // Bytes on last page of file
cout<<"Pages in file: -------------------"<<hex<<m_DosHeader->e_cp<<endl; // Pages in file
cout<<"Relocations: ---------------------"<<hex<<m_DosHeader->e_crlc<<endl; // Relocations
cout<<"Size of header in paragraphs: ----"<<hex<<m_DosHeader->e_cparhdr<<endl; // Size of header in paragraphs
cout<<"Minimum extra paragraphs needed: -"<<hex<<m_DosHeader->e_minalloc<<endl; // Minimum extra paragraphs needed
cout<<" Maximum extra paragraphs needed: "<<hex<<m_DosHeader->e_maxalloc<<endl; // Maximum extra paragraphs needed
cout<<"Initial (relative) SS value: -----"<<hex<<m_DosHeader->e_ss<<endl; // Initial (relative) SS value
cout<<"Initial SP value: ----------------"<<hex<<m_DosHeader->e_sp<<endl; // Initial SP value
cout<<"Checksum: ------------------------"<<hex<<m_DosHeader->e_csum<<endl; // Checksum
cout<<"Initial IP value: ----------------"<<hex<<m_DosHeader->e_ip<<endl; // Initial IP value
cout<<"Initial (relative) CS value: -----"<<hex<<m_DosHeader->e_cs<<endl; // Initial (relative) CS value
cout<<"File address of relocation table: "<<hex<<m_DosHeader->e_lfarlc<<endl; // File address of relocation table
cout<<"Overlay number: ------------------"<<hex<<m_DosHeader->e_ovno<<endl; // Overlay number
cout<<"Reserved words: ------------------"<<hex<<m_DosHeader->e_res[4]<<endl; // Reserved words
cout<<"OEM identifier (for e_oeminfo):---"<<hex<<m_DosHeader->e_oemid<<endl; // OEM identifier (for e_oeminfo)
cout<<"OEM information e_oemid specific: "<<hex<<m_DosHeader->e_oeminfo<<endl; // OEM information; e_oemid specific
cout<<"Reserved words: ------------------"<<hex<<m_DosHeader->e_res2[10]<<endl; // Reserved words
cout<<"File address of new exe header: --"<<hex<<m_DosHeader->e_lfanew<<endl; // File address of new exe header
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void Get_Image_NT_Header_Info()
{
cout<<"==========================================================================\n";
cout<<"Image_NT_Header:\n";
//m_NT_Header = (IMAGE_NT_HEADERS *)(m_DosHeader+m_DosHeader->e_lfanew);
m_NT_Header = (IMAGE_NT_HEADERS *)((BYTE *)LpAddr+m_DosHeader->e_lfanew);
printf("Signature: %s\n",(char *)&m_NT_Header->Signature);
//m_Image_File_Head = (IMAGE_FILE_HEADER *)&(m_NT_Header->FileHeader);
//m_Image_Optional_Header = (IMAGE_OPTIONAL_HEADER32 *)&(m_NT_Header->OptionalHeader);
m_Image_File_Head = (IMAGE_FILE_HEADER *)((BYTE *)LpAddr+m_DosHeader->e_lfanew + 4);
m_Image_Optional_Header = (IMAGE_OPTIONAL_HEADER32 *)((BYTE *)LpAddr+m_DosHeader->e_lfanew + 4 + 20);
cout<<"==========================================================================\n";
cout<<"IMAGE_FILE_HEADER:\n"<<endl;
printf("Machine: %X\t",m_Image_File_Head->Machine);
if (m_Image_File_Head->Machine == IMAGE_FILE_MACHINE_I386)
{
printf("Machine: Intel 386\n");
}
cout<<"NumberOfSections: ----- "<<hex<<m_Image_File_Head->NumberOfSections<<endl;
cout<<"TimeDateStamp: -------- "<<hex<<m_Image_File_Head->TimeDateStamp<<endl;
cout<<"PointerToSymbolTable:-- "<<hex<<m_Image_File_Head->PointerToSymbolTable<<endl;
cout<<"NumberOfSymbols: ------ "<<hex<<m_Image_File_Head->NumberOfSymbols<<endl;
cout<<"SizeOfOptionalHeader:---"<<hex<<m_Image_File_Head->SizeOfOptionalHeader<<endl;
cout<<"Characteristics: ------ "<<hex<<m_Image_File_Head->Characteristics<<endl;
cout<<"==========================================================================\n";
cout<<"IMAGE_OPTIONAL_HEADER :\n"<<endl;
printf("Magic: %X\n",m_Image_Optional_Header->Magic); // = IMAGE_NT_OPTIONAL_HDR_MAGIC
printf("ImageBase: %X\n",m_Image_Optional_Header->ImageBase);
printf("MajorLinkerVersion: %X\n",m_Image_Optional_Header->MajorLinkerVersion);
printf("MinorLinkerVersion: %X\n",m_Image_Optional_Header->MinorLinkerVersion);
printf("SizeOfCode: %X\n",m_Image_Optional_Header->SizeOfCode);
printf("SizeOfInitializedData: %X\n",m_Image_Optional_Header->SizeOfInitializedData);
printf("SizeOfUninitializedData: %X\n",m_Image_Optional_Header->SizeOfUninitializedData);
printf("AddressOfEntryPoint: %X\n",m_Image_Optional_Header->AddressOfEntryPoint);
printf("BaseOfCode: %X\n",m_Image_Optional_Header->BaseOfCode);
printf("BaseOfData: %X\n",m_Image_Optional_Header->BaseOfData);
printf("ImageBase: %X\n",m_Image_Optional_Header->ImageBase);
printf("SectionAlignment: %X\n",m_Image_Optional_Header->SectionAlignment);
printf("FileAlignment: %X\n",m_Image_Optional_Header->FileAlignment);
printf("MajorOperatingSystemVersion: %X\n",m_Image_Optional_Header->MajorOperatingSystemVersion);
printf("MinorImageVersion: %X\n",m_Image_Optional_Header->MinorImageVersion);
printf("MajorSubsystemVersion: %X\n",m_Image_Optional_Header->MajorSubsystemVersion);
printf("MinorSubsystemVersion: %X\n",m_Image_Optional_Header->MinorSubsystemVersion);
printf("Win32VersionValue: %X\n",m_Image_Optional_Header->Win32VersionValue);
printf("SizeOfImage: %X\n",m_Image_Optional_Header->SizeOfImage);
printf("SizeOfHeaders: %X\n",m_Image_Optional_Header->SizeOfHeaders);
printf("CheckSum: %X\n",m_Image_Optional_Header->CheckSum);
printf("Subsystem: %X-----",m_Image_Optional_Header->Subsystem);
if (IMAGE_SUBSYSTEM_WINDOWS_GUI ==m_Image_Optional_Header->Subsystem)
{
printf("WINDOWS_GUI APP \n");
}
if (IMAGE_SUBSYSTEM_WINDOWS_CUI ==m_Image_Optional_Header->Subsystem)
{
printf("WINDOWS_CUI APP \n");
}
printf("DllCharacteristics: %X\n",m_Image_Optional_Header->DllCharacteristics);
printf("SizeOfStackReserve: %X\n",m_Image_Optional_Header->SizeOfStackReserve);
printf("SizeOfStackCommit: %X\n",m_Image_Optional_Header->SizeOfStackCommit);
printf("SizeOfHeapReserve: %X\n",m_Image_Optional_Header->SizeOfHeapReserve);
printf("SizeOfHeapCommit: %X\n",m_Image_Optional_Header->SizeOfHeapCommit);
printf("LoaderFlags: %X\n",m_Image_Optional_Header->LoaderFlags);
printf("NumberOfRvaAndSizes: %X\n",m_Image_Optional_Header->NumberOfRvaAndSizes);
cout<<"==========================================================================\n";
printf("IMPORT: \n");
IMAGE_IMPORT_DESCRIPTOR *m_PImport = (IMAGE_IMPORT_DESCRIPTOR *)
( (BYTE *)LpAddr + m_Image_Optional_Header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress );
while(m_PImport&&m_PImport->FirstThunk&&m_PImport->OriginalFirstThunk)
{
CHAR *P = (char *)((BYTE*)LpAddr + m_PImport->Name);
printf("=========================================\nimported DLL's name : %s\n", P);
//IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)((DWORD)LpAddr + m_PImport->FirstThunk);
//IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)((DWORD)LpAddr + m_PImport->FirstThunk);
IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)ImageRvaToVa(m_NT_Header,LpAddr,(ULONG)m_PImport->FirstThunk,NULL);
while(pThunk->u1.AddressOfData) // pThunk->u1.AddressOfData Function
{
//char* name = (char *)((DWORD)LpAddr + pThunk + 2);
//char* name = (char *)(*(DWORD*)pThunk + (DWORD)LpAddr + 2);
//printf("%s\n",name);
PVOID pName = ImageRvaToVa(m_NT_Header,LpAddr,(ULONG)pThunk->u1.AddressOfData->Name,NULL);
printf("%s\n",pName);
pThunk++;
}
m_PImport++;
}
cout<<"==========================================================================\n\n";
printf("EXPORT: \n");
//IMAGE_EXPORT_DIRECTORY *m_PExport = (IMAGE_EXPORT_DIRECTORY *)
// ( (BYTE *)LpAddr + m_Image_Optional_Header->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress );
PIMAGE_EXPORT_DIRECTORY m_PExport = (PIMAGE_EXPORT_DIRECTORY)ImageRvaToVa
(m_NT_Header,LpAddr,m_NT_Header->OptionalHeader.DataDirectory[0].VirtualAddress,NULL);
CHAR *P = (char *)((BYTE*)LpAddr + m_PExport->Name);
printf("exported DLL's name : %s\n", P);
ULONG num=0;
PULONG pName=NULL;
PULONG *pAddr=NULL;
do
{
pAddr = (PULONG *)ImageRvaToVa(m_NT_Header,LpAddr,(ULONG)m_PExport->AddressOfFunctions + num*sizeof(num),NULL);
pName = (PULONG )ImageRvaToVa(m_NT_Header,LpAddr,(ULONG)*pAddr,NULL);
printf("%s\n",pName);
num++;
}while(pName);
}