项目地址
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

reverse

上一篇brute ratel C4 badger全分析文档

下一篇利用dll通知回调加载shellcode

__相关推荐

__2024-04-28 CobaltStrike UPX脱壳加壳

__2024-01-17 PE文件浅析

__2024-04-28 dll injection(dll注入)

__2024-04-28 go语言样本逆向分析特点

__2024-07-08 wannacry勒索病毒加密解密过程分析

__2024-10-25 brute ratel C4 badger全分析文档

avatar

helson

吾生有涯,其知无涯

文章12标签4分类1

__Follow Me

____

__公告

This is my Blog

__目录

    1. 源码
    1. 结果对比

__最新文章

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

框架 Hexo|主题 Butterfly