mirror of
https://github.com/x64dbg/xdbg.git
synced 2026-11-07 12:16:01 -10:00
686 lines
22 KiB
C++
686 lines
22 KiB
C++
//*******************************************************************************************************
|
|
// loadEXE.cpp : Defines the entry point for the console application.
|
|
//
|
|
// Proof-Of-Concept Code
|
|
// Copyright (c) 2004
|
|
// All rights reserved.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
// copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, and/or sell copies of the Software, and to permit persons
|
|
// to whom the Software is furnished to do so, provided that the above
|
|
// copyright notice(s) and this permission notice appear in all copies of
|
|
// the Software and that both the above copyright notice(s) and this
|
|
// permission notice appear in supporting documentation.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
// OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
// HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
|
|
// INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
|
|
// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
|
// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
//
|
|
// Usage:
|
|
// loadEXE <EXE filename>
|
|
//
|
|
// This will execute calc.exe in suspended mode and replace its image with
|
|
// the new EXE's image. The thread is then resumed, thus causing the new EXE to
|
|
// execute within the process space of svchost.exe.
|
|
//
|
|
//*******************************************************************************************************
|
|
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include <tlhelp32.h>
|
|
#include <psapi.h>
|
|
|
|
struct PE_Header
|
|
{
|
|
unsigned long signature;
|
|
unsigned short machine;
|
|
unsigned short numSections;
|
|
unsigned long timeDateStamp;
|
|
unsigned long pointerToSymbolTable;
|
|
unsigned long numOfSymbols;
|
|
unsigned short sizeOfOptionHeader;
|
|
unsigned short characteristics;
|
|
};
|
|
|
|
struct PE_ExtHeader
|
|
{
|
|
unsigned short magic;
|
|
unsigned char majorLinkerVersion;
|
|
unsigned char minorLinkerVersion;
|
|
unsigned long sizeOfCode;
|
|
unsigned long sizeOfInitializedData;
|
|
unsigned long sizeOfUninitializedData;
|
|
unsigned long addressOfEntryPoint;
|
|
unsigned long baseOfCode;
|
|
unsigned long baseOfData;
|
|
unsigned long imageBase;
|
|
unsigned long sectionAlignment;
|
|
unsigned long fileAlignment;
|
|
unsigned short majorOSVersion;
|
|
unsigned short minorOSVersion;
|
|
unsigned short majorImageVersion;
|
|
unsigned short minorImageVersion;
|
|
unsigned short majorSubsystemVersion;
|
|
unsigned short minorSubsystemVersion;
|
|
unsigned long reserved1;
|
|
unsigned long sizeOfImage;
|
|
unsigned long sizeOfHeaders;
|
|
unsigned long checksum;
|
|
unsigned short subsystem;
|
|
unsigned short DLLCharacteristics;
|
|
unsigned long sizeOfStackReserve;
|
|
unsigned long sizeOfStackCommit;
|
|
unsigned long sizeOfHeapReserve;
|
|
unsigned long sizeOfHeapCommit;
|
|
unsigned long loaderFlags;
|
|
unsigned long numberOfRVAAndSizes;
|
|
unsigned long exportTableAddress;
|
|
unsigned long exportTableSize;
|
|
unsigned long importTableAddress;
|
|
unsigned long importTableSize;
|
|
unsigned long resourceTableAddress;
|
|
unsigned long resourceTableSize;
|
|
unsigned long exceptionTableAddress;
|
|
unsigned long exceptionTableSize;
|
|
unsigned long certFilePointer;
|
|
unsigned long certTableSize;
|
|
unsigned long relocationTableAddress;
|
|
unsigned long relocationTableSize;
|
|
unsigned long debugDataAddress;
|
|
unsigned long debugDataSize;
|
|
unsigned long archDataAddress;
|
|
unsigned long archDataSize;
|
|
unsigned long globalPtrAddress;
|
|
unsigned long globalPtrSize;
|
|
unsigned long TLSTableAddress;
|
|
unsigned long TLSTableSize;
|
|
unsigned long loadConfigTableAddress;
|
|
unsigned long loadConfigTableSize;
|
|
unsigned long boundImportTableAddress;
|
|
unsigned long boundImportTableSize;
|
|
unsigned long importAddressTableAddress;
|
|
unsigned long importAddressTableSize;
|
|
unsigned long delayImportDescAddress;
|
|
unsigned long delayImportDescSize;
|
|
unsigned long COMHeaderAddress;
|
|
unsigned long COMHeaderSize;
|
|
unsigned long reserved2;
|
|
unsigned long reserved3;
|
|
};
|
|
|
|
|
|
struct SectionHeader
|
|
{
|
|
unsigned char sectionName[8];
|
|
unsigned long virtualSize;
|
|
unsigned long virtualAddress;
|
|
unsigned long sizeOfRawData;
|
|
unsigned long pointerToRawData;
|
|
unsigned long pointerToRelocations;
|
|
unsigned long pointerToLineNumbers;
|
|
unsigned short numberOfRelocations;
|
|
unsigned short numberOfLineNumbers;
|
|
unsigned long characteristics;
|
|
};
|
|
|
|
struct MZHeader
|
|
{
|
|
unsigned short signature;
|
|
unsigned short partPag;
|
|
unsigned short pageCnt;
|
|
unsigned short reloCnt;
|
|
unsigned short hdrSize;
|
|
unsigned short minMem;
|
|
unsigned short maxMem;
|
|
unsigned short reloSS;
|
|
unsigned short exeSP;
|
|
unsigned short chksum;
|
|
unsigned short exeIP;
|
|
unsigned short reloCS;
|
|
unsigned short tablOff;
|
|
unsigned short overlay;
|
|
unsigned char reserved[32];
|
|
unsigned long offsetToPE;
|
|
};
|
|
|
|
|
|
struct ImportDirEntry
|
|
{
|
|
DWORD importLookupTable;
|
|
DWORD timeDateStamp;
|
|
DWORD fowarderChain;
|
|
DWORD nameRVA;
|
|
DWORD importAddressTable;
|
|
};
|
|
|
|
|
|
//**********************************************************************************************************
|
|
//
|
|
// This function reads the MZ, PE, PE extended and Section Headers from an EXE file.
|
|
//
|
|
//**********************************************************************************************************
|
|
|
|
bool readPEInfo(FILE *fp, MZHeader *outMZ, PE_Header *outPE, PE_ExtHeader *outpeXH,
|
|
SectionHeader **outSecHdr)
|
|
{
|
|
fseek(fp, 0, SEEK_END);
|
|
long fileSize = ftell(fp);
|
|
fseek(fp, 0, SEEK_SET);
|
|
|
|
if(fileSize < sizeof(MZHeader))
|
|
{
|
|
printf("File size too small ");
|
|
return false;
|
|
}
|
|
|
|
// read MZ Header
|
|
MZHeader mzH;
|
|
fread(&mzH, sizeof(MZHeader), 1, fp);
|
|
|
|
if(mzH.signature != 0x5a4d) // MZ
|
|
{
|
|
printf("File does not have MZ header ");
|
|
return false;
|
|
}
|
|
|
|
//printf("Offset to PE Header = %X ", mzH.offsetToPE);
|
|
|
|
if((unsigned long)fileSize < mzH.offsetToPE + sizeof(PE_Header))
|
|
{
|
|
printf("File size too small ");
|
|
return false;
|
|
}
|
|
|
|
// read PE Header
|
|
fseek(fp, mzH.offsetToPE, SEEK_SET);
|
|
PE_Header peH;
|
|
fread(&peH, sizeof(PE_Header), 1, fp);
|
|
|
|
//printf("Size of option header = %d ", peH.sizeOfOptionHeader);
|
|
//printf("Number of sections = %d ", peH.numSections);
|
|
|
|
if(peH.sizeOfOptionHeader != sizeof(PE_ExtHeader))
|
|
{
|
|
printf("Unexpected option header size. ");
|
|
|
|
return false;
|
|
}
|
|
|
|
// read PE Ext Header
|
|
PE_ExtHeader peXH;
|
|
|
|
fread(&peXH, sizeof(PE_ExtHeader), 1, fp);
|
|
|
|
//printf("Import table address = %X ", peXH.importTableAddress);
|
|
//printf("Import table size = %X ", peXH.importTableSize);
|
|
//printf("Import address table address = %X ", peXH.importAddressTableAddress);
|
|
//printf("Import address table size = %X ", peXH.importAddressTableSize);
|
|
|
|
|
|
// read the sections
|
|
SectionHeader *secHdr = new SectionHeader[peH.numSections];
|
|
|
|
fread(secHdr, sizeof(SectionHeader) * peH.numSections, 1, fp);
|
|
|
|
*outMZ = mzH;
|
|
*outPE = peH;
|
|
*outpeXH = peXH;
|
|
*outSecHdr = secHdr;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//**********************************************************************************************************
|
|
//
|
|
// This function calculates the size required to load an EXE into memory with proper alignment.
|
|
//
|
|
//**********************************************************************************************************
|
|
|
|
int calcTotalImageSize(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
|
|
SectionHeader *inSecHdr)
|
|
{
|
|
int result = 0;
|
|
int alignment = inpeXH->sectionAlignment;
|
|
|
|
if(inpeXH->sizeOfHeaders % alignment == 0)
|
|
result += inpeXH->sizeOfHeaders;
|
|
else
|
|
{
|
|
int val = inpeXH->sizeOfHeaders / alignment;
|
|
val++;
|
|
result += (val * alignment);
|
|
}
|
|
|
|
|
|
for(int i = 0; i < inPE->numSections; i++)
|
|
{
|
|
if(inSecHdr[i].virtualSize)
|
|
{
|
|
if(inSecHdr[i].virtualSize % alignment == 0)
|
|
result += inSecHdr[i].virtualSize;
|
|
else
|
|
{
|
|
int val = inSecHdr[i].virtualSize / alignment;
|
|
val++;
|
|
result += (val * alignment);
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
//**********************************************************************************************************
|
|
//
|
|
// This function calculates the aligned size of a section
|
|
//
|
|
//**********************************************************************************************************
|
|
|
|
unsigned long getAlignedSize(unsigned long curSize, unsigned long alignment)
|
|
{
|
|
if(curSize % alignment == 0)
|
|
return curSize;
|
|
else
|
|
{
|
|
int val = curSize / alignment;
|
|
val++;
|
|
return (val * alignment);
|
|
}
|
|
}
|
|
|
|
|
|
//**********************************************************************************************************
|
|
//
|
|
// This function loads a PE file into memory with proper alignment.
|
|
// Enough memory must be allocated at ptrLoc.
|
|
//
|
|
//**********************************************************************************************************
|
|
|
|
bool loadPE(FILE *fp, MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
|
|
SectionHeader *inSecHdr, LPVOID ptrLoc)
|
|
{
|
|
char *outPtr = (char *)ptrLoc;
|
|
|
|
fseek(fp, 0, SEEK_SET);
|
|
unsigned long headerSize = inpeXH->sizeOfHeaders;
|
|
|
|
// certain PE files have sectionHeaderSize value > size of PE file itself.
|
|
// this loop handles this situation by find the section that is nearest to the
|
|
// PE header.
|
|
|
|
for(int i = 0; i < inPE->numSections; i++)
|
|
{
|
|
if(inSecHdr[i].pointerToRawData < headerSize)
|
|
headerSize = inSecHdr[i].pointerToRawData;
|
|
}
|
|
|
|
// read the PE header
|
|
unsigned long readSize = fread(outPtr, 1, headerSize, fp);
|
|
//printf("HeaderSize = %d ", headerSize);
|
|
if(readSize != headerSize)
|
|
{
|
|
printf("Error reading headers (%d %d) ", readSize, headerSize);
|
|
return false;
|
|
}
|
|
|
|
outPtr += getAlignedSize(inpeXH->sizeOfHeaders, inpeXH->sectionAlignment);
|
|
|
|
// read the sections
|
|
for(i = 0; i < inPE->numSections; i++)
|
|
{
|
|
if(inSecHdr[i].sizeOfRawData > 0)
|
|
{
|
|
unsigned long toRead = inSecHdr[i].sizeOfRawData;
|
|
if(toRead > inSecHdr[i].virtualSize)
|
|
toRead = inSecHdr[i].virtualSize;
|
|
|
|
fseek(fp, inSecHdr[i].pointerToRawData, SEEK_SET);
|
|
readSize = fread(outPtr, 1, toRead, fp);
|
|
|
|
if(readSize != toRead)
|
|
{
|
|
printf("Error reading section %d ", i);
|
|
return false;
|
|
}
|
|
outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH->sectionAlignment);
|
|
}
|
|
else
|
|
{
|
|
// this handles the case where the PE file has an empty section. E.g. UPX0 section
|
|
// in UPXed files.
|
|
|
|
if(inSecHdr[i].virtualSize)
|
|
outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH->sectionAlignment);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
struct FixupBlock
|
|
{
|
|
unsigned long pageRVA;
|
|
unsigned long blockSize;
|
|
};
|
|
|
|
|
|
//**********************************************************************************************************
|
|
//
|
|
// This function loads a PE file into memory with proper alignment.
|
|
// Enough memory must be allocated at ptrLoc.
|
|
//
|
|
//**********************************************************************************************************
|
|
|
|
void doRelocation(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
|
|
SectionHeader *inSecHdr, LPVOID ptrLoc, DWORD newBase)
|
|
{
|
|
if(inpeXH->relocationTableAddress && inpeXH->relocationTableSize)
|
|
{
|
|
FixupBlock *fixBlk = (FixupBlock *)((char *)ptrLoc + inpeXH->relocationTableAddress);
|
|
long delta = newBase - inpeXH->imageBase;
|
|
|
|
while(fixBlk->blockSize)
|
|
{
|
|
//printf("Addr = %X ", fixBlk->pageRVA);
|
|
//printf("Size = %X ", fixBlk->blockSize);
|
|
|
|
int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1;
|
|
//printf("Num Entries = %d ", numEntries);
|
|
|
|
unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1);
|
|
|
|
for(int i = 0; i < numEntries; i++)
|
|
{
|
|
DWORD *codeLoc = (DWORD *)((char *)ptrLoc + fixBlk->pageRVA + (*offsetPtr & 0x0FFF));
|
|
|
|
int relocType = (*offsetPtr & 0xF000) >> 12;
|
|
|
|
//printf("Val = %X ", *offsetPtr);
|
|
//printf("Type = %X ", relocType);
|
|
|
|
if(relocType == 3)
|
|
*codeLoc = ((DWORD)*codeLoc) + delta;
|
|
else
|
|
{
|
|
printf("Unknown relocation type = %d ", relocType);
|
|
}
|
|
offsetPtr++;
|
|
}
|
|
|
|
fixBlk = (FixupBlock *)offsetPtr;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#define TARGETPROC "calc.exe"
|
|
CHAR szDefDir[] = "I:/MyProject/tools/Xptools";
|
|
//CHAR szDeft[] = "E:/WINDOWS/system32/notepad.exe";
|
|
//CHAR szDeft[] = "I:/MyProject/tools/Xptools/XPtools.exe";
|
|
//CHAR szDeft[] = "I:/MyProject/Test/Calcu/debug/Calcu.exe";
|
|
CHAR szDeft[] = "I:/MyProject/PCBTest/Bin/PCBTest.exe";
|
|
|
|
typedef struct _PROCINFO
|
|
{
|
|
DWORD baseAddr;
|
|
DWORD imageSize;
|
|
} PROCINFO;
|
|
|
|
|
|
|
|
//**********************************************************************************************************
|
|
//
|
|
// Creates the original EXE in suspended mode and returns its info in the PROCINFO structure.
|
|
//
|
|
//**********************************************************************************************************
|
|
|
|
|
|
BOOL createChild(PPROCESS_INFORMATION pi, PCONTEXT ctx, PROCINFO *outChildProcInfo)
|
|
{
|
|
STARTUPINFO si = {0};
|
|
|
|
if(CreateProcess(NULL, TARGETPROC,
|
|
NULL, NULL, 0, CREATE_SUSPENDED, NULL, szDefDir, &si, pi))
|
|
{
|
|
ctx->ContextFlags=CONTEXT_FULL;
|
|
GetThreadContext(pi->hThread, ctx);
|
|
|
|
DWORD *pebInfo = (DWORD *)ctx->Ebx;
|
|
DWORD read;
|
|
ReadProcessMemory(pi->hProcess, &pebInfo[2], (LPVOID)&(outChildProcInfo->baseAddr), sizeof(DWORD), &read);
|
|
|
|
DWORD curAddr = outChildProcInfo->baseAddr;
|
|
MEMORY_BASIC_INFORMATION memInfo;
|
|
while(VirtualQueryEx(pi->hProcess, (LPVOID)curAddr, &memInfo, sizeof(memInfo)))
|
|
{
|
|
if(memInfo.State == MEM_FREE)
|
|
break;
|
|
curAddr += memInfo.RegionSize;
|
|
}
|
|
outChildProcInfo->imageSize = (DWORD)curAddr - (DWORD)outChildProcInfo->baseAddr;
|
|
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//**********************************************************************************************************
|
|
//
|
|
// Returns true if the PE file has a relocation table
|
|
//
|
|
//**********************************************************************************************************
|
|
|
|
BOOL hasRelocationTable(PE_ExtHeader *inpeXH)
|
|
{
|
|
if(inpeXH->relocationTableAddress && inpeXH->relocationTableSize)
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
typedef DWORD (WINAPI *PTRZwUnmapViewOfSection)(IN HANDLE ProcessHandle, IN PVOID BaseAddress);
|
|
|
|
|
|
//**********************************************************************************************************
|
|
//
|
|
// To replace the original EXE with another one we do the following.
|
|
// 1) Create the original EXE process in suspended mode.
|
|
// 2) Unmap the image of the original EXE.
|
|
// 3) Allocate memory at the baseaddress of the new EXE.
|
|
// 4) Load the new EXE image into the allocated memory.
|
|
// 5) Windows will do the necessary imports and load the required DLLs for us when we resume the suspended
|
|
// thread.
|
|
//
|
|
// When the original EXE process is created in suspend mode, GetThreadContext returns these useful
|
|
// register values.
|
|
// EAX - process entry point
|
|
// EBX - points to PEB
|
|
//
|
|
// So before resuming the suspended thread, we need to set EAX of the context to the entry point of the
|
|
// new EXE.
|
|
//
|
|
//**********************************************************************************************************
|
|
|
|
void doFork(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
|
|
SectionHeader *inSecHdr, LPVOID ptrLoc, DWORD imageSize)
|
|
{
|
|
STARTUPINFO si = {0};
|
|
PROCESS_INFORMATION pi;
|
|
CONTEXT ctx;
|
|
PROCINFO childInfo;
|
|
|
|
if(createChild(&pi, &ctx, &childInfo))
|
|
{
|
|
printf("Original EXE loaded (PID = %d). ", pi.dwProcessId);
|
|
printf("Original Base Addr = %X, Size = %X ", childInfo.baseAddr, childInfo.imageSize);
|
|
|
|
LPVOID v = (LPVOID)NULL;
|
|
|
|
if(inpeXH->imageBase == childInfo.baseAddr && imageSize <= childInfo.imageSize)
|
|
{
|
|
// if new EXE has same baseaddr and is its size is <= to the original EXE, just
|
|
// overwrite it in memory
|
|
v = (LPVOID)childInfo.baseAddr;
|
|
DWORD oldProtect;
|
|
VirtualProtectEx(pi.hProcess, (LPVOID)childInfo.baseAddr, childInfo.imageSize, PAGE_EXECUTE_READWRITE, &oldProtect);
|
|
|
|
printf("Using Existing Mem for New EXE at %X ", (unsigned long)v);
|
|
}
|
|
else
|
|
{
|
|
// get address of ZwUnmapViewOfSection
|
|
PTRZwUnmapViewOfSection pZwUnmapViewOfSection = (PTRZwUnmapViewOfSection)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwUnmapViewOfSection");
|
|
|
|
// try to unmap the original EXE image
|
|
if(pZwUnmapViewOfSection(pi.hProcess, (LPVOID)childInfo.baseAddr) == 0)
|
|
{
|
|
// allocate memory for the new EXE image at the prefered imagebase.
|
|
v = VirtualAllocEx(pi.hProcess, (LPVOID)inpeXH->imageBase, imageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
if(v)
|
|
printf("Unmapped and Allocated Mem for New EXE at %X ", (unsigned long)v);
|
|
}
|
|
}
|
|
|
|
if(!v && hasRelocationTable(inpeXH))
|
|
{
|
|
// if unmap failed but EXE is relocatable, then we try to load the EXE at another
|
|
// location
|
|
v = VirtualAllocEx(pi.hProcess, (void *)NULL, imageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
if(v)
|
|
{
|
|
printf("Allocated Mem for New EXE at %X. EXE will be relocated. ", (unsigned long)v);
|
|
|
|
// we've got to do the relocation ourself if we load the image at another
|
|
// memory location
|
|
doRelocation(inMZ, inPE, inpeXH, inSecHdr, ptrLoc, (DWORD)v);
|
|
}
|
|
}
|
|
|
|
printf("EIP = %X ", ctx.Eip);
|
|
printf("EAX = %X ", ctx.Eax);
|
|
printf("EBX = %X ", ctx.Ebx); // EBX points to PEB
|
|
printf("ECX = %X ", ctx.Ecx);
|
|
printf("EDX = %X ", ctx.Edx);
|
|
|
|
if(v)
|
|
{
|
|
printf("New EXE Image Size = %X ", imageSize);
|
|
|
|
// patch the EXE base addr in PEB (PEB + 8 holds process base addr)
|
|
DWORD *pebInfo = (DWORD *)ctx.Ebx;
|
|
DWORD wrote;
|
|
WriteProcessMemory(pi.hProcess, &pebInfo[2], &v, sizeof(DWORD), &wrote);
|
|
|
|
// patch the base addr in the PE header of the EXE that we load ourselves
|
|
PE_ExtHeader *peXH = (PE_ExtHeader *)((DWORD)inMZ->offsetToPE + sizeof(PE_Header) + (DWORD)ptrLoc);
|
|
peXH->imageBase = (DWORD)v;
|
|
|
|
if(WriteProcessMemory(pi.hProcess, v, ptrLoc, imageSize, NULL))
|
|
{
|
|
printf("New EXE image injected into process. ");
|
|
|
|
ctx.ContextFlags=CONTEXT_FULL;
|
|
//ctx.Eip = (DWORD)v + ((DWORD)dllLoaderWritePtr - (DWORD)ptrLoc);
|
|
//ctx.Eip = 0x007B9640;
|
|
|
|
if((DWORD)v == childInfo.baseAddr)
|
|
{
|
|
ctx.Eax = (DWORD)inpeXH->imageBase + inpeXH->addressOfEntryPoint; // eax holds new entry point
|
|
}
|
|
else
|
|
{
|
|
// in this case, the DLL was not loaded at the baseaddr, i.e. manual relocation was
|
|
// performed.
|
|
ctx.Eax = (DWORD)v + inpeXH->addressOfEntryPoint; // eax holds new entry point
|
|
}
|
|
|
|
printf("********> EIP = %X ", ctx.Eip);
|
|
printf("********> EAX = %X ", ctx.Eax);
|
|
|
|
SetThreadContext(pi.hThread,&ctx);
|
|
|
|
ResumeThread(pi.hThread);
|
|
printf("Process resumed (PID = %d). ", pi.dwProcessId);
|
|
}
|
|
else
|
|
{
|
|
printf("WriteProcessMemory failed ");
|
|
TerminateProcess(pi.hProcess, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Load failed. Consider making this EXE relocatable. ");
|
|
TerminateProcess(pi.hProcess, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Cannot load %s ", TARGETPROC);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
POINT pt;
|
|
GetCursorPos(&pt);
|
|
|
|
FILE *fp;
|
|
if(argc != 2)
|
|
{
|
|
printf(" Usage: %s <EXE filename> ", argv[0]);
|
|
printf("No Input EXE, use: %s ", szDeft);
|
|
fp = fopen(szDeft, "rb");
|
|
}
|
|
else
|
|
fp = fopen(argv[1], "rb");
|
|
if(fp)
|
|
{
|
|
MZHeader mzH;
|
|
PE_Header peH;
|
|
PE_ExtHeader peXH;
|
|
SectionHeader *secHdr;
|
|
|
|
if(readPEInfo(fp, &mzH, &peH, &peXH, &secHdr))
|
|
{
|
|
int imageSize = calcTotalImageSize(&mzH, &peH, &peXH, secHdr);
|
|
//printf("Image Size = %X ", imageSize);
|
|
|
|
LPVOID ptrLoc = VirtualAlloc(NULL, imageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
if(ptrLoc)
|
|
{
|
|
//printf("Memory allocated at %X ", ptrLoc);
|
|
loadPE(fp, &mzH, &peH, &peXH, secHdr, ptrLoc);
|
|
|
|
doFork(&mzH, &peH, &peXH, secHdr, ptrLoc, imageSize);
|
|
}
|
|
else
|
|
printf("Allocation failed ");
|
|
}
|
|
|
|
fclose(fp);
|
|
}
|
|
else
|
|
printf(" Cannot open the EXE file! ");
|
|
|
|
return 0;
|
|
}
|