扩大节一般选择最后一节,因为拓展中间的节可能会覆盖有用的内存
本文使用的是海哥的思路:
FileBufferFileBuffer的最后一节中从Misc.VirtualSize开始向后扩大Misc.VirtualSize需要计算文件对齐写入SizeOfRawDataMisc.VirtualSize需要计算内存对齐得出新的SizeOfImageFileBuffer拉伸到ImageBuffer后再缩小写入新EXE实际上可以不进行拉伸,直接在FileBuffer层面进行操作
不过本文的思路和代码都采用了海哥的视频

处理PE头和NT头部分代码同上文
xxxxxxxxxxif (!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);拿到最后一节各个字段的指针,用于修改设置新属性
xxxxxxxxxxpLastSectionHeader = &(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
xxxxxxxxxxDWORD OldVirtualSize = *pVirtualSize;*pVirtualSize = *pVirtualSize + 0x1234;
先来整一个对齐函数:如果除尽认为对齐,有余数则做一些简单的计算来对齐
xxxxxxxxxxDWORD 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对齐
xxxxxxxxxxprintf("修改前SizeOfRawData: %X\n", *pSizeOfRawData);*pSizeOfRawData = AlignLength((DWORD)*pSizeOfRawData + 0x1234, pOptionHeader->FileAlignment);printf("修改后SizeOfRawData: %X\n", *pSizeOfRawData);内存对齐需要修改的是SizeOfImage属性,参考开头的图片,该属性表示了整个ImageBuffer的大小。先保存一份旧SizeOfImage后续使用,计算出新的最后一节的对齐大小NewLastSize(将目前的VirtualSize按照SectionAlignment对齐)之后根据原始VirtualAddress偏移加新对齐大小,得到总大小SizeOfImage
xxxxxxxxxxprintf("修改前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后复制头部不变的信息
xxxxxxxxxxDWORD NewImageSize = *pSizeOfImage;pTempNewImageBuffer = malloc(NewImageSize);if (!pTempNewImageBuffer){    return 0;}memset(pTempNewImageBuffer, 0, NewImageSize);memcpy(pTempNewImageBuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
创建一个临时指针pTempSectionHeader用于遍历复制所有节,其中遇到最后一节时,记录对齐前VirtualSize处的偏移,后续清理内存使用该偏移
xxxxxxxxxxPIMAGE_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之差的数量
xxxxxxxxxxif (LastOff == 0){    return 0;}memset((PBYTE)LastOff - 0x1234,0, NewImageSize-OldSizeOfImage);使用二进制编辑器打开文件,观察到末尾都是0,成功清理

整个函数的代码如下
xxxxxxxxxxDWORD 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;}