-
-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
What do you use this library for? #1
Comments
The current readme makes an assumption that you already know the concept of function hooking but I assume that may not hold true for anyone, so allow me to make a simple (but non-short) explanation. The main purpose of the library is to allow for the extension/modification of precompiled functions/subroutines present in external closed source applications (inside C#) where you are do not have access to the source code. 0. PreambleSuppose that you compile a sample calculator application in a native language such as C/C++/D, with the following function: int add(int a, int b) { return a + b; } Under the hood, this would of course be turned into architecture specific assembly instructions to be executed directly on the processor, in x86/x86-64, such a function may become compiled as:
1. Patching with hooks.Now let's assume there was a bug in the calculator, and for instance the actual function was: int add(int a, int b) { return (a + b) + 1; } And likewise, the assembly representation may look like this:
Suppose this calculator application was last updated 10 years ago. It is prioprietary, closed source and the developer has long either stopped supporting the application or went bankrupt. You really like the calculator but with such a glaring bug, it is not comfortable to use. With no possible means of obtaining a possible official fix, what is there that you can do? The obvious option is fix it yourself. In this specific case you can just remove the extra instruction and call it a day. However, consider what if the bug was considerably more complex, where there is either simply not enough space before the next function or the changes required are relatively complex to do. Using a high level language would be relatively comfortable. 2. Introducing Function HooksSo you are going to patch the function yourself. Let's pretend the bug is nontrivial to patch in assembly or you simply do not want to patch it in assembly. You are going to do it in a high level language. While there are a few possibilities from here, though the preferred way to do this would be using a "function hook", which is what this library provides. In general terms, "hooking" covers a range of techniques alter or augment the behaviour of software (imagine "latching" to software). In the common case, "function hooking" as you may read about it online refers to replacing a compiled assembly function in application code with your own. In effect this means that every time the game calls the original function, it will call your code instead. (Explaining how this works under the hood is beyond the scope of this post). So how do you get started? The first thing you do, is you let Reloaded.Hooks know what kind of function we're dealing with. In our case, the function follows the standard Cdecl X86 calling convention (set of rules on how to call a function), where all of the parameters are passed up the stack in right to left (as in right to left written in C) order. /* Define the function. */
[Function(CallingConventions.Cdecl)]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int AddFunction(int a, int b); From there you can create a function hook using the Hook class, and activate the hook: /* Define the function. */
public IHook<AddFunction> _addHook = new Hook<AddFunction>(AddImpl, (long)addPointer).Activate();
// addPointer is the address of the original Add function in memory.
// AddImpl is the new function to execute. So what happens now? Everytime the original application will call the Add function, instead of executing its own, it will execute your C# function, So, the original function now belongs to our C# code, what can we do? Option A: Replacing Original Function public static void Add(int a, int b) { return a + b; } We can replace the original function outright, and do the calculation ourselves and return the result. The original function is now entirely handled by us. Option B: Using the Original Function public static void Add(int a, int b) { return _addHook.OriginalFunction(a,b) - 1; } We know the original function will return a number which is 1 greater than we expect, so why not just let it run and subtract 1 from the result? Job done. Summary In practice, when you make function hooks, you are practically overriding virtual functions. Precompiled native functions from C#, That's all there is to it. 3. Some Common examples of hooking.Graphics API overlays: Steam, AMD Relive, GeForce Experience, game hack overlays. 4. Why Reloaded.Hooks specifically exists.In practice, there are many libraries providing function hooks across a multitude of languages. The main reason I originally built this library is because at the time of writing there is no other libraries supporting non-standard and/or custom calling conventions for functions. In the modern day we have optimising compilers that will try to squeeze the most of performance possible. As a result, in reality, it is very often the case that standard calling conventions (rules) are often broken in favour of performance. For example imagine a (x86) fastcall calling convention version of the above add function:
In this case, rather than the parameters being on the stack, they are passed through the use of registers as a performance optimisation. Other C# libraries, for example EasyHook would not be able to support hooking such functions. In [Function(CallingConventions.Fastcall)] // Set to Fastcall template here.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int AddFunction(int a, int b); Of course the constructor with the // Fastcall: Accept two register parameters EDX, ECX. Return value in EAX.
// Caller fixes stack after function call.
[Function(new []{ Register.ecx, Register.edx}, Register.eax, StackCleanup.Caller)]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int AddFunction(int a, int b); 5. Extra note(s)In order to make use of this library, your program must be in the same address space (process) as the application you want to modify. This is nothing for a bit of Dll Injection to put your DLL inside the target process and DLLExport to be able to call your C# DLL. Originally I wrote what is in this library as part of Reloaded (Mod Loader), but as the main library (libReloaded) was getting rather huge and difficult to maintain, I decided to slowly start refactoring all of the code, improving it and republishing as small, separate modules. |
At the moment I'm actually a student. My entire portfolio of knowledge regarding low level programming and reverse engineering has been acquired on my own as a hobbyist. Aside from that, as mentioned in the footnote of the post above, mainly to tamper with games. |
Add support for scanning arbitrary ranges & saving compiled patterns
I imagine you do some kind of software security testing? Otherwise, are there practical use cases for this? Just trying to widen my breadth and depth of knowledge as an engineer. Thank you!
The text was updated successfully, but these errors were encountered: