neptools

Modding tools to Neptunia games
git clone https://git.neptards.moe/neptards/neptools.git
Log | Files | Refs | Submodules | README | LICENSE

hook.cpp (2264B)


      1 #include "hook.hpp"
      2 #include <new>
      3 #include <stdexcept>
      4 #include <cstdlib>
      5 
      6 #define LIBSHIT_LOG_NAME "hook"
      7 #include <libshit/logger_helper.hpp>
      8 
      9 #define WIN32_LEAN_AND_MEAN
     10 #include <windows.h>
     11 
     12 namespace Neptools
     13 {
     14 
     15   Byte* image_base;
     16   static HANDLE heap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
     17 
     18   static constexpr size_t JMP_SIZE = 5;
     19 
     20   size_t GetImageSize() noexcept
     21   {
     22     auto dos_hdr = reinterpret_cast<IMAGE_DOS_HEADER*>(image_base);
     23     auto hdr = reinterpret_cast<IMAGE_NT_HEADERS32*>(image_base + dos_hdr->e_lfanew);
     24     DBG(1) << "Image size: " << hdr->OptionalHeader.SizeOfImage << std::endl;
     25     return hdr->OptionalHeader.SizeOfImage;
     26   }
     27 
     28   Byte* GetEntryPoint() noexcept
     29   {
     30     auto dos_hdr = reinterpret_cast<IMAGE_DOS_HEADER*>(image_base);
     31     auto hdr = reinterpret_cast<IMAGE_NT_HEADERS32*>(image_base + dos_hdr->e_lfanew);
     32     auto ret = image_base + hdr->OptionalHeader.AddressOfEntryPoint;
     33     DBG(1) << "OEP: " << ret << std::endl;
     34     return ret;
     35   }
     36 
     37   void* Hook(void* fun, void* dst, size_t copy)
     38   {
     39     DBG(2) << "Hooking " << fun << " to " << dst << " (" << copy << " bytes)"
     40            << std::endl;
     41 
     42     char* addr = reinterpret_cast<char*>(fun);
     43 
     44     char* ret = nullptr;
     45     if (copy)
     46     {
     47       ret = static_cast<char*>(HeapAlloc(heap, 0, copy + JMP_SIZE));
     48       if (!ret) LIBSHIT_THROW(std::bad_alloc, std::make_tuple());
     49       memcpy(ret, addr, copy);
     50       ret[copy] = 0xe9; // jmp
     51       auto base = ret + copy + JMP_SIZE;
     52       auto tgt = addr + copy;
     53       As<int>(ret+copy+1) = tgt - base;
     54     }
     55 
     56     try
     57     {
     58       Unprotect up{addr, 5};
     59       addr[0] = 0xe9; // jmp
     60       As<int>(addr+1) = reinterpret_cast<char*>(dst) - addr - JMP_SIZE;
     61     }
     62     catch (...)
     63     {
     64       if (ret) HeapFree(heap, 0, ret);
     65       throw;
     66     }
     67 
     68     DBG(4) << "done" << std::endl;
     69     return ret;
     70   }
     71 
     72   Unprotect::Unprotect(void* ptr, size_t len) : ptr{ptr}, len{len}
     73   {
     74     if (!VirtualProtect(ptr, len, PAGE_EXECUTE_READWRITE, &orig_prot))
     75       LIBSHIT_THROW(std::runtime_error, "Unprotect: VirtualProtect");
     76   }
     77 
     78   Unprotect::~Unprotect()
     79   {
     80     if (!VirtualProtect(ptr, len, orig_prot, &orig_prot))
     81       MessageBoxA(nullptr, "Failed to unprotect memory", "Neptools",
     82                   MB_OK | MB_ICONERROR);
     83   }
     84 
     85 }