Jump to content
Tuts 4 You

injecting code into a process


Messias

Recommended Posts

I have been injecting a DLL into a computer game to increase stamina, speed, etc but now i would like to learn how to inject code directly.

injecting a DLL is easy, inside my DLL i call API functions, for example i can show a MessageBox easily because my DLL has its own import section and the text i show on my MessageBox is located inside the DLL's data section.

Now im searching on injecting code directly into the game process but i don't know how to inject an API call that will show some text that im also going to inject.

i would like an example on injecting fox example:

MessageBox(0, "hello", "hi", 0);

i thought about injection a function that will get me the MessageBoxA function address at runtime but to get that address also requires calling another API function, GetProcessAddress() so how to inject code that will call API functions?

maybe my injecting code has to have it own import section but, will windows fill the values?, because it is not a DLL. any ideas?

i dont know if i explain myself correctly, i hope so. thanks!

Link to comment

Before I show you how to do what you are asking, I am going to say this.. I highly recommend you stick to DLL injection. It is a lot easier to deal with things rather then completely rewriting functions into byte arrays, patching, and fixing addresses to be properly aligned, calculated, etc. Having your DLL automatically do this for you makes things a lot easier.

This is just one of the ways you can go about doing this so please don't think this is the only way. I did it this way because I am used to doing it like this from creating trainers and such in past times. If you find a different way you like better so be it, to each their own. :)

Ok to start. We need to convert our function from C/C++ to 'inject' into our target. For my post I will be using Winmine.exe (Minesweeper) on a Windows XP pro machine for testing with. I usually write things out in a C/C++ program first, debug with Olly to see the function bytes and adjust as needed. This example will show you what I mean. We are going to need to do a bit of editing with our function.

Our C++ function for HelloWorld will look like this:

void HelloWorld( void )
{
char* szMessage = "Hello World!";
char* szCaption = "Hello!"; HMODULE hModule = LoadLibraryA( "user32.dll" );
FARPROC fFuncProc = GetProcAddress( hModule, "MessageBoxA" ); ( ( int ( WINAPI *)( HWND, LPCSTR, LPCSTR, UINT ) ) fFuncProc )( 0, szMessage, szCaption, 0 );
}

Basic and to the point, using LoadLibrary/GetProcAddress method with type casting to get better output in ASM. Olly shows this function like this:

00401000  /$ 55             PUSH EBP
00401001 |. 8BEC MOV EBP,ESP
00401003 |. 83EC 10 SUB ESP,10
00401006 |. C745 F0 142040>MOV DWORD PTR SS:[EBP-10],HelloWor.00402>; ASCII "Hello World!"
0040100D |. C745 FC 242040>MOV DWORD PTR SS:[EBP-4],HelloWor.004020>; ASCII "Hello!"
00401014 |. 68 2C204000 PUSH HelloWor.0040202C ; /FileName = "user32.dll"
00401019 |. FF15 04204000 CALL DWORD PTR DS:[<&KERNEL32.LoadLibrar>; \LoadLibraryA
0040101F |. 8945 F4 MOV DWORD PTR SS:[EBP-C],EAX
00401022 |. 68 38204000 PUSH HelloWor.00402038 ; /ProcNameOrOrdinal = "MessageBoxA"
00401027 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C] ; |
0040102A |. 50 PUSH EAX ; |hModule
0040102B |. FF15 00204000 CALL DWORD PTR DS:[<&KERNEL32.GetProcAdd>; \GetProcAddress
00401031 |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
00401034 |. 6A 00 PUSH 0
00401036 |. 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]
00401039 |. 51 PUSH ECX
0040103A |. 8B55 F0 MOV EDX,DWORD PTR SS:[EBP-10]
0040103D |. 52 PUSH EDX
0040103E |. 6A 00 PUSH 0
00401040 |. FF55 F8 CALL DWORD PTR SS:[EBP-8]
00401043 |. 8BE5 MOV ESP,EBP
00401045 |. 5D POP EBP
00401046 \. C3 RETN

Right off the bat there are a few things we will be REQUIRED to edit and change with this. Firstly, rather then using the actual calls:

