PE 文件加载器实现

介绍 pe 重定位表的文章:https://blog.csdn.net/qq_40890756/article/details/90080880?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-2.control

下面的代码实现了pe 文件的加载功能,经测试是可以正常运行exe文件的。有个地方需要注意:在pe 文件加载完成之后,调用pe 文件的入口函数时,需要确保其函数原型是一致的。样例中的pe 入口函数是没有给参数。如果不一样,会导致函数执行异常,程序会崩掉,可以根据实际的测试样例进行修改。

/**
 * peLoader.cpp
 * Windows APT Warfare
 * by aaaddress1@chroot.org
 */
#include <stdio.h>
#include <windows.h>
#pragma warning(disable : 4996)
#define getNtHdr(buf) ((IMAGE_NT_HEADERS *)((size_t)buf + ((IMAGE_DOS_HEADER *)buf)->e_lfanew))
#define getSectionArr(buf) ((IMAGE_SECTION_HEADER *)((size_t)buf + ((IMAGE_DOS_HEADER *)buf)->e_lfanew + sizeof(IMAGE_NT_HEADERS)))

bool readBinFile(const char fileName[], char **bufPtr, size_t &length)
{
	if (FILE *fp = fopen(fileName, "rb"))
	{
		fseek(fp, 0, SEEK_END);
		length = ftell(fp);
		*bufPtr = (char *)malloc(length + 1);
		fseek(fp, 0, SEEK_SET);
		fread(*bufPtr, sizeof(char), length, fp);
		return true;
	}
	else
		return false;
}

void fixIat(char *peImage)
{
	auto dir_ImportTable = getNtHdr(peImage)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
	auto impModuleList = (IMAGE_IMPORT_DESCRIPTOR *)&peImage[dir_ImportTable.VirtualAddress];
	for (HMODULE currMod; impModuleList->Name; impModuleList++)
	{
		printf("\timport module : %s\n", &peImage[impModuleList->Name]);
		currMod = LoadLibraryA(&peImage[impModuleList->Name]);

		auto arr_callVia = (IMAGE_THUNK_DATA *)&peImage[impModuleList->FirstThunk];
		for (int count = 0; arr_callVia->u1.Function; count++, arr_callVia++)
		{
			auto curr_impApi = (PIMAGE_IMPORT_BY_NAME)&peImage[arr_callVia->u1.Function];
			arr_callVia->u1.Function = (size_t)GetProcAddress(currMod, (char *)curr_impApi->Name);
			if (count < 5)
				printf("\t\t- fix imp_%s\n", curr_impApi->Name);
		}
	}
}

#define RELOC_32BIT_FIELD 0x03
#define RELOC_64BIT_FIELD 0x0A
typedef struct BASE_RELOCATION_ENTRY
{
	WORD Offset : 12;
	WORD Type : 4;
} entry;

void fixReloc(char *peImage)
{
	auto dir_RelocTable = getNtHdr(peImage)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
	auto relocHdrBase = &peImage[dir_RelocTable.VirtualAddress];
	for (UINT hdrOffset = 0; hdrOffset < dir_RelocTable.Size;)
	{
		auto relocHdr = (IMAGE_BASE_RELOCATION *)&relocHdrBase[hdrOffset];
		entry *entryList = (entry *)((size_t)relocHdr + sizeof(*relocHdr));
		for (size_t i = 0; i < (relocHdr->SizeOfBlock - sizeof(*relocHdr)) / sizeof(entry); i++)
		{
			size_t rva_Where2Patch = relocHdr->VirtualAddress + entryList[i].Offset;
			if (entryList[i].Type == RELOC_32BIT_FIELD)
			{
				*(UINT32 *)&peImage[rva_Where2Patch] -= (size_t)getNtHdr(peImage)->OptionalHeader.ImageBase;
				*(UINT32 *)&peImage[rva_Where2Patch] += (size_t)peImage;
			}
			else if (entryList[i].Type == RELOC_64BIT_FIELD)
			{
				*(UINT64 *)&peImage[rva_Where2Patch] -= (size_t)getNtHdr(peImage)->OptionalHeader.ImageBase;
				*(UINT64 *)&peImage[rva_Where2Patch] += (size_t)peImage;
			}
		}
		hdrOffset += relocHdr->SizeOfBlock;
	}
}

void peLoader(char *exeData)
{
	auto imgBaseAt = (void *)getNtHdr(exeData)->OptionalHeader.ImageBase;
	auto imgSize = getNtHdr(exeData)->OptionalHeader.SizeOfImage;
	bool relocOk = !!getNtHdr(exeData)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;

	char *peImage = (char *)VirtualAlloc(relocOk ? 0 : imgBaseAt, imgSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if (peImage)
	{
		printf("[v] exe file mapped @ %p\n", peImage);
		memcpy(peImage, exeData, getNtHdr(exeData)->OptionalHeader.SizeOfHeaders);
		for (int i = 0; i < getNtHdr(exeData)->FileHeader.NumberOfSections; i++)
		{
			auto curr_section = getSectionArr(exeData)[i];
			memcpy(
				&peImage[curr_section.VirtualAddress],
				&exeData[curr_section.PointerToRawData],
				curr_section.SizeOfRawData);
		}
		printf("[v] file mapping ok\n");

		fixIat(peImage);
		printf("[v] fix iat.\n");

		if (relocOk)
		{
			fixReloc(peImage);
			printf("[v] apply reloc.\n");
		}

		auto addrOfEntry = getNtHdr(exeData)->OptionalHeader.AddressOfEntryPoint;
		printf("[v] invoke entry @ %p ...\n", &peImage[addrOfEntry]);
		((void (*)()) & peImage[addrOfEntry])();
	}
	else
		printf("[x] alloc memory for exe @ %p failure.\n", imgBaseAt);
}

int main(int argc, char **argv)
{
	char *exeBuf;
	size_t exeSize;
	if (argc != 2)
		puts("usage: ./peLoader [path/to/exe]");
	else if (readBinFile(argv[1], &exeBuf, exeSize))
		peLoader(exeBuf);
	else
		puts("[!] exe file not found.");
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值