8.PE文件之新增节

目录

新增节对PE文件中哪些值会有影响?

新增节步骤:

手动新增节

代码新增节


如果需要在PE文件中构建一端SHELLCODE(默认节区剩余空间不足情况下),可以通过新增节来解决此问题.通常大部分加壳软件都会新增节来移动或者备份各种目录项数据.

新增节对PE文件中哪些值会有影响?

新增节步骤:

  • 通过判断IMAGE_OPTIONAL_HEADER → SizeOfHeaders(所有头+节表文件对齐后的大小)来检查是否有足够空间新增一个节表数据,如果不够抹除DOS_STUB数据并整体移动NT,SECTION的数据到DOS_STUB位置.并修正IMAGE_DOS_HEADER → e_lfanew.
  • 在当前最后节后面新增一个IMAGE_SECTION_HEADER结构,并依据新增节大小修正其属性.
  • 修复IMAGE_FILE_HEADER→NumberOfSections.
  • 修复IMAGE_OPTIONAL_HEADER → SizeOfImage.
  • 重新分配新增后对应大小的文件缓存.
  • 拷贝先前数据.

手动新增节

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

1).判断空间是否足够新增节

当前最后一个节后存在SIZEOF(IMAGE_SECTION_HEADER) * 2(80BYTE) 大小的空闲数据.

2).最后节处追加一个节表结构

内存与文件中的大小设置为0x1000方便一点(文件中大小为文件对齐后的大小).

内存与文件中的偏移设置为上一个节中pointertorawdata + sizeofrawdata.

节属性根据实际要求设置即可标志位对应数据点此查看.

3).修复IMAGE_FILE_HEADER→NumberOfSections.

4.修复IMAGE_OPTIONAL_HEADER → SizeOfImage.

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

移至文件尾部选中最后一个字节,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);
}

移动NT+节表代码

BOOL MoveNtAndSectionToDosStub(IN PCHAR pBuffer)
{
	//定位结构
	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);

	//清空DOS_STUB数据
	memset(pBuffer + sizeof(IMAGE_DOS_HEADER), 0, pDos->e_lfanew - sizeof(IMAGE_DOS_HEADER));

	//移动数据大小
	DWORD dwMoveSize = sizeof(IMAGE_NT_HEADERS) + pFil->NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER;

	//备份数据
	PUCHAR pTemp = (PUCHAR)malloc(dwMoveSize);
	if (!pTemp)
	{
		return FALSE;
	}
	memset(pTemp,0, dwMoveSize);
	memcpy(pTemp, pBuffer + pDos->e_lfanew, dwMoveSize);

	//清空默认数据
	memset(pBuffer + pDos->e_lfanew, 0, dwMoveSize);

	//移动数据
	memcpy(pBuffer + sizeof(IMAGE_DOS_HEADER), pTemp, dwMoveSize);

	//修正e_lfanew指向
	pDos->e_lfanew = sizeof(IMAGE_DOS_HEADER);

	free(pTemp);

	return TRUE;
}

新增节代码

PVOID AddNewSection(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);

	//判断头部是否有空间新增节
	if (pBuffer + pOpo->SizeOfHeaders - &pSec[pFil->NumberOfSections + 1] < IMAGE_SIZEOF_SECTION_HEADER )
	{
		//抹除DOS_STUB数据并将NT,SECTION整理向上移动
		BOOL bRet = MoveNtAndSectionToDosStub(pBuffer);
		if (!bRet)
		{
			printf("AddNewSection MoveNtAndSectionToDosStub Fail \r\n");
			free(pBuffer);
			return NULL;
		}

		pDos = (PIMAGE_DOS_HEADER)pBuffer;
		pNth = (PIMAGE_NT_HEADERS)(pBuffer + pDos->e_lfanew);
		pFil = (PIMAGE_FILE_HEADER)((PUCHAR)pNth + 4);
		pOpo = (PIMAGE_OPTIONAL_HEADER)((PUCHAR)pFil + IMAGE_SIZEOF_FILE_HEADER);
		pSec = (PIMAGE_SECTION_HEADER)((PUCHAR)pOpo + pFil->SizeOfOptionalHeader);

	}

	//填充新增节数据
	CHAR szName[] = ".Kernel";
	memcpy(pSec[pFil->NumberOfSections].Name, szName,8);
	pSec[pFil->NumberOfSections].Misc.VirtualSize = dwSectionSize;//内存中对齐前的大小
	pSec[pFil->NumberOfSections].VirtualAddress = Align(pOpo->SectionAlignment, pSec[pFil->NumberOfSections - 1].Misc.VirtualSize + pSec[pFil->NumberOfSections - 1].VirtualAddress);//内存中的偏移
	pSec[pFil->NumberOfSections].SizeOfRawData = Align(pOpo->FileAlignment, dwSectionSize);//文件中对齐后的大小
	pSec[pFil->NumberOfSections].PointerToRawData = Align(pOpo->FileAlignment, pSec[pFil->NumberOfSections - 1].PointerToRawData + pSec[pFil->NumberOfSections - 1].SizeOfRawData);//文件中的偏移
	pSec[pFil->NumberOfSections].PointerToRelocations = 0;
	pSec[pFil->NumberOfSections].PointerToLinenumbers = 0;
	pSec[pFil->NumberOfSections].NumberOfRelocations = 0;
	pSec[pFil->NumberOfSections].NumberOfLinenumbers = 0;
	pSec[pFil->NumberOfSections].Characteristics |= pSec->Characteristics;//默认代码节
	pSec[pFil->NumberOfSections].Characteristics |= 0xC0000040;
	
	//新增节后补充大小为IMAGE_SECTION_HEADER结构的0数据
	memset(&pSec[pFil->NumberOfSections + 1], 0, IMAGE_SIZEOF_SECTION_HEADER);

	//修复默认节数量
	pFil->NumberOfSections++;

	//修复内存镜像大小
	pOpo->SizeOfImage += Align(pOpo->SectionAlignment, dwSectionSize);

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

	//当前文件大小
	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 = AddNewSection(pFileBuffer, 0x2222, &dwFileSize);

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

	return 0;
}

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值