Skip to content

A high-performance, modern, C++20 library designed around game hacking

License

Notifications You must be signed in to change notification settings

shinkiro-inc/libhat

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

libhat

A modern, high-performance library for C++20 designed around game hacking

Feature overview

  • Windows x86/x64 support
  • Vectorized scanning for byte patterns
  • RAII memory protector
  • Convenience wrappers over OS APIs
  • Language bindings (C, C#, etc.)

Benchmarks

The table below compares the single threaded throughput in bytes/s (real time) between libhat and two other commonly used implementations for pattern scanning. The input buffers were randomly generated using a fixed seed, and the pattern scanned does not contain any match in the buffer. The benchmark was run on a system with an i7-9700K (which supports libhat's AVX2 scanner implementation). The full source code is available here.

---------------------------------------------------------------------------------------
Benchmark                            Time             CPU   Iterations bytes_per_second
---------------------------------------------------------------------------------------
BM_Throughput_Libhat/4MiB       131578 ns        48967 ns        21379      29.6876Gi/s
BM_Throughput_Libhat/16MiB      813977 ns       413524 ns         3514      19.1959Gi/s
BM_Throughput_Libhat/128MiB    6910936 ns      3993486 ns          403      18.0873Gi/s
BM_Throughput_Libhat/256MiB   13959379 ns      8121906 ns          202      17.9091Gi/s

BM_Throughput_UC1/4MiB         4739731 ns      2776015 ns          591       843.93Mi/s
BM_Throughput_UC1/16MiB       19011485 ns     10841837 ns          147      841.597Mi/s
BM_Throughput_UC1/128MiB     152277511 ns     82465278 ns           18      840.571Mi/s
BM_Throughput_UC1/256MiB     304964544 ns    180555556 ns            9      839.442Mi/s

BM_Throughput_UC2/4MiB         9633499 ns      4617698 ns          291      415.218Mi/s
BM_Throughput_UC2/16MiB       38507193 ns     22474315 ns           73      415.507Mi/s
BM_Throughput_UC2/128MiB     307989100 ns    164930556 ns            9      415.599Mi/s
BM_Throughput_UC2/256MiB     616449240 ns    331250000 ns            5      415.282Mi/s

Quick start

Pattern scanning

#include <libhat/Scanner.hpp>

// Parse a pattern's string representation to an array of bytes at compile time
constexpr hat::fixed_signature pattern = hat::compile_signature<"48 8D 05 ? ? ? ? E8">();

// ...or parse it at runtime
using parsed_t = hat::result<hat::signature, hat::signature_parse_error>;
parsed_t runtime_pattern = hat::parse_signature("48 8D 05 ? ? ? ? E8");

// Scan for this pattern using your CPU's vectorization features
auto begin = /* a contiguous iterator over std::byte */;
auto end = /* ... */;
hat::scan_result result = hat::find_pattern(begin, end, pattern);

// Scan a section in the process's base module
hat::scan_result result = hat::find_pattern(pattern, ".text");

// Or another module loaded into the process
hat::process::module_t ntdll = hat::process::get_module("ntdll.dll");
hat::scan_result result = hat::find_pattern(pattern, ntdll, ".text");

// Get the address pointed at by the pattern
const std::byte* address = result.get();

// Resolve an RIP relative address at a given offset
// 
//   | signature matches here
//   |        | relative address located at +3
//   v        v
//   48 8D 05 BE 53 23 01    lea  rax, [rip+0x12353be]
//
const std::byte* relative_address = result.rel(3);

Accessing offsets

#include <libhat/Access.hpp>

// An example struct and it's member offsets
struct S {
    uint32_t a{}; // 0x0
    uint32_t b{}; // 0x4
    uint32_t c{}; // 0x8
    uint32_t d{}; // 0xC
};

S s;

// Obtain a mutable reference to 's.b' via it's offset
uint32_t& b = hat::member_at<uint32_t>(&s, 0x4);

// If the provided pointer is const, the returned reference is const
const uint32_t& b = hat::member_at<uint32_t>(&std::as_const(s), 0x4);

Writing to protected memory

#include <libhat/MemoryProtector.hpp>

uintptr_t* vftable = ...;       // Pointer to a virtual function table in read-only data
size_t target_func_index = ...; // Index to an interesting function

// Use memory_protector to enable write protections
hat::memory_protector prot{
    (uintptr_t) &vftable[target_func_index],        // a pointer to the target memory
    sizeof(uintptr_t),                              // the size of the memory block
    hat::protection::Read | hat::protection::Write  // the new protection flags
};

// Overwrite function table entry to redirect to a custom callback
vftable[target_func_index] = (uintptr_t) my_callback;

// On scope exit, original protections will be restored
prot.~memory_protector(); // compiler generated

About

A high-performance, modern, C++20 library designed around game hacking

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C++ 76.0%
  • Java 12.2%
  • C# 7.3%
  • CMake 3.1%
  • C 1.4%