2015-01-16 13:23:52 +00:00
|
|
|
[![Build Status][build_status]][build]
|
2015-02-16 16:04:57 +00:00
|
|
|
[![Build Status - Windows][build_status_win]][build_win]
|
2015-01-15 17:45:26 +00:00
|
|
|
|
2018-08-31 18:29:09 +00:00
|
|
|
SubHook is a super-simple hooking library for C and C++ that works on Windows,
|
|
|
|
Linux and macOS. It supports x86 only (32-bit and 64-bit).
|
2013-06-26 07:15:37 +00:00
|
|
|
|
2018-09-01 11:19:53 +00:00
|
|
|
Installation
|
|
|
|
------------
|
|
|
|
|
2018-09-06 17:52:15 +00:00
|
|
|
Simply copy the files to your project and include subhook.c in your build.
|
|
|
|
The other source files wil be `#included` by the main C file automatically
|
2018-09-01 11:19:53 +00:00
|
|
|
depending on the OS and achitecture.
|
|
|
|
|
|
|
|
Use of CMake is not mandatory, the library can be built wihtout it (no extra
|
|
|
|
build configuration required).
|
|
|
|
|
2013-01-13 17:02:16 +00:00
|
|
|
Examples
|
|
|
|
--------
|
|
|
|
|
2013-09-26 20:44:02 +00:00
|
|
|
In the following examples `foo` is some function or a function pointer that
|
|
|
|
takes a single argument of type `int` and uses the same calling convention
|
|
|
|
as `my_foo` (depends on compiler).
|
2013-01-14 21:40:12 +00:00
|
|
|
|
2014-11-26 18:07:51 +00:00
|
|
|
### Basic usage
|
2013-01-13 17:02:16 +00:00
|
|
|
|
2013-01-16 09:15:57 +00:00
|
|
|
```c
|
2013-01-14 21:40:12 +00:00
|
|
|
#include <stdio.h>
|
2013-01-13 17:02:16 +00:00
|
|
|
#include <subhook.h>
|
|
|
|
|
2013-12-05 17:00:59 +00:00
|
|
|
subhook_t foo_hook;
|
2013-01-13 17:02:16 +00:00
|
|
|
|
2013-01-14 21:40:12 +00:00
|
|
|
void my_foo(int x) {
|
2014-11-26 18:07:51 +00:00
|
|
|
/* Remove the hook so that you can call the original function. */
|
2013-01-13 17:02:16 +00:00
|
|
|
subhook_remove(foo_hook);
|
|
|
|
|
2013-01-14 21:40:12 +00:00
|
|
|
printf("foo(%d) called\n", x);
|
|
|
|
foo(x);
|
2013-01-13 17:02:16 +00:00
|
|
|
|
2014-11-26 18:07:51 +00:00
|
|
|
/* Install the hook back to intercept further calls. */
|
2013-01-13 17:02:16 +00:00
|
|
|
subhook_install(foo_hook);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main() {
|
2014-11-26 18:07:51 +00:00
|
|
|
/* Create a hook that will redirect all foo() calls to to my_foo(). */
|
2016-08-15 14:05:37 +00:00
|
|
|
foo_hook = subhook_new((void *)foo, (void *)my_foo, 0);
|
2013-01-13 17:02:16 +00:00
|
|
|
|
2014-11-26 18:07:51 +00:00
|
|
|
/* Install it. */
|
2013-01-13 17:02:16 +00:00
|
|
|
subhook_install(foo_hook);
|
2013-12-04 19:04:59 +00:00
|
|
|
|
2014-11-26 18:07:51 +00:00
|
|
|
foo(123);
|
|
|
|
|
|
|
|
/* Remove the hook and free memory when you're done. */
|
|
|
|
subhook_remove(foo_hook);
|
2013-01-13 17:06:51 +00:00
|
|
|
subhook_free(foo_hook);
|
2013-01-13 17:02:16 +00:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2014-11-26 18:07:51 +00:00
|
|
|
### Trampolines
|
|
|
|
|
|
|
|
Using trampolines allows you to jump to the original code without removing
|
|
|
|
and re-installing hooks every time your function gets called.
|
|
|
|
|
|
|
|
```c
|
|
|
|
typedef void (*foo_func)(int x);
|
|
|
|
|
|
|
|
void my_foo(int x) {
|
|
|
|
printf("foo(%d) called\n", x);
|
|
|
|
|
|
|
|
/* Call foo() via trampoline. */
|
|
|
|
((foo_func)subhook_get_trampoline(foo_hook))(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
/* Same code as in previous example. */
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2016-08-15 14:05:37 +00:00
|
|
|
Please note that subhook has a very simple length disassmebler engine (LDE)
|
|
|
|
that works only with most common prologue instructions like push, mov, call,
|
|
|
|
etc. When it encounters an unknown instruction subhook_get_trampoline() will
|
|
|
|
return NULL.
|
2014-11-26 18:07:51 +00:00
|
|
|
|
2013-01-13 17:02:16 +00:00
|
|
|
### C++
|
|
|
|
|
2013-01-16 09:15:57 +00:00
|
|
|
```c++
|
2013-01-14 21:40:12 +00:00
|
|
|
#include <iostream>
|
2013-01-13 17:02:16 +00:00
|
|
|
#include <subhook.h>
|
|
|
|
|
2016-08-15 14:05:37 +00:00
|
|
|
subhook::Hook foo_hook;
|
|
|
|
subhook::Hook foo_hook_tr;
|
2014-11-26 18:07:51 +00:00
|
|
|
|
|
|
|
typedef void (*foo_func)(int x);
|
2013-01-13 17:02:16 +00:00
|
|
|
|
2013-01-14 21:40:12 +00:00
|
|
|
void my_foo(int x) {
|
2016-08-15 14:05:37 +00:00
|
|
|
// ScopedHookRemove removes the specified hook and automatically re-installs
|
|
|
|
// it when the objectt goes out of scope (thanks to C++ destructors).
|
|
|
|
subhook::ScopedHookRemove remove(&foo_hook);
|
2013-01-13 17:02:16 +00:00
|
|
|
|
2017-06-19 03:49:40 +00:00
|
|
|
std::cout << "foo(" << x << ") called" << std::endl;
|
2014-11-26 18:07:51 +00:00
|
|
|
foo(x + 1);
|
2013-01-13 17:02:16 +00:00
|
|
|
}
|
|
|
|
|
2014-11-26 18:07:51 +00:00
|
|
|
void my_foo_tr(int x) {
|
2017-06-19 03:49:40 +00:00
|
|
|
std::cout << "foo(" << x << ") called" << std::endl;
|
2014-11-26 18:07:51 +00:00
|
|
|
|
|
|
|
// Call the original function via trampoline.
|
|
|
|
((foo_func)foo_hook_tr.GetTrampoline())(x + 1);
|
2013-01-13 17:02:16 +00:00
|
|
|
}
|
|
|
|
|
2014-11-26 18:07:51 +00:00
|
|
|
int main() {
|
|
|
|
foo_hook.Install((void *)foo, (void *)my_foo);
|
2015-01-16 13:08:54 +00:00
|
|
|
foo_hook_tr.Install((void *)foo, (void *)my_foo_tr);
|
2014-11-26 18:07:51 +00:00
|
|
|
}
|
2013-01-13 17:02:16 +00:00
|
|
|
```
|
2013-01-14 21:40:12 +00:00
|
|
|
|
2018-08-31 18:51:43 +00:00
|
|
|
Known issues
|
|
|
|
------------
|
|
|
|
|
2018-09-06 17:52:15 +00:00
|
|
|
* If a target function (the function you are hooking) is less than N bytes
|
|
|
|
in length, for example if it's a short 2-byte jump to a nearby location
|
2018-08-31 18:51:43 +00:00
|
|
|
(sometimes compilers generate code like this), then you will not be able
|
|
|
|
to hook it.
|
|
|
|
|
2018-09-06 17:52:15 +00:00
|
|
|
N is 5 by default (1-byte jmp opcode + 32-bit offset), but it you enable
|
|
|
|
the use of 64-bit offsets in 64-bit mode N becomes 14 (see the definition
|
2018-08-31 18:51:43 +00:00
|
|
|
of `subhook_jmp64`).
|
|
|
|
|
2018-09-06 17:52:15 +00:00
|
|
|
* Some systems protect executable code form being modified at runtime, which
|
|
|
|
will not allow you to install hooks, or don't allow to mark heap-allocated
|
2018-08-31 18:51:43 +00:00
|
|
|
memory as executable, which prevents the use of trampolines.
|
2018-09-06 17:52:15 +00:00
|
|
|
|
2018-08-31 18:51:43 +00:00
|
|
|
For example, on Fedora you can have such problems because of SELinux (though
|
|
|
|
you can disable it or exclude your files).
|
|
|
|
|
2015-03-22 10:49:31 +00:00
|
|
|
License
|
|
|
|
-------
|
|
|
|
|
|
|
|
Licensed under the 2-clause BSD license.
|
|
|
|
|
2015-01-16 13:23:52 +00:00
|
|
|
[build]: https://travis-ci.org/Zeex/subhook
|
|
|
|
[build_status]: https://travis-ci.org/Zeex/subhook.svg?branch=master
|
2015-02-16 16:04:57 +00:00
|
|
|
[build_win]: https://ci.appveyor.com/project/Zeex/subhook/branch/master
|
|
|
|
[build_status_win]: https://ci.appveyor.com/api/projects/status/q5sp0p8ahuqfh8e4/branch/master?svg=true
|