#    This file is part of Metasm, the Ruby assembly manipulation suite
#    Copyright (C) 2006-2009 Yoann GUILLOT
#
#    Licence is LGPL, see LICENCE in the top-level directory

# This samples generates a binary loader that will load and patch a Win32 program in memory
# The patch data are read from assembly files named 'patch_<hex addr>.asm'
# The 1st mandatory argument is the name of the target binary to load
# The 2nd optional argument is the name of the loader to be generated

require 'metasm'

target = ARGV.shift
loader = ARGV.shift || "loader.exe"

abort "need a target binary name to load&patch" if not target

cpu = Metasm::Ia32.new

# assemble the patches, to put the binary in the C source
patches = Dir['patch_*.asm'].map { |f|
	puts " [+] assembling #{f}"
	addr = f[/patch_(.*)\.asm/, 1].to_i(16)
	sc = Metasm::Shellcode.assemble_file(cpu, f)
	sc.base_addr = addr
	raw = sc.encode_string
	[addr, raw]
}


# the C program skeleton
c_src = <<EOS

void main(void)
{
	static PROCESS_INFORMATION pi;
	static STARTUPINFO si = { .cb = sizeof(si) };
	int i;

	CreateProcess(#{target.inspect}, 0, 0, 0, 0, CREATE_SUSPENDED, 0, 0, &si, &pi);

	#{patches.map { |addr, raw|
		"WriteProcessMemory(pi.hProcess, (void*)#{'0x%X' % addr}, #{raw.inspect}, #{raw.length}, 0);"
	}.join("\n\t")}

	CloseHandle(pi.hProcess);

	ResumeThread(pi.hThread);
	CloseHandle(pi.hThread);

	ExitProcess(0);
}
EOS


# the winapi definitions (generated by factorize_headers.rb)
c_hdr = <<EOS
#define CREATE_SUSPENDED 0x00000004
#define CreateProcess CreateProcessA

typedef int BOOL;
typedef unsigned char BYTE;
typedef char CHAR;
typedef unsigned long DWORD;
typedef void *HANDLE;
typedef const void *LPCVOID;
typedef void *LPVOID;
typedef unsigned int UINT;
typedef unsigned long ULONG_PTR;
typedef unsigned short WORD;

__stdcall BOOL CloseHandle __attribute__((dllimport))(HANDLE hObject);
__noreturn __stdcall void ExitProcess __attribute__((dllimport))(UINT uExitCode);
typedef BYTE *LPBYTE;
typedef const CHAR *LPCSTR;
typedef CHAR *LPSTR;
__stdcall DWORD ResumeThread __attribute__((dllimport))(HANDLE hThread);
typedef ULONG_PTR SIZE_T;

struct _PROCESS_INFORMATION {
	HANDLE hProcess;
	HANDLE hThread;
	DWORD dwProcessId;
	DWORD dwThreadId;
};

struct _SECURITY_ATTRIBUTES {
	DWORD nLength;
	LPVOID lpSecurityDescriptor;
	BOOL bInheritHandle;
};

typedef struct _PROCESS_INFORMATION *LPPROCESS_INFORMATION;
typedef struct _SECURITY_ATTRIBUTES *LPSECURITY_ATTRIBUTES;
typedef struct _PROCESS_INFORMATION PROCESS_INFORMATION;
__stdcall BOOL WriteProcessMemory __attribute__((dllimport))(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten);

struct _STARTUPINFOA {
	DWORD cb;
	LPSTR lpReserved;
	LPSTR lpDesktop;
	LPSTR lpTitle;
	DWORD dwX;
	DWORD dwY;
	DWORD dwXSize;
	DWORD dwYSize;
	DWORD dwXCountChars;
	DWORD dwYCountChars;
	DWORD dwFillAttribute;
	DWORD dwFlags;
	WORD wShowWindow;
	WORD cbReserved2;
	LPBYTE lpReserved2;
	HANDLE hStdInput;
	HANDLE hStdOutput;
	HANDLE hStdError;
};

typedef struct _STARTUPINFOA *LPSTARTUPINFOA;
typedef struct _STARTUPINFOA STARTUPINFOA;

__stdcall BOOL CreateProcessA __attribute__((dllimport))(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);
typedef STARTUPINFOA STARTUPINFO;
EOS


puts c_src, ''

# compile the loader
Metasm::PE.compile_c(cpu, c_hdr+c_src).encode_file(loader)

puts " [+] #{loader} saved"
