把所有節合併成一個節,好處是可以騰出節表空間,保證能成功新增節。
方法是先拉伸成imagebuffer,修改第一個節的VirtualSize = SizeOfRawData = SizeOfImage - VirtualAddress,因爲PE文件本身就對齊好了,所以不用關心對齊問題。由於修改了SizeOfRawData ,處理後PE文件會變大。除此之外還要修改節的數量,和第一個節必須具有其他節的屬性。
代碼
// 合併所有節
BOOL MergeSection(LPVOID pImageBuffer, LPVOID *pNewImageBuffer, DWORD imageSize)
{
*pNewImageBuffer = malloc(imageSize);
memcpy(*pNewImageBuffer, pImageBuffer, imageSize);
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;
pDosHeader = (PIMAGE_DOS_HEADER)*pNewImageBuffer;
pNTHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + (DWORD)*pNewImageBuffer);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pNTHeader + 0x18);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
// 第一個節的VirtualSize = SizeOfRawData = SizeOfImage - VirtualAddress
pSectionHeader->Misc.VirtualSize = pSectionHeader->SizeOfRawData = \
pOptionHeader->SizeOfImage - pSectionHeader->VirtualAddress;
//對齊
//pSectionHeader->Misc.VirtualSize = Align(pSectionHeader->Misc.VirtualSize, pOptionHeader->SectionAlignment);
//pSectionHeader->SizeOfRawData = Align(pSectionHeader->SizeOfRawData, pOptionHeader->FileAlignment);
// 屬性包含所有節的屬性
for (int i = 1; i < pPEHeader->NumberOfSections; i++)
{
pSectionHeader[0].Characteristics |= pSectionHeader[i].Characteristics;
}
// 節的數量 = 1
pPEHeader->NumberOfSections = 1;
return TRUE;
}
結果
測試了幾個32位GUI程序,擴大後均能正常運行。
下圖是notepad合併節後的結果對比:
可以看到,文件大小改變了,節的數量也由原來的3變成了1。
附上驅動程序
// 測試合併節
DWORD TestMergeSection(LPSTR lpszFile, LPSTR lpszOut)
{
LPVOID pFileBuffer = NULL;
LPVOID pNewFileBuffer = NULL;
LPVOID pImageBuffer = NULL;
LPVOID pNewImageBuffer = NULL;
DWORD fileBufferSize = 0;
DWORD newFileBufferSize = 0;
DWORD imageBufferSize = 0;
DWORD newImageBufferSize = 0;
fileBufferSize = ReadPEFile(lpszFile, &pFileBuffer);
if (fileBufferSize == 0)
{
printf("打開文件失敗\n");
return -1;
}
imageBufferSize = CopyFileBufferToImageBuffer(pFileBuffer, &pImageBuffer);
if (imageBufferSize == 0)
{
printf("拉伸失敗\n");
return -1;
}
if (!MergeSection(pImageBuffer, &pNewImageBuffer, imageBufferSize))
{
printf("合併節失敗\n");
return -1;
}
newFileBufferSize = CopyImageBufferToNewBuffer(pNewImageBuffer, &pNewFileBuffer);
if (newFileBufferSize == 0)
{
printf("CopyImageBufferToNewBuffer 失敗\n");
return -1;
}
if (!MemeryTOFile(pNewFileBuffer,newFileBufferSize,lpszOut))
{
printf("存盤失敗\n");
return -1;
}
free(pFileBuffer);
free(pNewFileBuffer);
free(pImageBuffer);
free(pNewImageBuffer);
return 0;
}
int main(int argc, char *argv[])
{
TestMergeSection("c:\\winmine.exe", "c:\\out.exe");
return 0;
}