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;
}
User contributions licensed under CC BY-SA 3.0