remotemono
|
RemoteMono is a modern C++ (requires C++17) header-only library that allows you to call the functions of the Mono Embedded API in a remote process from the local process. It was mainly intended for hacking Unity games, but it can work with any program that exports the Mono Embedded API.
It was inspired by Cheat Engine's MonoDataCollector and provides similar functionality in a library form, although it works quite differently internally.
Note that RemoteMono is a bit different from what many people seem to do in memory hacking: You use RemoteMono in your own local process in order to call Mono API functions in a remote process via RPC. If you use DLL injection, your own code is already running in the remote process, in which case you can just get pointers to the raw Mono API functions and call them directly like you would any other function. RemoteMono is for when your process and the one you're hacking are different. With RemoteMono, you can do things like create C# objects, get and set field and property values, call methods, and other things without having to do any injection or modifying the remote process yourself. You can probably even write a .NET assembly loader with it, though I haven't tried that.
Before trying RemoteMono, please at least read the chapters Requirements and Caveats below to make sure it can do what you want it do do.
Before anything else, there are a few requirements for using RemoteMono in your project:
If you want to build the unit tests, sample project or documentation, there are additional requirements:
Aside from these requirements on your own project, there are a few cases in which RemoteMono will not work with certain remote processes. See the section Caveats below.
You don't need to build RemoteMono itself, but there are a few things to keep in mind when building your own project:
/std:c++17
in Visual Studio)/bigobj
option, because apparently RemoteMono uses too many template functions/methods to fit into a normal object file...impl
directories directly, it will blow up in your face. You should only have to include the headers in remotemono
. You can however include the ones in remotemono/impl/mono
.For BlackBone (and other dependencies), I strongly recommend you compile them from source yourself. You can currently find prebuilt dependencies in the GitHub releases page, but they might not work for you, and I might be too lazy to update them.
RemoteMono is a header-only library, so there is no need to compile it. Just make sure that the directory containing the remotemono
directory (which in turn contains RMonoAPI.h
) is in your include path. That being said, RemoteMono depends on BlackBone, and you do need to compile that (or use some prebuilt library). You do not need the BlackBone driver, only the BlackBone library itself.
The main class you will be using is RMonoAPI
, so take a look at remotemono/impl/RMonoAPI_Def.h
. Most of the methods it provides have a 1:1 correspondence to one of the Mono Embedded API functions in the remote process, so take a look at the Mono Embedded API docs and just call the corresponding method in RMonoAPI
.
You should also look at the classes RMonoVariant
and RMonoVariantArray
. It's very important that you know how to use them, especially when calling methods or working with properties. If you use them incorrectly, you can produce hard-to-trace crashes.
To write more compact and easier-to-read code, you can also look at the helper classes in remotemono/helper
. They provide a more high-level wrapper around some of the functionality of RMonoAPI
.
I don't currently have a tutorial or anything like that (other than what you're reading right now), so the best place to start is probably the...
In place of a tutorial, you can take a look at the sample project in samples/redrunner
. It is a simple console application that uses RemoteMono to manipulate an instance of the open-source Unity platformer Red Runner. Install and run Red Runner, enter the game world (where you can move around with your character), then start the sample executable from the console. It will attach RemoteMono to the running game and then do a bit of silly stuff to demonstrate a few things that RemoteMono can do: Increase your movement speed, enable double-jumping, play a sound, and add a bit of text to the bottom-left corner of the game that is updated with your character's current position. It's nothing fancy, and certainly doesn't show off all of the things you can do with the Mono API that's behind RemoteMono, but it's a good starting point.
The sample project now provides two implementations of the same code: One that just uses direct API in RMonoAPI
, and one that uses the helper classes. You can take a look at both of them to see how they differ and to decide if you want to use the helper classes.
You can find the API documentation here, although that may not always be the latest version. Note that it is of limited use for many of RemoteMono's internals, since Doxygen isn't capable of parsing some of the template stuff correctly. It's best to look at the sources directly instead.
There are a few things you have to be aware of before deciding to give RemoteMono a try:
RemoteMono uses the memory hacking library BlackBone, most importantly for its RPC functionality, but also for other features like reading and writing remote memory and listing remote process modules. BlackBone allows us to call the raw Mono API functions in the remote from the local process. RemoteMono is a layer on top of this RPC functionality that abstracts away a lot of the difficulties of using the Mono API properly.
While you could just call the raw Mono API functions directly using BlackBone or any other RPC mechanism, there are a few problems with that approach:
mono_*_foreach()
functions), so how would you call those?RemoteMono solves all of these problems. On the frontend, it provides a bunch of methods that closely match the ones of the original Mono API (with some extensions and changes to make them more C++-friendly). In the backend, it generates wrapper functions for many of the Mono API functions using the AsmJit that's bundled with BlackBone. These wrapper functions are generated automatically from a table of Mono API function signatures, and the generated code is then uploaded into the remote process. These wrapper functions in turn call the raw Mono API functions with some added pre- and post-processing. For example, the wrapper functions will take GC handles instead of the raw MonoObject*
parameters, and convert them to raw pointers just before the call (so that the raw pointer will then be on the remote stack). Likewise, return values and output parameters of type MonoObject* will be converted to GC handles by the wrapper functions.
RemoteMono is released under the terms of the GNU Lesser General Public License version 3, or (at your option) any later version.
In short, this means that you can use RemoteMono in closed-source projects, as long as you publish any changes you make to RemoteMono itself under the terms of the LGPL. If that means anything to you, I would however urge you to think about making your project open-source in the spirit of knowledge sharing unless you have a really good reason not to.