9.PE文件之扩大节

目录

扩大节对PE文件中哪些值会有影响?

扩大节步骤:

手动扩大节

代码扩大节


通常扩大最后一个节比较方便,假设扩大第一个节则后续所有节对应的数据都需要更改.

扩大节对PE文件中哪些值会有影响?

扩大节步骤:

  • 将最后一个节文件中的大小修改为当前文件大小加新增大小(文件对齐后的大小),节内存中的大小修改为当前内存大小加新增大小.
  • 修复IMAGE_OPTIONAL_HEADER → SizeOfImage.
  • 重新分配新增后对应大小的文件缓存.
  • 拷贝先前数据.

手动扩大节

通过WinHex工具查看PE文件默认属性

1).修改最后一个节文件与内存大小

方便测试这里扩大1000h(下述代码示例会自动检测对齐).

2).修复IMAGE_OPTIONAL_HEADER → SizeOfImage

这个值必须是内存对齐后的大小,默认值为0x00033000,扩大节大小为0x1000,内存对齐为1000h.

3.在文件中新增对应节数据

移至文件尾部选中最后一个字节,WinHex选中菜单栏中编辑,选中菜单项粘贴0数据

扩大节大小为1000h,对应十进制为4096.

新增数据后另存为文件,通过PE工具查看其数据

程序是否可以正常运行就知道扩大节成功与否.

代码扩大节

读取文件代码

PVOID FileToMem(IN PCHAR szFilePath, OUT LPDWORD dwFileSize)
{
	//打开文件
	FILE* pFile = fopen(szFilePath, "rb");
	if (!pFile)
	{
		printf("FileToMem fopen Fail \r\n");
		return NULL;
	}
 
	//获取文件长度
	fseek(pFile, 0, SEEK_END);			//SEEK_END文件结尾
	DWORD Size = ftell(pFile);
	fseek(pFile, 0, SEEK_SET);			//SEEK_SET文件开头
 
	//申请存储文件数据缓冲区
	PCHAR pFileBuffer = (PCHAR)malloc(Size);
	if (!pFileBuffer)
	{
		printf("FileToMem malloc Fail \r\n");
		fclose(pFile);
		return NULL;
	}
 
	//读取文件数据
	fread(pFileBuffer, Size, 1, pFile);
 
	//判断是否为可执行文件
	if (*(PSHORT)pFileBuffer != IMAGE_DOS_SIGNATURE)
	{
		printf("Error: MZ \r\n");
		fclose(pFile);
		free(pFileBuffer);
		return NULL;
	}
 
	if (*(PDWORD)(pFileBuffer + *(PDWORD)(pFileBuffer + 0x3C)) != IMAGE_NT_SIGNATURE)
	{
		printf("Error: PE \r\n");
		fclose(pFile);
		free(pFileBuffer);
		return NULL;
	}
 
	if (dwFileSize)
	{
		*dwFileSize = Size;
	}
 
	fclose(pFile);
 
	return pFileBuffer;
}

输出文件代码

VOID MemToFile(IN PCHAR szFilePath, IN PVOID pFileBuffer, IN DWORD dwFileSize)
{
	//打开文件
	FILE* pFile = fopen(szFilePath, "wb");
	if (!pFile)
	{
		printf("MemToFile fopen Fail \r\n");
		return;
	}
 
	//输出文件
	fwrite(pFileBuffer, dwFileSize, 1, pFile);
 
	fclose(pFile);
}

扩大节代码

