Small rewrite
This commit is contained in:
parent
5f88edcc5b
commit
1d79ce4ca8
@ -1,15 +1,8 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 2.6)
|
cmake_minimum_required(VERSION 3.14)
|
||||||
project(nekohack)
|
project(crackem)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CRACKEM_BUILD_SHARED OFF CACHE BOOL "Build the shared library")
|
||||||
file(GLOB_RECURSE NEKOHACK_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
|
set(CRACKEM_BUILD_STATIC ON CACHE BOOL "Build the static library")
|
||||||
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)
|
|
||||||
|
|
||||||
add_library(nekohack-dummy SHARED "${CMAKE_CURRENT_SOURCE_DIR}/example/dummy.cpp")
|
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/src/")
|
||||||
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)
|
|
||||||
|
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
|
* Copyright (C) 2018 Rebekah Rowe
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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/>.
|
* 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>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace neko::hack::mem {
|
namespace crackem::mem {
|
||||||
|
|
||||||
template <typename Type, class Ptr>
|
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);
|
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/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#include "memory.hpp"
|
#include "memory.hpp"
|
||||||
|
|
||||||
#include "sharedlibrary.hpp"
|
#include "sharedlibrary.hpp"
|
||||||
|
|
||||||
namespace neko::hack {
|
namespace crackem {
|
||||||
|
|
||||||
struct Passthrough {
|
SharedLibrary::SharedLibrary() : loaded(false) {}
|
||||||
std::string name;
|
SharedLibrary::SharedLibrary(std::string_view _name) { this->Load(_name); }
|
||||||
fs::path path;
|
SharedLibrary::SharedLibrary(const SharedLibrary& v) { *this = v; }
|
||||||
void* begin;
|
SharedLibrary::SharedLibrary(SharedLibrary&& v) { *this = v; }
|
||||||
std::size_t size;
|
SharedLibrary& SharedLibrary::operator=(SharedLibrary&& v) {
|
||||||
};
|
this->loaded = false;
|
||||||
|
this->name = v.name;
|
||||||
SharedLibrary::SharedLibrary(){}
|
if (v.loaded) {
|
||||||
SharedLibrary::SharedLibrary(std::string_view _name) : name(_name) {
|
v.loaded = false;
|
||||||
try {
|
this->path = std::move(v.path);
|
||||||
this->Init(_name);
|
this->_begin = v._begin;
|
||||||
} catch(...){}
|
this->_end = v._end;
|
||||||
|
this->_size = v._size;
|
||||||
|
this->lmap = v.lmap;
|
||||||
|
this->loaded = true;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
SharedLibrary& SharedLibrary::operator=(const SharedLibrary& v) {
|
||||||
void SharedLibrary::Init(std::string_view _name){
|
this->loaded = false;
|
||||||
if (!init_flag) {
|
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;
|
||||||
|
}
|
||||||
|
void SharedLibrary::Load(std::string_view _name) {
|
||||||
this->name = _name;
|
this->name = _name;
|
||||||
if (this->name.empty())
|
this->Load();
|
||||||
throw std::runtime_error("SharedLibrary: no name avaiable.");
|
}
|
||||||
Passthrough pass;
|
void SharedLibrary::Load() {
|
||||||
pass.name = '/' + std::string(_name) + '.';
|
assert(!this->loaded && !this->name.empty());
|
||||||
|
this->loaded = false;
|
||||||
|
|
||||||
if (!dl_iterate_phdr([](struct dl_phdr_info* info, size_t, void* _pass) {
|
if (!dl_iterate_phdr([](struct dl_phdr_info* info, size_t, void* _pass) {
|
||||||
auto* pass = reinterpret_cast<Passthrough*>(_pass);
|
auto* _this = reinterpret_cast<SharedLibrary*>(_pass);
|
||||||
if (!strstr(info->dlpi_name, pass->name.c_str()))
|
_this->path = info->dlpi_name;
|
||||||
|
if (_this->path.stem() != _this->name/* || _this->path.extention() ==*/)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pass->path = info->dlpi_name;
|
_this->_begin = reinterpret_cast<void*>(info->dlpi_addr + info->dlpi_phdr[0].p_vaddr);
|
||||||
pass->begin = reinterpret_cast<void*>(info->dlpi_addr + info->dlpi_phdr[0].p_vaddr);
|
_this->_size = info->dlpi_phdr[0].p_memsz;
|
||||||
pass->size = info->dlpi_phdr[0].p_memsz;
|
|
||||||
return 1;
|
return 1;
|
||||||
}, reinterpret_cast<void*>(&pass)))
|
}, reinterpret_cast<void*>(this)))
|
||||||
throw std::runtime_error("SharedLibrary: Unable to find loaded library");
|
return;
|
||||||
|
|
||||||
this->path = pass.path;
|
this->loaded = true;
|
||||||
this->_begin = pass.begin;
|
this->_end = mem::Offset<void*>(this->_begin, this->_size);
|
||||||
this->_end = mem::Offset<void*>(pass.begin, pass.size);
|
this->lmap = static_cast<Handle>(dlopen(this->path.c_str(), RTLD_NOLOAD));
|
||||||
this->_size = pass.size;
|
|
||||||
|
|
||||||
this->lmap = static_cast<LMap>(dlopen(this->path.c_str(), RTLD_NOLOAD));
|
|
||||||
if (const char* error = dlerror())
|
if (const char* error = dlerror())
|
||||||
throw std::runtime_error("SharedLibrary recieved dlerror: " + std::string(error));
|
throw std::runtime_error("SharedLibrary recieved dlerror(dlopen): " + std::string(error));
|
||||||
|
|
||||||
this->init_flag = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void SharedLibrary::ForceInit(std::string_view _name) {
|
bool SharedLibrary::IsLoaded() const {
|
||||||
while(!this->init_flag) {
|
return this->loaded;
|
||||||
try {
|
|
||||||
this->Init();
|
|
||||||
} catch(...) {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
std::string_view SharedLibrary::GetName() {
|
std::string_view SharedLibrary::GetName() const {
|
||||||
return name;
|
assert(this->loaded);
|
||||||
|
return this->name;
|
||||||
}
|
}
|
||||||
void* SharedLibrary::begin() {
|
const fs::path& SharedLibrary::GetPath() const {
|
||||||
this->Init();
|
assert(this->loaded);
|
||||||
|
return this->path;
|
||||||
|
}
|
||||||
|
void* SharedLibrary::begin() const {
|
||||||
|
assert(this->loaded);
|
||||||
return this->_begin;
|
return this->_begin;
|
||||||
}
|
}
|
||||||
void* SharedLibrary::end() {
|
void* SharedLibrary::end() const {
|
||||||
this->Init();
|
assert(this->loaded);
|
||||||
return this->_end;
|
return this->_end;
|
||||||
}
|
}
|
||||||
std::size_t SharedLibrary::size() {
|
std::size_t SharedLibrary::size() const {
|
||||||
this->Init();
|
assert(this->loaded);
|
||||||
return this->_size;
|
return this->_size;
|
||||||
}
|
}
|
||||||
LMap SharedLibrary::GetLMap() {
|
Handle SharedLibrary::GetHandle() const {
|
||||||
this->Init();
|
assert(this->loaded);
|
||||||
return this->lmap;
|
return this->lmap;
|
||||||
}
|
}
|
||||||
void SharedLibrary::Clear(){
|
void* SharedLibrary::GetSymInternal(SymStr name) const {
|
||||||
this->init_flag = false;
|
|
||||||
this->name = std::string_view();
|
|
||||||
}
|
|
||||||
void* SharedLibrary::GetSymInternal(SymStr name) {
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
void* symbol = dlsym(this->GetLMap(), name);
|
void* symbol = dlsym(this->GetHandle(), name);
|
||||||
if (const char* error = dlerror())
|
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;
|
return symbol;
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
return GetProcAddress(this->GetLMap(), name);
|
return GetProcAddress(this->GetLMap(), name);
|
||||||
|
#else
|
||||||
|
assert(false);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,45 +21,53 @@
|
|||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
#include <link.h> // link maps
|
#include <link.h> // link maps
|
||||||
using LMap = link_map*;
|
using Handle = link_map*;
|
||||||
using SymStr = const char*;
|
using SymStr = const char*;
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
#include <windows.h> // loadlibrary
|
#include <windows.h> // loadlibrary
|
||||||
using LMap = HMODULE;
|
using Handle = HMODULE;
|
||||||
using SymStr = LPCSTR;
|
using SymStr = LPCSTR;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
namespace fs = std::filesystem;
|
|
||||||
|
|
||||||
namespace neko::hack {
|
namespace crackem {
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
class SharedLibrary {
|
class SharedLibrary {
|
||||||
public:
|
public:
|
||||||
SharedLibrary();
|
SharedLibrary();
|
||||||
SharedLibrary(std::string_view _name);
|
SharedLibrary(std::string_view _name);
|
||||||
void Init() { this->Init(this->name); }
|
SharedLibrary(const SharedLibrary&);
|
||||||
void ForceInit() { this->ForceInit(this->name); }
|
SharedLibrary(SharedLibrary&&);
|
||||||
void Init(std::string_view _name);
|
void Load();
|
||||||
void ForceInit(std::string_view _name);
|
void Load(std::string_view _name);
|
||||||
std::string_view GetName();
|
|
||||||
void* begin();
|
SharedLibrary& operator=(SharedLibrary&& v);
|
||||||
void* end();
|
SharedLibrary& operator=(const SharedLibrary& v);
|
||||||
std::size_t size();
|
|
||||||
void Clear();
|
bool IsLoaded() const;
|
||||||
LMap GetLMap();
|
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>
|
template<typename T>
|
||||||
T GetSym(SymStr s) { return reinterpret_cast<T>(this->GetSymInternal(s)); }
|
T GetSym(SymStr s) { return reinterpret_cast<T>(this->GetSymInternal(s)); }
|
||||||
private:
|
private:
|
||||||
void* GetSymInternal(SymStr);
|
void* GetSymInternal(SymStr) const;
|
||||||
bool init_flag = false;
|
|
||||||
|
bool loaded;
|
||||||
std::string_view name;
|
std::string_view name;
|
||||||
fs::path path;
|
fs::path path;
|
||||||
void* _begin;
|
void* _begin;
|
||||||
void* _end;
|
void* _end;
|
||||||
std::size_t _size;
|
std::size_t _size;
|
||||||
LMap lmap;
|
Handle lmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
@ -24,58 +24,41 @@
|
|||||||
|
|
||||||
#include "signature.hpp"
|
#include "signature.hpp"
|
||||||
|
|
||||||
class Pattern {
|
namespace crackem::sig {
|
||||||
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);
|
|
||||||
|
|
||||||
// act on delim
|
// Original function by learn_more -- https://github.com/learn-more/findpattern-bench
|
||||||
// Wildcard
|
static bool InRange(uint8_t x, uint8_t a, uint8_t b) { return x >= a && x <= b; }
|
||||||
if (input.front() == '?') {
|
static uint8_t GetBits(uint8_t x) { return InRange((x & (~0x20)), 'A', 'F') ? ((x & (~0x20)) - 'A' + 0xA): (InRange(x, '0', '9') ? x - '0': 0); }
|
||||||
this->wilds.push_back(true);
|
static uint8_t GetByte(const char* x) { return GetBits(x[0]) << 4 | GetBits(x[1]); }
|
||||||
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;
|
|
||||||
|
|
||||||
std::string hex = {input[0], input[1]};
|
uintptr_t FindPattern(uintptr_t start_address, uintptr_t end_address, const char* target_pattern) {
|
||||||
uint8_t nibble = std::stoul(hex, nullptr, 16);
|
const char* pattern = target_pattern;
|
||||||
this->pat.push_back(*reinterpret_cast<std::byte*>(nibble));
|
|
||||||
input.remove_prefix(2);
|
uintptr_t first_match = 0;
|
||||||
}
|
|
||||||
}
|
for (uintptr_t position = start_address; position < end_address; position++) {
|
||||||
}
|
if (!*pattern)
|
||||||
inline std::byte Get(std::size_t i) {
|
return first_match;
|
||||||
assert(!this->IsWild(i));
|
|
||||||
return pat[i];
|
const uint8_t pattern_current = *reinterpret_cast<const uint8_t*>(pattern);
|
||||||
}
|
const uint8_t memory_current = *reinterpret_cast<const uint8_t*>(position);
|
||||||
inline bool IsWild(std::size_t i) {
|
|
||||||
auto find = std::find(wilds.begin(), wilds.end(), i);
|
if (pattern_current == '\?' || memory_current == GetByte(pattern)) {
|
||||||
return find != wilds.end();
|
if (!first_match)
|
||||||
}
|
first_match = position;
|
||||||
inline std::size_t size(){
|
|
||||||
return this->pat.size();
|
if (!pattern[2])
|
||||||
}
|
return first_match;
|
||||||
private:
|
|
||||||
std::vector<std::byte> pat;
|
pattern += pattern_current != '\?' ? 3 : 2;
|
||||||
std::vector<bool> wilds;
|
}
|
||||||
};
|
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>
|
#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 <cstring>
|
||||||
|
|
||||||
|
#include "memory.hpp"
|
||||||
#include "vfthook.hpp"
|
#include "vfthook.hpp"
|
||||||
|
|
||||||
namespace neko::hack {
|
namespace crackem::vft::hook {
|
||||||
|
|
||||||
VFTHook::VFTHook(){}
|
struct Ref::HookData {
|
||||||
VFTHook::~VFTHook() {
|
bool Verify() {
|
||||||
try {
|
return this->magic = kMagic;
|
||||||
this->Undo();
|
}
|
||||||
}catch(...){}
|
static HookData* Get(VInst* v) {
|
||||||
}
|
return mem::Offset<HookData>(*v, -int(sizeof(HookData)));
|
||||||
|
}
|
||||||
void VFTHook::IntInit(void* instance) {
|
VInst* instance;
|
||||||
try {
|
VFT* original;
|
||||||
this->Undo();
|
std::size_t size;
|
||||||
}catch(...){}
|
constexpr static uint32_t kMagic = 0xCAFEBEEF;
|
||||||
|
uint32_t magic;
|
||||||
this->vtable = reinterpret_cast<void***>(instance);
|
VF* replacement[];
|
||||||
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);
|
|
||||||
};
|
};
|
||||||
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) {
|
Ref::HookData* Ref::IntCreate(VInst* v) {
|
||||||
//if (this->original[idx] != this->replacement[idx])
|
if (HookData::Get(v)->Verify())
|
||||||
//throw std::logic_error("Already Hooked");
|
throw std::runtime_error("Hook already exists!");
|
||||||
this->replacement[idx] = func;
|
|
||||||
|
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