>
PE文件结构在windows安全中是必须了解的 >
本程序是一个通用分析32位PE文件的程序
程序包括分析DOS头,PE头中的文件映像头、可选映像头、数据目录项分析,节表分析以及导出表、导出函数分析
可修改宏改变打开的pe文件名 必须是32位PE
#include <stdio.h>
#include<windows.h>
#include<iostream>
#include<String>
#include<vector>
#define CLEN 20
#define ELEN 25
#define NLEN 6
#define DLLNAME "Your_Path\kernel32.dll"
void showData(const char Chinese[], const char English[],unsigned char * dataAddress, int len);
unsigned long long HexStringToLong(unsigned char * a, int len);
void showDataS(unsigned char * dataAddress, int len);
void showDataH(unsigned char * dataAddress, int len);
void showData1(unsigned char * buf, int len);
long long calcOffset(long long RVA);
;
using namespace std
{
class section :
publicint SectionsRVA;
int PointerToRawData;
int SizeOFRawData;
() {
section= 0;
SectionsRVA = 0;
PointerToRawData = 0;
SizeOFRawData }
~section() {
}
;
};
int NumOfSections = 0; //节表个数
int ExportTableRVA = 0; //导出表RVA
int ExportTablePointer = 0; //导出表文件偏移
<section> Sections;
vectorint main() {
FILE *fp;
unsigned char buffer[512];
if ((fp = fopen(DLLNAME,"rb")) != NULL) {
(buffer, sizeof(unsigned char), 0x40, fp);
fread/*------------------------------------DOS头-------------------------------------------*/
("DOS头分析:\n");
printf("PE头偏移", "e_lfanew", &buffer[0x3c], 1);
showData//将指针指向PE头开始
(fp, buffer[0x3c], 0); //当前读取指针指向PE头
fseek(buffer, sizeof(unsigned char), 0x88, fp);
fread//showData1(buffer,0x88);
/*------------------------------------PE头-------------------------------------------*/
//映像文件头
("映像文件头分析:\n");
printf("运行环境及平台", "Machine", &buffer[0x4], 2);
showData("节个数", "NumOfSections", &buffer[0x6], 2);
showData= HexStringToLong(&buffer[0x6], 2);
NumOfSections ("文件建立时间戳", "TimeDateStamp", &buffer[0x8], 4);
showData("标志集合", "Characteristics", &buffer[0x16], 2);
showData//可选映像头
("可选映像头分析:\n");
printf("代码入口RVA", "AddressSOfEntryPoint", &buffer[0x28], 4);
showData("模块首选载入RVA", "ImageBase", &buffer[0x34], 4);
showData("节内存中对齐", "SectionAlignment", &buffer[0x38], 4);
showData("节文件中对齐", "FileAlignment", &buffer[0x3c], 4);
showData("调入内存大小", "SizeOfImage", &buffer[0x50], 4);
showData("文件头大小之和", "SizeOfHeaders", &buffer[0x54], 4);
showData("数据目录项项数", "NumberOfRvaAndSizes", &buffer[0x74], 4);
showData//数据目录项
("数据目录项分析:\n");
printf("导出表地址", "ExportTableRVA", &buffer[0x78], 4);
showData= HexStringToLong(&buffer[0x78], 4);
ExportTableRVA ("导出表大小", "ExportTableSize", &buffer[0x78 + 4], 4);
showData("导入表地址", "ImportTableRVA", &buffer[0x78 + 8], 4);
showData("导入表大小", "ImportTableSize", &buffer[0x78 + 12], 4);
showData//将指针指向PE头开始
(fp, 0x70, 1); //当前读取指针指向节表头
fseek
(buffer, sizeof(unsigned char), NumOfSections * 0x28, fp);
fread/*------------------------------------节表-------------------------------------------*/
("节表分析:\n");
printf;
section Sectionfor (int i = 0; i < NumOfSections; i++) {
("节表名字", "NameOfSectionTable", &buffer[i * 0x28], 0);
showData(&buffer[i * 0x28], 8);
showDataS
("节表RVA", "VirtualAddress", &buffer[i * 0x28 + 12], 4);
showData.SectionsRVA = HexStringToLong(&buffer[i * 0x28 + 12], 4);
Section
("文件对齐后尺寸", "SizeOFRawData", &buffer[i * 0x28 + 16], 4);
showData.SizeOFRawData = HexStringToLong(&buffer[i * 0x28 + 16], 4);
Section
("数据在文件中的位置", "PointerToRawData", &buffer[i * 0x28 + 20],4);
showData.PointerToRawData = HexStringToLong(&buffer[i * 0x28 + 20],4);
Section
("\t=================================================================\n");
printf.push_back(Section);
Sections
}
//计算导出表文件偏移
= calcOffset(ExportTableRVA);
ExportTablePointer
/*------------------------------------导出表-------------------------------------------*/
("导出表分析:\n");
printfunsigned char buff[512];
int base = 0; //导出表基数
int NumOfFunctions = 0; //函数个数
int NumOfNames = 0; //函数名字个数
int AddressOfFunctions = 0; //函数RVA
int AddressOfNames = 0; //函数名字RVA
int AddressOfNameOrdinals = 0; //函数名字序号RVA
//跳转到导出表目录头 IMAGE_EXPORT_DIRETORY
(fp, ExportTablePointer, 0);
fseek(buffer, sizeof(unsigned char), 40, fp);
fread
("DLL名字", "DLLName", &buffer[12], 0);
showData(fp, (int) calcOffset(HexStringToLong(&buffer[12], 4)), 0);
fseek(buff, sizeof(unsigned char), sizeof(buff), fp);
fread("%s\n", buff);
printf//showData1(buffer,512);
("基数", "NumOfFunctions", &buffer[16], 4);
showData= HexStringToLong(&buffer[16], 4);
base ("函数个数", "NumOfFunctions", &buffer[20], 4);
showData= HexStringToLong(&buffer[20], 4);
NumOfFunctions ("函数名字个数", "NumOfNames", &buffer[24], 4);
showData= HexStringToLong(&buffer[24], 4);
NumOfNames ("函数RVA", "AddressOfFunctions", &buffer[28], 4);
showData= HexStringToLong(&buffer[28], 4);
AddressOfFunctions ("函数名字RVA", "AddressOfNames", &buffer[32], 4);
showData= HexStringToLong(&buffer[32], 4);
AddressOfNames ("函数名字序号RVA", "AddressOfNameOrdinals", &buffer[36], 4);
showData= HexStringToLong(&buffer[36], 4);
AddressOfNameOrdinals ("导出表函数:\n");
printf("\n\t%-29s%-28s%s", "序号", "函数名", "函数RVA\n");
printf//函数序号
unsigned char nameBuff[1024];
unsigned char nameBuffer[1024];
int count = 0;
for (int i = 0; i < NumOfNames / 256 + (NumOfNames % 256 != 0); i++) {
(fp, calcOffset(AddressOfNameOrdinals) + i * sizeof(buffer),0);
fseek(buffer, sizeof(unsigned char), sizeof(buffer), fp);
fread
(fp, calcOffset(AddressOfNames) + i * sizeof(nameBuffer), 0);
fseek(nameBuffer, sizeof(unsigned char), sizeof(nameBuffer), fp);
fread
for (int j = 0; j < 512 / 2 && count < NumOfNames; j++) {
("\t%-20X ",(int) HexStringToLong(&buffer[j * 2], 2) + base);
printf(fp,(int) calcOffset(AddressOfFunctions)+ HexStringToLong(&buffer[j * 2], 2) * 4, 0);
fseek(buff, sizeof(unsigned char), 512, fp);
fread
(fp, calcOffset(HexStringToLong(&nameBuffer[j * 4], 4)),0);
fseek(nameBuff, sizeof(unsigned char), sizeof(nameBuff), fp);
fread("%-35s", nameBuff);
printf(buff, 4);
showDataH++;
count}
}
}
(fp);
fclosereturn 0;
}
void showData1(unsigned char * buf, int len) {
for (int i = 0; i < len; i++) {
("%02X", buf[i]);
printf}
("\n");
printf}
long long calcOffset(long long RVA) {
for (int i = 0; i < NumOfSections; i++) {
if (Sections[i].SectionsRVA < RVA
&& RVA < Sections[i].SizeOFRawData + Sections[i].SectionsRVA) {
return RVA - Sections[i].SectionsRVA + Sections[i].PointerToRawData;
}
}
return 0;
}
void showData(const char Chinese[], const char English[],
unsigned char * dataAddress, int len) {
int flag = 0;
("\t%-*s %-*s=> ", CLEN, Chinese, ELEN, English);
printf
for (int i = len - 1; i >= 0; i--) {
if (flag) {
("%02X", *(dataAddress + i));
printf} else if (*(dataAddress + i) != 0) {
= 1;
flag ("%X", *(dataAddress + i));
printf}
}
if (len != 0) {
("\n");
printfif (flag == 0)
("0");
printf}
}
void showDataS(unsigned char * dataAddress, int len) {
("%-*.*s\n", len, len, dataAddress);
printf}
void showDataH(unsigned char * dataAddress, int len) {
int flag = 0;
for (int i = len - 1; i >= 0; i--) {
if (flag) {
("%02X", *(dataAddress + i));
printf} else if (*(dataAddress + i) != 0) {
= 1;
flag ("%X", *(dataAddress + i));
printf}
}
if (len != 0) {
("\n");
printfif (flag == 0)
("0");
printf}
}
unsigned long long HexStringToLong(unsigned char * a, int len) {
unsigned long long num = 0, t = 0;
for (int i = 0; i < len; i++) {
= a[i];
t for (int j = i; j > 0; j--) {
*= 256;
t }
+= t;
num }
return num;
}
运行结果个人认为还是比较美观的