diff --git a/3rdparty/zydis b/3rdparty/zydis index 9ec1e0c..1ba75ae 160000 --- a/3rdparty/zydis +++ b/3rdparty/zydis @@ -1 +1 @@ -Subproject commit 9ec1e0c4d17bf08f17575e25b0c2cf70c5cc879b +Subproject commit 1ba75aeefae37094c7be8eba07ff81d4fe0f1f20 diff --git a/CMakeLists.txt b/CMakeLists.txt index ac634bb..4789252 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,4 +15,4 @@ add_library(${LIB_NAME} inline_hook.cpp) target_link_libraries(${LIB_NAME} Zydis) add_dependencies(${LIB_NAME} Zydis) add_executable(hooker-test hooktest.cpp) -target_link_libraries(hooker-test ${LIB_NAME} Zydis) +target_link_libraries(hooker-test ${LIB_NAME} Zydis dl -pthread) diff --git a/PFishHook.h b/PFishHook.h index 36e8030..d1f608c 100644 --- a/PFishHook.h +++ b/PFishHook.h @@ -7,8 +7,7 @@ enum HookStatus FHMprotectFail, FHAllocFailed, FHPatchFailed, - FHTooManyPatches, - FHUnrecognizedRIP, + FHEncodeFailed, }; #ifdef __cplusplus diff --git a/hooktest.cpp b/hooktest.cpp index bfed2d3..ad65d2a 100644 --- a/hooktest.cpp +++ b/hooktest.cpp @@ -1,143 +1,82 @@ #include "PFishHook.h" -#include +#include #include -#include +#include +#include +#include -int main(); +typedef void (*quick_exit_t)(int status); +static quick_exit_t quick_exit_f = nullptr; -asm("testfunc:\n\ -ja gofurther2\n\ -gofurther:\n\ - call main\n\ -gofurther2:\n\ - call main\n\ -"); -extern "C" void testfunc(); - -void(*poldfunc)(); -void test_replace() -{ - return poldfunc(); +void quick_exit_call(int status) { + printf("hook quick exit\n"); + quick_exit_f(status); } -asm(R"(testfunc2: -jne gofurther3 -cmpl $0x0,0x10(%rip) -ja gofurther4 -ja gofurther5 -gofurther3: - call main -gofurther4: - call main -gofurther5: - call main -)"); -extern "C" void testfunc2(); - -extern "C" void testfunc_lea(); -asm(R"(testfunc_lea: -lea 0x123450(%rip),%ecx -lea 0x123450(%rip),%rcx -ret -)"); +typedef void (*pthread_exit_t) (void *__retval); +static pthread_exit_t pthread_exit_f = nullptr; -extern "C" void testfunc_call(); -asm(R"(testfunc_call: -jmp main -call main -ret -)"); - -void(*poldfunc2)(); -void(*poldfunc3)(); -void(*poldfunc4)(); -void(*poldfunc5)(); -void(*poldfunc6)(); -void(*poldfunc7)(); -void test_dummy(){ - printf("DUMMY: orig func\n"); -} -void test_replace_d() -{ -printf("shadow 1\n"); - return poldfunc5(); -} -void test_replace_d2() -{ - printf("shadow 2\n"); - return poldfunc6(); -} -void test_replace_d3() -{ - printf("shadow 3\n"); - return poldfunc7(); +void pthread_exit_call(void *__retval) { + printf("hook pthread_exit\n"); + pthread_exit_f(__retval); } -void test_replace2() -{ - return poldfunc2(); -} - - +typedef void (*endprotoent_t)(void); +static endprotoent_t endprotoent_f = nullptr; +void endprotoent_call() { + printf("hook endprotoent\n"); + endprotoent_f(); +} int main() { - ZydisFormatter formatter; - ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL); - //ZydisFormatterSetProperty(&formatter, ZYDIS_FORMATTER_PROP_ADDR_FORMAT, ZYDIS_ADDR_FORMAT_RELATIVE_SIGNED); - ZydisDecoder decoder; - ZydisDecoderInit( - &decoder, - ZYDIS_MACHINE_MODE_LONG_64, - ZYDIS_ADDRESS_WIDTH_64); - - typedef void(*functype)(); - auto disas = [&](functype f, int sz) - { - uint8_t* readPointer = (uint8_t*)f; - ZydisDecodedInstruction instruction; - while (ZYDIS_SUCCESS(ZydisDecoderDecodeBuffer( - &decoder, readPointer, 128, (uint64_t)readPointer, &instruction))) - { - char buffer[256]; - ZydisFormatterFormatInstruction( - &formatter, &instruction, buffer, sizeof(buffer)); - printf("0x%p: %s\n", readPointer, buffer); - sz--; - if (sz <= 0) - break; - readPointer += instruction.length; - } - printf("==============================\n"); - }; - - - auto runtest = [&](const char* name,functype target, functype* old, functype newfunc) - { - printf("==============================\n%s\n==============================\nBefore Hook:\n", name); - disas(target, 5); - auto ret = HookIt((void*)target, (void**)old, (void*)newfunc); - printf("Hook status=%d\n", ret); - if (ret == FHSuccess) - { - printf("After Hook:\n"); - disas(target, 7); - printf("\nShadow Func:\n"); - disas(*old, 10); - } - }; - - printf("main=%p\ntest_replace=%p\ntest_replace2=%p\n", main, test_replace, test_replace2); - - runtest("testfunc", testfunc, &poldfunc, test_replace); - runtest("testfunc2", testfunc2, &poldfunc2, test_replace2); - runtest("testfunc_lea", testfunc_lea, &poldfunc3, test_replace2); - runtest("testfunc_call", testfunc_call, &poldfunc4, test_replace2); - //test for dup hooks - runtest("testfunc_dup", test_dummy, &poldfunc5, test_replace_d); - runtest("testfunc_dup2", test_dummy, &poldfunc6, test_replace_d2); - runtest("testfunc_dup3", test_dummy, &poldfunc7, test_replace_d3); - test_dummy(); - return 0; -} + HookStatus ret; + /* + Dump of assembler code for function quick_exit: + 0x00007ffff78434b0 <+0>: 48 8d 35 49 a1 38 00 lea 0x38a149(%rip),%rsi # 0x7ffff7bcd600 <__quick_exit_funcs> + 0x00007ffff78434b7 <+7>: 48 83 ec 08 sub $0x8,%rsp + 0x00007ffff78434bb <+11>: 31 d2 xor %edx,%edx + 0x00007ffff78434bd <+13>: e8 4e fa ff ff callq 0x7ffff7842f10 <__run_exit_handlers> + */ + void* quick_exit_handler = dlsym(RTLD_NEXT, "quick_exit"); + ret = HookIt(quick_exit_handler, (void **)&quick_exit_f, (void *)quick_exit_call); + if (ret != FHSuccess) { + printf("hook quick_exit fail%d\n", ret); + } + // UnHook(quick_exit_handler, (void*)quick_exit_f); + + /* + Dump of assembler code for function __pthread_exit: + 0x00007ffff791dea0 <+0>: sub $0x8,%rsp + 0x00007ffff791dea4 <+4>: mov 0x2b4886(%rip),%eax # 0x7ffff7bd2730 <__libc_pthread_functions_init> + 0x00007ffff791deaa <+10>: test %eax,%eax + 0x00007ffff791deac <+12>: jne 0x7ffff791deb5 <__pthread_exit+21> + */ + void* pthread_exit_handler = dlsym(RTLD_NEXT, "pthread_exit"); + ret = HookIt(pthread_exit_handler, (void **)&pthread_exit_f, (void *)pthread_exit_call); + if (ret != FHSuccess) { + printf("hook pthread_exit fail%d\n", ret); + } + + /* + Dump of assembler code for function endprotoent: + 0x00007ffff7924ca0 <+0>: 48 83 3d 80 c7 2a 00 00 cmpq $0x0,0x2ac780(%rip) # 0x7ffff7bd1428 + 0x00007ffff7924ca8 <+8>: 0f 84 b5 00 00 00 je 0x7ffff7924d63 + */ + void* endprotoent_handler = dlsym(RTLD_NEXT, "endprotoent"); + ret = HookIt(endprotoent_handler, (void **)&endprotoent_f, (void *)endprotoent_call); + if (ret != FHSuccess) { + printf("hook endprotoent fail%d\n", ret); + } + + /* + Dump of assembler code for function htons: + 0x00007ffff79223a0 <+0>: 89 f8 mov %edi,%eax + 0x00007ffff79223a2 <+2>: 66 c1 c8 08 ror $0x8,%ax + 0x00007ffff79223a6 <+6>: c3 retq + */ + // we must reject the hook of htons, because it is too small to be hooked + + quick_exit(0); +} \ No newline at end of file diff --git a/inline_hook.cpp b/inline_hook.cpp index dedce95..b2bc4d0 100644 --- a/inline_hook.cpp +++ b/inline_hook.cpp @@ -1,18 +1,21 @@ +#include +#include +#include #include #include #include #include +#include "Zycore/String.h" #include "Zydis/Zydis.h" -#include +#include #include #include "PFishHook.h" #include -#include +#include - -static size_t PageSize2= 0; +static size_t PageSize= 0; static ZydisFormatter formatter; -static ZydisStatus (*ptrParseOperandMem)(const ZydisFormatter* formatter, ZydisString* string, +static ZyanStatus (*ptrParseOperandMem)(const ZydisFormatter* formatter, ZyanString* string, const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operand, void* userData); inline size_t divide_and_ceil(size_t x, size_t y) @@ -23,12 +26,12 @@ inline size_t divide_and_ceil(size_t x, size_t y) //align to the floor page inline void* AlignToPage(void* addr) { - return (void*)((uintptr_t)addr & ~(PageSize2 - 1)); + return (void*)((uintptr_t)addr & ~(PageSize - 1)); } //align to the ceil page inline void* AlignToPage_UP(void* addr) { - return (void*)(((uintptr_t)addr+PageSize2-1) & ~(PageSize2 - 1)); + return (void*)(((uintptr_t)addr+PageSize-1) & ~(PageSize - 1)); } inline size_t AddressDiff(void* a, void* b) @@ -47,10 +50,10 @@ static bool hasRIP = false; /* The function to check if there is RIP-relative memory loads in the instruction */ -static ZydisStatus ParseOperandMem(const ZydisFormatter* formatter, ZydisString* string, +static ZyanStatus ParseOperandMem(const ZydisFormatter* formatter, ZyanString* string, const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operand, void* userData) { - if (operand->mem.disp.hasDisplacement && ( + if (operand->mem.disp.has_displacement && ( (operand->mem.base == ZYDIS_REGISTER_EIP) || (operand->mem.base == ZYDIS_REGISTER_RIP)) && (operand->mem.index == ZYDIS_REGISTER_NONE) && (operand->mem.scale == 0)) @@ -92,21 +95,21 @@ void GenerateJmp(char* pWriteTo, void* pTarget) /* Get the length of instructions to be gengerated by GenerateJmp() */ -int GetJmpLen(void* pWriteTo, void* pTarget) +int GetJmpLenLarge() { - if (AddressDiff((char*)pWriteTo + 6, pTarget) < ((1ULL << 31) - 1)) - { - return 5; - } return 14; } /* Get the length of instructions to be gengerated by GenerateJmp() */ -int GetJmpLenLarge() +int GetJmpLen(void* pWriteTo, void* pTarget) { - return 14; + if (AddressDiff((char*)pWriteTo + 6, pTarget) < ((1ULL << 31) - 1)) + { + return 5; + } + return GetJmpLenLarge(); } /*///////////////////////////////////////////////////// @@ -195,37 +198,11 @@ static char* AllocFunc(size_t sz, void* addr) End Allocator definitions *////////////////////////////////////////////////////// -enum PatchType -{ - FHPatchLoad32, - FHPatchJump8, -}; -struct PatchInfo -{ - PatchType type; - int patch_addr_offset; //the offset of the address of the target to patch -}; -#define MAX_PATCH_POINTS 10 - - -inline bool InsertPatchPoint(PatchInfo* pool, int& num_patch_points, PatchType type, int offset) -{ - //alloacte a patch point info - if (num_patch_points >= MAX_PATCH_POINTS) - return true; - PatchInfo* pinfo = pool + num_patch_points; - num_patch_points++; - - pinfo->type = type;// FHPatchLoad32; - pinfo->patch_addr_offset = offset;//(readPointer + len) - (uint8_t*)oldfunc; - return false; -} - #define FHASSERT(cond,pinst) do{\ if(!(cond)){\ fprintf(stderr, "PFishHook is unable to patch this instructions with RIP: %lx\n",\ *(uint64_t*)pinst);\ - return FHUnrecognizedRIP;\ + return FHPatchFailed;\ }\ }while (0); @@ -245,193 +222,147 @@ the "jump space" with "poutold". If success, return "FHSuccess" */ HookStatus HookItSafe(void* oldfunc, void** poutold, void* newfunc, int need_checking,void* suggested_address) { - int num_patch_points = 0; - static PatchInfo PatchInfoPool[MAX_PATCH_POINTS]; - - if (PageSize2 == 0) +/* + newfunc + ^ + | jmp + | + +-+------+ +------+ + oldfunc ----> | header | | body | + +--------+ +------+ + | | ^ + | | | + | | | ++-----+------------+-----+------------+--------+ | +| len | new header | jmp | backup len | backup | | ++--1--+------------+-14--+-----1------+--------+ | + ^ | | + | +---------------------------+ + | + poutold + */ + if (oldfunc == nullptr) { + return FHDecodeFailed; + } + if (PageSize == 0) { - PageSize2 = sysconf(_SC_PAGESIZE); + PageSize = sysconf(_SC_PAGESIZE); ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL); ptrParseOperandMem = ParseOperandMem; - ZydisFormatterSetHook(&formatter, ZYDIS_FORMATTER_HOOK_FORMAT_OPERAND_MEM, (const void**)&ptrParseOperandMem); + ZydisFormatterSetHook(&formatter, ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_MEM, + (const void**)&ptrParseOperandMem); } ZydisDecoder decoder; ZydisDecoderInit( &decoder, ZYDIS_MACHINE_MODE_LONG_64, - ZYDIS_ADDRESS_WIDTH_64); + ZYDIS_STACK_WIDTH_64); uint64_t instructionPointer = (uint64_t)oldfunc; uint8_t* readPointer = (uint8_t*)oldfunc; - size_t length = 0; + char length = 0; - int patch_jump_bed_size = 0; //we first check the head of oldfunc. We use the disassembler to //find the length of each instruction until there is enough space //to hold our "jmp" instructions + //FIXME:now, we dont have effective methods to get the length of oldfunc. + //from symbol-table?from debug info? hasRIP = false; ZydisDecodedInstruction instruction; const int jmplen=GetJmpLen(oldfunc,newfunc); - uint8_t* QWORDPointer=nullptr; - while (ZYDIS_SUCCESS(ZydisDecoderDecodeBuffer( - &decoder, readPointer, 128, instructionPointer, &instruction))) + ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]; + memset(operands, 0, sizeof(operands)); + char* outfunc = AllocFunc(128, nullptr); + if (!outfunc) + return FHAllocFailed; + char* changeHeader = outfunc + 1; + while (ZYAN_SUCCESS(ZydisDecoderDecodeFull( + &decoder, readPointer, 128, &instruction, operands))) { - bool patched = false; if (instruction.attributes & ZYDIS_ATTRIB_IS_RELATIVE) { - FHASSERT(instruction.operandCount >= 1, instruction.instrAddress); - for (int i = 0; i < instruction.operandCount; i++) //for all operands, check if it is RIP-relative + bool farJump = false; + ZydisEncoderRequest req; + memset(&req, 0, sizeof(req)); + if(!ZYAN_SUCCESS(ZydisEncoderDecodedInstructionToEncoderRequest(&instruction, operands, + instruction.operand_count_visible, &req))) { - auto operand = &instruction.operands[i]; - if (operand->type == ZYDIS_OPERAND_TYPE_MEMORY && operand->mem.disp.hasDisplacement) + return FHEncodeFailed; + } + FHASSERT(instruction.operand_count_visible >= 1, instructionPointer); + for (int i = 0; i < instruction.operand_count_visible; i++) //for all operands, check if it is RIP-relative + { + auto operand = &operands[i]; + if (operand->type == ZYDIS_OPERAND_TYPE_MEMORY && operand->mem.disp.has_displacement) { - FHASSERT(operand->mem.base != ZYDIS_REGISTER_EIP, instruction.instrAddress); + FHASSERT(operand->mem.base != ZYDIS_REGISTER_EIP, instructionPointer); if (operand->mem.base == ZYDIS_REGISTER_RIP) { - FHASSERT(instruction.raw.disp.size == 32, instruction.instrAddress); - patched = true; + req.operands[i].mem.displacement = operand->mem.disp.value - (uint64_t)changeHeader + instructionPointer; + FHASSERT(instruction.raw.disp.size == 32, instructionPointer); /* NOTE: We might meet jmp QWORD PTR [rip].While this instr reads mem at rip+6 (we will modify this address), we should copy QWORD rip+6 to shadow function */ auto pOffset=(int32_t*)(readPointer + instruction.raw.disp.offset); auto word_offset=(readPointer + *pOffset) - (uint8_t*)oldfunc+instruction.length; - //printf("off %d\n",*pOffset); //jmpq QWORD ptr [rip+0] (6) QWORD (8) if(word_offset=ZYDIS_MNEMONIC_JB && instruction.mnemonic<=ZYDIS_MNEMONIC_JZ){ //Uhh We should copy this word to shadow function //In most cases,This only happen when a function is hooked - FHASSERT(QWORDPointer==nullptr,instruction.instrAddress); - QWORDPointer=readPointer+(*pOffset)+instruction.length; - }else{ - if (InsertPatchPoint(PatchInfoPool, num_patch_points, FHPatchLoad32, (readPointer + instruction.raw.disp.offset) - (uint8_t*)oldfunc)) - return FHTooManyPatches; + farJump = true; } } } else if (operand->type == ZYDIS_OPERAND_TYPE_IMMEDIATE) { - if (operand->imm.isSigned && operand->imm.isRelative) + if (operand->imm.is_signed && operand->imm.is_relative) { - if (instruction.raw.imm[0].size == 8) - { - patched = true; - if (InsertPatchPoint(PatchInfoPool, num_patch_points, FHPatchJump8, - (readPointer + instruction.raw.imm[0].offset) - (uint8_t*)oldfunc)) - return FHTooManyPatches; - //if there is a jmp instruction, we need one more "jmp" in - //our jump space to patch it, so add alloc_size with GetJmpLen() - patch_jump_bed_size += GetJmpLenLarge(); - } - else if (instruction.raw.imm[0].size == 32) - { - patched = true; - if (InsertPatchPoint(PatchInfoPool, num_patch_points, FHPatchLoad32, - (readPointer + instruction.raw.imm[0].offset) - (uint8_t*)oldfunc)) - return FHTooManyPatches; - } - else - { - FHASSERT(0, instruction.instrAddress); + // the jmp range in the oldfunc usually small. when we copy instruction to jump chunk, we need a far jmp + // if the jump range is larger than 32-bit, encode func will return FHEncodeFailed + if (req.mnemonic != ZYDIS_MNEMONIC_CALL) {// jmp rel32 + req.branch_width = ZYDIS_BRANCH_WIDTH_32; + req.branch_type = ZYDIS_BRANCH_TYPE_NEAR; } + req.operands[i].imm.s = operand->imm.value.s - (uint64_t)changeHeader + instructionPointer; } } - } - FHASSERT(patched, instruction.instrAddress); - } - if(readPointer+instruction.length==QWORDPointer){ - instruction.length+=8; - //skip the QWORD + } + ZyanU8 encoded_instruction[ZYDIS_MAX_INSTRUCTION_LENGTH]; + ZyanUSize encoded_length = sizeof(encoded_instruction); + memset(encoded_instruction, 0, sizeof(encoded_instruction)); + if(!ZYAN_SUCCESS(ZydisEncoderEncodeInstruction(&req, encoded_instruction, &encoded_length))) + { + return FHEncodeFailed; + } + memcpy(changeHeader, encoded_instruction, encoded_length); + changeHeader += encoded_length; + if(farJump) + { + memcpy(changeHeader, changeHeader, 8); + changeHeader += 8; + instruction.length+=8; + } + } else { + memcpy(changeHeader, readPointer, instruction.length); + changeHeader += instruction.length; } readPointer += instruction.length; + instructionPointer += instruction.length; length += instruction.length; if (length >= jmplen) break; - instructionPointer += instruction.length; } - if (length < jmplen) - return FHDecodeFailed; - - //now "length" is the length of instructions in oldfunc to be replaced - /* - The jump space is composed of - - oldfunc's replaced function head (with length "length") - - the "jmp" instruction jumping to the body of oldfunc - Also, we need to remember the alloc_size - */ - size_t alloc_size = length + GetJmpLenLarge() + sizeof(size_t) + patch_jump_bed_size; - - char* outfunc = AllocFunc(alloc_size, suggested_address); - if (!outfunc) - return FHAllocFailed; - - //record the length of replaced instructions - *(size_t*)outfunc = length; - outfunc += sizeof(size_t); - //copy oldfunc's first several instructions to the jump space - memcpy(outfunc, oldfunc, length); + *poutold = (void*)(outfunc + 1); + //now, we need to update the length of changed header + *outfunc = changeHeader - (char*)*poutold; //generate a "jmp" back to oldfunc's body - GenerateJmpLarge(outfunc + length,(char*)oldfunc+length); - - //now get each PatchInfo and do patching in the copied function head - int jump_bed_num = 0; - for (int i = 0; i < num_patch_points; i++) - { - switch (PatchInfoPool[i].type) - { - case FHPatchLoad32: - //if there is a 32-bit relative instr - int32_t offset; offset = *(int32_t*)((unsigned char*)oldfunc + PatchInfoPool[i].patch_addr_offset); - //calculate the new relative offset - int64_t delta; delta = (int64_t)offset - ((char*)outfunc - (char*)oldfunc); - if (delta > INT_MAX || delta < INT_MIN) - { - //if the relative offset is too large to be held in 32 bits - //we retry with a suggested address. If there is already a - //suggested address, return failure. - if(suggested_address) - return FHPatchFailed; - return HookItSafe(oldfunc, poutold, newfunc, need_checking, oldfunc); - } - //the patch point in copied function - int32_t* patch_point;patch_point = (int32_t*)(outfunc + PatchInfoPool[i].patch_addr_offset); - *patch_point = delta; - break; - case FHPatchJump8: - //if there is a jne "near" relative instr, the offset is too small to - //jump from jump space to oldfun's body. So we first "jne near" to a place - //in jump space, and then use our "far jmp" to jump to the target - unsigned char* patch_addr_jne; // the address of the instruction in old function - patch_addr_jne = (unsigned char* )oldfunc + PatchInfoPool[i].patch_addr_offset - 1; - //the address of the instruction in new function - char* patch_instruction; patch_instruction = (char*)(outfunc + PatchInfoPool[i].patch_addr_offset - 1); - uintptr_t target; target = (uintptr_t)patch_addr_jne + 2 + patch_addr_jne[1]; - - //check if the jump target is within the copied part of the function. If so, no need to patch - int jump_target_offset; jump_target_offset = (char*)target - (char*)oldfunc; - if (jump_target_offset >= 0 && jump_target_offset < length) - continue; - /*where should we jump to now? - remember the layout of the jump space: - [copied function head] ---- length= "length" - [a "jmp" instruction to original function] ---- length= "GetJmpLen()" - [several "jmp" instructions to handle near jmp(s)] - */ - int delta8; - delta8 = outfunc + length + GetJmpLenLarge() + jump_bed_num * GetJmpLenLarge() - (patch_instruction + 2); - if (delta8 > 127 || delta8 < -128) - { - return FHPatchFailed; - } - patch_instruction[1] = delta8; - - char* jmp_bed = outfunc + length + GetJmpLenLarge()+ jump_bed_num * GetJmpLenLarge(); - GenerateJmpLarge(jmp_bed, (void*)target); - jump_bed_num++; - } - } + GenerateJmpLarge(outfunc + length + 1,(char*)oldfunc+length); + changeHeader += GetJmpLenLarge(); + // backup old header for restoring old function in the future + *changeHeader = length; + memcpy(changeHeader + 1, oldfunc, length); - *poutold = (void*)outfunc; //Let the pages of oldfunc writable if(RangeProtect(oldfunc,length,1)!=FHSuccess) return FHMprotectFail; //replace the head of oldfunc with newfunc @@ -446,12 +377,15 @@ HookStatus HookIt(void* oldfunc, void** poutold, void* newfunc) { return HookItSafe(oldfunc, poutold, newfunc, 1,nullptr); } -HookStatus UnHook(void* oldfunc, void* func) +HookStatus UnHook(void* oldfunc, void* poutold) { - //todo : reset patch - size_t length = *((size_t*)func - 1); + //see HookItSafe for jump func memory layout + char* outfunc = (char*)poutold; + int8_t length = *(outfunc - 1); + outfunc += length + GetJmpLenLarge(); + length = *outfunc; if(RangeProtect(oldfunc,length,1)!=FHSuccess) return FHMprotectFail; - memcpy(oldfunc,func,length); + memcpy(oldfunc,outfunc + 1,length); if(RangeProtect(oldfunc,length,0)!=FHSuccess) return FHMprotectFail; return FHSuccess; }