diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-04-12 02:40:16 -0500 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-04-12 02:40:16 -0500 |
| commit | bf7a57fc55493247a624ecfd65e4d73964e7d8d2 (patch) | |
| tree | 0a4b2d6123672768187a5ab863e63cd3f21bb319 /libs/usvfs/src/thooklib | |
| parent | e0fb66428a9b78b4c326df8d7e30429a5b271d74 (diff) | |
Remove vendored usvfs and Windows-only usvfs code paths
The Linux port uses its own in-process FUSE VFS (FuseConnector), so
usvfs was dead weight: libs/usvfs/ was never built, usvfsconnector.cpp
was explicitly REMOVE_ITEM'd from the source list, and every call site
was already guarded by #ifdef _WIN32 with a working Linux branch (the
Windows build is also broken on this branch, since FUSE3 is a hard
find_package dependency).
- Drop libs/usvfs/ and src/src/usvfsconnector.{cpp,h}
- Collapse #ifdef _WIN32 / usvfs include branches in organizercore,
mainwindow, settings, util, spawn
- Remove getUsvfsVersionString() and the "usvfs: ..." log field
- Remove vfs32/64DLLName APPPARAMs (nothing reads them)
- Relabel About dialog "usvfs:" row to "VFS: FUSE 3"
Diffstat (limited to 'libs/usvfs/src/thooklib')
| -rw-r--r-- | libs/usvfs/src/thooklib/CMakeLists.txt | 14 | ||||
| -rw-r--r-- | libs/usvfs/src/thooklib/asmjit_sane.h | 29 | ||||
| -rw-r--r-- | libs/usvfs/src/thooklib/hooklib.cpp | 740 | ||||
| -rw-r--r-- | libs/usvfs/src/thooklib/hooklib.h | 125 | ||||
| -rw-r--r-- | libs/usvfs/src/thooklib/pch.cpp | 1 | ||||
| -rw-r--r-- | libs/usvfs/src/thooklib/ttrampolinepool.cpp | 601 | ||||
| -rw-r--r-- | libs/usvfs/src/thooklib/ttrampolinepool.h | 222 | ||||
| -rw-r--r-- | libs/usvfs/src/thooklib/udis86wrapper.cpp | 102 | ||||
| -rw-r--r-- | libs/usvfs/src/thooklib/udis86wrapper.h | 62 | ||||
| -rw-r--r-- | libs/usvfs/src/thooklib/utility.cpp | 86 | ||||
| -rw-r--r-- | libs/usvfs/src/thooklib/utility.h | 35 |
11 files changed, 0 insertions, 2017 deletions
diff --git a/libs/usvfs/src/thooklib/CMakeLists.txt b/libs/usvfs/src/thooklib/CMakeLists.txt deleted file mode 100644 index 48426db..0000000 --- a/libs/usvfs/src/thooklib/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -find_package(asmjit CONFIG REQUIRED) -find_library(LIBUDIS86_LIBRARY libudis86) -find_package(spdlog CONFIG REQUIRED) - -file(GLOB sources CONFIGURE_DEPENDS "*.cpp" "*.h") -source_group("" FILES ${sources}) - -add_library(thooklib STATIC ${sources}) -target_link_libraries(thooklib PRIVATE shared asmjit::asmjit ${LIBUDIS86_LIBRARY} spdlog::spdlog_header_only) -target_include_directories(thooklib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -set_target_properties(thooklib PROPERTIES FOLDER injection) -target_precompile_headers(shared PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../shared/pch.h) diff --git a/libs/usvfs/src/thooklib/asmjit_sane.h b/libs/usvfs/src/thooklib/asmjit_sane.h deleted file mode 100644 index 365622a..0000000 --- a/libs/usvfs/src/thooklib/asmjit_sane.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs 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. - -usvfs 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 usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#pragma warning(push) -#pragma warning(disable : 4201) -#pragma warning(disable : 4244) -#pragma warning(disable : 4245) -#include <asmjit/asmjit.h> -#include <asmjit/x86.h> -#pragma warning(pop) diff --git a/libs/usvfs/src/thooklib/hooklib.cpp b/libs/usvfs/src/thooklib/hooklib.cpp deleted file mode 100644 index 9dbbafa..0000000 --- a/libs/usvfs/src/thooklib/hooklib.cpp +++ /dev/null @@ -1,740 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs 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. - -usvfs 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 usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "udis86wrapper.h" -#include <boost/format.hpp> -#include <boost/predef.h> -#include <map> -#pragma warning(push, 3) -#include <asmjit/asmjit.h> -#pragma warning(pop) -#include "hooklib.h" -#include "ttrampolinepool.h" -#include "utility.h" -#include <addrtools.h> -#include <formatters.h> -#include <shmlogger.h> -#include <winapi.h> - -#if BOOST_ARCH_X86_64 -#pragma message("64bit build") -#define JUMP_SIZE 13 -#elif BOOST_ARCH_X86_32 -#define JUMP_SIZE 5 -#else -#error "unsupported architecture" -#endif - -using namespace asmjit; -// from here on out I'll only test for 64 or "other" - -using namespace HookLib; -using namespace asmjit; - -using namespace usvfs; - -struct THookInfo -{ - LPVOID originalFunction; - LPVOID replacementFunction; - LPVOID detour; // detour to call the original function after hook was installed. - LPVOID trampoline; // code fragment that decides whether the replacement function or - // detour is executed (preventing endless loops) - std::vector<uint8_t> - preamble; // part of the detour that needs to be re-inserted into the original - // function to return it to vanilla state - bool stub; // if this is true, the trampoline calls the "replacement"-function that - // before the original function, not instead of it - enum - { - TYPE_HOTPATCH, // official hot-patch variant as used on 32-bit windows - TYPE_WIN64PATCH, // custom patch variant used on 64-bit windows - TYPE_CHAINPATCH, // the hook is part of the hook chain (and not the first) - TYPE_OVERWRITE, // full jump overwrite used if none of the above work - TYPE_RIPINDIRECT // the function already started on a rip-relative jump so we only - // modified that variable - } type; -}; - -UDis86Wrapper& disasm() -{ - static UDis86Wrapper instance; - return instance; -} - -void PauseOtherThreads() -{ - // TODO: implement me! -} - -void ResumePausedThreads() -{ - // TODO: implement me! should resume only the threads paused by PauseOtherThreads -} - -// not using the disassembler because this is simpler -LPBYTE ShortJumpTarget(LPBYTE address) -{ - int8_t off = *(address + 1); - return address + 2 + off; -} - -size_t GetJumpSize(LPBYTE, LPVOID) -{ - // TODO: it would be neater to use asmjit to generate this jump and ask asmjit for - // the size of this jump but with asmjit I can only generate absolute jumps, which - // take too much space. - - // Since trampoline buffers is always allocated within 32-bit - // address range of jump, we can say with confidence that a 5-byte jump is possible - return 5; -} - -void WriteLongJump(LPBYTE jumpAddr, LPVOID destination) -{ - // TODO: not using asmjit here because I couldn't figure out how to generate - // a working, space-optimized, relative jump to outside the generated code and - // we do want to optimize this jump -#if BOOST_ARCH_X86_64 - intptr_t dist = reinterpret_cast<intptr_t>(destination) - - (reinterpret_cast<intptr_t>(jumpAddr) + 5); - int32_t distShort = static_cast<int32_t>(dist); -#else - int32_t distShort = reinterpret_cast<intptr_t>(destination) - - (reinterpret_cast<intptr_t>(jumpAddr) + 5); -#endif - *jumpAddr = 0xE9; - *reinterpret_cast<int32_t*>(jumpAddr + 1) = distShort; -} - -void WriteSingleJump(THookInfo& hookInfo, HookError* error) -{ - DWORD oldprotect, ignore; - // Set the target function to copy on write, so we don't modify code for other - // processes - if (!VirtualProtect(hookInfo.originalFunction, JUMP_SIZE, PAGE_EXECUTE_WRITECOPY, - &oldprotect)) { - throw std::runtime_error("failed to change virtual protection"); - } - - WriteLongJump(reinterpret_cast<LPBYTE>(hookInfo.originalFunction), - hookInfo.trampoline); - - // restore old memory protection - if (!VirtualProtect(hookInfo.originalFunction, JUMP_SIZE, oldprotect, &ignore)) { - throw std::runtime_error("failed to change virtual protection"); - } - - if (error != nullptr) { - *error = ERR_NONE; - } -} - -void WriteShortJump(LPBYTE jumpAddr, const signed char offset) -{ - *jumpAddr = 0xEB; - *(jumpAddr + 1) = offset; -} - -void WriteIndirectJump(THookInfo& hookInfo, size_t jumpSize, HookError* error) -{ - DWORD oldProtect = 0; - LPBYTE jumpAddr = reinterpret_cast<LPBYTE>(hookInfo.originalFunction) - jumpSize; - // allow write to jump address + the short jump inside the function - if (!VirtualProtect(jumpAddr, jumpSize + 2, PAGE_EXECUTE_WRITECOPY, &oldProtect)) { - throw std::runtime_error("failed to change virtual protection"); - } - - // insert the long jump first, then the short jump to the long jump, thus - // activating the reroute - WriteLongJump(jumpAddr, hookInfo.trampoline); - - PauseOtherThreads(); - WriteShortJump(jumpAddr + jumpSize, -(static_cast<int8_t>(jumpSize) + 2)); - ResumePausedThreads(); - - // restore access protection - if (!VirtualProtect(jumpAddr, jumpSize + 2, oldProtect, &oldProtect)) { - throw std::runtime_error("failed to change virtual protection"); - } - if (error != nullptr) { - *error = ERR_NONE; - } -} - -/// implements function hooking using the mechanism intended for hot patching -/// Explanation: the visual studio compiler offers an option to prepare functions -/// for hot patching. In this case the compiler leaves room for one far jump before -/// the actual function and a 2-byte nop inside the function. -/// to hook such a function we write a jump to our replacement function to the -/// space before the function and short jump to that jump to where the 2-byte nop -/// was. -/// On 32-bit windows, MS seems to have compiled all relevant functions in the -/// windows API for hot patching starting with Windows XP SP3 -/// On 64-bit windows a lot of functions have the space for a jump before the function -/// but they don't have the 2-byte nop so this function doesn't work -/// \param hookInfo info about the hook to be installed -/// \return true on success, false on error -BOOL HookHotPatch(THookInfo& hookInfo, HookError* error) -{ - LPVOID original = reinterpret_cast<LPVOID>(hookInfo.originalFunction); - - if (hookInfo.stub) { - hookInfo.trampoline = TrampolinePool::instance().storeStub( - hookInfo.replacementFunction, - reinterpret_cast<LPVOID>(hookInfo.originalFunction), - shared::AddrAdd(original, 2)); - } else { - hookInfo.trampoline = TrampolinePool::instance().storeTrampoline( - hookInfo.replacementFunction, - reinterpret_cast<LPVOID>(hookInfo.originalFunction), - shared::AddrAdd(original, 2)); - } - - WriteIndirectJump(hookInfo, JUMP_SIZE, error); - hookInfo.type = THookInfo::TYPE_HOTPATCH; - // in this case we don't need a separate detour, we simply jump past the 2-byte nop - hookInfo.detour = reinterpret_cast<LPBYTE>(hookInfo.originalFunction) + 2; - - return TRUE; -} - -uintptr_t followJumps(THookInfo& hookInfo) -{ - LPBYTE original = reinterpret_cast<LPBYTE>(hookInfo.originalFunction); - LPBYTE shortTarget = ShortJumpTarget(original); - - // disassemble the long jump - disasm().setInputBuffer(shortTarget, JUMP_SIZE); - - ud_disassemble(disasm()); - if (ud_insn_mnemonic(disasm()) != UD_Ijmp) { - // this shouldn't happen, we only call this if the jump was discovered before - throw std::runtime_error("failed to find jump in patch"); - } - - uint64_t res = ud_insn_off(disasm()) + ud_insn_len(disasm()); - res += disasm().jumpOffset(); - - return static_cast<uintptr_t>(res); -} - -/// -/// \brief hook a call that is implemented as a short-jump to a long jump using a -/// rip-relative address variable -/// \param hookInfo info about the hook to be installed -/// \param error if the return code is false and this is not null, the referred-to -/// variable is set to an error code -/// \return true on success, false on error -/// -BOOL HookRIPIndirection(THookInfo& hookInfo, HookError* error) -{ - uintptr_t res = followJumps(hookInfo); - - const ud_operand_t* op = ud_insn_opr(disasm(), 0); - - if (op->base != UD_R_RIP) { - throw std::runtime_error("expected rip-relative addressing"); - } - - auto chainNext = disasm().jumpTarget(); - if (hookInfo.stub) { - hookInfo.trampoline = TrampolinePool::instance().storeStub( - hookInfo.replacementFunction, - reinterpret_cast<LPVOID>(hookInfo.originalFunction), - reinterpret_cast<LPVOID>(chainNext)); - } else { - hookInfo.trampoline = TrampolinePool::instance().storeTrampoline( - hookInfo.replacementFunction, - reinterpret_cast<LPVOID>(hookInfo.originalFunction), - reinterpret_cast<LPVOID>(chainNext)); - } - - DWORD oldProtect = 0; - if (!VirtualProtect(reinterpret_cast<LPVOID>(res), 2, PAGE_EXECUTE_WRITECOPY, - &oldProtect)) { - throw std::runtime_error("failed to change virtual protection"); - } - - *reinterpret_cast<uintptr_t*>(res) = reinterpret_cast<uintptr_t>(hookInfo.trampoline); - - if (!VirtualProtect(reinterpret_cast<LPVOID>(res), 2, oldProtect, &oldProtect)) { - throw std::runtime_error("failed to change virtual protection"); - } - - hookInfo.type = THookInfo::TYPE_RIPINDIRECT; - hookInfo.detour = reinterpret_cast<LPVOID>(chainNext); - - if (error != nullptr) { - *error = ERR_NONE; - } - - return TRUE; -} - -BOOL HookChainHook(THookInfo& hookInfo, LPBYTE jumpPos, HookError* error) -{ - // disassemble the long jump - disasm().setInputBuffer(jumpPos, JUMP_SIZE); - - ud_disassemble(disasm()); - if (ud_insn_mnemonic(disasm()) != UD_Ijmp) { - // this shouldn't happen, we only call this if the jump was discovered before - throw std::runtime_error("failed to find jump in patch"); - } - - auto chainTarget = disasm().jumpTarget(); - - size_t size = ud_insn_len(disasm()); - - // save the original code for the preamble so we can restore it later - hookInfo.preamble.resize(size); - memcpy(&hookInfo.preamble[0], jumpPos, size); - - spdlog::get("usvfs")->info("existing hook to {0:x} in {1}", chainTarget, - shared::string_cast<std::string>( - winapi::ex::wide::getSectionName((void*)chainTarget))); - - if (hookInfo.stub) { - hookInfo.trampoline = TrampolinePool::instance().storeStub( - hookInfo.replacementFunction, - reinterpret_cast<LPVOID>(hookInfo.originalFunction), - reinterpret_cast<LPVOID>(chainTarget)); - } else { - hookInfo.trampoline = TrampolinePool::instance().storeTrampoline( - hookInfo.replacementFunction, - reinterpret_cast<LPVOID>(hookInfo.originalFunction), - reinterpret_cast<LPVOID>(chainTarget)); - } - - DWORD oldProtect = 0; - if (!VirtualProtect(jumpPos, size, PAGE_EXECUTE_WRITECOPY, &oldProtect)) { - throw std::runtime_error("failed to change virtual protection"); - } - - WriteLongJump(jumpPos, hookInfo.trampoline); - - if (!VirtualProtect(jumpPos, size, oldProtect, &oldProtect)) { - throw std::runtime_error("failed to change virtual protection"); - } - - hookInfo.type = THookInfo::TYPE_CHAINPATCH; - hookInfo.detour = reinterpret_cast<LPVOID>(chainTarget); - - if (error != nullptr) { - *error = ERR_NONE; - } - - return TRUE; -} - -/// -/// implements hooking by chaining to an existing hook -/// \param hookInfo info about the hook to be installed -/// \param error if the return code is false and this is not null, -/// the referred-to variable is set to an error code -/// \return true on success, false on error -/// -BOOL HookChainHook(THookInfo& hookInfo, HookError* error) -{ - return HookChainHook(hookInfo, reinterpret_cast<LPBYTE>(hookInfo.originalFunction), - error); -} - -/// -/// implements hooking by chaining to an existing hot patch -/// \param hookInfo info about the hook to be installed -/// \param error if the return code is false and this is not null, -/// the referred-to variable is set to an error code -/// \return true on success, false on error -/// -BOOL HookChainPatch(THookInfo& hookInfo, HookError* error) -{ - LPBYTE original = reinterpret_cast<LPBYTE>(hookInfo.originalFunction); - LPBYTE shortTarget = ShortJumpTarget(original); - - return HookChainHook(hookInfo, shortTarget, error); -} - -/// implements function hooking by overwriting the first n bytes of the function -/// with a jump to the replacement function. Since this is destructive to the original -/// function code the first n bytes of the function need to be copied somewhere else -/// and that code needs to be called via a detour. This is a lot more complex than -/// the hotpatch mechanism. -/// \param hookInfo info about the hook to be installed -/// \param error if the return code is false and this is not null, the referred-to -/// variable is set to an error code -/// \return true on success, false on error -BOOL HookDisasm(THookInfo& hookInfo, HookError* error) -{ - LPBYTE address = reinterpret_cast<LPBYTE>(hookInfo.originalFunction); - ud_set_input_buffer(disasm(), address, 40); - - size_t jumpSize = GetJumpSize( - static_cast<LPBYTE>(hookInfo.originalFunction), - TrampolinePool::instance().currentBufferAddress(hookInfo.originalFunction)); - - // test if we have room for a jump before the function - bool jumpspace = true; - for (size_t i = 0; i < jumpSize; ++i) { - if (*(address - i - 1) != 0x90) { - jumpspace = false; - break; - } - } - - size_t minSize = jumpspace ? 2 : jumpSize; - - // iterate over all instructions that overlap with the jump instructions - // we want to write. - // TODO right now, this does not test if the function is smaller than the jump. - size_t size = 0; - while (size < minSize) { - if (ud_disassemble(disasm()) == 0) { - throw std::runtime_error("premature end of file in disassembly"); - } - - if ((size == 0) && (ud_insn_mnemonic(disasm()) == UD_Ijmp)) { - if (error != nullptr) { - *error = ERR_JUMP; - } - return FALSE; - } - - size += ud_insn_len(disasm()); - - // ret instruction or int3 smells like function end - if ((ud_insn_mnemonic(disasm()) == UD_Iret) || - (ud_insn_mnemonic(disasm()) == UD_Iint3)) { - if (error != nullptr) { - *error = ERR_FUNCEND; - } - return FALSE; - } - - // check the operands for relative addressing (not supported) - for (int i = 0; i < 3; ++i) { - const ud_operand* op = ud_insn_opr(disasm(), i); - if (op) { - if ( - // rip-relative are not handled, usually relative jumps - op->base == UD_R_RIP - - // rsp-relative call are not handled (there are valid rsp-relative - // instructions, e.g. sub) - || (ud_insn_mnemonic(disasm()) == UD_Icall && op->base == UD_R_RSP)) { - if (error != nullptr) { - *error = ERR_RIP; - } - return FALSE; - } - } - } - } - - // save the original code for the preamble so we can restore it later - hookInfo.preamble.resize(size); - memcpy(&hookInfo.preamble[0], hookInfo.originalFunction, size); - - size_t rerouteOffset = 0; - if (hookInfo.stub) { - hookInfo.trampoline = TrampolinePool::instance().storeStub( - hookInfo.replacementFunction, hookInfo.originalFunction, size, &rerouteOffset); - } else { - hookInfo.trampoline = TrampolinePool::instance().storeTrampoline( - hookInfo.replacementFunction, hookInfo.originalFunction, size, &rerouteOffset); - } - - if (jumpspace) { - WriteIndirectJump(hookInfo, jumpSize, error); - hookInfo.type = THookInfo::TYPE_WIN64PATCH; - } else { - WriteSingleJump(hookInfo, error); - hookInfo.type = THookInfo::TYPE_OVERWRITE; - } - hookInfo.detour = reinterpret_cast<LPBYTE>(hookInfo.trampoline) + rerouteOffset; - - return TRUE; -} - -enum EPreamble -{ - PRE_PATCHFREE, - PRE_PATCHUSED, - PRE_RIPINDIRECT, - PRE_FOREIGNHOOK, - PRE_UNKNOWN -}; - -EPreamble DeterminePreamble(LPBYTE address) -{ - ud_set_input_buffer(disasm(), address, JUMP_SIZE); - ud_disassemble(disasm()); - - if ((ud_insn_mnemonic(disasm()) == UD_Imov) && - (ud_insn_opr(disasm(), 0) == ud_insn_opr(disasm(), 1)) && - (ud_insn_opr(disasm(), 0)->type == UD_OP_REG)) { - // mov edi, edi - return PRE_PATCHFREE; - } else if ((ud_insn_mnemonic(disasm()) == UD_Ijmp) && (ud_insn_len(disasm()) == 2)) { - // determine target of the short jump - LPBYTE shortTarget = ShortJumpTarget(address); - - // test if that short jump leads to a long jump - ud_set_input_buffer(disasm(), shortTarget, JUMP_SIZE); - ud_disassemble(disasm()); - if (ud_insn_mnemonic(disasm()) == UD_Ijmp) { - const ud_operand* op = ud_insn_opr(disasm(), 0); - if (op->base == UD_R_RIP) { - return PRE_RIPINDIRECT; - } else { - return PRE_PATCHUSED; - } - } else { - return PRE_UNKNOWN; - } - } else if (ud_insn_mnemonic(disasm()) == UD_Ijmp) { - return PRE_FOREIGNHOOK; - } else { - return PRE_UNKNOWN; - } -} - -static std::map<HOOKHANDLE, THookInfo> s_Hooks; - -static HOOKHANDLE GenerateHandle() -{ - static ULONG NextHandle = 1; - return NextHandle++; -} - -HOOKHANDLE applyHook(THookInfo info, HookError* error) -{ - // apply the correct hook function depending on how the function start looks - EPreamble preamble = DeterminePreamble((LPBYTE)info.originalFunction); - - BOOL success = FALSE; - switch (preamble) { - case PRE_PATCHUSED: { - success = HookChainPatch(info, error); - } break; - case PRE_PATCHFREE: { - success = HookHotPatch(info, error); - } break; - case PRE_RIPINDIRECT: { - success = HookRIPIndirection(info, error); - } break; - case PRE_FOREIGNHOOK: { - success = HookChainHook(info, error); - } break; - default: { - success = HookDisasm(info, error); - } break; - } - - if (success == TRUE) { - HOOKHANDLE handle = GenerateHandle(); - s_Hooks[handle] = info; - return handle; - } else { - return INVALID_HOOK; - } -} - -HOOKHANDLE HookLib::InstallStub(LPVOID functionAddress, LPVOID stubAddress, - HookError* error) -{ - if (functionAddress == nullptr) { - if (error != nullptr) - *error = ERR_INVALIDPARAMETERS; - return INVALID_HOOK; - } - - THookInfo info; - info.originalFunction = functionAddress; - info.replacementFunction = stubAddress; - info.stub = true; - info.detour = nullptr; - info.trampoline = nullptr; - info.type = THookInfo::TYPE_OVERWRITE; - - return applyHook(info, error); -} - -HOOKHANDLE HookLib::InstallStub(HMODULE module, LPCSTR functionName, LPVOID stubAddress, - HookError* error) -{ - LPVOID funcAddr = MyGetProcAddress(module, functionName); - return InstallStub(funcAddr, stubAddress, error); -} - -HOOKHANDLE HookLib::InstallHook(LPVOID functionAddress, LPVOID hookAddress, - HookError* error) -{ - if (functionAddress == nullptr) { - if (error != nullptr) - *error = ERR_INVALIDPARAMETERS; - return INVALID_HOOK; - } - THookInfo info; - info.originalFunction = functionAddress; - info.replacementFunction = hookAddress; - info.stub = false; - info.detour = nullptr; - info.trampoline = nullptr; - info.type = THookInfo::TYPE_OVERWRITE; - - return applyHook(info, error); -} - -HOOKHANDLE HookLib::InstallHook(HMODULE module, LPCSTR functionName, LPVOID hookAddress, - HookError* error) -{ - LPVOID funcAddr = MyGetProcAddress(module, functionName); - return InstallHook(funcAddr, hookAddress, error); -} - -void HookLib::RemoveHook(HOOKHANDLE handle) -{ - auto iter = s_Hooks.find(handle); - if (iter != s_Hooks.end()) { - THookInfo info = iter->second; - PauseOtherThreads(); - LPBYTE address = reinterpret_cast<LPBYTE>(info.originalFunction); - if (info.type == THookInfo::TYPE_HOTPATCH) { - // return the short jump to 2-byte nop - // TODO: This doesn't take into account if we chain-loaded another hook - - DWORD oldProtect = 0; - if (!VirtualProtect(address, 2, PAGE_EXECUTE_WRITECOPY, &oldProtect)) { - throw shared::windows_error("failed to gain write access to remove hook"); - } - *address = 0x8b; - *(address + 1) = 0xff; - VirtualProtect(address, 2, oldProtect, &oldProtect); - } else if ((info.type == THookInfo::TYPE_OVERWRITE) || - (info.type == THookInfo::TYPE_WIN64PATCH)) { - DWORD oldProtect = 0; - if (!VirtualProtect(address, info.preamble.size(), PAGE_EXECUTE_WRITECOPY, - &oldProtect)) { - throw shared::windows_error("failed to gain write access to remove hook"); - } - // TODO: remove hook by restoring the original function. This only works if we - // have the exact code available somewhere - memcpy(address, &info.preamble[0], info.preamble.size()); - VirtualProtect(address, info.preamble.size(), oldProtect, &oldProtect); - } else if (info.type == THookInfo::TYPE_CHAINPATCH) { - // we could attempt to restore the original function preamble but I'm not - // sure we can reliably write the jump with same (or lower) size. - // Instead overwrite our own trampoline - disasm().setInputBuffer(static_cast<uint8_t*>(info.originalFunction), JUMP_SIZE); - ud_disassemble(disasm()); - if (ud_insn_mnemonic(disasm()) != UD_Ijmp) { - // this shouldn't happen, we only call this if the jump was discovered before - throw std::runtime_error("failed to find jump in patch"); - } - - LPBYTE jumpPos = static_cast<LPBYTE>(info.originalFunction); - if (ud_insn_len(disasm()) == 2) { - jumpPos = reinterpret_cast<LPBYTE>(disasm().jumpTarget()); - } - - DWORD oldProtect = 0; - if (!VirtualProtect(jumpPos, info.preamble.size(), PAGE_EXECUTE_WRITECOPY, - &oldProtect)) { - throw shared::windows_error("failed to gain write access to remove hook"); - } - memcpy(jumpPos, info.preamble.data(), info.preamble.size()); - VirtualProtect(jumpPos, info.preamble.size(), oldProtect, &oldProtect); - } else if (info.type == THookInfo::TYPE_RIPINDIRECT) { - uintptr_t res = followJumps(info); - DWORD oldProtect = 0; - if (!VirtualProtect(reinterpret_cast<LPVOID>(res), JUMP_SIZE, - PAGE_EXECUTE_WRITECOPY, &oldProtect)) { - throw shared::windows_error("failed to gain write access to remove hook"); - } - *reinterpret_cast<uintptr_t*>(res) = - reinterpret_cast<uintptr_t>(info.originalFunction); - VirtualProtect(reinterpret_cast<LPVOID>(res), JUMP_SIZE, oldProtect, &oldProtect); - } else { - spdlog::get("usvfs")->critical("can't remove hook, unknown hook type!"); - } - - s_Hooks.erase(iter); - ResumePausedThreads(); - } else { - spdlog::get("usvfs")->info("handle unknown: {0:x}", handle); - } -} - -const char* HookLib::GetErrorString(HookError err) -{ - switch (err) { - case ERR_NONE: - return "No Error"; - case ERR_INVALIDPARAMETERS: - return "Invalid parameters"; - case ERR_FUNCEND: - return "Function too short"; - case ERR_JUMP: - return "Function starts on a jump"; - case ERR_RIP: - return "RIP-relative addressing can't be relocated."; - case ERR_RELJUMP: - return "Relative Jump can't be relocated."; - default: - return "Unkown error code"; - } -} - -const char* HookLib::GetHookType(HOOKHANDLE handle) -{ - auto iter = s_Hooks.find(handle); - if (iter != s_Hooks.end()) { - THookInfo info = iter->second; - switch (info.type) { - case THookInfo::TYPE_HOTPATCH: - return "hot patch"; - case THookInfo::TYPE_WIN64PATCH: - return "64-bit hot patch"; - case THookInfo::TYPE_CHAINPATCH: - return "chained patch"; - case THookInfo::TYPE_OVERWRITE: - return "overwrite"; - case THookInfo::TYPE_RIPINDIRECT: - return "rip indirection modified"; - default: { - spdlog::get("usvfs")->error("invalid hook type {0}", info.type); - return "invalid hook type"; - } - } - } - return "invalid handle"; -} - -LPVOID HookLib::GetDetour(HOOKHANDLE handle) -{ - auto iter = s_Hooks.find(handle); - if (iter != s_Hooks.end()) { - THookInfo info = iter->second; - return info.detour; - } - return nullptr; -} diff --git a/libs/usvfs/src/thooklib/hooklib.h b/libs/usvfs/src/thooklib/hooklib.h deleted file mode 100644 index a549c03..0000000 --- a/libs/usvfs/src/thooklib/hooklib.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs 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. - -usvfs 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 usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <map> -#include <windows_sane.h> - -namespace HookLib -{ - -enum HookError -{ - ERR_NONE, - ERR_INVALIDPARAMETERS, // parameters are invalid - ERR_FUNCEND, // function is too short to be hooked - ERR_JUMP, // function consists only of an unconditional jump. Maybe it has already - // been hooked? - ERR_RIP, // segment of the function to be overwritten contains a instruction-relative - // operation - ERR_RELJUMP // segment of the function to be overwritten contains a relative jump we - // can't relocated -}; - -typedef ULONG HOOKHANDLE; -static const HOOKHANDLE INVALID_HOOK = (HOOKHANDLE)-1; - -/// -/// \brief install a stub (function to be called before the target function) -/// \param functionAddress address of the function to stub -/// \param stubAddress address of the stub function. This function has to have the -/// signature of void foobar(LPVOID address). -/// address receives the address of the function. -/// \param error (optional) if set, the referenced variable will receive an error code -/// describing the problem (if any) -/// \return a handle to reference the hook in later operations or INVALID_HOOK on error -/// -HOOKHANDLE InstallStub(LPVOID functionAddress, LPVOID stubAddress, - HookError* error = nullptr); - -/// -/// \brief install a stub (function to be called before the target function) -/// \param module the module containing the function to hook -/// \param functionName name of the function to stub (as exported by the library) -/// \param stubAddress address of the stub function. This function has to have the -/// signature of void foobar(LPVOID address). -/// address receives the address of the function. -/// \param error (optional) if set, the referenced variable will receive an error code -/// describing the problem (if any) -/// \return a handle to reference the hook in later operations or INVALID_HOOK on error -/// -HOOKHANDLE InstallStub(HMODULE module, LPCSTR functionName, LPVOID stubAddress, - HookError* error = nullptr); - -/// -/// \brief install a hook (function replacing the existing functionality of the -/// function) -/// \param functionAddress address of the function to hook -/// \param hookAddress address of the replacement function. This function has to have -/// the exact same signature as the replaced function -/// \param error (optional) if set, the referenced variable will receive an error code -/// describing the problem (if any) -/// \return a handle to reference the hook in later operations or INVALID_HOOK on error -/// -HOOKHANDLE InstallHook(LPVOID functionAddress, LPVOID hookAddress, - HookError* error = nullptr); - -/// -/// \brief install a hook (function replacing the existing functionality of the -/// function) -/// \param functionName name of the function to hook (as exported by the library) -/// \param hookAddress address of the replacement function. This function has to have -/// the exact same signature as the replaced function -/// \param error (optional) if set, the referenced variable will receive an error code -/// describing the problem (if any) -/// \return a handle to reference the hook in later operations or INVALID_HOOK on error -/// -HOOKHANDLE InstallHook(HMODULE module, LPCSTR functionName, LPVOID hookAddress, - HookError* error = nullptr); - -/// -/// \brief remove a hook -/// \param handle handle returned in InstallStub or InstallHook -/// -void RemoveHook(HOOKHANDLE handle); - -/// -/// \brief determine the type of a hook -/// \param handle the handle to look up -/// \return a string describing the used hooking mechanism -/// -const char* GetHookType(HOOKHANDLE handle); - -/// -/// \brief retrieve the address that can be used to directly call a detour -/// \param handle handle for the hook -/// \return function address -/// -LPVOID GetDetour(HOOKHANDLE handle); - -/// -/// \brief resolve an error code to a descriptive string -/// \param err the error code to resolve -/// \return the error string -/// -const char* GetErrorString(HookError err); - -} // namespace HookLib diff --git a/libs/usvfs/src/thooklib/pch.cpp b/libs/usvfs/src/thooklib/pch.cpp deleted file mode 100644 index 1d9f38c..0000000 --- a/libs/usvfs/src/thooklib/pch.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "pch.h" diff --git a/libs/usvfs/src/thooklib/ttrampolinepool.cpp b/libs/usvfs/src/thooklib/ttrampolinepool.cpp deleted file mode 100644 index 3b6a51f..0000000 --- a/libs/usvfs/src/thooklib/ttrampolinepool.cpp +++ /dev/null @@ -1,601 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs 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. - -usvfs 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 usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "ttrampolinepool.h" -#include <addrtools.h> -#include <shmlogger.h> -// #include <boost/thread/lock_guard.hpp> -#include "udis86wrapper.h" - -using namespace asmjit; -#if BOOST_ARCH_X86_64 -using namespace x86; -#elif BOOST_ARCH_X86_32 -using namespace asmjit::x86; -#endif - -using namespace usvfs::shared; - -namespace HookLib -{ - -TrampolinePool* TrampolinePool::s_Instance = nullptr; - -TrampolinePool::TrampolinePool() : m_MaxTrampolineSize(sizeof(LPVOID)) -{ - m_BarrierAddr = &TrampolinePool::barrier; - m_ReleaseAddr = &TrampolinePool::release; - - SYSTEM_INFO sysInfo; - ::ZeroMemory(&sysInfo, sizeof(SYSTEM_INFO)); - GetSystemInfo(&sysInfo); - m_BufferSize = sysInfo.dwPageSize; - - // if search range = ffffff then addressmask = ffffffffff000000 - // => all jumps between xxxxxxxxxx000000 and xxxxxxxxxxffffff will use the same buffer - // for trampolines which is guaranteed to be in that range - // TODO it should be valid to use 2 ^ 32 as the search range to increase our chances - // of finding a memory block we can reserve but then there is a problem with - // converting negative jump distances to 32 bit I didn't understand. Everything - // up to 2 ^ 31 seems to be fine though - m_SearchRange = static_cast<size_t>(pow(2, 30)) - 1; - m_AddressMask = std::numeric_limits<uint64_t>::max() - m_SearchRange; -} - -// static -void TrampolinePool::initialize() -{ - if (!s_Instance) - s_Instance = new TrampolinePool(); -} - -void TrampolinePool::setBlock(bool block) -{ - m_FullBlock = block; - if (m_ThreadGuards.get() == nullptr) { - m_ThreadGuards.reset(new TThreadMap()); - } -} - -#if BOOST_ARCH_X86_64 -// push all registers (except rax) and flags to the stack -static void pushAll(X86Assembler& assembler) -{ - assembler.pushf(); - assembler.push(rcx); - assembler.push(rdx); - assembler.push(rbx); - assembler.push(rbp); - assembler.push(rsi); - assembler.push(rdi); - assembler.push(r8); - assembler.push(r9); - assembler.push(r10); - assembler.push(r11); - assembler.push(r12); - assembler.push(r13); - assembler.push(r14); - assembler.push(r15); -} - -// pop all registers (except rax) and flags from stack -static void popAll(X86Assembler& assembler) -{ - assembler.pop(r15); - assembler.pop(r14); - assembler.pop(r13); - assembler.pop(r12); - assembler.pop(r11); - assembler.pop(r10); - assembler.pop(r9); - assembler.pop(r8); - assembler.pop(rdi); - assembler.pop(rsi); - assembler.pop(rbp); - assembler.pop(rbx); - assembler.pop(rdx); - assembler.pop(rcx); - assembler.popf(); -} -#endif // BOOST_ARCH_X86_64 - -void TrampolinePool::addBarrier(LPVOID rerouteAddr, LPVOID original, - X86Assembler& assembler) -{ - Label skipLabel = assembler.newLabel(); - -#if BOOST_ARCH_X86_64 - pushAll(assembler); - assembler.mov(rcx, - imm(reinterpret_cast<int64_t>( - original))); // set call parameter for call to barrier function - assembler.mov(rax, imm((intptr_t)(void*)barrier)); - assembler.sub(rsp, 32); - assembler.call(rax); - assembler.add(rsp, 32); - popAll(assembler); - // test barrier - assembler.cmp(rax, 0); // test if the barrier is locked - assembler.jz(skipLabel); // skip if barrier was locked - - // call replacement function - // for this call no registers are saved. the called function is a compiled function so - // it should correctly save non-volatile registers, and the caller can't expect the - // volatile ones to remain valid - assembler.pop(r10); - assembler.mov(dword_ptr(rax), r10); // store that return address to the variable - // supplied by the barrier function - assembler.mov(rax, imm((intptr_t)(LPVOID)rerouteAddr)); - assembler.call(rax); - assembler.push(rax); // save away result - - // open the barrier again - pushAll(assembler); - assembler.mov(rcx, imm(reinterpret_cast<int64_t>(original))); - assembler.mov(rax, imm((intptr_t)(void*)release)); - assembler.sub(rsp, 32); - assembler.call(rax); - assembler.add(rsp, 32); - popAll(assembler); - assembler.pop(r10); // get the result from the replacement function to a register - assembler.push(rax); // push the original return address back on the stack - assembler.mov(rax, r10); // move result of actual call to rax - assembler.ret(); // return, using the original return address -#else // BOOST_ARCH_X86_64 - assembler.push(imm(void_ptr_cast<int32_t>( - original))); // push original function, as parameter to barrier - assembler.mov(ecx, (Ptr) static_cast<void*>(TrampolinePool::barrier)); - assembler.call(ecx); // call barrier function - assembler.cmp(eax, 0); - assembler.jz(skipLabel); // if barrier is locked, jump to end of function - - // case a: we got through the barrier - assembler.pop(ecx); // pop the return address into ecx - assembler.mov(dword_ptr(eax), ecx); // store that return address in the variable - // supplied by the barrier function - - assembler.mov(eax, (Ptr) static_cast<void*>(rerouteAddr)); - assembler.call(eax); // call replacement function (pointer was stored in front of the - // trampoline) (this function gets the parameters that were on - // the stack already and cleans - // them up itself (stdcall convention)) - assembler.push(eax); // save away result - assembler.push(imm(void_ptr_cast<int32_t>(original))); // open the barrier again - assembler.mov(eax, (Ptr) static_cast<void*>(TrampolinePool::release)); - assembler.call(eax); - assembler.pop(ecx); // pop the result from the actual call to ecx - assembler.push(eax); // push the original return address (returned by - // TTrampolinePool::release) back on the stack - assembler.mov(eax, ecx); // move result of actual call to eax - assembler.ret(); // return, using the original return address -#endif // BOOST_ARCH_X86_64 - - assembler.bind(skipLabel); -} - -LPVOID TrampolinePool::roundAddress(LPVOID address) const -{ - return reinterpret_cast<LPVOID>(reinterpret_cast<intptr_t>(address) & m_AddressMask); -} - -TrampolinePool::BufferList& TrampolinePool::getBufferList(LPVOID address) -{ - LPVOID rounded = roundAddress(address); - auto iter = m_Buffers.find(rounded); - if (iter == m_Buffers.end()) { - BufferList newBufList = {0, std::vector<LPVOID>()}; - m_Buffers[rounded] = newBufList; - iter = allocateBuffer(address); - } - return iter->second; -} - -LPVOID TrampolinePool::storeStub(LPVOID reroute, LPVOID original, LPVOID returnAddress) -{ - BufferList& bufferList = getBufferList(original); - // first test to increase likelyhood we don't have to reallocate later - if (bufferList.offset + m_MaxTrampolineSize > m_BufferSize) { - allocateBuffer(original); - } - - LPVOID spot = AddrAdd(*bufferList.buffers.rbegin(), bufferList.offset); - - // ??? write address of reroute to trampoline and move past the address - *reinterpret_cast<LPVOID*>(spot) = reroute; - // coverity[suspicious_sizeof] - spot = AddrAdd(spot, sizeof(LPVOID)); - bufferList.offset += sizeof(LPVOID); - - JitRuntime runtime; -#if BOOST_ARCH_X86_64 - X86Assembler assembler(&runtime); -#else - X86Assembler assembler(&runtime); -#endif - addCallToStub(assembler, original, reroute); - addAbsoluteJump(assembler, reinterpret_cast<uint64_t>(returnAddress)); - - size_t codeSize = assembler.getCodeSize(); - - m_MaxTrampolineSize = - std::max(m_MaxTrampolineSize, static_cast<int>(codeSize + sizeof(LPVOID))); - - // final test to see if we can store the trampoline in the buffer - if ((bufferList.offset + codeSize) > m_BufferSize) { - // can't place function in buffer, allocate another and try again - allocateBuffer(original); - // we could relocate the code and the data but this is simpler - return storeStub(reroute, original, returnAddress); - } - - // adjust relative jumps for move to buffer - codeSize = assembler.relocCode(spot); - - uint8_t* code = assembler.getBuffer(); - memcpy(spot, code, codeSize); - - bufferList.offset += codeSize; - - return spot; -} - -LPVOID TrampolinePool::storeTrampoline(LPVOID reroute, LPVOID original, - LPVOID returnAddress) -{ - BufferList& bufferList = getBufferList(original); - // first test to increase likelyhood we don't have to reallocate later - if (bufferList.offset + m_MaxTrampolineSize > m_BufferSize) { - allocateBuffer(original); - } - - LPVOID spot = AddrAdd(*bufferList.buffers.rbegin(), bufferList.offset); - - *reinterpret_cast<LPVOID*>(spot) = reroute; - // coverity[suspicious_sizeof] - spot = AddrAdd(spot, sizeof(LPVOID)); - bufferList.offset += sizeof(LPVOID); - - JitRuntime runtime; - X86Assembler assembler(&runtime); - addBarrier(reroute, original, assembler); -#if BOOST_ARCH_X86_64 - assembler.mov(rax, imm((intptr_t)(void*)(returnAddress))); - assembler.jmp(rax); -#else - assembler.mov(eax, imm((intptr_t)(void*)(returnAddress))); - assembler.jmp(eax); -#endif - size_t codeSize = assembler.getCodeSize(); - - m_MaxTrampolineSize = - std::max(m_MaxTrampolineSize, static_cast<int>(codeSize + sizeof(LPVOID))); - - // final test to see if we can store the trampoline in the buffer - if ((bufferList.offset + codeSize) > m_BufferSize) { - // can't place function in buffer, allocate another and try again - allocateBuffer(original); - // we could relocate the code and the data but this is simpler - return storeTrampoline(reroute, original, returnAddress); - } - - // adjust relative jumps for move to buffer - codeSize = assembler.relocCode(spot); - - // copy code to buffer - uint8_t* code = assembler.getBuffer(); - memcpy(spot, code, codeSize); - - bufferList.offset += codeSize; - return spot; -} - -#if BOOST_ARCH_X86_64 -void TrampolinePool::copyCode(X86Assembler& assembler, LPVOID source, size_t numBytes) -{ - static UDis86Wrapper disasm; - - disasm.setInputBuffer(static_cast<const uint8_t*>(source), numBytes); - - size_t offset = 0; - - while (ud_disassemble(disasm) != 0) { - // rewrite relative jumps, blind copy everything else - - offset += ud_insn_len(disasm); - - // WARNING: doesn't support conditional jumps - if ((ud_insn_mnemonic(disasm) == UD_Ijmp) && - (ud_insn_opr(disasm, 0)->type == UD_OP_JIMM)) { - uintptr_t dest = disasm.jumpTarget(); - assembler.mov(rax, imm(static_cast<uint64_t>(dest))); - assembler.jmp(rax); - } else { - assembler.embed(ud_insn_ptr(&disasm.obj()), ud_insn_len(&disasm.obj())); - // assembler.data(); - } - } -} -#endif - -void TrampolinePool::addCallToStub(X86Assembler& assembler, LPVOID original, - LPVOID reroute) -{ -#if BOOST_ARCH_X86_64 - pushAll(assembler); - assembler.mov(rcx, imm(reinterpret_cast<int64_t>(original))); - assembler.mov(rax, imm((intptr_t)(LPVOID)reroute)); - assembler.sub(rsp, 32); - assembler.call(rax); - assembler.add(rsp, 32); - popAll(assembler); -#else // BOOST_ARCH_X86_64 - assembler.push(reinterpret_cast<int64_t>(original)); - assembler.mov(ecx, imm((intptr_t)(LPVOID)reroute)); - assembler.call(ecx); - assembler.pop(ecx); // remove argument from stack -#endif // BOOST_ARCH_X86_64 -} - -void TrampolinePool::addAbsoluteJump(X86Assembler& assembler, uint64_t destination) -{ -#if BOOST_ARCH_X86_64 - assembler.push(rax); - assembler.push(rax); - assembler.mov(rax, imm(destination)); - assembler.mov(ptr(rsp, 8), rax); - assembler.pop(rax); - assembler.ret(); -#else // BOOST_ARCH_X86_64 - assembler.push(imm(destination)); - assembler.ret(); -#endif // BOOST_ARCH_X86_64 -} - -LPVOID TrampolinePool::storeStub(LPVOID reroute, LPVOID original, size_t preambleSize, - size_t* rerouteOffset) -{ - BufferList& bufferList = getBufferList(original); - // first test to increase likelyhood we don't have to reallocate later - if (bufferList.offset + m_MaxTrampolineSize > m_BufferSize) { - allocateBuffer(original); - } - - LPVOID spot = AddrAdd(*bufferList.buffers.rbegin(), bufferList.offset); - - *reinterpret_cast<LPVOID*>(spot) = reroute; - // coverity[suspicious_sizeof] - spot = AddrAdd(spot, sizeof(LPVOID)); - bufferList.offset += sizeof(LPVOID); - - JitRuntime runtime; - X86Assembler assembler(&runtime); - addCallToStub(assembler, original, reroute); -#if BOOST_ARCH_X86_64 - // insert backup code - *rerouteOffset = assembler.getCodeSize(); - copyCode(assembler, original, preambleSize); -#else // BOOST_ARCH_X86_64 - assembler.embed(original, preambleSize); -#endif // BOOST_ARCH_X86_64 - addAbsoluteJump(assembler, reinterpret_cast<uint64_t>(original) + preambleSize); - - // adjust relative jumps for move to buffer - size_t codeSize = assembler.getCodeSize(); - - m_MaxTrampolineSize = - std::max(m_MaxTrampolineSize, static_cast<int>(codeSize + sizeof(LPVOID))); - - // final test to see if we can store the trampoline in the buffer - if ((bufferList.offset + codeSize) > m_BufferSize) { - // can't place function in buffer, allocate another and try again - allocateBuffer(original); - // we could relocate the code and the data but this is simpler - return storeStub(reroute, original, preambleSize, rerouteOffset); - } - - // copy code to buffer - codeSize = assembler.relocCode(spot); - - bufferList.offset += preambleSize + codeSize; - return spot; -} - -LPVOID TrampolinePool::storeTrampoline(LPVOID reroute, LPVOID original, - size_t preambleSize, size_t* rerouteOffset) -{ - BufferList& bufferList = getBufferList(original); - // first test to increase likelyhood we don't have to reallocate later - if (bufferList.offset + m_MaxTrampolineSize > m_BufferSize) { - allocateBuffer(original); - } - - LPVOID spot = AddrAdd(*bufferList.buffers.rbegin(), bufferList.offset); - - *reinterpret_cast<LPVOID*>(spot) = reroute; - // coverity[suspicious_sizeof] - spot = AddrAdd(spot, sizeof(LPVOID)); - bufferList.offset += sizeof(LPVOID); - - JitRuntime runtime; - X86Assembler assembler(&runtime); - addBarrier(reroute, original, assembler); - // insert backup code - *rerouteOffset = assembler.getCodeSize(); - assembler.embed(original, static_cast<uint32_t>(preambleSize)); - addAbsoluteJump(assembler, reinterpret_cast<uint64_t>(original) + preambleSize); - - // adjust relative jumps for move to buffer - size_t codeSize = assembler.getCodeSize(); - - m_MaxTrampolineSize = - std::max(m_MaxTrampolineSize, static_cast<int>(codeSize + sizeof(LPVOID))); - - // TODO this does not take into account that the code size may technically change - // after relocation in which case the following test may determine the code fits into - // the buffer when it really doesnt't. asmjit doesn't seem to provide a way to adjust - // jumps without actually moving the code though - - // final test to see if we can store the trampoline in the buffer - if ((bufferList.offset + codeSize) > m_BufferSize) { - // can't place function in buffer, allocate another and try again - allocateBuffer(original); - // we could relocate the code and the data but this is simpler - return storeTrampoline(reroute, original, preambleSize, rerouteOffset); - } - - // copy code to buffer - codeSize = static_cast<size_t>(assembler.relocCode(spot)); - - bufferList.offset += preambleSize + codeSize; - - return spot; -} - -LPVOID TrampolinePool::currentBufferAddress(LPVOID addressNear) -{ - LPVOID rounded = roundAddress(addressNear); - auto lookupAddress = m_Buffers.find(rounded); - - if (lookupAddress == m_Buffers.end()) { - lookupAddress = m_Buffers.insert(std::make_pair(rounded, BufferList())).first; - } - if (lookupAddress->second.buffers.size() == 0) { - allocateBuffer(addressNear); - } - - LPVOID res = *(lookupAddress->second.buffers.rbegin()); - return res; -} - -void TrampolinePool::forceUnlockBarrier() -{ - if (m_ThreadGuards.get() != nullptr) { - for (auto funcId : *m_ThreadGuards) { - (*m_ThreadGuards)[funcId.first] = nullptr; - } - } // else no barriers to unlock -} - -TrampolinePool::BufferMap::iterator TrampolinePool::allocateBuffer(LPVOID addressNear) -{ - // allocate a buffer that we can write to and that is executable - SYSTEM_INFO sysInfo; - ::ZeroMemory(&sysInfo, sizeof(SYSTEM_INFO)); - GetSystemInfo(&sysInfo); - - LPVOID rounded = roundAddress(addressNear); - auto iter = m_Buffers.find(rounded); - uintptr_t lowerEnd = reinterpret_cast<uintptr_t>(rounded); - if (iter->second.buffers.size() > 0) { - // start searching were we last found a buffer - lowerEnd = reinterpret_cast<uintptr_t>(*iter->second.buffers.rbegin()) + - sysInfo.dwPageSize; - } - - uintptr_t start = - std::max(std::max(lowerEnd, MIN_ALLOC_ADDR), - reinterpret_cast<uintptr_t>(sysInfo.lpMinimumApplicationAddress)); - uintptr_t upperEnd = reinterpret_cast<uintptr_t>(rounded) + m_SearchRange; - uintptr_t end = std::min( - upperEnd, reinterpret_cast<uintptr_t>(sysInfo.lpMaximumApplicationAddress)); - - LPVOID buffer = nullptr; - for (uintptr_t cur = start; cur < end; cur += sysInfo.dwPageSize) { - buffer = VirtualAlloc(reinterpret_cast<LPVOID>(cur), m_BufferSize, - MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (buffer != nullptr) { - break; - } - } - if (buffer == nullptr) { - throw std::runtime_error("failed to allocate buffer in range"); - } - - // the caller must have looked up the bufferlist in order to determine that a - // buffer has to be allocated - assert(iter != m_Buffers.end()); - - iter->second.offset = 0; - iter->second.buffers.push_back(buffer); - spdlog::get("usvfs")->debug( - "allocated trampoline buffer for jumps between {0:p} and {1:x} at {2:p}" - "(size {3})", - rounded, (reinterpret_cast<uintptr_t>(rounded) + m_SearchRange), buffer, - m_BufferSize); - return iter; -} - -LPVOID TrampolinePool::barrier(LPVOID function) -{ - DWORD err = GetLastError(); - LPVOID res = instance().barrierInt(function); - SetLastError(err); - return res; -} - -LPVOID TrampolinePool::release(LPVOID function) -{ - DWORD err = GetLastError(); - LPVOID res = instance().releaseInt(function); - SetLastError(err); - return res; -} - -LPVOID TrampolinePool::barrierInt(LPVOID func) -{ - if (m_FullBlock) { - return nullptr; - } - - if (m_ThreadGuards.get() == nullptr) { - m_ThreadGuards.reset(new TThreadMap()); - } - - auto iter = m_ThreadGuards->find(func); - if ((iter == m_ThreadGuards->end()) || (iter->second == nullptr)) { - (*m_ThreadGuards)[func] = reinterpret_cast<LPVOID>(1); - return &(*m_ThreadGuards)[func]; - } else { - return nullptr; - } -} - -LPVOID TrampolinePool::releaseInt(LPVOID func) -{ - DWORD lastError = GetLastError(); - if (m_ThreadGuards.get() == nullptr) { - m_ThreadGuards.reset(new TThreadMap()); - } - - auto iter = m_ThreadGuards->find(func); - if (iter == m_ThreadGuards->end()) { - spdlog::get("hooks")->error("failed to release barrier for func {}", func); - ::SetLastError(lastError); - return nullptr; - } - - LPVOID res = (*m_ThreadGuards)[func]; - (*m_ThreadGuards)[func] = nullptr; - - ::SetLastError(lastError); - return res; -} - -} // namespace HookLib diff --git a/libs/usvfs/src/thooklib/ttrampolinepool.h b/libs/usvfs/src/thooklib/ttrampolinepool.h deleted file mode 100644 index 5b44c51..0000000 --- a/libs/usvfs/src/thooklib/ttrampolinepool.h +++ /dev/null @@ -1,222 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs 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. - -usvfs 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 usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include "asmjit_sane.h" -#include <logging.h> -#include <map> -#include <vector> -#include <windows_sane.h> - -#ifdef _MSC_VER -#pragma warning(disable : 4714) -#include <boost/config/compiler/visualc.hpp> -#else -#include <boost/config/compiler/gcc.hpp> -#endif -#include <boost/predef.h> -#include <boost/thread.hpp> -#include <mutex> - -// #include <boost/thread/mutex.hpp> - -namespace HookLib -{ - -/// -/// trampolines are runtime-generated mini-functions that are used to call the -/// original code of a function -/// -class TrampolinePool -{ -public: - /// Call initialize before you use the TrampolinePool - static void initialize(); - - static TrampolinePool& instance() - { - // This is a very very sensitive place so we want to keep this function as simple as - // possible and having it inlined probably cann't hurt - return *s_Instance; - } - - void setBlock(bool block); - - /// - /// store a stub without moving code from the original function. This is used in cases - /// where the hook can be placed without overwriting logic (i.e. hot-patchable - /// functions and when chaining hooks) - /// \param reroute the stub function to call before the regular function (on x86 this - /// needs to be cdecl calling convention!) - /// \param original the original function - /// \param returnAddress address under which the original functionality can be - /// reached. - /// for the first hook this should be (original + 2), otherwise - /// the address of the next hook in the chain - /// \return address of the created trampoline function - /// - LPVOID storeStub(LPVOID reroute, LPVOID original, LPVOID returnAddress); - - /// - /// store a stub, moving part of the original function to the trampoline - /// \param reroute the stub function to call before the regular function (on x86 this - /// needs to be cdecl calling convention!) - /// \param original the original function - /// \param preambleSize number of bytes from the original function to backup. Needs to - /// correspond to complete instructions - /// \param rerouteOffset offset in bytes from the created trampoline to the preamble - /// that leads back to the original code - /// \return address of the created trampoline function - /// - LPVOID storeStub(LPVOID reroute, LPVOID original, size_t preambleSize, - size_t* rerouteOffset); - - /// - /// store a trampoline for hot-patchable functions, where the original function - /// is unharmed. - /// \param reroute the reroute function - /// \param original original function - /// \param returnAddress address under which the original functionality can be - /// reached. - /// \return address of the trampoline function - /// - LPVOID storeTrampoline(LPVOID reroute, LPVOID original, LPVOID returnAddress); - - /// - /// store a trampoline, copying a part of the original function to the trampoline. - /// This is used for the case where the hooking mechanism needs to overwrite part of - /// the function - /// \param reroute the reroute function - /// \param original original function - /// \param preambleSize number of bytes from the original function to backup. Needs to - /// correspond to complete instructions - /// \param rerouteOffset offset in bytes from the created trampoline to the preamble - /// that leads us back to the original code - /// \return address of the trampoline function - /// - LPVOID storeTrampoline(LPVOID reroute, LPVOID original, size_t preambleSize, - size_t* rerouteOffset); - - /// - /// \param addressNear used to find a trampoline buffer near the jump instruction - /// \return retrieve address of current trampoline buffer - /// - LPVOID currentBufferAddress(LPVOID addressNear); - - /// - /// \brief forces the barrier(s) for the current thread to be released - /// - void forceUnlockBarrier(); - -private: - struct BufferList - { - size_t offset; - std::vector<LPVOID> buffers; - }; - - typedef std::map<LPVOID, BufferList> BufferMap; - static const intptr_t ADDRESS_MASK = - 0xFFFFFFFFFF000000LL; // mask to "round" addresses to consolidate near - // trampolines - -private: - TrampolinePool(); - - TrampolinePool& operator=(const TrampolinePool& reference); // not implemented - - /** - * @brief allocates a buffer with read, write and execute rights near the - * specified adress. The purpose is that we want to be able to jump from - * adressNear to generated code with a 5-byte jump, even on x64 systems. - * @param addressNear the reference adress - * @note the resulting buffer is stored in the m_Buffers map - */ - BufferMap::iterator allocateBuffer(LPVOID addressNear); - - void addBarrier(LPVOID rerouteAddr, LPVOID original, asmjit::X86Assembler& assembler); - -#if BOOST_ARCH_X86_64 - void copyCode(asmjit::X86Assembler& assembler, LPVOID source, size_t numBytes); -#endif // BOOST_ARCH_X86_64 - - BufferList& getBufferList(LPVOID address); - - LPVOID roundAddress(LPVOID address) const; - -public: - static LPVOID __stdcall barrier(LPVOID function); - static LPVOID __stdcall release(LPVOID function); - - LPVOID barrierInt(LPVOID function); - LPVOID releaseInt(LPVOID function); - - void addCallToStub(asmjit::X86Assembler& assembler, LPVOID original, LPVOID reroute); - -private: - /// - /// \brief add a jump to an address outside the custom generated asm code (without - /// modifying registers) - /// \param assembler the assembler generator to write to - /// \param destination destination address - /// \note this currently generates a lot code on x64, may be overly complicated - /// - void addAbsoluteJump(asmjit::X86Assembler& assembler, uint64_t destination); - - DWORD determinePageSize(); - -private: -#if BOOST_ARCH_X86_64 - static const int SIZE_OF_JUMP = 13; -#elif BOOST_ARCH_X86_32 - static const int SIZE_OF_JUMP = 5; -#endif - - // the hook lib tries to allocate buffer close to the hooked functions, - // for 32-bits application, this often falls on 0x40000000, which is the - // address at which DLLs can be loaded on Windows - // - // some old-style DRM (e.g. Dragon Age 2) check that address and prevent - // the game from running if it's not 0x40000000, so we give them a bit of - // spaces before allocating our buffers - // - static constexpr uintptr_t MIN_ALLOC_ADDR = 0x40000000 + 0x200000; - - static TrampolinePool* s_Instance; - - bool m_FullBlock{false}; - - BufferMap m_Buffers; - - typedef std::map<void*, void*> TThreadMap; - boost::thread_specific_ptr<TThreadMap> m_ThreadGuards; - - LPVOID m_BarrierAddr; - LPVOID m_ReleaseAddr; - - DWORD m_BufferSize = {1024}; - size_t m_SearchRange; - uint64_t m_AddressMask; - - int m_MaxTrampolineSize; -}; - -} // namespace HookLib diff --git a/libs/usvfs/src/thooklib/udis86wrapper.cpp b/libs/usvfs/src/thooklib/udis86wrapper.cpp deleted file mode 100644 index 1ac7332..0000000 --- a/libs/usvfs/src/thooklib/udis86wrapper.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs 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. - -usvfs 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 usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "udis86wrapper.h" -#include "pch.h" -#include <boost/predef.h> -#include <shmlogger.h> -#include <stdexcept> - -namespace HookLib -{ - -UDis86Wrapper::UDis86Wrapper() -{ - ud_init(&m_Obj); - ud_set_syntax(&m_Obj, UD_SYN_INTEL); -#if BOOST_ARCH_X86_64 - ud_set_mode(&m_Obj, 64); -#else - ud_set_mode(&m_Obj, 32); -#endif -} - -void UDis86Wrapper::setInputBuffer(const uint8_t* buffer, size_t size) -{ - m_Buffer = buffer; - ud_set_input_buffer(&m_Obj, buffer, size); - ud_set_pc(&m_Obj, reinterpret_cast<uint64_t>(m_Buffer)); -} - -ud_t& UDis86Wrapper::obj() -{ - return m_Obj; -} - -bool UDis86Wrapper::isRelativeJump() -{ - ud_mnemonic_code code = ud_insn_mnemonic(&m_Obj); - // all conditional jumps and loops are relative, as are unconditional jumps with an - // offset operand - return (code == UD_Ijo) || (code == UD_Ijno) || (code == UD_Ijb) || - (code == UD_Ijae) || (code == UD_Ijz) || (code == UD_Ijnz) || - (code == UD_Ijbe) || (code == UD_Ija) || (code == UD_Ijs) || - (code == UD_Ijns) || (code == UD_Ijp) || (code == UD_Ijnp) || - (code == UD_Ijl) || (code == UD_Ijge) || (code == UD_Ijle) || - (code == UD_Ijg) || (code == UD_Ijcxz) || (code == UD_Ijecxz) || - (code == UD_Ijrcxz) || (code == UD_Iloop) || (code == UD_Iloope) || - (code == UD_Iloopne) || - ((code == UD_Icall) && (ud_insn_opr(&m_Obj, 0)->type == UD_OP_JIMM)) || - ((code == UD_Ijmp) && (ud_insn_opr(&m_Obj, 0)->type == UD_OP_JIMM)); -} - -intptr_t UDis86Wrapper::jumpOffset() -{ - const ud_operand_t* op = ud_insn_opr(&m_Obj, 0); - switch (op->size) { - case 8: - return static_cast<intptr_t>(op->lval.sbyte); - case 16: - return static_cast<intptr_t>(op->lval.sword); - case 32: - return static_cast<intptr_t>(op->lval.sdword); - case 64: - return static_cast<intptr_t>(op->lval.sqword); - default: - throw std::runtime_error("unsupported jump size"); - } -} - -uint64_t UDis86Wrapper::jumpTarget() -{ - // TODO: assert we're actually on a jump - - uint64_t res = ud_insn_off(&m_Obj) + ud_insn_len(&m_Obj); - - res += jumpOffset(); - - if (ud_insn_opr(&m_Obj, 0)->base == UD_R_RIP) { - res = *reinterpret_cast<uintptr_t*>(res); - } - - return res; -} - -} // namespace HookLib diff --git a/libs/usvfs/src/thooklib/udis86wrapper.h b/libs/usvfs/src/thooklib/udis86wrapper.h deleted file mode 100644 index 48d8a42..0000000 --- a/libs/usvfs/src/thooklib/udis86wrapper.h +++ /dev/null @@ -1,62 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs 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. - -usvfs 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 usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <udis86.h> -#undef inline // libudis86/types.h defines inline to __inline which is no longer legal - // since vs2012 - -namespace HookLib -{ - -class UDis86Wrapper -{ - -public: - UDis86Wrapper(); - - void setInputBuffer(const uint8_t* buffer, size_t size); - - ud_t& obj(); - - operator ud_t*() { return &m_Obj; } - - bool isRelativeJump(); - - intptr_t jumpOffset(); - - /// - /// determines the absolute jump target at the current instruction, taking into - /// account relative instructions of all sizes and RIP-relative addressing. - /// \return absolute address of the jump at the current disassembler instruction - /// \note this works correctly ONLY if the input buffer has been set with - /// setInputBuffer or - /// if ud_set_pc has been called - /// - uint64_t jumpTarget(); - -private: -private: - ud_t m_Obj; - const uint8_t* m_Buffer{nullptr}; -}; - -} // namespace HookLib diff --git a/libs/usvfs/src/thooklib/utility.cpp b/libs/usvfs/src/thooklib/utility.cpp deleted file mode 100644 index 124141f..0000000 --- a/libs/usvfs/src/thooklib/utility.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs 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. - -usvfs 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 usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "utility.h" -#include "exceptionex.h" -#include <cstdlib> - -namespace HookLib -{ - -FARPROC MyGetProcAddress(HMODULE module, LPCSTR functionName) -{ - // determine position of the exports of the module - PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)module; - if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { - return nullptr; - } - - PIMAGE_NT_HEADERS ntHeaders = - (PIMAGE_NT_HEADERS)(((LPBYTE)dosHeader) + dosHeader->e_lfanew); - if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) { - return nullptr; - } - - PIMAGE_OPTIONAL_HEADER optionalHeader = &ntHeaders->OptionalHeader; - if (optionalHeader->NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_EXPORT) { - return nullptr; - } - PIMAGE_DATA_DIRECTORY dataDirectory = - &optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; - PIMAGE_EXPORT_DIRECTORY exportDirectory = - (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)dosHeader + dataDirectory->VirtualAddress); - - ULONG* addressOfNames = (ULONG*)((LPBYTE)module + exportDirectory->AddressOfNames); - ULONG* funcAddr = (ULONG*)((LPBYTE)module + exportDirectory->AddressOfFunctions); - - // search exports for the specified name - for (DWORD i = 0; i < exportDirectory->NumberOfNames; ++i) { - char* curFunctionName = (char*)((LPBYTE)module + addressOfNames[i]); - USHORT* nameOrdinals = - (USHORT*)((LPBYTE)module + exportDirectory->AddressOfNameOrdinals); - if (strcmp(functionName, curFunctionName) == 0) { - if (funcAddr[nameOrdinals[i]] >= dataDirectory->VirtualAddress && - funcAddr[nameOrdinals[i]] < - dataDirectory->VirtualAddress + dataDirectory->Size) { - char* forwardLibName = _strdup((LPSTR)module + funcAddr[nameOrdinals[i]]); - ON_BLOCK_EXIT([forwardLibName]() { - free(forwardLibName); - }); - char* forwardFunctionName = strchr(forwardLibName, '.'); - *forwardFunctionName = 0; - ++forwardFunctionName; - - HMODULE forwardLib = LoadLibraryA(forwardLibName); - FARPROC forward = nullptr; - if (forwardLib != nullptr) { - forward = MyGetProcAddress(forwardLib, forwardFunctionName); - FreeLibrary(forwardLib); - } - - return forward; - } - return (FARPROC)((LPBYTE)module + funcAddr[nameOrdinals[i]]); - } - } - return nullptr; -} - -} // namespace HookLib diff --git a/libs/usvfs/src/thooklib/utility.h b/libs/usvfs/src/thooklib/utility.h deleted file mode 100644 index e0be9f7..0000000 --- a/libs/usvfs/src/thooklib/utility.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -Userspace Virtual Filesystem - -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This file is part of usvfs. - -usvfs 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. - -usvfs 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 usvfs. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <windows_sane.h> - -namespace HookLib -{ - -/// \brief reimplementation of GetProcAddress to circumvent foreign hooks of -/// GetProcAddress like AcLayer -/// \param module handle to the module that contains the function or variable -/// \param functionName function to retrieve the address of -/// \return address of the exported function -FARPROC MyGetProcAddress(HMODULE module, LPCSTR functionName); - -} // namespace HookLib |
