Small rewrite
This commit is contained in:
parent
5f88edcc5b
commit
1d79ce4ca8
@ -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
27
compile_commands.json
Normal 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
0
example.cpp
Normal file
@ -1,8 +0,0 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
int GetInt() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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
|
||||
};*/
|
||||
|
||||
}
|
@ -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
32
src/CMakeLists.txt
Normal 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)
|
@ -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
|
||||
};*/
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -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 )
|
||||
});*/
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
}
|
102
src/vfthook.cpp
102
src/vfthook.cpp
@ -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
72
src/vfthook.hpp
Normal 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));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
Reference in New Issue
Block a user