C++17, multi-architecture cross-platform hooking library with clean API.
rcmp - C++17, multi-architecture cross-platform hooking library with clean API.
cdecl
, stdcall
, thiscall
, fastcall
, native-x64
)Clone repository to subfolder and link rcmp
to your project:
add_subdirectory(path/to/rcmp)
target_link_libraries(your-project-name PRIVATE rcmp)
rcmp::hook_function<&foo>( {
return original_foo(arg * 2) + 1;
});
- However, in most cases you probably want to hook function **knowing only its address and signature** (in fact, that's everything you need to make hook)
```c++
rcmp::hook_function<0xDEADBEEF, int(float)>([](auto original_foo, float arg) {
return original_foo(arg * 2) + 1;
});
rcmp::hook_function<&do_something>( {
std::cout << “do_something(“ << id << “, “ << action << “) called..\n”;
original_function(id, action);
});
- Replace return value
```c++
bool check_license() { /* body */ }
rcmp::hook_function<&check_license>([](auto /* original_function */) {
return true;
});
rcmp::hook_function<0xDEADBEEF, unsigned int(int, float, bool, double, void*, long)>( {
print(“args are: “, args…);
return original(args…);
});
- Function address can be known at runtime or compile-time
```c++
// compile-time address
rcmp::hook_function<0xDEADBEEF, int(int)>([](auto original, int arg) { ... });
// runtime address (i.e. from GetProcAddress/dlopen)
rcmp::hook_function<int(int)>(0xDEADBEEF, [](auto original, int arg) { ... });
// good:
rcmp::hookfunction
rcmp::hook_function
rcmp::hook_function is an alias for rcmp::generic_signature_t<S, rcmp::cdecl
>)
// bad, compiler-specific
rcmp::hook_function
rcmp::hook_function
// x86 supported conventions
rcmp::cdeclt :cdecl
rcmp::stdcallt :stdcall
rcmp::thiscallt:thiscall
rcmp::fastcallt:fastcall
// x64
rcmp::hook_function
rcmp::hook_function
rcmp::hook_function
- VTable hooking (`hook_indirect_function`)
```c++
// Let's assume:
// 5 - index of function in vtable
// int A::f(int) - function signature
using signature_t = rcmp::thiscall_t<int(A*, int)>; // x86, MSVC
using signature_t = rcmp::cdecl_t<int(A*, int)>; // x86, gcc/clang
using signature_t = int(A*, int); // x64
// vtable address can be known at compile-time (0xDEADBEEF)
rcmp::hook_indirect_function<0xDEADBEEF + 5 * sizeof(void*), signature_t>([](auto original, A* self, int arg) { ... });
// ..or at runtime
rcmp::hook_indirect_function<signature_t>(get_vtable_address() + 5 * sizeof(void*), [](auto original, A* self, int arg) { ... });
Why yet another hooking library?
There are too many libraries with similar or even more powerful features. Most of them have been perfectly designed; however, they don’t provide all the features I need.
I like to develop unofficial mods (plugins) and cheats for various games (both for client and server-side).
This is a very specific area of development that requires continuous experimentation with function hooking.
Suppose you want to hook a function. All you need to know about this function - its address and signature, that’s it.
Just write an interceptor (replacement function) and call something like cool_lib::hook_function
. Very simple, isn’t it? Of course it’s not.
Most libraries require:
That’s really annoying. I want to express my intentions in a single expression without boilerplate, code repetitions and ugly C-style code.
So I ended up with developing my own library - rcmp
.
At work I need both windows (.dll
) and linux (.so
) support, but most libraries aren’t cross-platform (some of them also use compiler-specific extensions, that’s not portable).
Moreover, there are moddable games for Oculus Quest VR that works on ARM64 architecture.rcmp
was designed to be easily extendable, so I was able to use it even for Android apps (ARM64 support comes soon!).
Most libraries use not-so-modern C++ standards (C++11 and below), so they have limited capabilities.
Modern C++ features allow developer to write compact and type-safe code without boilerplate and repetitions (especially in case of hooking).
Due to C++17, rcmp
has convenient API as well as minimalistic and readable implementation.
rcmp
has single-header bundled lightweight dependency - nmd by Nomade040 (only as a length disassembler for x86/x86-64).
Most of hooking libraries depend on big, verbose or even deprecated frameworks.
rcmp
can be easily added to any cmake-based project. No external requirements or dependencies, no installation or manual non-trivial actions to build - just add two lines in CMakeLists.txt
.
...
) support