diff options
author | Zeex <zeex@rocketmail.com> | 2018-11-22 04:22:15 +0600 |
---|---|---|
committer | Zeex <zeex@rocketmail.com> | 2018-11-22 04:22:15 +0600 |
commit | dae419521cba2213a04ee8c80ebf07b58fd725a4 (patch) | |
tree | 3088fda108fd2e77b60561a22e2397285f3ac1e2 | |
parent | e0b2b684952ad55523f37e84a82e1a9ebfd2f35d (diff) | |
download | subhook-dae419521cba2213a04ee8c80ebf07b58fd725a4.zip subhook-dae419521cba2213a04ee8c80ebf07b58fd725a4.tar.gz subhook-dae419521cba2213a04ee8c80ebf07b58fd725a4.tar.bz2 |
Add subhook_set_disasm_handler()
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | subhook.c | 7 | ||||
-rw-r--r-- | subhook.h | 30 | ||||
-rw-r--r-- | subhook_x86.c | 16 |
4 files changed, 45 insertions, 16 deletions
@@ -78,7 +78,8 @@ int main() { Please note that subhook has a very simple length disassmebler engine (LDE) that works only with most common prologue instructions like push, mov, call, etc. When it encounters an unknown instruction subhook_get_trampoline() will -return NULL. +return NULL. You can delegate instruction decoding to a custom disassembler +of your choice via `subhook_set_disasm_handler()`. ### C++ @@ -117,10 +118,9 @@ Known issues ------------ * `subhook_get_trampoline()` may return NULL because only a small subset of - x86 instructions is supported by the disassembler in this library (only + x86 instructions is supported by the disassembler in this library (just common prologue instructions). As a workaround you can plug in a more - advanced disassembler engine in `subhook_disasm()` (currently there is no - simple way to do it, you have to modify the code manually). + advanced instruction length decoder using `subhook_set_disasm_handler()`. * If a target function (the function you are hooking) is less than N bytes in length, for example if it's a short 2-byte jump to a nearby location @@ -26,6 +26,8 @@ #include "subhook.h" #include "subhook_private.h" +subhook_disasm_handler_t subhook_disasm_handler = NULL; + SUBHOOK_EXPORT void *SUBHOOK_API subhook_get_src(subhook_t hook) { if (hook == NULL) { return NULL; @@ -54,6 +56,11 @@ SUBHOOK_EXPORT int SUBHOOK_API subhook_is_installed(subhook_t hook) { return hook->installed; } +SUBHOOK_EXPORT void SUBHOOK_API subhook_set_disasm_handler( + subhook_disasm_handler_t handler) { + subhook_disasm_handler = handler; +} + #ifndef SUBHOOK_SEPARATE_SOURCE_FILES #if defined SUBHOOK_WINDOWS @@ -97,6 +97,10 @@ typedef enum subhook_flags { struct subhook_struct; typedef struct subhook_struct *subhook_t; +typedef int (SUBHOOK_API *subhook_disasm_handler_t)( + void *src, + int *reloc_op_offset); + SUBHOOK_EXPORT subhook_t SUBHOOK_API subhook_new(void *src, void *dst, subhook_flags_t flags); @@ -112,11 +116,21 @@ SUBHOOK_EXPORT int SUBHOOK_API subhook_remove(subhook_t hook); /* Reads hook destination address from code. * - * This is useful when you don't know the address or want to check - * whether src is already hooked. + * This is useful when you don't know the address or want to check whether + * src is already hooked. */ SUBHOOK_EXPORT void *SUBHOOK_API subhook_read_dst(void *src); +/* Set a custom disassmbler function to use in place of the default one + * (subhook_disasm). + * + * The default function recognized a small st of x86 instructiosn commonly + * in prologues. If it fails in your situation you might want to use a more + * advanced disassembler library. + */ +SUBHOOK_EXPORT void SUBHOOK_API subhook_set_disasm_handler( + subhook_disasm_handler_t handler); + #ifdef __cplusplus namespace subhook { @@ -136,6 +150,14 @@ inline HookFlags operator&(HookFlags o1, HookFlags o2) { static_cast<unsigned int>(o1) & static_cast<unsigned int>(o2)); } +inline void *ReadHookDst(void *src) { + return subhook_read_dst(src); +} + +inline void SetDisasmHandler(subhook_disasm_handler_t handler) { + subhook_set_disasm_handler(handler); +} + class Hook { public: Hook() : hook_(0) {} @@ -174,10 +196,6 @@ class Hook { return !!subhook_is_installed(hook_); } - static void *ReadDst(void *src) { - return subhook_read_dst(src); - } - private: Hook(const Hook &); void operator=(const Hook &); diff --git a/subhook_x86.c b/subhook_x86.c index f70ee0c..d5eae84 100644 --- a/subhook_x86.c +++ b/subhook_x86.c @@ -85,7 +85,9 @@ struct subhook_jmp64 { #pragma pack(pop) -static size_t subhook_disasm(void *src, int32_t *reloc_op_offset) { +extern subhook_disasm_handler_t subhook_disasm_handler; + +static int subhook_disasm(void *src, int *reloc_op_offset) { enum flags { MODRM = 1, PLUS_R = 1 << 1, @@ -202,8 +204,8 @@ static size_t subhook_disasm(void *src, int32_t *reloc_op_offset) { uint8_t *code = src; size_t i; - size_t len = 0; - size_t operand_size = 4; + int len = 0; + int operand_size = 4; uint8_t opcode = 0; int found_opcode = false; @@ -255,7 +257,7 @@ static size_t subhook_disasm(void *src, int32_t *reloc_op_offset) { } if (reloc_op_offset != NULL && opcodes[i].flags & RELOC) { - *reloc_op_offset = (int32_t)len; /* relative call or jump */ + *reloc_op_offset = len; /* relative call or jump */ } if (opcodes[i].flags & MODRM) { @@ -378,6 +380,8 @@ static int subhook_make_trampoline(void *trampoline, size_t insn_len; intptr_t trampoline_addr = (intptr_t)trampoline; intptr_t src_addr = (intptr_t)src; + subhook_disasm_handler_t disasm_handler = + subhook_disasm_handler != NULL ? subhook_disasm_handler : subhook_disasm; assert(trampoline_len != NULL); @@ -385,10 +389,10 @@ static int subhook_make_trampoline(void *trampoline, * to the trampoline. */ while (orig_size < jmp_size) { - int32_t reloc_op_offset = 0; + int reloc_op_offset = 0; insn_len = - subhook_disasm((void *)(src_addr + orig_size), &reloc_op_offset); + disasm_handler((void *)(src_addr + orig_size), &reloc_op_offset); if (insn_len == 0) { return -EINVAL; |