扩大节一般选择最后一节,因为拓展中间的节可能会覆盖有用的内存
本文使用的是海哥的思路:
FileBuffer
FileBuffer
的最后一节中从Misc.VirtualSize
开始向后扩大Misc.VirtualSize
需要计算文件对齐写入SizeOfRawData
Misc.VirtualSize
需要计算内存对齐得出新的SizeOfImage
FileBuffer
拉伸到ImageBuffer
后再缩小写入新EXE实际上可以不进行拉伸,直接在FileBuffer
层面进行操作
不过本文的思路和代码都采用了海哥的视频
处理PE头和NT头部分代码同上文
xxxxxxxxxx
if (!pFileBuffer)
{
return 0;
}
if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
{
return 0;
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
if (*((PWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
return 0;
}
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + (DWORD)0x04);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
numberOfSection = pPEHeader->NumberOfSections;
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
拿到最后一节各个字段的指针,用于修改设置新属性
xxxxxxxxxx
pLastSectionHeader = &(pSectionHeader[pPEHeader->NumberOfSections - 1]);
PDWORD pVirtualSize = &(pLastSectionHeader->Misc.VirtualSize);
PDWORD pSizeOfRawData = &(pLastSectionHeader->SizeOfRawData);
PDWORD pPointerToRawData = &(pLastSectionHeader->PointerToRawData);
PDWORD pSizeOfImage = &(pOptionHeader->SizeOfImage);
海哥举例使用的扩大0x1000
字节,这个数不能直观地看到对齐信息,所以我选0x1234
保存一份原来的对其前节大小OldVirtualSize
然后设置节对齐前大小增加0x1234
xxxxxxxxxx
DWORD OldVirtualSize = *pVirtualSize;
*pVirtualSize = *pVirtualSize + 0x1234;
先来整一个对齐函数:如果除尽认为对齐,有余数则做一些简单的计算来对齐
xxxxxxxxxx
DWORD AlignLength(DWORD ActualSize, DWORD AlignSize)
{
if (ActualSize % AlignSize == 0)
{
return ActualSize;
}
else
{
DWORD n = ActualSize / AlignSize;
return AlignSize * (n + 1);
}
}
首先计算文件中的对齐,由于VirtualSize
增加了0x1234
字节,对应的SizeOfRawData
至少会增加0x1234
字节,由于增加这样一个不寻常的值,所以无法对齐,需要利用上述的函数通过FileAlignment
对齐
xxxxxxxxxx
printf("修改前SizeOfRawData: %X\n", *pSizeOfRawData);
*pSizeOfRawData = AlignLength((DWORD)*pSizeOfRawData + 0x1234, pOptionHeader->FileAlignment);
printf("修改后SizeOfRawData: %X\n", *pSizeOfRawData);
内存对齐需要修改的是SizeOfImage
属性,参考开头的图片,该属性表示了整个ImageBuffer
的大小。先保存一份旧SizeOfImage
后续使用,计算出新的最后一节的对齐大小NewLastSize
(将目前的VirtualSize
按照SectionAlignment
对齐)之后根据原始VirtualAddress
偏移加新对齐大小,得到总大小SizeOfImage
xxxxxxxxxx
printf("修改前SizeOfImage: %X\n", *pSizeOfImage);
DWORD OldSizeOfImage = *pSizeOfImage;
DWORD NewLastSize = AlignLength((DWORD)*pVirtualSize, pOptionHeader->SectionAlignment);
*pSizeOfImage = pLastSectionHeader->VirtualAddress + NewLastSize;
printf("修改后SizeOfImage: %X\n", *pSizeOfImage);
对NOTEPAD.EXE
最后一节扩大后,输出如图,符合预期(文件对齐200内存对齐1000)
接下来的思路是拉伸FileIBuffer
得到一个扩大后的ImageBuffer
然后调用之前写的缩小函数,将这个拉伸后的ImageBuffer
再次缩小为FileBuffer
后保存
按照NewImageSize
分配内存,初始化为0后复制头部不变的信息
xxxxxxxxxx
DWORD NewImageSize = *pSizeOfImage;
pTempNewImageBuffer = malloc(NewImageSize);
if (!pTempNewImageBuffer)
{
return 0;
}
memset(pTempNewImageBuffer, 0, NewImageSize);
memcpy(pTempNewImageBuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
创建一个临时指针pTempSectionHeader
用于遍历复制所有节,其中遇到最后一节时,记录对齐前VirtualSize
处的偏移,后续清理内存使用该偏移
xxxxxxxxxx
PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
DWORD LastOff = 0;
for (DWORD i = 0; i < pPEHeader->NumberOfSections; i++)
{
if (i == pPEHeader->NumberOfSections - 1)
{
LastOff = (DWORD)pTempNewImageBuffer +
pTempSectionHeader->VirtualAddress+ pTempSectionHeader->Misc.VirtualSize;
}
memcpy((PVOID)((DWORD)pTempNewImageBuffer + pTempSectionHeader->VirtualAddress),
(PDWORD)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData), pTempSectionHeader->SizeOfRawData);
pTempSectionHeader++;
}
从LastOff
减去0x1234
字节得到最初的VirtualSize
处偏移,意味着从该处往后是内存对齐数据,这部分数据可以进行清理初始化,设置为0供后续使用,具体应该设置新旧SizeOfImage
之差的数量
xxxxxxxxxx
if (LastOff == 0)
{
return 0;
}
memset((PBYTE)LastOff - 0x1234,0, NewImageSize-OldSizeOfImage);
使用二进制编辑器打开文件,观察到末尾都是0,成功清理
整个函数的代码如下
xxxxxxxxxx
DWORD FileBufferToModifyImageBuffer(IN LPVOID pFileBuffer, OUT LPVOID* pNewImageBuffer)
{
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_SECTION_HEADER pLastSectionHeader = NULL;
LPVOID pTempNewImageBuffer = NULL;
DWORD ImageBufferSize = 0;
DWORD numberOfSection = 0;
if (!pFileBuffer)
{
return 0;
}
if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
{
return 0;
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
if (*((PWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
return 0;
}
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + (DWORD)0x04);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
numberOfSection = pPEHeader->NumberOfSections;
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
pLastSectionHeader = &(pSectionHeader[pPEHeader->NumberOfSections - 1]);
PDWORD pVirtualSize = &(pLastSectionHeader->Misc.VirtualSize);
PDWORD pSizeOfRawData = &(pLastSectionHeader->SizeOfRawData);
PDWORD pPointerToRawData = &(pLastSectionHeader->PointerToRawData);
PDWORD pSizeOfImage = &(pOptionHeader->SizeOfImage);
DWORD OldVirtualSize = *pVirtualSize;
*pVirtualSize = *pVirtualSize + 0x1234;
printf("修改前SizeOfRawData: %X\n", *pSizeOfRawData);
*pSizeOfRawData = AlignLength((DWORD)*pSizeOfRawData + 0x1234, pOptionHeader->FileAlignment);
printf("修改后SizeOfRawData: %X\n", *pSizeOfRawData);
printf("修改前SizeOfImage: %X\n", *pSizeOfImage);
DWORD OldSizeOfImage = *pSizeOfImage;
DWORD NewLastSize = AlignLength((DWORD)*pVirtualSize, pOptionHeader->SectionAlignment);
*pSizeOfImage = pLastSectionHeader->VirtualAddress + NewLastSize;
printf("修改后SizeOfImage: %X\n", *pSizeOfImage);
DWORD NewImageSize = *pSizeOfImage;
pTempNewImageBuffer = malloc(NewImageSize);
if (!pTempNewImageBuffer)
{
return 0;
}
memset(pTempNewImageBuffer, 0, NewImageSize);
memcpy(pTempNewImageBuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
DWORD LastOff = 0;
for (DWORD i = 0; i < pPEHeader->NumberOfSections; i++)
{
if (i == pPEHeader->NumberOfSections - 1)
{
LastOff = (DWORD)pTempNewImageBuffer +
pTempSectionHeader->VirtualAddress+ pTempSectionHeader->Misc.VirtualSize;
}
memcpy((PVOID)((DWORD)pTempNewImageBuffer + pTempSectionHeader->VirtualAddress),
(PDWORD)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData), pTempSectionHeader->SizeOfRawData);
pTempSectionHeader++;
}
if (LastOff == 0)
{
return 0;
}
memset((PBYTE)LastOff - 0x1234,0, NewImageSize-OldSizeOfImage);
*pNewImageBuffer = pTempNewImageBuffer;
pTempNewImageBuffer = NULL;
return NewImageSize;
}