summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/hook.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/src/hook.c b/src/hook.c
index 09dc403..61cf614 100644
--- a/src/hook.c
+++ b/src/hook.c
@@ -43,6 +43,10 @@ static void setrwx(void) {
void *hook_inline(void *func_, void *target) {
uchar *func = func_;
+ // dumb hack: rather than correcting jmp offsets and having to painstakingly
+ // track them all, just look for the underlying thing being jmp-ed to and
+ // hook _that_.
+ while (*func == RELJMP) func += mem_loadoffset(func + 1) + 5;
if (!os_mprot(func, 5, PAGE_EXECUTE_READWRITE)) return false;
struct ud udis;
ud_init(&udis);
@@ -50,14 +54,19 @@ void *hook_inline(void *func_, void *target) {
// max insn length is 15, we overwrite 5, so max to copy is 4 + 15 = 19
ud_set_input_buffer(&udis, func, 19);
int len = 0;
- while (ud_disassemble(&udis) && len < 5) {
+ do {
+ ud_disassemble(&udis); // assume we don't run out of bytes
+ // TODO(opt): this check should probably be gone, keeping it to make dev
+ // life easier/less crashy. Really, we should just refrain from hooking
+ // things that immediately call or branch (als, immediate jump is
+ // already handled above).
if (ud_insn_mnemonic(&udis) == UD_Ijmp ||
ud_insn_mnemonic(&udis) == UD_Icall) {
- con_warn("hook_inline: jmp adjustment NYI\n");
+ con_warn("hook_inline: jmp/call adjustment NYI\n");
return 0;
}
len += ud_insn_len(&udis);
- }
+ } while (len < 5);
// for simplicity, just bump alloc the trampoline. no need to free anyway
if (nexttrampoline - trampolines > sizeof(trampolines) - len - 6) goto nospc;
uchar *trampoline = (uchar *)InterlockedExchangeAdd(
@@ -86,7 +95,7 @@ nospc: con_warn("hook_inline: out of trampoline space\n");
void unhook_inline(void *orig) {
uchar *p = (uchar *)orig;
int len = p[-1];
- uint off = mem_load32(p + len + 1);
+ int off = mem_load32(p + len + 1);
uchar *q = p + off + 5;
memcpy(q, p, 5); // XXX not atomic atm! (does any of it even need to be?)
FlushInstructionCache(GetCurrentProcess(), q, 5);