功能类似PEID,图形界面暂时没做出来 暑假学学QT
读文件只能在主函数里写文件路径 , 是有点low… (流下了没技术的泪水)
头文件代码:
#pragma once
#include<Windows.h>
class CPe
{
private:
PTCHAR ptcFilePath; //PE文件路径
IMAGE_DOS_HEADER pe_cDosHeader;
IMAGE_NT_HEADERS32 pe_cNtHeader;
PIMAGE_SECTION_HEADER pe_pSectionHeader;
PBYTE pe_lpImageBase; //手动装载PE时文件首指针,这里写byte是因为文件操作一般以字节为单位
public:
CPe();
~CPe();
void PrintPE();
void LordPE(HANDLE , DWORD); //二参是直到节表的总大小,因为硬盘内存一个样
HANDLE Init(TCHAR[]);
int GetImportTablePtr(OUT PIMAGE_DATA_DIRECTORY);
int GetNtHeadr32Ptr(OUT PIMAGE_NT_HEADERS32);
int GetImageBasePtr(OUT PBYTE);
void PrintImport();
};
函数实现
#include "CPe.h"
#include <Windows.h>
#include<stdio.h>
CPe::CPe()
{
memset(this, 0, sizeof(CPe));
}
CPe::~CPe()
{
if (pe_pSectionHeader)
delete[] pe_pSectionHeader;
pe_pSectionHeader = NULL;
if (pe_lpImageBase)
delete[] pe_lpImageBase;
pe_lpImageBase = NULL;
}
int CPe::GetImportTablePtr(OUT PIMAGE_DATA_DIRECTORY p)
{
p = this->pe_cNtHeader.OptionalHeader.DataDirectory + 1;
return 1;
}
int CPe::GetNtHeadr32Ptr(OUT PIMAGE_NT_HEADERS32 p)
{
p = &(this->pe_cNtHeader);
return 1;
}
int CPe::GetImageBasePtr(OUT PBYTE p)
{
p = this->pe_lpImageBase;
return 1;
}
HANDLE CPe::Init(TCHAR tcFilePath[])
{
bool blFlag = false;
ptcFilePath = tcFilePath;
DWORD dwTempNum = 0;
HANDLE hPeFile = CreateFile(tcFilePath, GENERIC_READ, NULL, NULL, OPEN_EXISTING, NULL, NULL);
if (INVALID_HANDLE_VALUE == hPeFile)
return 0;
ReadFile(hPeFile, &pe_cDosHeader, sizeof(IMAGE_DOS_HEADER), &dwTempNum, NULL);
if (sizeof(IMAGE_DOS_HEADER) != dwTempNum)
return NULL;
if (0x5a4d != pe_cDosHeader.e_magic)
return NULL; //此文件不是一个有效的PE文件,或者PE文件魔数遭到修改
SetFilePointer(hPeFile, pe_cDosHeader.e_lfanew, NULL, FILE_BEGIN);
ReadFile(hPeFile, &pe_cNtHeader, sizeof(IMAGE_NT_HEADERS32), &dwTempNum, NULL);
if (sizeof(IMAGE_NT_HEADERS32) != dwTempNum)
return NULL;
if (0x4550 != pe_cNtHeader.Signature)
return NULL; //PE指纹不存在
pe_pSectionHeader = new IMAGE_SECTION_HEADER[pe_cNtHeader.FileHeader.NumberOfSections];
memset(pe_pSectionHeader, 0, sizeof(IMAGE_SECTION_HEADER) * pe_cNtHeader.FileHeader.NumberOfSections);
ReadFile(hPeFile, pe_pSectionHeader, sizeof(IMAGE_SECTION_HEADER) * pe_cNtHeader.FileHeader.NumberOfSections, &dwTempNum, NULL);
if (dwTempNum != sizeof(IMAGE_SECTION_HEADER) * pe_cNtHeader.FileHeader.NumberOfSections)
return NULL;
return hPeFile;
}
void CPe::PrintImport()
{
PIMAGE_IMPORT_DESCRIPTOR pImportor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->pe_lpImageBase + this->pe_cNtHeader.OptionalHeader.DataDirectory[1].VirtualAddress);
while (pImportor->Characteristics)
{
DWORD dwThunkRVA = pImportor->OriginalFirstThunk == NULL ? pImportor->FirstThunk : pImportor->OriginalFirstThunk;
PIMAGE_THUNK_DATA32 pThunk = reinterpret_cast<PIMAGE_THUNK_DATA32>(this->pe_lpImageBase + dwThunkRVA);
while (pThunk->u1.AddressOfData)
{
if (pThunk->u1.AddressOfData & 0x80000000)
{
printf("%s --------> %x\n", this->pe_lpImageBase + pImportor->Name, pThunk->u1.AddressOfData & 0x7fffffff);
}
else
{
printf("%s --------> %s\n", this->pe_lpImageBase + pImportor->Name,this->pe_lpImageBase+pThunk->u1.AddressOfData+2); // +2因为最后又指向了_IMAGE_IMPORT_BY_NAME
}
pThunk++;
}
pImportor++;
}
}
void CPe::LordPE(HANDLE hFile, DWORD dwSize)
{
DWORD dwTempNum = 0;
SetFilePointer(hFile, NULL, NULL, FILE_BEGIN);
pe_lpImageBase = new byte[this->pe_cNtHeader.OptionalHeader.SizeOfImage];
if (!pe_lpImageBase)
return;
memset(pe_lpImageBase, 0, this->pe_cNtHeader.OptionalHeader.SizeOfImage);
ReadFile(hFile, pe_lpImageBase, dwSize, &dwTempNum, NULL);
if (dwSize != dwTempNum)
return;
for (int i = 0; i < this->pe_cNtHeader.FileHeader.NumberOfSections; i++)
{
SetFilePointer(hFile, this->pe_pSectionHeader[i].PointerToRawData, NULL, FILE_BEGIN);//
ReadFile(hFile, pe_lpImageBase + this->pe_pSectionHeader[i].VirtualAddress, this->pe_pSectionHeader[i].SizeOfRawData, &dwTempNum, NULL);
}
//至此 手动装载PE已经完成 装载PE的目的是更方便的找数据目录项
}
void CPe::PrintPE()
{
TCHAR tcDivide[60] = "********************************************************";
printf("主要信息\n%s\n", tcDivide);//
printf("文件路径:%s\n", this->ptcFilePath);//
printf("入口点:%08x\n", this->pe_cNtHeader.OptionalHeader.AddressOfEntryPoint);//
//printf("文件偏移:%08x\n",p.pe_cNtHeader.OptionalHeader.); //看不懂这个参数
printf("链接器版本:%02d.%02d\n", this->pe_cNtHeader.OptionalHeader.MajorLinkerVersion, this->pe_cNtHeader.OptionalHeader.MinorLinkerVersion);//
//printf("文件大小:%08x\n",);
//printf("首字节:%2x,%2x,%2x,%2x\n",); //本程序没有读入文件,只读了头,so 阉割此功能
if (3 == this->pe_cNtHeader.OptionalHeader.Subsystem)
printf("子系统:Win32 Console\n");
else
printf("子系统:%08x\n", this->pe_cNtHeader.OptionalHeader.Subsystem);//映射懒得写了。
printf("%s\n\n\n", tcDivide);//
printf("基本信息\n%s\n", tcDivide);
printf("入口点:%08x\t子系统:%08x\n", this->pe_cNtHeader.OptionalHeader.AddressOfEntryPoint, this->pe_cNtHeader.OptionalHeader.Subsystem);//
printf("映像基址:%08x\t区段数量%08x\n", this->pe_cNtHeader.OptionalHeader.ImageBase, this->pe_cNtHeader.FileHeader.NumberOfSections);//
printf("映像大小:%08x\t时间戳:%08x\n", this->pe_cNtHeader.OptionalHeader.SizeOfImage, this->pe_cNtHeader.FileHeader.TimeDateStamp);//
printf("代码基址:%08x\t头部大小:%08x\n", this->pe_cNtHeader.OptionalHeader.BaseOfCode, this->pe_cNtHeader.OptionalHeader.SizeOfHeaders);//
printf("数据基址:%08x\t特性:%08x\n", this->pe_cNtHeader.OptionalHeader.BaseOfData, this->pe_cNtHeader.FileHeader.Characteristics);//
printf("区段对齐:%08x\t校检和:%08x\n", this->pe_cNtHeader.OptionalHeader.SectionAlignment, this->pe_cNtHeader.OptionalHeader.CheckSum);//
printf("文件对齐:%08x\t可选头部大小:%08x\n", this->pe_cNtHeader.OptionalHeader.FileAlignment, this->pe_cNtHeader.FileHeader.SizeOfOptionalHeader);//
printf("幻数:%08x\t数据目录项的个数:%08x\n", this->pe_cNtHeader.OptionalHeader.Magic, this->pe_cNtHeader.OptionalHeader.NumberOfRvaAndSizes);//
printf("%s\n\n\n", tcDivide);
printf("目录信息\n%s\n", tcDivide);
printf("导出表的RVA及大小:%08x %08x\n", this->pe_cNtHeader.OptionalHeader.DataDirectory[0].VirtualAddress, this->pe_cNtHeader.OptionalHeader.DataDirectory[0].Size);
printf("导入表的RVA及大小:%08x %08x\n", this->pe_cNtHeader.OptionalHeader.DataDirectory[1].VirtualAddress, this->pe_cNtHeader.OptionalHeader.DataDirectory[1].Size);
printf("资源的RVA及大小:%08x %08x\n", this->pe_cNtHeader.OptionalHeader.DataDirectory[2].VirtualAddress, this->pe_cNtHeader.OptionalHeader.DataDirectory[2].Size);
printf("TLS表的RVA及大小:%08x %08x\n", this->pe_cNtHeader.OptionalHeader.DataDirectory[9].VirtualAddress, this->pe_cNtHeader.OptionalHeader.DataDirectory[9].Size);
printf("调试的RVA及大小:%08x %08x\n", this->pe_cNtHeader.OptionalHeader.DataDirectory[6].VirtualAddress, this->pe_cNtHeader.OptionalHeader.DataDirectory[6].Size);
printf("%s\n\n\n", tcDivide);
}
主函数实现:
#include<stdio.h>
#include<Windows.h>
#include"CPe.h"
int main(void)
{
TCHAR tcPath[MAX_PATH] = "D:\\test\\exper.exe";
CPe cPeData;
HANDLE hFile = cPeData.Init(tcPath); //文件指针此时已经指向节表末尾
cPeData.LordPE(hFile,SetFilePointer(hFile,NULL,NULL,FILE_CURRENT));
cPeData.PrintPE();
cPeData.PrintImport();
getchar();
}