With the accelerating advancement of Rust language, more and more tech companies are recompiling their programs using Rust, especially client security software. However, there are few documents available that explain how to hook any functions using Rust. Therefore, I have written this blog to help you understand how to hook programs using the retour-rs crate for Rust.
In the C language, two hook libraries, detour and MinHook, are commonly used and both have been implemented in Rust. However, I encountered some problems when trying to use MinHook, and the detour-rs crate have not been maintained for a long time. Therefore, I decided to use the retour-rs crate, which is a reconstructed version of detour using the Rust language. Both detour-rs and retour-rs have Generic Hook and Static Hook methods. If you want to use Static Hook, you have to install nightly Rust. In this blog, I will explain how to hook programs in various ways using these two types of hooks.
Environment
Static Hook feature require you to install the nightly rust toolchain, and lots of practical methods can only run in the nightly Rust, such as Backtrace. You can use the following commands to install the nightly Rust.
rustup install nightly
rustup default nightly
rustc --version
And you can install retour-rs crate easily by:
cargo add retour
InlineHook
There is no denying that InlineHook is the most common hook method. I will introduce how to use Generic and Static to hook API and functions.
GenericHook
I will give the easiest GenericHook demo to Hook Windows API “LoadLibraryA”, which can print the path of loaded file and ret_val.
|
|
If you want to hook a specific address instead of an API, you just need replace ori to a specific address. Sure, you need cast this address number to a function type, same as hooked_function.
StaticHook
The “ReadMe” of retour-rs introduces an easy method for hooking functions. There is an easiest demo which can hook two functions using static_detour! macro, which will be expanded to StaticHook instance. Sure, this feature requires the nightly version.
|
|
Obviously, this demo is easier than GenericHook demo. However, if you want to hook any address rather than two functions you wrote with the same type, you must do some extra work.
|
|
To use StaticHook, we have to first define a function type like GenericHook, and then initalize a StaticHook instance using static_detour! macro. And it is important to ensure that two parameters of StaticHook.initialize are the same. However, this can be challenging in certain scenarios, particularly obtaining the address with usize type from get_proc_address. So I implemented a trait to help me cast the ret_val’s type.
With StaticHook, you can easily hook any address to your functions by replacing the API address with a specific address casting its type, like using GenericHook. As shown in the example above, we found that StaticHook is not much simpler than GenericHook if we want to hook an API or a specific address.
VirtualTableHook
In C++, classes that implement polymorphim usually contain virtual functions, which form a virtual table, that stores the address of each virtual function. Every object of this class contains a pointer to its virtual table, which is called vtable pointer. VTable Hook has the advantage that we don’t need to modify the page protect attributes compared with replacing the virtual function address from VTable, because the page stored the vtable pointer is writable.
I have implemented a simple function that allows us to hook any class’s vtable pointer and returns the original vtable pointer.
|
|