PVOID ExpandSection(PCHAR pBuffer, DWORD dwSectionSize, LPDWORD pNewFileSize)
{
	//定位结构
	PIMAGE_DOS_HEADER        pDos = (PIMAGE_DOS_HEADER)pBuffer;
	PIMAGE_NT_HEADERS        pNth = (PIMAGE_NT_HEADERS)(pBuffer + pDos->e_lfanew);
	PIMAGE_FILE_HEADER		 pFil = (PIMAGE_FILE_HEADER)((PUCHAR)pNth + 4);
	PIMAGE_OPTIONAL_HEADER   pOpo = (PIMAGE_OPTIONAL_HEADER)((PUCHAR)pFil + IMAGE_SIZEOF_FILE_HEADER);
	PIMAGE_SECTION_HEADER    pSec = (PIMAGE_SECTION_HEADER)((PUCHAR)pOpo + pFil->SizeOfOptionalHeader);

	//默认文件大小
	DWORD dwOldSize = pSec[pFil->NumberOfSections - 1].SizeOfRawData + pSec[pFil->NumberOfSections - 1].PointerToRawData;

	//修改最后一个节的属性
	pSec[pFil->NumberOfSections - 1].Misc.VirtualSize += dwSectionSize;//内存中对齐前的大小
	pSec[pFil->NumberOfSections - 1].SizeOfRawData += Align(pOpo->FileAlignment, dwSectionSize);//文件中对齐后的大小
	
	//修复内存镜像大小
	pOpo->SizeOfImage += Align(pOpo->SectionAlignment, dwSectionSize);

	//当前文件大小
	DWORD dwNewSize = pSec[pFil->NumberOfSections - 1].SizeOfRawData + pSec[pFil->NumberOfSections - 1].PointerToRawData;
	if (pNewFileSize)
	{
		*pNewFileSize = dwNewSize;
	}

	//重新分配缓冲区
	PUCHAR pTemp = (PUCHAR)malloc(dwNewSize);
	if (!pTemp)
	{
		printf("AddNewSection malloc Fail \r\n");
		free(pBuffer);
		return NULL;
	}
	memset(pTemp, 0, dwNewSize);
	memcpy(pTemp, pBuffer, dwOldSize);
	free(pBuffer);

	return pTemp;
}

测试代码

int main()
{
	//读取文件二进制数据
	DWORD dwFileSize = 0;
	PCHAR pFileBuffer = FileToMem(FILE_PATH_IN, &dwFileSize);
	if (!pFileBuffer)
	{
		return;
	}

	//扩大节
	pFileBuffer = ExpandSection(pFileBuffer, 0x2222, &dwFileSize);

	//将二进制数据输出到文件
	MemToFile(FILE_PATH_OUT, pFileBuffer, dwFileSize);

	return
		;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
为了实现.exe文件表免疫,可以通过以下步骤: 1. 使用Windows API函数打开可执行文件,获取可执行文件文件头和表信息。 2. 计算新的NT头偏移量,将NT头偏移至表之后。 3. 将修改后的NT头信息写回可执行文件中。 以下是相应的C++代码实现: ```c++ #include <windows.h> #include <iostream> using namespace std; int main() { // 打开可执行文件 HANDLE hFile = CreateFileA("test.exe", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { cout << "Open file failed!" << endl; return 0; } // 获取可执行文件文件头 IMAGE_DOS_HEADER dosHeader; DWORD dwBytesRead = 0; ReadFile(hFile, &dosHeader, sizeof(dosHeader), &dwBytesRead, NULL); if (dwBytesRead != sizeof(dosHeader)) { cout << "Read file header failed!" << endl; CloseHandle(hFile); return 0; } IMAGE_NT_HEADERS ntHeader; ReadFile(hFile, &ntHeader, sizeof(ntHeader), &dwBytesRead, NULL); if (dwBytesRead != sizeof(ntHeader)) { cout << "Read file header failed!" << endl; CloseHandle(hFile); return 0; } // 获取表信息 DWORD dwSectionOffset = dosHeader.e_lfanew + sizeof(ntHeader.Signature) + sizeof(ntHeader.FileHeader) + ntHeader.FileHeader.SizeOfOptionalHeader; IMAGE_SECTION_HEADER sectionHeader; SetFilePointer(hFile, dwSectionOffset, NULL, FILE_BEGIN); for (int i = 0; i < ntHeader.FileHeader.NumberOfSections; i++) { ReadFile(hFile, &sectionHeader, sizeof(sectionHeader), &dwBytesRead, NULL); if (dwBytesRead != sizeof(sectionHeader)) { cout << "Read section header failed!" << endl; CloseHandle(hFile); return 0; } } // 计算新的NT头偏移量 DWORD dwNewNtHeaderOffset = dwSectionOffset + ntHeader.FileHeader.NumberOfSections * sizeof(sectionHeader); // 将NT头偏移至表之后 SetFilePointer(hFile, dwNewNtHeaderOffset, NULL, FILE_BEGIN); WriteFile(hFile, &ntHeader, sizeof(ntHeader), &dwBytesRead, NULL); if (dwBytesRead != sizeof(ntHeader)) { cout << "Write NT header failed!" << endl; CloseHandle(hFile); return 0; } // 关闭文件句柄 CloseHandle(hFile); cout << "File section table immune success!" << endl; return 0; } ``` 需要注意的是,此代码仅供学习和参考使用,具体实现可能需要根据实际情况进行调整和优化。同时,对于修改可执行文件的操作需谨慎,应在测试环境下进行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值