PE解析器编写
项目地址
pe-parse/ at master · helsome/pe-parse (github.com)
理论部分见令一篇文章:PE结构浅析。
源码
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include<iostream>
#include<windows.h>
/*运行前需要为项目赋予admin权限,点击项目右键->属性->配置属性->链接器->清单文件->UAC执行级别->requireAdministrator(选择)。 这样生成的程序在运行时就可以获得管理员权限,向C盘写入文件
否则szBuffer会为NULL,无法运行*/
//文件加载函数
char* LoadFile(const char* szFilePath)
{
//打开文件
HANDLE hFile = CreateFileA(szFilePath, GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)//判断文件是否正确打开
return NULL;
DWORD dwFileSize = GetFileSize(hFile, NULL);
char* szBuffer = new char [dwFileSize] {0};
DWORD dwReadSize = 0;
BOOL bRet = ReadFile(hFile, szBuffer, dwFileSize, &dwFileSize, NULL);//lpbuffer指向接收从文件或设备读取的数据的缓冲区的指针。
if (bRet)
return szBuffer;
else
return 0;
}
DWORD RvaToFoa(DWORD dwRva, char* szBuffer)//计算地址偏移量
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)szBuffer;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(szBuffer + pDos->e_lfanew);
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNt);
if (dwRva<pSectionHeader[0].VirtualAddress)//判断此时rva是否在头部
{
return dwRva;
}
for (size_t i = 0; i < pNt->FileHeader.NumberOfSections; i++)
{
if (dwRva >= pSectionHeader[i].VirtualAddress && dwRva <= pSectionHeader[i].VirtualAddress + pSectionHeader[i].Misc.VirtualSize)//判断位置
{
return dwRva - pSectionHeader[i].VirtualAddress + pSectionHeader[i].PointerToRawData;//返回偏移量
}
}
}
bool CheckPEFormat(char* szBuffer) {
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)szBuffer;
if (pDos->e_magic != IMAGE_DOS_SIGNATURE) {
return false; // Not a valid PE file
}
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(szBuffer + pDos->e_lfanew);
return pNt->Signature == IMAGE_NT_SIGNATURE; // Check PE signature
}
void ReadFileHeader(char* szBuffer) {
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)szBuffer;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(szBuffer + pDos->e_lfanew);
PIMAGE_FILE_HEADER pFileHeader = &pNt->FileHeader;
printf("Machine: %04X\n", pFileHeader->Machine);
printf("Number of Sections: %04X\n", pFileHeader->NumberOfSections);
printf("Time Date Stamp: %08X\n", pFileHeader->TimeDateStamp);
printf("Characteristics: %04X\n", pFileHeader->Characteristics);
}
void ReadOptionalHeader(char* szBuffer) {
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)szBuffer;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(szBuffer + pDos->e_lfanew);
PIMAGE_OPTIONAL_HEADER pOptHeader = &pNt->OptionalHeader;
printf("Magic: %04X\n", pOptHeader->Magic);
printf("Image Base: %08X\n", pOptHeader->ImageBase);
printf("Section Alignment: %08X\n", pOptHeader->SectionAlignment);
//printf("Size of Optional Header: %04X\n", pFileHeader->SizeOfOptionalHeader);
}
void ReadDataDirectory(char* szBuffer) {
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)szBuffer;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(szBuffer + pDos->e_lfanew);
for (int i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) {
PIMAGE_DATA_DIRECTORY pDir = &pNt->OptionalHeader.DataDirectory[i];
printf("Data Directory %d: VA = %08X, Size = %08X\n", i, pDir->VirtualAddress, pDir->Size);
}
}
void ReadSectionTable(char* szBuffer) {
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)szBuffer;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(szBuffer + pDos->e_lfanew);
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNt);
for (int i = 0; i < pNt->FileHeader.NumberOfSections; i++) {
printf("Section Name: %.8s\n", pSectionHeader[i].Name);
printf("Virtual Size: %08X\n", pSectionHeader[i].Misc.VirtualSize);
printf("Virtual Address: %08X\n", pSectionHeader[i].VirtualAddress);
printf("Size of Raw Data: %08X\n", pSectionHeader[i].SizeOfRawData);
pSectionHeader++;
}
}
//解析导入表
void ImportTable(char* szBuffer)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)szBuffer;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(szBuffer + pDos->e_lfanew);
//定位导入表
PIMAGE_OPTIONAL_HEADER pOptionHeader = &pNt->OptionalHeader;
PIMAGE_DATA_DIRECTORY pImportDir = pOptionHeader->DataDirectory + IMAGE_DIRECTORY_ENTRY_IMPORT;
//填入导出表
PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(RvaToFoa(pImportDir->VirtualAddress, szBuffer) + szBuffer);//Rvatofoa计算导入表的头到文件头的距离
while(pImport->Name!= NULL)
{
char* szModuleName = (char*)(RvaToFoa(pImport->Name, szBuffer) + szBuffer);
printf("DLL名称:%s\r\n", szModuleName);
printf("时间日期标志\r\n", pImport->TimeDateStamp);
printf("ForwarderChain%08X\r\n", pImport->ForwarderChain);
printf("NameRva;%08X\r\n", pImport->Name);
printf("OriginalFirstThunk;%08X\r\n", pImport->OriginalFirstThunk);
printf("FirstThunk;%08X\r\n", pImport->FirstThunk);
//指向导入地址表的RVA
PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)(RvaToFoa(pImport->FirstThunk, szBuffer) + szBuffer);//IAT导入地址表
DWORD dwIndex = 0;
DWORD dwImportOffset = 0;
//被导入函数序号
while (pIAT->u1.Ordinal)
{
printf("ThunkRVA:08X\r\n", pImport->OriginalFirstThunk + dwIndex);
dwImportOffset = RvaToFoa(pImport->OriginalFirstThunk, szBuffer);
printf("ThunkFOA:08X\r\n", dwImportOffset + dwIndex);
dwIndex += 4;
if ((pIAT->u1.Ordinal && 0x80000000) != 1)
{
PIMAGE_IMPORT_BY_NAME pName = (PIMAGE_IMPORT_BY_NAME)(RvaToFoa(RvaToFoa(pIAT->u1.AddressOfData, szBuffer), szBuffer));
printf("API name:%s\n", pName->Name);
printf("Hint:%04X\n", pName->Hint);
//被导入函数的地址
printf("ThunkValue:%08X\n",pIAT->u1.Function);
}
pIAT++;
}
pImport++;
}
}
void TSLTable(char* szBuffer)
{
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)szBuffer;
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(szBuffer + pDos->e_lfanew);
//定位TSL表
PIMAGE_DATA_DIRECTORY pTSLDir = (pNt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_TLS);
//填充TLS结构
PIMAGE_TLS_DIRECTORY pTLS = (PIMAGE_TLS_DIRECTORY)(RvaToFoa(pTSLDir->VirtualAddress, szBuffer) + szBuffer);
printf("数据块开始VA:%08X\n",pTLS->StartAddressOfRawData);
printf("数据块结束VA:%08X\n",pTLS->EndAddressOfRawData);
printf("索引变量VA:%08X\n", pTLS->AddressOfIndex);
printf("特征值:%08X\n", pTLS->Characteristics);
}
int main()
{
char* szBuffer = LoadFile("C:\\Users\\helse\\Desktop\\artifact2.exe");
if (CheckPEFormat(szBuffer))
{
ReadFileHeader(szBuffer);
ReadOptionalHeader(szBuffer);
ReadDataDirectory(szBuffer);
ReadSectionTable(szBuffer);
ImportTable(szBuffer);
TSLTable(szBuffer);
}
else {
printf("Not a valid PE file.\n");
}
system("pause");
return 0;
}
结果对比






__文章作者:helson
__文章链接:https://helsome.gihub.io/2024/10/25/PE%E8%A7%A3%E6%9E%90%E5%99%A8%E7%BC%96%E5%86%99/
__版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 infinite!
__相关推荐
__2024-04-28 CobaltStrike UPX脱壳加壳
__2024-04-28 dll injection(dll注入)
__2024-07-08 wannacry勒索病毒加密解密过程分析
__2024-10-25 brute ratel C4 badger全分析文档
![]()
helson
吾生有涯,其知无涯
__公告
This is my Blog
__目录
- 源码
- 结果对比
__最新文章
brute ratel C4 badger全分析文档2024-10-25
PE解析器编写2024-10-25
利用dll通知回调加载shellcode2024-10-25
os cs1622024-09-23
wannacry勒索病毒加密解密过程分析2024-07-08
©2020 - 2024 By helson
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 infinite!