Git Product home page Git Product logo

kthook's Introduction

kthook

X86 hooking library with functor callbacks support, so you can use lambdas with state, std::bind values etc...

Windows Linux-x64 Linux-X86 Format check

Usage

Clone repository and simply include kthook.hpp. C++17 compatible compiler required

Examples

Callbacks backend is ktsignal

All hooks are automatically removed in the kthook destructor

All examples are shown based on this function

int FASTCALL func1(float a, float b) {
    print_info(a, b);
    a = 50; b = 100;
    return 5;
}

Basics

Creating hook and binding callback
All callbacks are given a reference to kthook as the first argument. You can get return address and trampoline pointer from hook object.
Hooks are installed after construction by default(last parameter can be set to false to prevent this)

int main() {
    // func_ptr is pointer to function
    auto func_ptr = &func1;

    // func_type is int(CFASTCALL*)(float, float)
    using func_type = decltype(&func1);

    // Creating simple hook object with function type is template parameter and function pointer in constructor
    kthook::kthook_simple<func_type> hook{ func_ptr };

    // Connecting lambda callback that receiving function arguments by references
    hook.before += [](const auto& hook, float& a, float& b) {
        print_info(a, b);
        return std::nullopt;
    };

    /*
    [operator () at 31]: a = 30; b = 20
    [func1 at 16 ]: a = 30; b = 20
    */
    func1(30.f, 20.f);
}

Same thing with common hooks:

int main() {
    // func_ptr is pointer to function
    auto func_ptr = &func1;

    // func_type is int(CFASTCALL*)(float, float)
    using func_type = decltype(&func1);

    auto cb = [](const auto& hook, float a, float b) {
        print_info(a, b);
        return hook.get_trampoline()(a, b);
    };

    // Creating simple hook object with function type is template parameter and function pointer in constructor
    kthook::kthook_simple<func_type> hook{ func_ptr, cb };

    /*
    [operator () at 31]: a = 30; b = 20
    [func1 at 16 ]: a = 30; b = 20
    */
    func1(30.f, 20.f);
}

Also you can bind after original function execution callbacks
If original function return value is non void, return value reference passed at 2 argument

int main() {
    auto func_ptr = &func1;
    using func_type = decltype(&func1);

    kthook::kthook_simple_t<func_type> hook{ func_ptr };

    hook.before.connect([](const auto& hook, float& a, float& b) { 
        print_info(a, b);
        // changing arguments
        a = 50.f, b = 30.f; 
        return std::nullopt;
        });

    // connect after callback
    hook.after.connect([](const auto& hook, int& return_value, float& a, float& b) {
        print_info(a, b);
        print_return_value(return_value);

        // changing return_value
        return_value = 20;
    });

    /*
    [operator () at 31]: a = 30; b = 20
    [func1 at 16 ]: a = 50; b = 30
    [operator () at 34]: a = 50; b = 30
    [operator () at 34]: return_value = 5;
    [main at 20]: return_value = 20;
    */
    auto ret_val = func1(30.f, 20.f);
    print_return_value(ret_val)
}

You can bind multiple before/after callbacks

int main() {
    auto func_ptr = &func1;
    using func_type = decltype(&func1);

    kthook::kthook_simple_t<func_type> hook{ func_ptr };

    hook.before.connect([](const auto& hook, float& a, float& b) { print_info(a, b); return std::nullopt; });
    hook.before.connect([](const auto& hook, float& a, float& b) { a = 20; b = 30; return std::nullopt; });
    hook.after.connect([](const auto& hook, int& ret_val, float& a, float& b) { print_info(a, b); });
    hook.after.connect([](const auto& hook, int& ret_val, float& a, float& b) { print_info(a, b); });
    /*
    [operator () at 31]: a = 0; b = 0
    [func1 at 16]: a = 20; b = 30
    [operator () at 33]: a = 20; b = 30
    [operator () at 34]: a = 20; b = 30
    [main at 20]: return_value = 5;
    */
    auto ret_val = func1(30.f, 20.f);
    print_return_value(ret_val)
}

important notes

  • Function return type must be default-constructible
  • If any before callback wiil return false, and function return type is non void, the original function and after callback are not called. Default constructed value is returned
  • If all before callbacks will return true, original function and after callbacks will be called

Advanced Usage

There is a kthook that allows you to change the return value from a function without calling the original function
For generating true return value, you can use std::make_optional(value) function
For generating false return value, you can use std::nullopt

If function return type is void, then you can just return true/false see notes

int main() {
    auto func_ptr = &func1;
    using func_type = decltype(&func1);

    kthook::kthook_signal<func_type> hook{ func_ptr };
    
    hook.before.connect([](const auto& hook, float& a, float& b) { print_info(a, b); return std::nullopt; });
    hook.after.connect([](const auto& hook, int& ret_val, float& a, float& b) { ret_val = 20; print_info(a, b); });
    /*
    [operator () at 44]: a = 30; b = 20
    [func1 at 16]: a = 30; b = 20
    [operator () at 45]: a = 30; b = 20
    [main at 20]: return_value = 20;
    */
    auto ret_val = func1(30.f, 20.f);
    print_return_value(ret_val)
}

Return false example

int main() {
    auto func_ptr = &func1;
    using func_type = decltype(&func1);

    kthook::kthook_signal<func_type> hook{ func_ptr };
    
    hook.before.connect([](auto& hook, float& a, float& b) { print_info(a, b); return std::make_optional(20); });
    hook.after.connect([](auto& hook, int& ret_val, float& a, float& b) { ret_val = 20; print_info(a, b); });
    /*
    [operator () at 44]: a = 30; b = 20
    [main at 20]: return_value = 20;
    */
    auto ret_val = func1(30.f, 20.f);
    print_return_value(ret_val)
}

More examples can be found here

Credits

xbyak - x86/x86-64 JIT assembler
ktsignal - C++17 signals library

License

kthook is licensed under the MIT License, see LICENSE.txt for more information.

kthook's People

Contributors

kin4stat avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.