From 48870c4cc3554552061c152495d4aa0ef066ac64 Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Fri, 12 May 2023 22:43:46 -0700 Subject: [PATCH] Reintroduce hook_del(Hook), since it seems useful. This also improves backwards compatibility a bit. --- bindings/java/tests/FunctionalityTests.java | 43 ++++++++++++++ bindings/java/unicorn/Unicorn.java | 63 ++++++++++++++------- 2 files changed, 85 insertions(+), 21 deletions(-) diff --git a/bindings/java/tests/FunctionalityTests.java b/bindings/java/tests/FunctionalityTests.java index ad3d6393..2c8bd79c 100644 --- a/bindings/java/tests/FunctionalityTests.java +++ b/bindings/java/tests/FunctionalityTests.java @@ -1,15 +1,18 @@ package tests; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; import java.nio.ByteBuffer; import java.nio.ByteOrder; import org.junit.Test; +import unicorn.CodeHook; import unicorn.MemRegion; import unicorn.TlbFillHook; import unicorn.Unicorn; +import unicorn.UnicornException; import unicorn.X86_Float80; public class FunctionalityTests { @@ -181,4 +184,44 @@ public class FunctionalityTests { assertEquals(Math.sin(-1.1), reg.toDouble(), 1e-12); u.close(); } + + @Test + public void testRemoveHook() { + byte[] X86_CODE = { 0x40, 0x40, 0x40, 0x40 }; // (inc eax) x 4 + int ADDRESS = 0x10000; + final int[] hook_accum = { 0 }; + + Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32); + u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL); + u.mem_write(ADDRESS, X86_CODE); + + CodeHook hook = + (uc, address, size, user) -> hook_accum[0] += (int) user; + long h1 = u.hook_add(hook, ADDRESS, ADDRESS, 1); + long h2 = u.hook_add(hook, ADDRESS + 1, ADDRESS + 1, 2); + long h3 = u.hook_add(hook, ADDRESS + 2, ADDRESS + 2, 4); + long h4 = u.hook_add(hook, ADDRESS + 3, ADDRESS + 3, 8); + + hook_accum[0] = 0; + u.emu_start(ADDRESS, ADDRESS + X86_CODE.length, 0, 0); + assertEquals(15, hook_accum[0]); + + u.hook_del(h2); + + hook_accum[0] = 0; + u.emu_start(ADDRESS, ADDRESS + X86_CODE.length, 0, 0); + assertEquals(13, hook_accum[0]); + + u.hook_del(hook); + + hook_accum[0] = 0; + u.emu_start(ADDRESS, ADDRESS + X86_CODE.length, 0, 0); + assertEquals(0, hook_accum[0]); + + assertThrows(UnicornException.class, () -> u.hook_del(h1)); + assertThrows(UnicornException.class, () -> u.hook_del(h3)); + assertThrows(UnicornException.class, () -> u.hook_del(h4)); + + u.close(); + } } diff --git a/bindings/java/unicorn/Unicorn.java b/bindings/java/unicorn/Unicorn.java index bc19b57e..7b7fe321 100644 --- a/bindings/java/unicorn/Unicorn.java +++ b/bindings/java/unicorn/Unicorn.java @@ -52,7 +52,8 @@ public class Unicorn /** Wrapper around a registered hook */ private static class HookWrapper { - private long nativePtr; + Hook hook; + long nativePtr; @Override protected void finalize() { @@ -685,8 +686,9 @@ public class Unicorn _ctl_tlb_mode(nativePtr, mode); } - private long registerHook(long val) { + private long registerHook(Hook hook, long val) { HookWrapper wrapper = new HookWrapper(); + wrapper.hook = hook; wrapper.nativePtr = val; long index = nextAllocCounter(); hooks.put(index, wrapper); @@ -705,7 +707,7 @@ public class Unicorn */ public long hook_add(InterruptHook callback, Object user_data) throws UnicornException { - return registerHook( + return registerHook(callback, _hook_add(nativePtr, UC_HOOK_INTR, callback, user_data, 1, 0)); } @@ -728,8 +730,8 @@ public class Unicorn long end, Object user_data) throws UnicornException { - return registerHook(_hook_add(nativePtr, UC_HOOK_INSN, callback, - user_data, begin, end, insn)); + return registerHook(callback, _hook_add(nativePtr, UC_HOOK_INSN, + callback, user_data, begin, end, insn)); } /** @@ -811,8 +813,8 @@ public class Unicorn public long hook_add(CodeHook callback, long begin, long end, Object user_data) throws UnicornException { - return registerHook(_hook_add(nativePtr, UC_HOOK_CODE, callback, - user_data, begin, end)); + return registerHook(callback, _hook_add(nativePtr, UC_HOOK_CODE, + callback, user_data, begin, end)); } /** @@ -833,8 +835,8 @@ public class Unicorn public long hook_add(BlockHook callback, long begin, long end, Object user_data) throws UnicornException { - return registerHook(_hook_add(nativePtr, UC_HOOK_BLOCK, callback, - user_data, begin, end)); + return registerHook(callback, _hook_add(nativePtr, UC_HOOK_BLOCK, + callback, user_data, begin, end)); } /** @@ -859,7 +861,7 @@ public class Unicorn public long hook_add(MemHook callback, int type, long begin, long end, Object user_data) throws UnicornException { - return registerHook( + return registerHook(callback, _hook_add(nativePtr, type, callback, user_data, begin, end)); } @@ -884,7 +886,7 @@ public class Unicorn public long hook_add(EventMemHook callback, int type, long begin, long end, Object user_data) throws UnicornException { - return registerHook( + return registerHook(callback, _hook_add(nativePtr, type, callback, user_data, begin, end)); } @@ -902,7 +904,7 @@ public class Unicorn */ public long hook_add(EventMemHook callback, int type, Object user_data) throws UnicornException { - return registerHook( + return registerHook(callback, _hook_add(nativePtr, type, callback, user_data, 1, 0)); } @@ -919,8 +921,8 @@ public class Unicorn */ public long hook_add(InvalidInstructionHook callback, Object user_data) { - return registerHook(_hook_add(nativePtr, UC_HOOK_INSN_INVALID, callback, - user_data, 1, 0)); + return registerHook(callback, _hook_add(nativePtr, UC_HOOK_INSN_INVALID, + callback, user_data, 1, 0)); } /** @@ -941,8 +943,8 @@ public class Unicorn public long hook_add(EdgeGeneratedHook callback, long begin, long end, Object user_data) throws UnicornException { - return registerHook(_hook_add(nativePtr, UC_HOOK_EDGE_GENERATED, - callback, user_data, begin, end)); + return registerHook(callback, _hook_add(nativePtr, + UC_HOOK_EDGE_GENERATED, callback, user_data, begin, end)); } /** @@ -966,8 +968,8 @@ public class Unicorn int opcode, int flags, Object user_data) throws UnicornException { - return registerHook(_hook_add(nativePtr, UC_HOOK_TCG_OPCODE, callback, - user_data, begin, end, opcode, flags)); + return registerHook(callback, _hook_add(nativePtr, UC_HOOK_TCG_OPCODE, + callback, user_data, begin, end, opcode, flags)); } /** @@ -986,8 +988,8 @@ public class Unicorn */ public long hook_add(TlbFillHook callback, long begin, long end, Object user_data) throws UnicornException { - return registerHook(_hook_add(nativePtr, UC_HOOK_TLB_FILL, callback, - user_data, begin, end)); + return registerHook(callback, _hook_add(nativePtr, UC_HOOK_TLB_FILL, + callback, user_data, begin, end)); } /** Remove a hook that was previously registered. @@ -1003,6 +1005,25 @@ public class Unicorn } } + /** Remove all registrations for a given {@link Hook} object. + * + * @param hook A {@link Hook} object to unregister. + */ + public void hook_del(Hook hook) throws UnicornException { + if (hook == null) { + // we use null for "special" hooks that can't be _hook_del'd + throw new NullPointerException("hook must not be null"); + } + Iterator> it = hooks.entrySet().iterator(); + while (it.hasNext()) { + HookWrapper wrapper = it.next().getValue(); + if (wrapper.hook == hook) { + it.remove(); + _hook_del(nativePtr, wrapper.nativePtr); + } + } + } + /** * Create a memory-mapped I/O range. * @@ -1026,7 +1047,7 @@ public class Unicorn long[] hooks = _mmio_map(nativePtr, address, size, read_cb, user_data_read, write_cb, user_data_write); for (long hook : hooks) { - registerHook(hook); + registerHook(null, hook); } }