--------- 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;
}
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;
}