PE可执行文件在添加新部分时损坏

问题描述

我试图在可移植可执行文件中添加一个新部分,在这里我需要写一些数据,在这种情况下是整个文件。

第二个文件能够解析自身并从我在其中创建的部分读取数据,但是由于某些原因,当我使用下面的代码修改它时,它会损坏。

Imgur链接如下:很抱歉,格式错误:(

此消息框应出现。

image

但是我收到此错误消息:“此应用程序无法在您的PC上运行。”

image

新部分已正确添加到PE中:

image

新部分中的数据:

image

我真的无法分辨出这里出了什么问题。

#include <iostream>
#include <Windows.h>
#include <ShlObj.h>
#include <Shlwapi.h>
 
#pragma comment(lib,"Shell32.lib")
#pragma comment(lib,"Shlwapi.lib")
 
DWORD align(DWORD size,DWORD align,DWORD addr) {
    if (!(size % align))
        return addr + size;
    return addr + (size / align + 1) * align;
}
 
int main(int argc,char* argv[])
{
    if (argc < 3)
    {
        std::cout << "Argomenti insufficienti.\n";
        return 0;
    }
 
    char PathToSave[MAX_PATH];
 
    if (SUCCEEDED(SHGetFolderPathA(NULL,CSIDL_COMMON_DOCUMENTS,NULL,PathToSave)))
    {
        PathAppendA(PathToSave,"Bind.exe");
    }
 
    HANDLE fOutput = CreateFileA(PathToSave,GENERIC_WRITE,FILE_SHARE_WRITE,CREATE_ALWAYS,NULL);         // Unused
 
    HANDLE FirstFile = CreateFileA(argv[5],GENERIC_READ,FILE_SHARE_READ,OPEN_EXISTING,NULL);            // File to read data from
    if (FirstFile == INVALID_HANDLE_VALUE)
    {
        std::cout << "Impossibile aprire il file passato come primo argomento.\n";
        return 0;
    }
 
    HANDLE SecFile = CreateFileA(argv[5],GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL);               // File to write the read data in
    if (SecFile == INVALID_HANDLE_VALUE)
    {
        std::cout << "Impossibile aprire il file passato come secondo argomento.\n";
        return 0;
    }
 
    DWORD FirstFS = GetFileSize(FirstFile,0);              // First file dimension
    DWORD SecondFS = GetFileSize(SecFile,0);               // Second file dimension
 
    BYTE* FirstFB = (BYTE*)VirtualAlloc(NULL,FirstFS,MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE);           // Allocates memory for the first file
    BYTE* SecondFB = (BYTE*)VirtualAlloc(NULL,SecondFS,PAGE_READWRITE);         // Allocates memory for the second file
 
    DWORD BytesRead = 0;
    DWORD BytesWritten = 0;
 
    if (bool Read = ReadFile(FirstFile,FirstFB,&BytesRead,NULL) == FALSE)                   // Reads the first file
    {
        std::cout << "Impossibile leggere primo file.\n";
        return 0;
    }
    else
    {
        std::cout << "Letti " << BytesRead << " dal primo file.\n";
        BytesRead = 0;
    }
 
    if (bool Read = ReadFile(SecFile,SecondFB,NULL) == FALSE)                       // Reads the second file
    {
        std::cout << "Impossibile leggere secondo file.\n";
        return 0;
    }
    else
    {
        std::cout << "Letti " << BytesRead << " bytes dal secondo file.\n";
        BytesRead = 0;
    }
 
    /*
    * 
    * The code is problematic beyond this point!
    * 
    * SecondFB = Pointer to the second file's data buffer that needs to be modified by adding the new section.
    * FirstFB = Pointer to the first file's data buffer that will be written inside the ".sdata" section.
    * Both of them have been loaded in memory using VirtualAlloc.
    * 
    * Ask me anything for further info and many,many thanks :D
    
    */
 
    // Here I add a new section to the second file.
 
    PIMAGE_DOS_HEADER sIDH = (IMAGE_DOS_HEADER*)SecondFB;                                              
    PIMAGE_NT_HEADERS sINH = (IMAGE_NT_HEADERS*)(SecondFB + sIDH->e_lfanew);
    PIMAGE_FILE_HEADER sIFH = (PIMAGE_FILE_HEADER)(SecondFB + sIDH->e_lfanew + sizeof(DWORD));
    PIMAGE_OPTIONAL_HEADER sIOH = (PIMAGE_OPTIONAL_HEADER)(SecondFB + sIDH->e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER));
    PIMAGE_SECTION_HEADER sISH = (PIMAGE_SECTION_HEADER)(SecondFB + sIDH->e_lfanew + sizeof(IMAGE_NT_HEADERS));
 
    // Here I name the new section inside the file
    ZeroMemory(sISH,sizeof(IMAGE_SECTION_HEADER));
    CopyMemory(sISH[sIFH->NumberOfSections].Name,".scode",8);
 
    /*
        0xE00000E0 = IMAGE_SCN_MEM_WRITE |
                     IMAGE_SCN_CNT_CODE  |
                     IMAGE_SCN_CNT_UNINITIALIZED_DATA  |
                     IMAGE_SCN_MEM_EXECUTE |
                     IMAGE_SCN_CNT_INITIALIZED_DATA |
                     IMAGE_SCN_MEM_READ
 
   
    */
 
    // Here all the required information gets filled in
    sISH[sIFH->NumberOfSections].VirtualAddress = align(sISH[sIFH->NumberOfSections - 1].Misc.VirtualSize,sIOH->SectionAlignment,sISH[sIFH->NumberOfSections - 1].VirtualAddress);
    sISH[sIFH->NumberOfSections].SizeOfRawData = align(FirstFS,0);
    sISH[sIFH->NumberOfSections].Misc.VirtualSize = align(FirstFS,0);
    sISH[sIFH->NumberOfSections].PointerToRawData = align(sISH[sIFH->NumberOfSections - 1].SizeOfRawData,sIOH->FileAlignment,sISH[sIFH->NumberOfSections - 1].PointerToRawData);
    sISH[sIFH->NumberOfSections].Characteristics = 0xE00000E0;
 
    // Here the changes are written to the second file
    SetFilePointer(SecFile,sISH[sIFH->NumberOfSections].PointerToRawData + sISH[sIFH->NumberOfSections].SizeOfRawData,FILE_BEGIN);
    SetEndOfFile(SecFile);
 
    sIOH->SizeOfImage = sISH[sIFH->NumberOfSections].VirtualAddress + sISH[sIFH->NumberOfSections].Misc.VirtualSize;
    sIFH->NumberOfSections += 1;
    SetFilePointer(SecFile,FILE_BEGIN);
 
    BytesWritten = 0;
 
    bool W = WriteFile(SecFile,&BytesWritten,NULL);
 
    if (W == FALSE)
    {
        std::cout << "Impossibile aggiungere sezione alla stub.\n";
        return 0;
    }
    else
    {
        std::cout << "Scritti " << BytesWritten << " bytes nella stub. (Aggiunta nuova sezione.)\n";
        BytesWritten = 0;
    }
 
    // Here I write the data inside the new section
    SetFilePointer(SecFile,sISH[sIFH->NumberOfSections - 1].PointerToRawData,FILE_BEGIN);
    if (bool Write = WriteFile(SecFile,NULL) == FALSE)
    {
        std::cout << "Impossibile aggiungere sezione alla stub.\n";
    }
    else
    {
        std::cout << "Scritti " << BytesWritten << " bytes nella stub.\n";
        BytesWritten = 0;
    }
 
// Here I close all the handles
 
    VirtualFree(FirstFB,MEM_RELEASE);
    CloseHandle(FirstFile);
 
    VirtualFree(SecondFB,MEM_RELEASE);
    CloseHandle(SecFile);
 
    std::cout << "Binding completato.\n";
 
    return 0;
}

解决方法

问题出在ZeroMemory(sISH,sizeof(IMAGE_SECTION_HEADER));

您删除了第一节的内存,这导致exe的节结构出现问题。这就是exe无法运行的原因。

解决方案:

=> ZeroMemory(&sISH[sIFH->NumberOfSections],sizeof(IMAGE_SECTION_HEADER)); //Clear the memory behind the last section

请不要忘记为第一个FILE_SHARE_WRITE添加CreateFileA,否则将导致第二个CreateFileA无法写入。

=> HANDLE FirstFile = CreateFileA(argv[5],GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,NULL); // File to read data from

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...