Small rewrite

This commit is contained in:
Rebekah 2020-08-10 16:51:34 -04:00
parent 5f88edcc5b
commit 1d79ce4ca8
16 changed files with 365 additions and 319 deletions

View File

@ -1,15 +1,8 @@
cmake_minimum_required(VERSION 2.6)
project(nekohack)
cmake_minimum_required(VERSION 3.14)
project(crackem)
set(CMAKE_CXX_STANDARD 17)
file(GLOB_RECURSE NEKOHACK_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(nekohack STATIC ${NEKOHACK_SOURCES})
target_include_directories(nekohack PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/hack")
target_include_directories(nekohack PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include/")
target_link_libraries(nekohack PUBLIC dl)
set(CRACKEM_BUILD_SHARED OFF CACHE BOOL "Build the shared library")
set(CRACKEM_BUILD_STATIC ON CACHE BOOL "Build the static library")
add_library(nekohack-dummy SHARED "${CMAKE_CURRENT_SOURCE_DIR}/example/dummy.cpp")
add_executable(nekohack-example "${CMAKE_CURRENT_SOURCE_DIR}/example/main.cpp")
target_include_directories(nekohack-example PRIVATE nekohack)
target_link_libraries(nekohack-example PRIVATE nekohack nekohack-dummy)
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/src/")

27
compile_commands.json Normal file
View File

@ -0,0 +1,27 @@
[
{
"directory": "/home/julianacat/github/crackem/build/src",
"command": "/usr/bin/clang++ -I/home/julianacat/github/crackem/src -I/home/julianacat/github/crackem/src/.. -std=gnu++17 -o CMakeFiles/crackem_static.dir/encrypt.cpp.o -c /home/julianacat/github/crackem/src/encrypt.cpp",
"file": "/home/julianacat/github/crackem/src/encrypt.cpp"
},
{
"directory": "/home/julianacat/github/crackem/build/src",
"command": "/usr/bin/clang++ -I/home/julianacat/github/crackem/src -I/home/julianacat/github/crackem/src/.. -std=gnu++17 -o CMakeFiles/crackem_static.dir/memory.cpp.o -c /home/julianacat/github/crackem/src/memory.cpp",
"file": "/home/julianacat/github/crackem/src/memory.cpp"
},
{
"directory": "/home/julianacat/github/crackem/build/src",
"command": "/usr/bin/clang++ -I/home/julianacat/github/crackem/src -I/home/julianacat/github/crackem/src/.. -std=gnu++17 -o CMakeFiles/crackem_static.dir/sharedlibrary.cpp.o -c /home/julianacat/github/crackem/src/sharedlibrary.cpp",
"file": "/home/julianacat/github/crackem/src/sharedlibrary.cpp"
},
{
"directory": "/home/julianacat/github/crackem/build/src",
"command": "/usr/bin/clang++ -I/home/julianacat/github/crackem/src -I/home/julianacat/github/crackem/src/.. -std=gnu++17 -o CMakeFiles/crackem_static.dir/signature.cpp.o -c /home/julianacat/github/crackem/src/signature.cpp",
"file": "/home/julianacat/github/crackem/src/signature.cpp"
},
{
"directory": "/home/julianacat/github/crackem/build/src",
"command": "/usr/bin/clang++ -I/home/julianacat/github/crackem/src -I/home/julianacat/github/crackem/src/.. -std=gnu++17 -o CMakeFiles/crackem_static.dir/vfthook.cpp.o -c /home/julianacat/github/crackem/src/vfthook.cpp",
"file": "/home/julianacat/github/crackem/src/vfthook.cpp"
}
]

0
example.cpp Normal file
View File

View File

@ -1,8 +0,0 @@
extern "C" {
int GetInt() {
return 5;
}
}

View File

@ -1,15 +0,0 @@
#include <iostream>
#include <hack/sharedlibrary.hpp>
using namespace neko;
int main() {
hack::SharedLibrary dummysl("libnekohack-dummy");
std::cout << "Lmap: " << dummysl.GetLMap() << std::endl;
using GetInt_f = int (*)();
GetInt_f GetInt = dummysl.GetSym<GetInt_f>("GetInt");
std::cout << "GetInt Location: " << std::hex << GetInt << std::endl;
std::cout << "GetInt: " << GetInt() << std::endl;
}

View File

@ -1,44 +0,0 @@
/*
* Nekohack: Break things in cool ways!
* Copyright (C) 2018 Rebekah Rowe
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace neko::hack {
// Overwrites calls in a function to the destination
/*class Overwrite {
public:
Overwrite(){}
Overwrite(void* func, std::size_t length, void* dest) {
this->Hook(func, length, dest);
}
Hook(void* func, std::size_t length, void* dest) {
}
private:
void* overwritten = nullptr;
};
class ASMHook {
public:
Hook();
~Hook();
enum Type {kOverwrite
AddJump
};*/
}

View File

@ -1,59 +0,0 @@
/*
* Nekohack: Break things in cool ways!
* Copyright (C) 2018 Rebekah Rowe
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <cstdint>
#include <memory>
namespace neko::hack {
// Virtual function table
using VF = void*;
using VFT = VF[];
// Virtual Function Table Hook
class VFTHook {
public:
VFTHook();
~VFTHook();
template<class TPtr>
void Init(TPtr instance) {
this->IntInit(reinterpret_cast<void*>(instance));
}
template<class TPtr>
void Hook(TPtr func, std::size_t idx) {
this->IntHook(reinterpret_cast<VF>(func), idx);
}
void Finish();
void Undo();
template <class T = void*>
inline T GetOriginal(std::size_t idx) const {
return reinterpret_cast<T>(this->original_data[idx]);
}
bool IsHooked();
std::size_t GetSize(){ return this->size; }
private:
void IntInit(void* instance);
void IntHook(VF func_ptr, std::size_t);
void*** vtable = nullptr;
void** original_data = nullptr;
std::unique_ptr<void*[]> replacement;
std::size_t size;
};
}

32
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,32 @@
file(GLOB_RECURSE sources "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
file(GLOB_RECURSE headers "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp")
add_custom_target(crackem)
macro(ApplyCommon in_target)
add_dependencies(crackem ${in_target})
set_property(TARGET ${in_target} PROPERTY OUTPUT_NAME crackem)
set_property(TARGET ${in_target} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
set_property(TARGET ${in_target} PROPERTY CXX_STANDARD 17)
target_include_directories(${in_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/")
target_include_directories(${in_target} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../")
if (UNIX AND NOT APPLE)
target_link_libraries(${in_target} PUBLIC rt pthread)
endif ()
install(TARGETS ${in_target} DESTINATION lib)
endmacro()
if(CRACKEM_BUILD_SHARED)
add_library(crackem_shared SHARED ${sources})
ApplyCommon(crackem_shared)
endif(CRACKEM_BUILD_SHARED)
if(CRACKEM_BUILD_STATIC)
add_library(crackem_static STATIC ${sources})
ApplyCommon(crackem_static)
endif(CRACKEM_BUILD_STATIC)
install(FILES ${headers} DESTINATION include/crackem)

View File

@ -1,6 +1,6 @@
/*
* Nekohack: Break things in cool ways!
* Crackem: Break things in cool ways!
* Copyright (C) 2018 Rebekah Rowe
*
* This program is free software: you can redistribute it and/or modify
@ -17,10 +17,30 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <r_asm.h>
#pragma once
namespace neko::hack {
namespace crackem {
RAsmOp* asm = r_asm_op_new(void);
// Overwrites calls in a function to the destination
/*class Overwrite {
public:
Overwrite(){}
Overwrite(void* func, std::size_t length, void* dest) {
this->Hook(func, length, dest);
}
Hook(void* func, std::size_t length, void* dest) {
}
private:
void* overwritten = nullptr;
};
class ASMHook {
public:
Hook();
~Hook();
enum Type {kOverwrite
AddJump
};*/
}

View File

@ -19,10 +19,10 @@
#include <cstdint>
namespace neko::hack::mem {
namespace crackem::mem {
template <typename Type, class Ptr>
inline auto Offset(Ptr src, std::ptrdiff_t offset) {
inline auto Offset(Ptr* src, std::ptrdiff_t offset) {
return reinterpret_cast<Type*>(reinterpret_cast<uint64_t>(src) + offset);
}

View File

@ -17,97 +17,110 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <cassert>
#include <cstring>
#include <dlfcn.h>
#include "memory.hpp"
#include "sharedlibrary.hpp"
namespace neko::hack {
namespace crackem {
struct Passthrough {
std::string name;
fs::path path;
void* begin;
std::size_t size;
};
SharedLibrary::SharedLibrary(){}
SharedLibrary::SharedLibrary(std::string_view _name) : name(_name) {
try {
this->Init(_name);
} catch(...){}
}
void SharedLibrary::Init(std::string_view _name){
if (!init_flag) {
this->name = _name;
if (this->name.empty())
throw std::runtime_error("SharedLibrary: no name avaiable.");
Passthrough pass;
pass.name = '/' + std::string(_name) + '.';
if (!dl_iterate_phdr([](struct dl_phdr_info* info, size_t, void* _pass) {
auto* pass = reinterpret_cast<Passthrough*>(_pass);
if (!strstr(info->dlpi_name, pass->name.c_str()))
return 0;
pass->path = info->dlpi_name;
pass->begin = reinterpret_cast<void*>(info->dlpi_addr + info->dlpi_phdr[0].p_vaddr);
pass->size = info->dlpi_phdr[0].p_memsz;
return 1;
}, reinterpret_cast<void*>(&pass)))
throw std::runtime_error("SharedLibrary: Unable to find loaded library");
this->path = pass.path;
this->_begin = pass.begin;
this->_end = mem::Offset<void*>(pass.begin, pass.size);
this->_size = pass.size;
this->lmap = static_cast<LMap>(dlopen(this->path.c_str(), RTLD_NOLOAD));
if (const char* error = dlerror())
throw std::runtime_error("SharedLibrary recieved dlerror: " + std::string(error));
this->init_flag = true;
SharedLibrary::SharedLibrary() : loaded(false) {}
SharedLibrary::SharedLibrary(std::string_view _name) { this->Load(_name); }
SharedLibrary::SharedLibrary(const SharedLibrary& v) { *this = v; }
SharedLibrary::SharedLibrary(SharedLibrary&& v) { *this = v; }
SharedLibrary& SharedLibrary::operator=(SharedLibrary&& v) {
this->loaded = false;
this->name = v.name;
if (v.loaded) {
v.loaded = false;
this->path = std::move(v.path);
this->_begin = v._begin;
this->_end = v._end;
this->_size = v._size;
this->lmap = v.lmap;
this->loaded = true;
}
return *this;
}
void SharedLibrary::ForceInit(std::string_view _name) {
while(!this->init_flag) {
try {
this->Init();
} catch(...) {}
SharedLibrary& SharedLibrary::operator=(const SharedLibrary& v) {
this->loaded = false;
this->name = v.name;
if (v.loaded) {
this->path = v.path;
this->_begin = v._begin;
this->_end = v._end;
this->_size = v._size;
this->lmap = v.lmap;
this->loaded = true;
}
return *this;
}
std::string_view SharedLibrary::GetName() {
return name;
void SharedLibrary::Load(std::string_view _name) {
this->name = _name;
this->Load();
}
void* SharedLibrary::begin() {
this->Init();
void SharedLibrary::Load() {
assert(!this->loaded && !this->name.empty());
this->loaded = false;
if (!dl_iterate_phdr([](struct dl_phdr_info* info, size_t, void* _pass) {
auto* _this = reinterpret_cast<SharedLibrary*>(_pass);
_this->path = info->dlpi_name;
if (_this->path.stem() != _this->name/* || _this->path.extention() ==*/)
return 0;
_this->_begin = reinterpret_cast<void*>(info->dlpi_addr + info->dlpi_phdr[0].p_vaddr);
_this->_size = info->dlpi_phdr[0].p_memsz;
return 1;
}, reinterpret_cast<void*>(this)))
return;
this->loaded = true;
this->_end = mem::Offset<void*>(this->_begin, this->_size);
this->lmap = static_cast<Handle>(dlopen(this->path.c_str(), RTLD_NOLOAD));
if (const char* error = dlerror())
throw std::runtime_error("SharedLibrary recieved dlerror(dlopen): " + std::string(error));
}
bool SharedLibrary::IsLoaded() const {
return this->loaded;
}
std::string_view SharedLibrary::GetName() const {
assert(this->loaded);
return this->name;
}
const fs::path& SharedLibrary::GetPath() const {
assert(this->loaded);
return this->path;
}
void* SharedLibrary::begin() const {
assert(this->loaded);
return this->_begin;
}
void* SharedLibrary::end() {
this->Init();
void* SharedLibrary::end() const {
assert(this->loaded);
return this->_end;
}
std::size_t SharedLibrary::size() {
this->Init();
std::size_t SharedLibrary::size() const {
assert(this->loaded);
return this->_size;
}
LMap SharedLibrary::GetLMap() {
this->Init();
Handle SharedLibrary::GetHandle() const {
assert(this->loaded);
return this->lmap;
}
void SharedLibrary::Clear(){
this->init_flag = false;
this->name = std::string_view();
}
void* SharedLibrary::GetSymInternal(SymStr name) {
void* SharedLibrary::GetSymInternal(SymStr name) const {
#if defined(__linux__)
void* symbol = dlsym(this->GetLMap(), name);
void* symbol = dlsym(this->GetHandle(), name);
if (const char* error = dlerror())
throw std::runtime_error("SharedLibrary recieved dlerror: " + std::string(error));
throw std::runtime_error("SharedLibrary recieved dlerror(dlsym): " + std::string(error));
return symbol;
#elif defined(_WIN32)
return GetProcAddress(this->GetLMap(), name);
#else
assert(false);
#endif
}

View File

@ -21,45 +21,53 @@
#if defined(__linux__)
#include <link.h> // link maps
using LMap = link_map*;
using Handle = link_map*;
using SymStr = const char*;
#elif defined(_WIN32)
#include <windows.h> // loadlibrary
using LMap = HMODULE;
using Handle = HMODULE;
using SymStr = LPCSTR;
#endif
#include <string_view>
#include <filesystem>
namespace fs = std::filesystem;
namespace neko::hack {
namespace crackem {
namespace fs = std::filesystem;
class SharedLibrary {
public:
SharedLibrary();
SharedLibrary(std::string_view _name);
void Init() { this->Init(this->name); }
void ForceInit() { this->ForceInit(this->name); }
void Init(std::string_view _name);
void ForceInit(std::string_view _name);
std::string_view GetName();
void* begin();
void* end();
std::size_t size();
void Clear();
LMap GetLMap();
SharedLibrary(const SharedLibrary&);
SharedLibrary(SharedLibrary&&);
void Load();
void Load(std::string_view _name);
SharedLibrary& operator=(SharedLibrary&& v);
SharedLibrary& operator=(const SharedLibrary& v);
bool IsLoaded() const;
std::string_view GetName() const;
const fs::path& GetPath() const;
void* begin() const;
void* end() const;
std::size_t size() const;
Handle GetHandle() const;
void Clear() const;
template<typename T>
T GetSym(SymStr s) { return reinterpret_cast<T>(this->GetSymInternal(s)); }
private:
void* GetSymInternal(SymStr);
bool init_flag = false;
void* GetSymInternal(SymStr) const;
bool loaded;
std::string_view name;
fs::path path;
void* _begin;
void* _end;
std::size_t _size;
LMap lmap;
Handle lmap;
};
}

View File

@ -24,58 +24,41 @@
#include "signature.hpp"
class Pattern {
public:
Pattern(std::string_view input) {
while (!input.empty()) {
// Discard whitespace
std::size_t non_white_start = input.find_first_not_of(' ');
if (non_white_start == std::string_view::npos) break;
input.remove_prefix(non_white_start);
namespace crackem::sig {
// act on delim
// Wildcard
if (input.front() == '?') {
this->wilds.push_back(true);
std::size_t next = input.find_first_not_of('?');
if (next == std::string_view::npos)
break;
input.remove_prefix(next);
} else {
this->wilds.push_back(false);
if (input.size() < 2)
break;
// Original function by learn_more -- https://github.com/learn-more/findpattern-bench
static bool InRange(uint8_t x, uint8_t a, uint8_t b) { return x >= a && x <= b; }
static uint8_t GetBits(uint8_t x) { return InRange((x & (~0x20)), 'A', 'F') ? ((x & (~0x20)) - 'A' + 0xA): (InRange(x, '0', '9') ? x - '0': 0); }
static uint8_t GetByte(const char* x) { return GetBits(x[0]) << 4 | GetBits(x[1]); }
std::string hex = {input[0], input[1]};
uint8_t nibble = std::stoul(hex, nullptr, 16);
this->pat.push_back(*reinterpret_cast<std::byte*>(nibble));
input.remove_prefix(2);
}
}
}
inline std::byte Get(std::size_t i) {
assert(!this->IsWild(i));
return pat[i];
}
inline bool IsWild(std::size_t i) {
auto find = std::find(wilds.begin(), wilds.end(), i);
return find != wilds.end();
}
inline std::size_t size(){
return this->pat.size();
}
private:
std::vector<std::byte> pat;
std::vector<bool> wilds;
};
uintptr_t FindPattern(uintptr_t start_address, uintptr_t end_address, const char* target_pattern) {
const char* pattern = target_pattern;
uintptr_t first_match = 0;
for (uintptr_t position = start_address; position < end_address; position++) {
if (!*pattern)
return first_match;
const uint8_t pattern_current = *reinterpret_cast<const uint8_t*>(pattern);
const uint8_t memory_current = *reinterpret_cast<const uint8_t*>(position);
if (pattern_current == '\?' || memory_current == GetByte(pattern)) {
if (!first_match)
first_match = position;
if (!pattern[2])
return first_match;
pattern += pattern_current != '\?' ? 3 : 2;
}
else {
pattern = target_pattern;
first_match = 0;
}
}
return NULL;
}
void* SearchN(void* _begin, void* _end, std::string_view _pat){
return nullptr;
/*Pattern pat(_pat);
std::byte* begin = reinterpret_cast<std::byte*>(_begin);
std::byte* end = reinterpret_cast<std::byte*>(_end);
auto find = std::find_if(begin, end, [&](std::byte* s) {
// Pattern equality
for (int )
});*/
}

View File

@ -21,8 +21,8 @@
#include <string_view>
namespace neko::hack::sig {
namespace crackem::sig {
void* SearchN(void* where, std::size_t len, std::string_view pat);
uintptr_t FindPattern(uintptr_t start_address, uintptr_t end_address, const char* target_pattern);
}

View File

@ -1,50 +1,74 @@
#include <cstring>
#include "memory.hpp"
#include "vfthook.hpp"
namespace neko::hack {
namespace crackem::vft::hook {
VFTHook::VFTHook(){}
VFTHook::~VFTHook() {
try {
this->Undo();
}catch(...){}
}
void VFTHook::IntInit(void* instance) {
try {
this->Undo();
}catch(...){}
this->vtable = reinterpret_cast<void***>(instance);
this->original_data = *this->vtable;
this->size = 0;
while (this->original_data[this->size]) this->size++;
this->replacement = std::make_unique<VFT>(this->size);
memcpy(this->replacement.get(), this->original_data, sizeof(VF) * this->size);
struct Ref::HookData {
bool Verify() {
return this->magic = kMagic;
}
static HookData* Get(VInst* v) {
return mem::Offset<HookData>(*v, -int(sizeof(HookData)));
}
VInst* instance;
VFT* original;
std::size_t size;
constexpr static uint32_t kMagic = 0xCAFEBEEF;
uint32_t magic;
VF* replacement[];
};
void VFTHook::Finish() {
if (this->IsHooked())
throw std::logic_error("VTFHook: Cant finish, hook in place");
*this->vtable = this->replacement.get();
}
void VFTHook::Undo() {
if (!this->IsHooked())
throw std::logic_error("VTFHook: Cant undo a hook that isnt there");
}
bool VFTHook::IsHooked() {
if (!this->vtable || !this->replacement)
return false;
return *this->vtable == this->replacement.get();
}
void VFTHook::IntHook(VF func, std::size_t idx) {
//if (this->original[idx] != this->replacement[idx])
//throw std::logic_error("Already Hooked");
this->replacement[idx] = func;
Ref::HookData* Ref::IntCreate(VInst* v) {
if (HookData::Get(v)->Verify())
throw std::runtime_error("Hook already exists!");
std::size_t size = 0;
while ((*v)[size])
size++;
HookData* hd = reinterpret_cast<HookData*>(malloc(sizeof(HookData) + (sizeof(VF*) * size)));
hd->instance = v;
hd->original = *v;
hd->size = size;
hd->magic = HookData::kMagic;
memcpy(hd->replacement, hd->original, sizeof(VF*) * size);
*hd->instance = hd->replacement;
return hd;
}
Ref::HookData* Ref::IntGet(VInst* v) {
HookData* r = HookData::Get(v);
if (r->Verify())
return r;
else
throw std::runtime_error("Hook not found!");
}
bool Ref::IntContains(VInst* v) {
return HookData::Get(v)->Verify();
}
void Ref::IntReplace(int idx, VF* fn) const {
assert(this->data && !this->Exists(idx));
this->data->replacement[idx] = fn;
}
VF* Ref::IntGetOriginal(int idx) const {
assert(this->data);
return this->data->original[idx];
}
void Ref::Clear(int idx) const {
assert(this->data && this->Exists(idx));
this->data->replacement[idx] = this->data->original[idx];
}
bool Ref::Exists(int idx) const {
assert(this->data);
return this->data->original[idx] == this->data->replacement[idx];
}
void Ref::Destroy() {
assert(this->data);
this->data = nullptr;
}
}

72
src/vfthook.hpp Normal file
View File

@ -0,0 +1,72 @@
/*
* Nekohack: Break things in cool ways!
* Copyright (C) 2018 Rebekah Rowe
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <cassert>
#include <cstdint>
#include <memory>
namespace crackem::vft::hook {
using VF = void;
using VFT = VF*;
using VInst = VFT*;
class Ref {
struct HookData;
static HookData* IntCreate(VInst*);
static HookData* IntGet(VInst*);
static bool IntContains(VInst*);
HookData* data = nullptr;
void IntReplace(int idx, VF*) const;
VF* IntGetOriginal(int idx) const;
public:
Ref() {}
Ref(HookData* _data) : data(_data) { assert(this->data); }
void Clear(int idx) const;
bool Exists(int idx) const;
void Destroy();
template<class T> Ref(T* inst) : Ref(Ref::Get(inst)) {
static_assert(!std::is_same_v<T, HookData>);
}
template<class T> void Replace(int idx, T replace_func) const {
this->IntReplace(idx, reinterpret_cast<void*>(&replace_func));
}
template<typename T>
T GetOriginal(std::size_t idx) const {
return reinterpret_cast<T>(this->IntGetOriginal(idx));
}
template<typename Ret, typename... T>
Ret CallOriginal(std::size_t idx, T... args) const {
using Func_t = Ret (*)(T...);
return this->GetOriginal<Func_t>(idx)(args...);
}
template<class T> static Ref Create(T* instance) {
return IntCreate(reinterpret_cast<VInst*>(instance));
}
template<class T> static Ref Get(T* instance) {
return IntGet(reinterpret_cast<VInst*>(instance));
}
template<class T> static bool Contains(T* instance) {
return IntContains(reinterpret_cast<VInst*>(instance));
}
};
}