00401019  |. FF15 04204000  CALL DWORD PTR DS:[<&KERNEL32.LoadLibrar>; \LoadLibraryA
...
0040102B |. FF15 00204000 CALL DWORD PTR DS:[<&KERNEL32.GetProcAdd>; \GetProcAddress

We will be changing these to direct calls to the API. These will be calculated and written during runtime to be sure they are correct as well.

Secondly, we will also need to fix the string addresses to point to proper locations for our strings. For example, injecting this code with keeping the strings the same addresses, we would have:

00401006  |. C745 F0 142040>MOV DWORD PTR SS:[EBP-10],HelloWor.00402>;  ASCII "Hello World!"
0040100D |. C745 FC 242040>MOV DWORD PTR SS:[EBP-4],HelloWor.004020>; ASCII "Hello!"

Which both of those addresses wouldn't be proper, so we need to fix those as well.

Basically, use Olly and copy the bytes of this function. (Highlight the function -> Binary Copy) Use notepad to replace the spaces with , 0x to convert to a C++ byte array, then we will have this:

BYTE btFunction[] = {	0x55, 
0x8B, 0xEC,
0x83, 0xEC, 0x10,
0xC7, 0x45, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, // Replace String #1
0xC7, 0x45, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, // Replace String #2
0x68, 0xFF, 0xFF, 0xFF, 0xFF, // Replace String #3
0xE8, 0xFF, 0xFF, 0xFF, 0xFF, // LoadLibraryA
0x89, 0x45, 0xF4,
0x68, 0xFF, 0xFF, 0xFF, 0xFF, // Replace String #4
0x8B, 0x45, 0xF4,
0x50,
0xE8, 0xFF, 0xFF, 0xFF, 0xFF, // GetProcAddress
0x89, 0x45, 0xF8,
0x6A, 0x00,
0x8B, 0x4D, 0xFC,
0x51,
0x8B, 0x55, 0xF0,
0x52,
0x6A, 0x00,
0xFF, 0x55, 0xF8,
0x8B, 0xE5,
0x5D,
0xC3};

As I said, we changed the calls to be direct rather then using any IAT or other pointers. We also need to fix the strings. I changed any calculated address to just be FF FF FF FF as we will replace them during runtime.

The next part is basic, we just need to find our target, obtain access via a handle (OpenProcess), write our information to the process and call our function with a thread, much like how DLL injection works.

My end result code:

//
// Code Injection Example
//
// Coded by: atom0s
// Coded on: Oct. 08, 2009
//#include <windows.h>
#include <tchar.h>
#include <stdio.h>#include <tlhelp32.h>/*
* The below byte array converts to a 'similar' look of the following
* C/C++ code. This has been converted to the asm bytes for injection.
*
void HelloWorld( void )
{
char* szMessage = "Hello World!";
char* szCaption = "Hello!"; HMODULE hModule = LoadLibraryA( "user32.dll" );
FARPROC fFuncProc = GetProcAddress( hModule, "MessageBoxA" ); ( ( int ( WINAPI *)( HWND, LPCSTR, LPCSTR, UINT ) ) fFuncProc )( 0, szMessage, szCaption, 0 );} */
BYTE btFunction[] = { 0x55,
0x8B, 0xEC,
0x83, 0xEC, 0x10,
0xC7, 0x45, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, // Replace String #1
0xC7, 0x45, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, // Replace String #2
0x68, 0xFF, 0xFF, 0xFF, 0xFF, // Replace String #3
0xE8, 0xFF, 0xFF, 0xFF, 0xFF, // LoadLibraryA
0x89, 0x45, 0xF4,
0x68, 0xFF, 0xFF, 0xFF, 0xFF, // Replace String #4
0x8B, 0x45, 0xF4,
0x50,
0xE8, 0xFF, 0xFF, 0xFF, 0xFF, // GetProcAddress
0x89, 0x45, 0xF8,
0x6A, 0x00,
0x8B, 0x4D, 0xFC,
0x51,
0x8B, 0x55, 0xF0,
0x52,
0x6A, 0x00,
0xFF, 0x55, 0xF8,
0x8B, 0xE5,
0x5D,
0xC3};
bool InjectCode( DWORD dwProcId )
{
/*
* Our various needed strings for our messagebox
* function to properly work.
*/ char* szModule = "user32.dll";
char* szFunction = "MessageBoxA";
char* szMessage = "Hello world!";
char* szCaption = "Hello!"; /*
* Open our process with proper access so we can
* do various memory operations and such.
*/ HANDLE hHandle = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, 0, dwProcId );
if( hHandle == INVALID_HANDLE_VALUE )
return false; /*
* Allocate memory for our strings and function,
* each string has it's own memory block.
*/ LPVOID lpString1 = VirtualAllocEx( hHandle, 0, 1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
LPVOID lpString2 = VirtualAllocEx( hHandle, 0, 1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
LPVOID lpString3 = VirtualAllocEx( hHandle, 0, 1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
LPVOID lpString4 = VirtualAllocEx( hHandle, 0, 1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
LPVOID lpFunction = VirtualAllocEx( hHandle, 0, 1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if( lpString1 == NULL || lpString2 == NULL || lpString3 == NULL || lpString4 == NULL || lpFunction == NULL ) {
CloseHandle( hHandle );
return false;
} /*
* Write our strings to their memory.
*/ WriteProcessMemory( hHandle, lpString1, szMessage, strlen( szMessage ), 0 );
WriteProcessMemory( hHandle, lpString2, szCaption, strlen( szCaption ), 0 );
WriteProcessMemory( hHandle, lpString3, szModule, strlen( szModule ), 0 );
WriteProcessMemory( hHandle, lpString4, szFunction, strlen( szFunction ), 0 ); /*
* Fix our functions string addresses before writing
* it to the process memory. (Faster this way.)
*/ memcpy( (LPVOID)( (DWORD)&btFunction + 0x09 ), &lpString1, 4 );
memcpy( (LPVOID)( (DWORD)&btFunction + 0x10 ), &lpString2, 4 );
memcpy( (LPVOID)( (DWORD)&btFunction + 0x15 ), &lpString3, 4 );
memcpy( (LPVOID)( (DWORD)&btFunction + 0x22 ), &lpString4, 4 ); /*
* Fix the API calls inside our function as well.
*/ DWORD dwLoadLibrary = ( ( (DWORD)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "LoadLibraryA" ) - ( (DWORD)lpFunction + 0x1A ) ) - 4 );
DWORD dwGetProcAddr = ( ( (DWORD)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "GetProcAddress" ) - ( (DWORD)lpFunction + 0x2B ) ) - 4 ); memcpy( (LPVOID)( (DWORD)&btFunction + 0x1A ), &dwLoadLibrary, 4 );
memcpy( (LPVOID)( (DWORD)&btFunction + 0x2B ), &dwGetProcAddr, 4 );
/*
* Write our function to the last memory block.
*/ WriteProcessMemory( hHandle, lpFunction, &btFunction, sizeof( btFunction ), 0 ); /*
* Create a thread and call the function.
*/ HANDLE hThread = CreateRemoteThread( hHandle, 0, 0, (LPTHREAD_START_ROUTINE) lpFunction, 0, 0, 0 );
if( hThread == NULL ) {
CloseHandle( hHandle );
return false;
} return true;
}int __cdecl main( int argc, TCHAR* argv[] )
{ PROCESSENTRY32 pe32 = { sizeof( PROCESSENTRY32 ) };
HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); if( hSnapshot == INVALID_HANDLE_VALUE )
return 0; if( ! Process32First( hSnapshot, &pe32 ) ) {
CloseHandle( hSnapshot );
return 0;
} do {
if( _tcsicmp( _T( "winmine.exe" ), pe32.szExeFile ) == 0 ) { CloseHandle( hSnapshot );
InjectCode( pe32.th32ProcessID );
return 0; }
} while( Process32Next( hSnapshot, &pe32 ) ); CloseHandle( hSnapshot ); return 0;
}

A bit of info on whats going on.. when my app starts, it locates Winmine by iterating through the current process list, once found it calls our inject function to inject our code.

My injection function obtains a handle to the process with the needed permissions, allocates 5 new blocks of memory for each of my strings and my function. After allocating memory, it writes each sting to its own buffer inside the target process.

Once the strings are written, I fix the byte array of our function inside the 'trainer' app first before writing it to memory as it's faster and less calls. I fix the string addresses first, then calculate and fix the API addresses next.

Once those are fixed and written to the function byte array I write the function to memory, then create a thread and call it.

Please note, this code has very little error protection or checking, just basics were added to debug with. I suggest going through and adding more to help ensure better flow and no crashes. I didn't add a ton as it was not the point of the post.

I can achieve this same effect of code with a DLL with a lot less work, as I mentioned, it is a lot more of a hassle to do things this way.

Hope this helps. :)

Link to comment

Nice example atomOs, very useful, but as you said its alot easier with injecting a dll :)

anyway learnt something from your short tutorial ;)

Link to comment

thanks for the example.

i wanted an example because my DLL is been unloaded from target process by the anticheat engine Hackshield.

I have been installing some hooks on the game but once my dll is unloaded i cant check if my hooks are active or not is difficult because my DLL is not on memory anymore, anticheat kills additional threads and also unloads my DLL.

checking where at my DLL gets unloaded is difficult because I have a problem running the game with a Modified OllyDbg because the game and the anticheat is packed with themida and it wont run under OllyDbg, so my modified OllyDbg debugger is not working :(.

i cant see anything because my ollydbg cant run the game, so far i have been able to unpacked the game, but i can't analyze the game at runtime.

i understand the idea so basically i will fixup the values.

i was not sure if that was going to work because i thought those values would be valid only on my process but i see now api addresses are system wide?, ok thanks

Edited by Messias
Link to comment
  • 2 months later...

Is it also possible, to Inject the dll from resource? Hmm or create the whole dll, then open with a hex editor and copy each single byte into an array and injected that array somehow?

Link to comment

Yes it is possible to inject the dll into the memory space of the process, but honestly by the time you perform all the fixups and such, its just as simple to inject the code as atom0s has shown imho.

HR,

Ghandi

Link to comment

Is it also possible, to Inject the dll from resource? Hmm or create the whole dll, then open with a hex editor and copy each single byte into an array and injected that array somehow?

Yes, you can either extract the resource and then do the normal method of injection (CreateRemoteThread with LoadLibrary) or any other injection method. Or you can manually map the resource directly from the resource to the other process and load it completely manually.

The second method is called manual mapping. It's more in depth and a lot more work involved to do it.

Heres some code from Darwak on how to do manual mapping. This code is pretty old so you may need to adjust it some to get it to work with your compiler/system:

//         ManualMap - by Darawk
// Featured @ www.RealmGX.com & www.Darawk.com
//
// The purpose of ManualMap is to "manually map" a dll
// module into a remote process's address space. This
// means that instead of just manipulating the remote
// process into calling the LoadLibrary function, we
// have our own emulation of what LoadLibrary does
// without all those annoying detectability issues ^^.
// The advantage of this method over using something
// like my CloakDll function, is that this method never
// has to call a function like LoadLibrary inside the
// remote process. Since LoadLibrary can be hooked,
// the dll could still be caught at the injection stage.
// Or possibly also through the weakness I discussed in
// the comment header of that file, which is not present
// when using this technique.
#include <windows.h>
#include <tlhelp32.h>
#include <shlwapi.h>#pragma comment(lib, "shlwapi.lib")#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5// Pietrek's macro
//
// MakePtr is a macro that allows you to easily add to values (including
// pointers) together without dealing with C's pointer arithmetic. It
// essentially treats the last two parameters as DWORDs. The first
// parameter is used to typecast the result to the appropriate pointer type.
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD_PTR)(ptr) + (DWORD_PTR)(addValue))// This one is mine, but obviously..."adapted" from matt's original idea =p
#define MakeDelta(cast, x, y) (cast) ( (DWORD_PTR)(x) - (DWORD_PTR)(y))bool MapRemoteModule(unsigned long, wchar_t *);unsigned long GetProcessIdByName(wchar_t *);
HMODULE GetRemoteModuleHandle(unsigned long, wchar_t *);
FARPROC GetRemoteProcAddress(unsigned long, wchar_t *, char *);bool FixImports(unsigned long, void *, IMAGE_NT_HEADERS *, IMAGE_IMPORT_DESCRIPTOR *);
bool FixRelocs(void *, void *, IMAGE_NT_HEADERS *, IMAGE_BASE_RELOCATION *, unsigned int);
bool MapSections(HANDLE, void *, void *, IMAGE_NT_HEADERS *);PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD, PIMAGE_NT_HEADERS);
LPVOID GetPtrFromRVA(DWORD, PIMAGE_NT_HEADERS, PBYTE);// Stub that calls the Dll from within the remote process.
// This is necessary because a DllMain function takes 3
// arguments, and CreateRemoteThread can pass only 1.
__declspec(naked) void DllCall_stub(HMODULE hMod)
{
_asm
{
push 0
push 1
push [esp+0Ch] // Pointer to the hMod argument
mov eax, 0xDEADBEEF // Patch this in with the real value at run-time call eax // MSVC++ doesn't like direct absolute calls, so we have to be
// clever about it. ret // Don't have to clean up the stack because the calling function
// is just going to call ExitThread() immediately after this
// function returns.
}
}// Marker for the end of the DllCall_stub function
__declspec(naked) void DC_stubend(void) { } int main(int argc, char **argv)
{
// Just my test values...Cmdline.dll is a plugin that comes with
// Olly Debug 1.10
bool success = MapRemoteModule(GetProcessIdByName(L"notepad.exe"), L"C:\\Documents and Settings\\<username>\\Desktop\\odbg110\\Cmdline.dll");
if (!success)
{
MessageBox(NULL, L"Failed to map the module to the process", L"Main", NULL);
}
return 0;
}bool MapRemoteModule(unsigned long pId, wchar_t *module)
{
IMAGE_DOS_HEADER *dosHd;
IMAGE_NT_HEADERS *ntHd; HANDLE hFile = CreateFile(module,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL); if(hFile == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, L"Error: unable to obtain handle to module", L"MapRemoteModule", NULL);
return false;
} unsigned int fSize; if(GetFileAttributes(module) & FILE_ATTRIBUTE_COMPRESSED)
fSize = GetCompressedFileSize(module, NULL);
else
fSize = GetFileSize(hFile, NULL); unsigned char *dllBin = new unsigned char[fSize];
unsigned int nBytes; ReadFile(hFile, dllBin, fSize, (LPDWORD)&nBytes, FALSE);
CloseHandle(hFile); // Every PE file contains a little DOS stub for backwards compatibility
// it's only real relevance is that it contains a pointer to the actual
// PE header.
dosHd = MakePtr(IMAGE_DOS_HEADER *, dllBin, 0); // Make sure we got a valid DOS header
if(dosHd->e_magic != IMAGE_DOS_SIGNATURE)
{
delete dllBin;
MessageBox(NULL, L"Error: invalid DOS header", L"MapRemoteModule", NULL);
return false;
} // Get the real PE header from the DOS stub header
ntHd = MakePtr(IMAGE_NT_HEADERS *, dllBin, dosHd->e_lfanew); // Verify the PE header
if(ntHd->Signature != IMAGE_NT_SIGNATURE)
{
delete dllBin;
MessageBox(NULL, L"Error: invalid PE header", L"MapRemoteModule", NULL);
return false;
} HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_SET_INFORMATION |
PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD | PROCESS_SET_QUOTA | PROCESS_DUP_HANDLE |
PROCESS_TERMINATE | PROCESS_SUSPEND_RESUME, FALSE, pId); if(!hProcess)
{
MessageBox(NULL, L"Error: unable to obtain handle for process", L"MapRemoteModule", NULL);
return false;
} // Allocate space for the module in the remote process
void *moduleBase = VirtualAllocEx(hProcess,
NULL,
ntHd->OptionalHeader.SizeOfImage,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE); // Make sure we got the memory space we wanted
if(!moduleBase)
{
MessageBox(NULL, L"Error: failed to allocate module memory", L"MapRemoteModule", NULL);
return false;
} // Allocate space for our stub
void *stubBase = VirtualAllocEx(hProcess,
NULL,
MakeDelta(SIZE_T, DC_stubend, DllCall_stub),
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE); // Make sure we got the memory space we wanted
if(!stubBase)
{
MessageBox(NULL, L"Error: failed to allocate stub memory", L"MapRemoteModule", NULL);
return false;
} // Fix up the import table of the new module
IMAGE_IMPORT_DESCRIPTOR *impDesc = (IMAGE_IMPORT_DESCRIPTOR *)GetPtrFromRVA(
(DWORD)(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress),
ntHd,
(PBYTE)dllBin); if(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
FixImports(pId,
(unsigned char *)dllBin,
ntHd,
impDesc); // Fix "base relocations" of the new module. Base relocations are places
// in the module that use absolute addresses to reference data. Since
// the base address of the module can be different at different times,
// the base relocation data is necessary to make the module loadable
// at any address.
IMAGE_BASE_RELOCATION *reloc = (IMAGE_BASE_RELOCATION *)GetPtrFromRVA(
(DWORD)(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress),
ntHd,
(PBYTE)dllBin); if(ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)
FixRelocs(dllBin,
moduleBase,
ntHd,
reloc,
ntHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); // Write the PE header into the remote process's memory space
WriteProcessMemory(hProcess,
moduleBase,
dllBin,
ntHd->FileHeader.SizeOfOptionalHeader + sizeof(ntHd->FileHeader) + sizeof(ntHd->Signature),
(SIZE_T *)&nBytes); // Map the sections into the remote process(they need to be aligned
// along their virtual addresses)
MapSections(hProcess, moduleBase, dllBin, ntHd); // Change the page protection on the DllCall_stub function from PAGE_EXECUTE_READ
// to PAGE_EXECUTE_READWRITE, so we can patch it.
VirtualProtect((LPVOID)DllCall_stub,
MakeDelta(SIZE_T, DC_stubend, DllCall_stub),
PAGE_EXECUTE_READWRITE,
(DWORD *)&nBytes); // Patch the stub so it calls the correct address
*MakePtr(unsigned long *, DllCall_stub, 9) =
MakePtr(unsigned long, moduleBase, ntHd->OptionalHeader.AddressOfEntryPoint);
// Write the stub into the remote process
WriteProcessMemory(hProcess,
stubBase,
(LPVOID)DllCall_stub,
MakeDelta(SIZE_T, DC_stubend, DllCall_stub),
(SIZE_T *)&nBytes); // Execute our stub in the remote process
CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)stubBase,
moduleBase, // Pass the base address of the module as the argument to the stub.
// All a module handle is, is the base address of the module(except
// in windows CE), so we're really passing a handle to the module
// so that it can refer to itself, create dialogs, etc..
0,
NULL); delete dllBin;
return true;
}bool MapSections(HANDLE hProcess, void *moduleBase, void *dllBin, IMAGE_NT_HEADERS *ntHd)
{
IMAGE_SECTION_HEADER *header = IMAGE_FIRST_SECTION(ntHd);
unsigned int nBytes = 0;
unsigned int virtualSize = 0;
unsigned int n = 0; // Loop through the list of sections
for(unsigned int i = 0; ntHd->FileHeader.NumberOfSections; i++)
{
// Once we've reached the SizeOfImage, the rest of the sections
// don't need to be mapped, if there are any.
if(nBytes >= ntHd->OptionalHeader.SizeOfImage)
break; WriteProcessMemory(hProcess,
MakePtr(LPVOID, moduleBase, header->VirtualAddress),
MakePtr(LPCVOID, dllBin, header->PointerToRawData),
header->SizeOfRawData,
(LPDWORD)&n); virtualSize = header->VirtualAddress;
header++;
virtualSize = header->VirtualAddress - virtualSize;
nBytes += virtualSize; // Set the proper page protections for this section.
// This really could be skipped, but it's not that
// hard to implement and it makes it more like a
// real loader.
VirtualProtectEx(hProcess,
MakePtr(LPVOID, moduleBase, header->VirtualAddress),
virtualSize,
header->Characteristics & 0x00FFFFFF,
NULL);
} return true;
}bool FixImports(unsigned long pId, void *base, IMAGE_NT_HEADERS *ntHd, IMAGE_IMPORT_DESCRIPTOR *impDesc)
{
wchar_t *module; // Loop through all the required modules
while((module = (wchar_t *)GetPtrFromRVA((DWORD)(impDesc->Name), ntHd, (PBYTE)base)))
{
// If the library is already loaded(like kernel32.dll or ntdll.dll) LoadLibrary will
// just return the handle to that module.
HMODULE localMod = LoadLibrary(module); // If the module isn't loaded in the remote process, we recursively call the
// module mapping code. This has the added benefit of ensuring that any of
// the current modules dependencies will be just as invisble as this one.
if(!GetRemoteModuleHandle(pId, module))
MapRemoteModule(pId, module); // Lookup the first import thunk for this module
// NOTE: It is possible this module could forward functions...which is something
// that I really should handle. Maybe i'll add support for forwared functions
// a little bit later.
IMAGE_THUNK_DATA *itd =
(IMAGE_THUNK_DATA *)GetPtrFromRVA((DWORD)(impDesc->FirstThunk), ntHd, (PBYTE)base); while(itd->u1.AddressOfData)
{
IMAGE_IMPORT_BY_NAME *iibn;
iibn = (IMAGE_IMPORT_BY_NAME *)GetPtrFromRVA((DWORD)(itd->u1.AddressOfData), ntHd, (PBYTE)base); itd->u1.Function = MakePtr(DWORD, GetRemoteProcAddress(pId,
module,
(char *)iibn->Name), 0); itd++;
}
impDesc++;
} return true;
}bool FixRelocs(void *base, void *rBase, IMAGE_NT_HEADERS *ntHd, IMAGE_BASE_RELOCATION *reloc, unsigned int size)
{
unsigned long ImageBase = ntHd->OptionalHeader.ImageBase;
unsigned int nBytes = 0; unsigned long delta = MakeDelta(unsigned long, rBase, ImageBase); while(1)
{
unsigned long *locBase =
(unsigned long *)GetPtrFromRVA((DWORD)(reloc->VirtualAddress), ntHd, (PBYTE)base);
unsigned int numRelocs = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); if(nBytes >= size) break; unsigned short *locData = MakePtr(unsigned short *, reloc, sizeof(IMAGE_BASE_RELOCATION));
for(unsigned int i = 0; i < numRelocs; i++)
{
if(((*locData >> 12) & IMAGE_REL_BASED_HIGHLOW))
*MakePtr(unsigned long *, locBase, (*locData & 0x0FFF)) += delta; locData++;
} nBytes += reloc->SizeOfBlock;
reloc = (IMAGE_BASE_RELOCATION *)locData;
} return true;
}
FARPROC GetRemoteProcAddress(unsigned long pId, wchar_t *module, char *func)
{
HMODULE remoteMod = GetRemoteModuleHandle(pId, module);
HMODULE localMod = GetModuleHandle(module); // Account for potential differences in base address
// of modules in different processes.
unsigned long delta = MakeDelta(unsigned long, remoteMod, localMod);
return MakePtr(FARPROC, GetProcAddress(localMod, func), delta);
}unsigned long GetProcessIdByName(wchar_t *process)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot;
BOOL retval, ProcFound = false; thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, L"Error: unable to create toolhelp snapshot", L"Loader", NULL);
return false;
} pe.dwSize = sizeof(PROCESSENTRY32); retval = Process32First(thSnapshot, &pe); while(retval)
{
if(StrStrI(pe.szExeFile, process) )
{
ProcFound = true;
break;
} retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
} if (!ProcFound)
{
MessageBox(NULL, L"Error: unable to find process", L"Loader", NULL);
return false;
} return pe.th32ProcessID;
}HMODULE GetRemoteModuleHandle(unsigned long pId, wchar_t *module)
{
MODULEENTRY32 modEntry;
HANDLE tlh = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pId); modEntry.dwSize = sizeof(MODULEENTRY32);
Module32First(tlh, &modEntry); do
{
if(!_wcsicmp(&modEntry.szModule[0], module))
return modEntry.hModule;
modEntry.dwSize = sizeof(MODULEENTRY32);
}
while(Module32Next(tlh, &modEntry)); return NULL;
}// Matt Pietrek's function
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader(DWORD rva, PIMAGE_NT_HEADERS pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned int i; for ( i = 0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
// This 3 line idiocy is because Watcom's linker actually sets the
// Misc.VirtualSize field to 0. (!!! - Retards....!!!)
DWORD size = section->Misc.VirtualSize;
if ( 0 == size )
size = section->SizeOfRawData; // Is the RVA within this section?
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + size)))
return section;
} return 0;
}// This function is also Pietrek's
LPVOID GetPtrFromRVA( DWORD rva, IMAGE_NT_HEADERS *pNTHeader, PBYTE imageBase )
{
PIMAGE_SECTION_HEADER pSectionHdr;
INT delta; pSectionHdr = GetEnclosingSectionHeader( rva, pNTHeader );
if ( !pSectionHdr )
return 0; delta = (INT)(pSectionHdr->VirtualAddress-pSectionHdr->PointerToRawData);
return (PVOID) ( imageBase + rva - delta );
}
Link to comment

wow thanks! I think i can modify it to get it work, but it uses a dll on the disk and not from resources?

Well do I just have to get a HANDLE to the dll in the resource instead of the handle from Readfile

Edited by CrazyRider
Link to comment

FindResource & LoadResource will get the base of your dll resource. Use SizeOfResource with the hResInfo you got from FindResource to get the size of it and allocate memory so you can copy it there and then you've got your 'dllBin'. :D

HR,

Ghandi

Link to comment

Hello i have a Newbie method to do this. i,ve do it this with MapleStory and Starcraft and works very well

1.- start the using ollydbg and inject DLL

2.- analyze the code and acivate the hacks (trainer or dll)

3.- the changed code and added code will be displayed on RED

4.- rightclick and save all modifications to fill

4.- save ur EXE with the modified data

maybe this is NO what u want but u can add ur working DLL to ur exe with this

Link to comment

wow thanks! I think i can modify it to get it work, but it uses a dll on the disk and not from resources?

Well do I just have to get a HANDLE to the dll in the resource instead of the handle from Readfile?

Yeah, just need to load the resource instead of using ReadFile and it should work fine the same way.

You can use, as ghandi said, FindResource and LoadResource to do this. You will also want to obtain a pointer to the resource data, much like you would do from reading the file if it were on the disk which you can use LockResource to obtain a pointer to the data.

In total, check out:

FindResource

LoadResource

LockResource

SizeofResource

Also, if you are using a newer version of Visual Studio, (such as 2005/2008), you will need to fix the handle flags for OpenProcess and such, you cannot use PROCESS_ALL_ACCESS without more defines and such, so it is more proper and better to define only the flags needed.

Link to comment

you all make one mistake, this code is only for xp. since vista and win7 you can have dll loaded into one of 256 memory regions.

so local address of getprocaddress, doesnt have to be at same address in remote process.

also thats why dll injection is better. you can inject dll and hook from injected dll.

btw what sick idea you have with training games and dll injection.

all you need is patch (nop) instruction that decreases life etc.

like dec,sub.

in some cases you inject code like jmp to code cave where you check if you want execute sub or not. for example when this one sub substracts life from you and also enemies.

because if you nop this you cant die and also enemies.

Edited by human
Link to comment

The basic concept works perfectly fine, human just added that it's a bad idea to pass local API pointers to the code you're injecting since due to ASLR and what not the API pointers will probably not be the same in the foreign process.

Link to comment

ASLR doesn't make much of a difference really...

The Windows Vista Address Space Load Randomization (ASLR) feature makes it impossible for malware to know where APIs are located by loading system DLLs and executables at a different location every time the system boots. Early in the boot process, the Memory Manager picks a random DLL image-load bias from one of 256 64KB-aligned addresses in the 16MB region at the top of the user-mode address space. As DLLs that have the new dynamic-relocation flag in their image header load into a process, the Memory Manager packs them into memory starting at the image-load bias address and working its way down.

Executables that have the flag set get a similar treatment, loading at a random 64KB-aligned point within 16MB of the base load address stored in their image header. Further, if a given DLL or executable loads again after being unloaded by all the processes using it, the Memory Manager reselects a random location at which to load it

The only 'problem' is that non-system dlls and a few system dlls do not load at the same base in different processes. Then again, you can easily retrieve the dll base after injecting it, either with psapi or the toolhelp functions.

Link to comment
  • 1 year later...

Delphi uses TLS for exceptions, I'm not sure about newest Delphi but I have no version of Delphi that puts any code in TLS.

Without seeing your code it's hard to guess, but if you are using the code above then there are a few possibilities.

The code above does not handle forwarded imports, this is easy to implement and for Win7 compatibility you should add this, as it's used a lot more in Win7.

Also the PE DataDirectory import data size is checked to see if there are any imports, but checking the RVA would be a better idea, as there is no law that says the size has to be valid.

Finally, you should try changing the injected DllCall_stub code to have PAGE_EXECUTE_READ memory protection after WriteProcessMemory, and before CreateRemoteThread.

This is because DEP protection does not like code being run from PAGE_EXECUTE_READWRITE protected memory.

Edited by BoB
Link to comment

copy...paste...RAT... :ermm:

anyways, what exactly is the problem?

