#pragma once #include #include #include // An Example to shou you how to use PatchHelper<> to patch the program // in this example, we change the code to call Item::_useOn via vftable in specific function // this is way better that modify vftable directly in some situation like this // //bool _Item_UseOn_Hook(Item* _this, ItemStack& item, Actor& actor, BlockPos blockPos, unsigned char unk, Vec3& pos) { // logger.info("Item::_useOn"); // return _this->_useOn(item, actor, blockPos, unk, pos); //} //useOnHook() { // constexpr size_t max_step = 0x300; // constexpr size_t ori_size = 11; // // unsigned char* begin = (unsigned char*)dlsym_real("?useOn@Item@@QEBA_NAEAVItemStack@@AEAVActor@@HHHEAEBVVec3@@@Z"); // unsigned char* end = begin + max_step; // // PatchHelper ori({ // 0x90, // nop // 0x48, 0x8B, 0x07, // mov rax, [rdi] // 0x4C, 0x8B, 0x90, 0x30, 0x04, 0x00, 0x00 // mov r10, [rax+430h] // }); // // unsigned char* fn = (unsigned char*)new unsigned __int64((unsigned __int64)_Item_UseOn_Hook); // // PatchHelper target({ // 0x90, // nop // 0x49, 0xBA, fn[0], fn[1], fn[2], fn[3], fn[4], fn[5], fn[6], fn[7], // mov r10, _Item_UseOn_Hook // }); // // unsigned char* found = find(begin, end, ori.data, ori_size); // if (!found) { // printf("Failed to hook Item::_useOn (asm patch target not found)\n"); // return; // } // printf("Found target asm at %X (%X)\n", found, found - begin); // if (!((PatchHelper*)found)->EasyPatch(ori, target)) { // printf("Failed to patch Item::_useOn\n"); // } //} template struct PatchHelper { unsigned char data[len]; using ref_t = unsigned char (&)[len]; constexpr bool operator==(ref_t ref) const noexcept { return memcmp(data, ref, sizeof data) == 0; } constexpr bool operator!=(ref_t ref) const noexcept { return memcmp(data, ref, sizeof data) != 0; } constexpr bool operator==(PatchHelper ref) const noexcept { return memcmp(data, ref.data, sizeof data) == 0; } constexpr bool operator!=(PatchHelper ref) const noexcept { return memcmp(data, ref.data, sizeof data) != 0; } inline void operator=(ref_t ref) { memcpy(data, ref, sizeof data); } inline bool DoPatch(PatchHelper expected, PatchHelper patched) { if (*this == expected) { *this = patched; return true; } return false; } inline bool EasyPatch(PatchHelper expected, PatchHelper patched) { DWORD old, tmp; VirtualProtect((LPVOID)this, (SIZE_T)len, PAGE_EXECUTE_READWRITE, &old); bool result = DoPatch(expected, patched); VirtualProtect((LPVOID)this, (SIZE_T)len, old, &tmp); return result; } inline std::string Dump() const noexcept { char buffer[2 * len + 1] = {}; char* ptr = buffer; for (auto ch : data) ptr += sprintf(ptr, "%02X", (unsigned)ch); return {buffer}; } }; struct NopFiller { template inline operator PatchHelper() { PatchHelper ret; memset(ret.data, 0x90, len); return ret; } };