定义一个struct _MAP_FILE_STRUCT结构来存放相关信息。
typedef struct _MAP_FILE_STRUCT
{
HANDLE hFile; //文件句柄
HANDLE hMapping;//映射文件句柄
LPVOID ImageBase;//映像基址
} MAP_FILE_STRUCT, *PMAP_FILE_STRUCT;
一、加载要打开的文件
采用内存映射的方式将文件加载到内存中,内存映射函数包括:CreateFileMapping, OpenFileMapping, MapViewOfFile, UnmapViewOfFile和FlushViewOfFile。
定义一个函数,如果是一个PE文件则返回true, 否则返回false:
//加载文件
bool LoadFile(LPTSTR lpFileName, PMAP_FILE_STRUCT pstMapFile)
{
if (lpFileName == nullptr)
{
return false;
}
HANDLE hFile;
HANDLE hMapping;
LPVOID ImageBase;
memset(pstMapFile, 0, sizeof(MAP_FILE_STRUCT));
//1、只读方式打开文件,返回文件句柄
hFile = CreateFile(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (!hFile)
{
return false;
}
//2、创建内存映射文件对象
hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, 0);
if (!hMapping)
{
CloseHandle(hFile);
return false;
}
//3、创建内存映射文件的视图
ImageBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
if (!ImageBase)
{
CloseHandle(hFile);
CloseHandle(hMapping);
return false;
}
pstMapFile->hFile = hFile;
pstMapFile->hMapping = hMapping;
pstMapFile->ImageBase = ImageBase;
return true;
}
二、程序执行完毕后,回收资源
void UnLoadFile(PMAP_FILE_STRUCT pstMapFile)
{
if (pstMapFile->hFile)
{
CloseHandle(pstMapFile->hFile);
}
if (pstMapFile->hMapping)
{
CloseHandle(pstMapFile->hMapping);
}
if (pstMapFile->ImageBase)
{
//撤销映射并使用CloseHandle函数关闭内存映射文件对象句柄
UnmapViewOfFile(pstMapFile->ImageBase);
}
}
三、文件格式检测
bool IsPEFile(LPVOID ImageBase)
{
PIMAGE_DOS_HEADER pDH = nullptr;
PIMAGE_NT_HEADERS32 pNtH = nullptr;
if (!ImageBase)
{
return false;
}
pDH = (PIMAGE_DOS_HEADER)ImageBase;
if (pDH->e_magic != IMAGE_DOS_SIGNATURE) //"MZ"
{
return false;
}
//pDH->e_lfanew保存PIMAGE_NT_HEADERS32的偏移地址,加上基址pDH即为MAGE_NT_HEADERS的地址
pNtH = (PIMAGE_NT_HEADERS32) ( (DWORD)pDH + pDH->e_lfanew);
if (pNtH->Signature != IMAGE_NT_SIGNATURE) //"PE"
{
return false;
}
return true;
}
四、读取FileHeader和OptionalHeader的内容
1、获取指向IMAGE_NT_HEADERS结构的指针
PIMAGE_NT_HEADERS GetNtHeaders(LPVOID ImageBase)
{
PIMAGE_DOS_HEADER pDH = nullptr;
PIMAGE_NT_HEADERS pNtH = nullptr;
if (!IsPEFile(ImageBase))
{
return nullptr;
}
pDH = (PIMAGE_DOS_HEADER)ImageBase;
pNtH = (PIMAGE_NT_HEADERS)((DWORD)pDH + pDH->e_lfanew);
return pNtH;
}
2、获取指向IMAGE_FILE_HEADER结构的指针
PIMAGE_FILE_HEADER GetFileHeader(LPVOID ImageBase)
{
PIMAGE_NT_HEADERS pNtH = GetNtHeaders(ImageBase);
if (!pNtH)
{
return nullptr;
}
return &(pNtH->FileHeader);
}
3、获取指向IMAGE_OPTIONAL_HEADER结构的指针
PIMAGE_OPTIONAL_HEADER GetOptionalHeader(LPVOID ImageBase)
{
PIMAGE_NT_HEADERS pNtH = GetNtHeaders(ImageBase);
if (!pNtH)
{
return nullptr;
}
return &(pNtH->OptionalHeader);
}
4、输出文件头信息
void ShowFileHeaderInfo(PMAP_FILE_STRUCT stMapFile)
{
char strTmp[1024] = {0};
PIMAGE_FILE_HEADER pFH = nullptr;
PIMAGE_OPTIONAL_HEADER pOH = nullptr;
pFH = GetFileHeader(stMapFile->ImageBase);
if (!pFH)
{
printf("Get File Header failed!\n");
return;
}
//时间转换
time_t t = pFH->TimeDateStamp;
char strTime[26] = {0};
tm* ptmBegin = localtime(&t);
strftime(strTime, 26, "%Y/%m/%d %H:%M:%S", ptmBegin);
//将信息按十六进制格式化
char *strFileHeaderFormat ="\
IMAGE_FILE_HEADER:\n\
Machine: %04lX\n\
NumberOfSections: %04lX\n\
TimeDateStamp: %s (%04lX)\n\
PointerToSymbolTable: %08X\n\
NumberOfSymbols: %08lX\n\
SizeOfOptionalHeader: %04lX\n\
Characteristics: %04lX\n\n\
";
sprintf(strTmp, strFileHeaderFormat, pFH->Machine, pFH->NumberOfSections, strTime, pFH->TimeDateStamp, pFH->PointerToSymbolTable, pFH->NumberOfSymbols,
pFH->SizeOfOptionalHeader, pFH->Characteristics);
printf("%s", strTmp);
memset(strTmp, 0, sizeof(strTmp));
char *strFileOptHeaderFormat = "\
IMAGE_OPTIONAL_HEADER:\n\
Entry Point: %08lX\n\
Image Base: %08lX\n\
Code Base: %08lX\n\
Data Base: %08lX\n\
Image Size: %08lX\n\
Headers Size: %08lX\n\
Section Alignment: %08lX\n\
File Alignment: %08lX\n\
Subsystem: %08lX\n\
Check Sum: %04lX\n\
Dll Flags: %04lX\n\
";
pOH= GetOptionalHeader(stMapFile->ImageBase);
if (!pOH)
{
printf("Get File Optional Header failed!\n");
return;
}
sprintf(strTmp, strFileOptHeaderFormat, pOH->AddressOfEntryPoint, pOH->ImageBase, pOH->BaseOfCode, pOH->BaseOfData,
pOH->SizeOfImage, pOH->SizeOfHeaders, pOH->SectionAlignment, pOH->FileAlignment, pOH->Subsystem, pOH->CheckSum, pOH->DllCharacteristics);
printf("%s", strTmp);
}
主函数:
MAP_FILE_STRUCT stMapFile = { nullptr, nullptr, nullptr };
int main()
{
LPTSTR filePath = TEXT("D:\\PEInfo_example.exe");
UnLoadFile(&stMapFile);
if (!LoadFile(filePath, &stMapFile))
{
return -1;
}
if (!IsPEFile(stMapFile.ImageBase))
{
UnLoadFile(&stMapFile);
return -1;
}
ShowFileHeaderInfo(&stMapFile);
UnLoadFile(&stMapFile);
return 0;
}
结果如下: