ProcessManipulator is a library that helps with manipulating arbitrary 32-bit processes in Windows, and it's particularly helpful for hacking video games. The library can be used to read and write memory from and to an arbitrary process, load and unload libraries, get handles to modules (DLLs and executables) in an external process's address space, and call exported (extern) __cdecl functions.
One of my driving reasons for writing this software is that, although there are many DLL injectors
available, most are deficient in my opinion. There are very few operations that can be performed safely in
DllMain
(refer to
MSDN's DllMain documentation).
For example, threads should not be created in DllMain
, nor should functions form user32
be called. Yet, most
DLL injectors provide examples that immediately spawn a thread or create a MessageBox. This is unsafe, and can
lead to difficult-to-diagnose errors. ProcessManipulator
handles this by allowing the user to export functions
in their DLL, and then call those functions after the DLL has been loaded. This can be used for setup and teardown
operations, allowing the user to safely create threads, load additional libraries, and call managed functions.
Likewise, most other DLL injectors ignore the return value of LoadLibrary
, and this makes it hard to "uninject"
DLLs because the handle to the DLL module (HMODULE
) is needed. ProcessManipulator
makes freeing DLLs trivial.
Documentation is light, but the code is thoroughly commented and a series of examples are included to help developers get up and running quickly. The examples should be compiled in Visual Studio 2015. The AssaultCube examples run against version 1.2.0.2.
This solution must be built in release mode; it absolutely will not work in debug mode.
I presented on the basics of game hacking at the 2016 CryptoNight convention. A recorded version of the presentation is available, here: https://youtu.be/WMdGvJTzx4k.
- Constructor
- WriteMemory
- ReadMemory
- LoadLibrary
- FreeLibrary
- CallFunction
- Malloc
- Free
- GetModuleHandle
- GetProcAddress
The ProcessManipulator
constructor takes a single argument, which is the title/name of a window. For example:
ProcessManipulator pm("AssaultCube");
This function allows the user to write memory to an arbitrary process. Parameters are as follows:
void* address
A pointer to the base address in the specified process to whichdata
is written. The method first sets this region of memory toPAGE_EXECUTE_READWRITE
, so the memory is guaranteed to be writable.void* data
A pointer to the buffer that containsdata
to be written in the address space of the specified process.size_t dataSize
The number of bytes to be written to the specified process (i.e. the size ofdata
).
The function returns the number of bytes written to the foreign process. If a failure occurs, a ProcessManipulatorException
is raised with a description of the error.
For an example, refer to GodMode.cpp
, which gives the player in BensGame
unlimited life.
This function allows the user to read memory from an arbitrary process. Parameters are as follows:
void* address
A pointer to the base address in the specified process from which to read. The memory region must be readable or aProcessManipulatorException
will be raised.void* data
A pointer to a buffer that receives the contents from the address space of the specified process.size_t dataSize
The number of bytes to be read from the specified process.
The function returns the number of bytes read from the foreign process. If a failure occurs, a ProcessManipulatorException
is raised with a description of the error.
This method is used to inject a DLL into the foreign process. The method takes a single argument:
const string& dllName
The name of the DLL to load. It's best to use the absolute path to the DLL; otherwise, the DLL must be in the system %PATH%. (The external process must be able to find the DLL in order to load it.)
A handle to the loaded module (HMODULE
) is returned. This handle should be kept so that the module can be freed using the FreeLibrary method.
For a trivial example, see injector.cpp
which injects the DLL created by the ChangeBullets2.cpp
file (the DLL changes the players bullets in the BensGame
process). Often a setup function needs to be called after the DLL is loaded. Refer to the CallFunction documentation below for an example of calling an initialization function.
Use this method to remove a library from the foreign process. A single parameter is needed:
const HMODULE& hmod
The handle to the module. This handle is returned from the LoadLibrary method, and can also be attained using the GetModuleHandle method.
A boolean is returned indicating whether or not the library was successfully unloaded.
For a simple example, see injector.cpp
and ChangeBullets2.cpp
.
Use this method to call an exported function in the foreign process. The function must have the following signature:
extern "C" __declspec(dllexport) void __cdecl initialize(DWORD arg1, DWORD argN)
This method is helpful for calling an initialization function after a DLL has been injected, or calling a teardown function before a DLL is unloaded. Parameters are as follows:
const void* procAddr
A pointer to the address of the function in the specified process from which to read. Use the GetProcAddress method to find the address of an exported function in the foreign process.const DWORD* args
A pointer to an array of DWORD arguments (the arguments can really be cast to any type). This method will automatically write the arguments to the foreign process.DWORD numArgs
The number of arguments provided inargs
.
The method returns a DWORD
that is the return value of the called function in the arbitrary process.
For an example, refer to Regenerate.cpp
which exports an initialize
method. initialize
is in turn called by injector.cpp
with a single argument. The example demonstrates how to safely create a thread in an injected DLL, and then how to safely remove the DLL after calling a cleanup
function.
Use this function to allocate memory in the arbitrary process. It is the user's responsobility to clean the memory up using the Free
method. This method takes a single parameter:
unsigned numBytes
The number of bytes to allocate in the foreign process.
The method returns the address of the allocated memory in the foreign process's address space. The memory is given read and write priveleges (PAGE_READWRITE
). If a failure occurs, a ProcessManipulatorException
is raised with a description of the error.
This method deallocates memory in the foreign process, and takes a single parameter:
void* addr
The address of the memory to free.
No size argument is needed; the memory is freed using a freeType
of MEM_RELEASE
. If a failure occurs, a ProcessManipulatorException
is raised with a description of the error.
This method gets the handle of a module (HMODULE
) in the foreign process's address space. A single parameter is required:
-const string& dllName
The name of the dll (or executable) for which the a handle shall be retrieved.
An HMODULE
is returned.
Get the address of a function in the foreign process. Parameters are as follows:
const HMODULE& hmod
A handle to the module that exports the function. This can be obtained from the LoadLibrary method in the case of an injected DLL, or by using the GetModuleHandle method.const string& functionName
The name of the function. Keep in mind that many WINAPI function have both a unicode and a multi-byte version (e.g.MessageBoxW
andMessageBoxA
).
A pointer to the address in the foreign process's address space is returned.