Loading Go binary into memory and Running from C++

1

I am doing some independent cybersecurity research trying to read load a Windows executable into memory and run it from memory using C++. Using some videos and other Stack posts I was able to get it working with a very simple application I built using C++ that just shows a single pop-up and it works perfectly. However, I want to do the same process using a Golang binary, but whenever I build a simple Golang program and try to us it with the code below, I get an application error that says: "The application was unable to start correctly (0xc0000005). Click OK to close the application."

Most of my programming experience is in Golang and Python so this C++ code is fairly new to me for this most recent cybersecurity project, so I would appreciate any assistance!

This is my C++ code (the Go code is just a single fmt.Println built to an exe)

int RunPortableExecutable(void* Image)
{
    IMAGE_DOS_HEADER* DOSHeader; // For Nt DOS Header symbols
    IMAGE_NT_HEADERS* NtHeader; // For Nt PE Header objects and symbols
    IMAGE_SECTION_HEADER* SectionHeader;

    PROCESS_INFORMATION PI;
    STARTUPINFOA SI;

    CONTEXT* CTX;

    DWORD* ImageBase; //Base address of the image
    void* pImageBase; //Pointer to the image base

    int count;

    char CurrentFilePath[1024];

    DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize variable
    NtHeader = PIMAGE_NT_HEADERS(DWORD(Image) + DOSHeader->e_lfanew); // Initialize

    GetModuleFileNameA(0, CurrentFilePath, 1024); // Path to current executable

        if (NtHeader->Signature == IMAGE_NT_SIGNATURE) // Check if image is a PE file
        {
            ZeroMemory(&PI, sizeof(PI)); // Null the memory
            ZeroMemory(&SI, sizeof(SI)); // Null the memory

            if (CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) //Create new instance of process in suspended state (for new image)
            {
                CTX = PCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE)); // Allocate context memory
                CTX->ContextFlags = CONTEXT_FULL; // Context is allocated

                if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) // If context is in thread
                {
                    // Read instructions
                    ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&ImageBase), 4, 0);

                    pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase), NtHeader->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);

                    // WRite the image to the process
                    WriteProcessMemory(PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL);


                    for (count = 0; count < NtHeader->FileHeader.NumberOfSections; count++)
                    {
                        SectionHeader = PIMAGE_SECTION_HEADER(DWORD(Image) + DOSHeader->e_lfanew + 248 + (count * 40));

                        WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress), LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0);
                    }
                    WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8), LPVOID(&NtHeader->OptionalHeader.ImageBase), 4, 0);

                    // Move address of entry point to the new eax register
                    CTX->Eax = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint;
                    SetThreadContext(PI.hThread, LPCONTEXT(CTX)); // set the context
                    ResumeThread(PI.hThread); //Start the process

                    return 0;
                }
            }
        }
}

// Get the size of a file
long getFileSize(FILE* file)
{
    long lCurPos, lEndPos;
    lCurPos = ftell(file);
    fseek(file, 0, 2);
    lEndPos = ftell(file);
    fseek(file, lCurPos, 0);
    return lEndPos;
}

int main()
{
    const char* filePath = "printtest.exe";
    BYTE* fileBuf;            // Pointer to our buffered data
    FILE* file = NULL;        // File pointer

    if ((file = fopen(filePath, "rb")) == NULL)
        std::cout << "Could not open specified file" << std::endl;
    else
        std::cout << "File opened successfully" << std::endl;

    long fileSize = getFileSize(file);

    fileBuf = new BYTE[fileSize];

    fread(fileBuf, fileSize, 1, file);
    fclose(file);   // Almost forgot this 

    // This just logs some characters to verify it read in properly
    for (int i = 0; i < 300; i++)
        std::cout << fileBuf[i];
        //printf("%X ", fileBuf[i]);

    RunPortableExecutable(fileBuf);

    std::cin.get();
    delete[]fileBuf;

}
c++
go
executable
cybersecurity
asked on Stack Overflow Dec 9, 2020 by ira88

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0