Some modules will not load when trying to fix the import table

src looks good to me.

Link to comment
No like for some DLLs it wont load the imports

why not?

loadlibaray() fails, GetProcAddress() fails,...?

call GetLastError() after the problem occurs and see what you get.

main injected dll crashes in one of the functions of the imported dll.

in the API?

screenshot, error message, which function/API...?

what`s your environment? XP SP3?

did you implement forwarded imports, as suggested by Killboy/BoB ?

...

Link to comment
It crashes in oleaut32.dll

the offset is 3.

there`s nothing to execute there, offset 3 obviously shouldnt be called.

Something went very wrong.

grab your favourite debugger and go for it. ;)

edit:

didnt see he posted the source... :rolleyes:

Edited by deepzero
Link to comment

The bug is trivial. :^

Hint: you should not comment out some code just because it shows errors and you don't understand what it does..

Link to comment

Even if all imports are loaded it still crashes? Well that's a whole different problem.

Anyway, ordinals are easy to implement, you gotta check the import RVA (itd->u1.AddressOfData I think) against the leftmost bit (1 << 31), if it's set, you have to remove it and use the RVA as an ordinal. Instead of GetPtrFromRVA and passing iibn->name to GetRemoteProcAddress, you can just pass the ordinal (cast as char*).

Also, I think there's no such thing as forwarded imports, there only are forwarded exports. And these are resolved by GetProcAddress automatically, nothing you should have to care about.

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...