From 14a71b5546881696ab75d604f7ff8e5d8a93bc83 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 24 Sep 2015 04:33:02 -0700 Subject: [PATCH 1/3] update java bindings for new memory event hooking constants --- bindings/java/samples/Sample_x86.java | 22 ++-- .../{ReadWriteHook.java => EventMemHook.java} | 4 +- bindings/java/unicorn/MemoryInvalidHook.java | 29 ----- bindings/java/unicorn/Unicorn.java | 103 ++++++++---------- bindings/java/unicorn/UnicornConst.java | 38 ++++--- bindings/java/unicorn_Unicorn.c | 25 ++--- 6 files changed, 89 insertions(+), 132 deletions(-) rename bindings/java/unicorn/{ReadWriteHook.java => EventMemHook.java} (84%) delete mode 100644 bindings/java/unicorn/MemoryInvalidHook.java diff --git a/bindings/java/samples/Sample_x86.java b/bindings/java/samples/Sample_x86.java index 24985713..edda0e97 100644 --- a/bindings/java/samples/Sample_x86.java +++ b/bindings/java/samples/Sample_x86.java @@ -83,18 +83,14 @@ public class Sample_x86 { } } - private static class MyMemInvalidHook implements MemoryInvalidHook { - public boolean hook(Unicorn u, int type, long address, int size, long value, Object user) { - switch(type) { - case Unicorn.UC_MEM_WRITE: - System.out.printf(">>> Missing memory is being WRITE at 0x%x, data size = %d, data value = 0x%x\n", - address, size, value); - // map this memory in with 2MB in size - u.mem_map(0xaaaa0000, 2 * 1024*1024, Unicorn.UC_PROT_ALL); - // return true to indicate we want to continue - return true; - } - return false; + private static class MyWriteInvalidHook implements EventMemHook { + public boolean hook(Unicorn u, long address, int size, long value, Object user) { + System.out.printf(">>> Missing memory is being WRITE at 0x%x, data size = %d, data value = 0x%x\n", + address, size, value); + // map this memory in with 2MB in size + u.mem_map(0xaaaa0000, 2 * 1024*1024, Unicorn.UC_PROT_ALL); + // return true to indicate we want to continue + return true; } } @@ -423,7 +419,7 @@ public class Sample_x86 { u.hook_add(new MyCodeHook(), 1, 0, null); // intercept invalid memory events - u.hook_add(new MyMemInvalidHook(), null); + u.hook_add(new MyWriteInvalidHook(), Unicorn.UC_HOOK_MEM_WRITE_INVALID, null); // emulate machine code in infinite time try { diff --git a/bindings/java/unicorn/ReadWriteHook.java b/bindings/java/unicorn/EventMemHook.java similarity index 84% rename from bindings/java/unicorn/ReadWriteHook.java rename to bindings/java/unicorn/EventMemHook.java index 4514b483..db1f12d9 100644 --- a/bindings/java/unicorn/ReadWriteHook.java +++ b/bindings/java/unicorn/EventMemHook.java @@ -21,9 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. package unicorn; -public interface ReadWriteHook extends Hook { +public interface EventMemHook extends Hook { - public void hook(Unicorn u, int type, long address, int size, long value, Object user); + public boolean hook(Unicorn u, long address, int size, long value, Object user); } diff --git a/bindings/java/unicorn/MemoryInvalidHook.java b/bindings/java/unicorn/MemoryInvalidHook.java deleted file mode 100644 index 8b0a02d5..00000000 --- a/bindings/java/unicorn/MemoryInvalidHook.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - -Java bindings for the Unicorn Emulator Engine - -Copyright(c) 2015 Chris Eagle - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -version 2 as published by the Free Software Foundation. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -*/ - -package unicorn; - -public interface MemoryInvalidHook extends Hook { - - public boolean hook(Unicorn u, int type, long address, int size, long value, Object user); - -} - diff --git a/bindings/java/unicorn/Unicorn.java b/bindings/java/unicorn/Unicorn.java index 40476ae0..c9ed1436 100644 --- a/bindings/java/unicorn/Unicorn.java +++ b/bindings/java/unicorn/Unicorn.java @@ -31,10 +31,15 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S private long interruptHandle = 0; private long codeHandle = 0; - private long memInvalidHandle = 0; + private Hashtable eventMemHandles = new Hashtable(); + private long readInvalidHandle = 0; + private long writeInvalidHandle = 0; + private long fetchProtHandle = 0; + private long readProtHandle = 0; + private long writeProtHandle = 0; + private long readHandle = 0; private long writeHandle = 0; - private long readWriteHandle = 0; private long inHandle = 0; private long outHandle = 0; private long syscallHandle = 0; @@ -51,21 +56,28 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S private ArrayList blockList = new ArrayList(); private ArrayList intrList = new ArrayList(); private ArrayList codeList = new ArrayList(); - private ArrayList memInvalidList = new ArrayList(); private ArrayList readList = new ArrayList(); private ArrayList writeList = new ArrayList(); - private ArrayList readWriteList = new ArrayList(); private ArrayList inList = new ArrayList(); private ArrayList outList = new ArrayList(); private ArrayList syscallList = new ArrayList(); + private Hashtable > eventMemLists = new Hashtable >(); + private ArrayList> allLists = new ArrayList>(); + private static Hashtable eventMemMap = new Hashtable(); private static Hashtable unicorns = new Hashtable(); //required to load native method implementations static { System.loadLibrary("unicorn_java"); //loads unicorn.dll or libunicorn.so + eventMemMap.put(UC_HOOK_MEM_READ_INVALID, UC_MEM_READ_INVALID); + eventMemMap.put(UC_HOOK_MEM_WRITE_INVALID, UC_MEM_WRITE_INVALID); + eventMemMap.put(UC_HOOK_MEM_FETCH_INVALID, UC_MEM_FETCH_INVALID); + eventMemMap.put(UC_HOOK_MEM_READ_PROT, UC_MEM_READ_PROT); + eventMemMap.put(UC_HOOK_MEM_WRITE_PROT, UC_MEM_WRITE_PROT); + eventMemMap.put(UC_HOOK_MEM_FETCH_PROT, UC_MEM_FETCH_PROT); } /** @@ -128,25 +140,29 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S } /** - * Invoke all UC_HOOK_MEM_INVALID callbacks registered for a specific Unicorn. + * Invoke all UC_HOOK_MEM_XXX_INVALID andor UC_HOOK_MEM_XXX_PROT callbacks registered + * for a specific Unicorn. * This function gets invoked from the native C callback registered for - * for UC_HOOK_MEM_INVALID + * for UC_HOOK_MEM_XXX_INVALID or UC_HOOK_MEM_XXX_PROT * * @param eng A Unicorn uc_engine* eng returned by uc_open - * @param type This memory is being read (UC_MEM_READ), or written (UC_MEM_WRITE) + * @param type The type of event that is taking place * @param address Address of instruction being executed * @param size Size of data being read or written * @param value Value of data being written to memory, or irrelevant if type = READ. * @return true to continue, or false to stop program (due to invalid memory). - * @see hook_add, unicorn.MemoryInvalidHook + * @see hook_add, unicorn.EventMemHook */ - private static boolean invokeMemInvalidCallbacks(long eng, int type, long address, int size, long value) { + private static boolean invokeEventMemCallbacks(long eng, int type, long address, int size, long value) { Unicorn u = unicorns.get(eng); boolean result = true; if (u != null) { - for (Tuple p : u.memInvalidList) { - MemoryInvalidHook mh = (MemoryInvalidHook)p.function; - result &= mh.hook(u, type, address, size, value, p.data); + ArrayList funcList = u.eventMemLists.get(type); + if (funcList != null) { + for (Tuple p : funcList) { + EventMemHook emh = (EventMemHook)p.function; + result &= emh.hook(u, address, size, value, p.data); + } } } return result; @@ -193,28 +209,6 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S } } -/** - * Invoke all UC_HOOK_MEM_READ_WRITE callbacks registered for a specific Unicorn. - * This function gets invoked from the native C callback registered for - * for UC_HOOK_MEM_READ_WRITE - * - * @param eng A Unicorn uc_engine* eng returned by uc_open - * @param type Type of access being performed (UC_MEM_READ, UC_MEM_WRITE, UC_MEM_READ_WRITE) - * @param address Address of instruction being executed - * @param size Size of data being read - * @param value value being written (if applicable) - * @see hook_add, unicorn.ReadWriteHook - */ - private static void invokeReadWriteCallbacks(long eng, int type, long address, int size, long value) { - Unicorn u = unicorns.get(eng); - if (u != null) { - for (Tuple p : u.readWriteList) { - ReadWriteHook rwh = (ReadWriteHook)p.function; - rwh.hook(u, type, address, size, value, p.data); - } - } - } - /** * Invoke all UC_HOOK_INSN callbacks registered for a specific Unicorn. * This is specifically for the x86 IN instruction. @@ -303,10 +297,8 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S allLists.add(blockList); allLists.add(intrList); allLists.add(codeList); - allLists.add(memInvalidList); allLists.add(readList); allLists.add(writeList); - allLists.add(readWriteList); allLists.add(inList); allLists.add(outList); allLists.add(syscallList); @@ -528,34 +520,27 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S } /** - * Hook registration for UC_HOOK_MEM_READ_WRITE hooks. The registered callback function will be - * invoked whenever a memory read or write is performed within the address range begin <= mem_addr <= end. For - * the special case in which begin > end, the callback will be invoked for ALL memory reads and writes. + * Hook registration for UC_HOOK_MEM_XXX_INVALID and UC_HOOK_MEM_XXX_PROT hooks. + * The registered callback function will be invoked whenever a read or write is + * attempted from an invalid or protected memory address. * - * @param callback Implementation of a ReadWriteHook interface - * @param begin Start address of memory read/write range - * @param end End address of memory read/write range + * @param callback Implementation of a EventMemHook interface + * @param type Type of memory event being hooked such as UC_HOOK_MEM_READ_INVALID or UC_HOOK_MEM_WRITE_PROT * @param user_data User data to be passed to the callback function each time the event is triggered */ - public void hook_add(ReadWriteHook callback, long begin, long end, Object user_data) throws UnicornException { - if (readWriteHandle == 0) { - readWriteHandle = registerHook(eng, UC_HOOK_MEM_READ_WRITE, begin, end); + public void hook_add(EventMemHook callback, int type, Object user_data) throws UnicornException { + Long handle = eventMemHandles.get(type); + if (handle == null) { + eventMemHandles.put(type, registerHook(eng, type)); } - readWriteList.add(new Tuple(callback, user_data)); - } - -/** - * Hook registration for UC_HOOK_MEM_INVALID hooks. The registered callback function will be - * invoked whenever a read or write is attempted from an unmapped memory address. - * - * @param callback Implementation of a MemoryInvalidHook interface - * @param user_data User data to be passed to the callback function each time the event is triggered - */ - public void hook_add(MemoryInvalidHook callback, Object user_data) throws UnicornException { - if (memInvalidHandle == 0) { - memInvalidHandle = registerHook(eng, UC_HOOK_MEM_INVALID); + int cbType = eventMemMap.get(type); + ArrayList flist = eventMemLists.get(cbType); + if (flist == null) { + flist = new ArrayList(); + allLists.add(flist); + eventMemLists.put(cbType, flist); } - memInvalidList.add(new Tuple(callback, user_data)); + flist.add(new Tuple(callback, user_data)); } /** diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index ba85074b..615a6906 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -50,23 +50,33 @@ public interface UnicornConst { public static final int UC_ERR_MAP = 12; public static final int UC_ERR_WRITE_PROT = 13; public static final int UC_ERR_READ_PROT = 14; - public static final int UC_ERR_EXEC_PROT = 15; + public static final int UC_ERR_FETCH_PROT = 15; public static final int UC_ERR_ARG = 16; + public static final int UC_ERR_READ_UNALIGNED = 17; + public static final int UC_ERR_WRITE_UNALIGNED = 18; + public static final int UC_ERR_FETCH_UNALIGNED = 19; public static final int UC_MEM_READ = 16; public static final int UC_MEM_WRITE = 17; - public static final int UC_MEM_READ_WRITE = 18; - public static final int UC_MEM_FETCH = 19; - public static final int UC_MEM_WRITE_PROT = 20; - public static final int UC_MEM_READ_PROT = 21; - public static final int UC_MEM_EXEC_PROT = 22; - public static final int UC_HOOK_INTR = 32; - public static final int UC_HOOK_INSN = 33; - public static final int UC_HOOK_CODE = 34; - public static final int UC_HOOK_BLOCK = 35; - public static final int UC_HOOK_MEM_INVALID = 36; - public static final int UC_HOOK_MEM_READ = 37; - public static final int UC_HOOK_MEM_WRITE = 38; - public static final int UC_HOOK_MEM_READ_WRITE = 39; + public static final int UC_MEM_FETCH = 18; + public static final int UC_MEM_READ_INVALID = 19; + public static final int UC_MEM_WRITE_INVALID = 20; + public static final int UC_MEM_FETCH_INVALID = 21; + public static final int UC_MEM_WRITE_PROT = 22; + public static final int UC_MEM_READ_PROT = 23; + public static final int UC_MEM_FETCH_PROT = 24; + public static final int UC_HOOK_INTR = 1; + public static final int UC_HOOK_INSN = 2; + public static final int UC_HOOK_CODE = 4; + public static final int UC_HOOK_BLOCK = 8; + public static final int UC_HOOK_MEM_READ_INVALID = 16; + public static final int UC_HOOK_MEM_WRITE_INVALID = 32; + public static final int UC_HOOK_MEM_FETCH_INVALID = 64; + public static final int UC_HOOK_MEM_READ_PROT = 128; + public static final int UC_HOOK_MEM_WRITE_PROT = 256; + public static final int UC_HOOK_MEM_FETCH_PROT = 512; + public static final int UC_HOOK_MEM_READ = 1024; + public static final int UC_HOOK_MEM_WRITE = 2048; + public static final int UC_HOOK_MEM_FETCH = 4096; public static final int UC_PROT_NONE = 0; public static final int UC_PROT_READ = 1; diff --git a/bindings/java/unicorn_Unicorn.c b/bindings/java/unicorn_Unicorn.c index 6a454a5a..470c6340 100644 --- a/bindings/java/unicorn_Unicorn.c +++ b/bindings/java/unicorn_Unicorn.c @@ -33,10 +33,9 @@ static jmethodID invokeBlockCallbacks = 0; static jmethodID invokeInterruptCallbacks = 0; static jmethodID invokeCodeCallbacks = 0; -static jmethodID invokeMemInvalidCallbacks = 0; +static jmethodID invokeEventMemCallbacks = 0; static jmethodID invokeReadCallbacks = 0; static jmethodID invokeWriteCallbacks = 0; -static jmethodID invokeReadWriteCallbacks = 0; static jmethodID invokeInCallbacks = 0; static jmethodID invokeOutCallbacks = 0; static jmethodID invokeSyscallCallbacks = 0; @@ -157,9 +156,6 @@ static void cb_hookmem(uc_engine *eng, uc_mem_type type, case UC_MEM_WRITE: (*env)->CallStaticVoidMethod(env, clz, invokeWriteCallbacks, (jlong)eng, (jlong)address, (int)size, (jlong)value); break; - case UC_MEM_READ_WRITE: - (*env)->CallStaticVoidMethod(env, clz, invokeReadWriteCallbacks, (jlong)eng, (int)type, (jlong)address, (int)size, (jlong)value); - break; } (*cachedJVM)->DetachCurrentThread(cachedJVM); } @@ -179,7 +175,7 @@ static bool cb_eventmem(uc_engine *eng, uc_mem_type type, if ((*env)->ExceptionCheck(env)) { return false; } - jboolean res = (*env)->CallStaticBooleanMethod(env, clz, invokeMemInvalidCallbacks, (jlong)eng, (int)type, (jlong)address, (int)size, (jlong)value); + jboolean res = (*env)->CallStaticBooleanMethod(env, clz, invokeEventMemCallbacks, (jlong)eng, (int)type, (jlong)address, (int)size, (jlong)value); (*cachedJVM)->DetachCurrentThread(cachedJVM); return res; } @@ -393,9 +389,14 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JI } err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookintr, env); break; - case UC_HOOK_MEM_INVALID: // Hook for all invalid memory access events - if (invokeMemInvalidCallbacks == 0) { - invokeMemInvalidCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeMemInvalidCallbacks", "(JIJIJ)Z"); + case UC_HOOK_MEM_FETCH_INVALID: // Hook for all invalid memory access events + case UC_HOOK_MEM_READ_INVALID: // Hook for all invalid memory access events + case UC_HOOK_MEM_WRITE_INVALID: // Hook for all invalid memory access events + case UC_HOOK_MEM_FETCH_PROT: // Hook for all invalid memory access events + case UC_HOOK_MEM_READ_PROT: // Hook for all invalid memory access events + case UC_HOOK_MEM_WRITE_PROT: // Hook for all invalid memory access events + if (invokeEventMemCallbacks == 0) { + invokeEventMemCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeEventMemCallbacks", "(JIJIJ)Z"); } err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_eventmem, env); break; @@ -471,12 +472,6 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JIJJ } err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, arg1, arg2); break; - case UC_HOOK_MEM_READ_WRITE: // Hook all memory accesses (either READ or WRITE). - if (invokeReadWriteCallbacks == 0) { - invokeReadWriteCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeReadWriteCallbacks", "(JIJIJ)V"); - } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, arg1, arg2); - break; } return (jlong)hh; } From 4297ba431019a9cc73b8bcf2161817b93062a0dc Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 24 Sep 2015 09:41:49 -0700 Subject: [PATCH 2/3] additional update to handle new hooking macros --- bindings/java/unicorn/MemHook.java | 27 +++++++++++++++++++ bindings/java/unicorn/Unicorn.java | 42 ++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 11 deletions(-) create mode 100755 bindings/java/unicorn/MemHook.java mode change 100644 => 100755 bindings/java/unicorn/Unicorn.java diff --git a/bindings/java/unicorn/MemHook.java b/bindings/java/unicorn/MemHook.java new file mode 100755 index 00000000..9f1a1889 --- /dev/null +++ b/bindings/java/unicorn/MemHook.java @@ -0,0 +1,27 @@ +/* + +Java bindings for the Unicorn Emulator Engine + +Copyright(c) 2015 Chris Eagle + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +package unicorn; + +public interface MemHook extends ReadHook,WriteHook { + +} + diff --git a/bindings/java/unicorn/Unicorn.java b/bindings/java/unicorn/Unicorn.java old mode 100644 new mode 100755 index c9ed1436..9abfeb60 --- a/bindings/java/unicorn/Unicorn.java +++ b/bindings/java/unicorn/Unicorn.java @@ -519,6 +519,21 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S writeList.add(new Tuple(callback, user_data)); } +/** + * Hook registration for UC_HOOK_MEM_WRITE | UC_HOOK_MEM_WRITE hooks. The registered callback function will be + * invoked whenever a memory write or read is performed within the address range begin <= addr <= end. For + * the special case in which begin > end, the callback will be invoked for ALL memory writes. + * + * @param callback Implementation of a MemHook interface + * @param begin Start address of memory range + * @param end End address of memory range + * @param user_data User data to be passed to the callback function each time the event is triggered + */ + public void hook_add(MemHook callback, long begin, long end, Object user_data) throws UnicornException { + hook_add((ReadHook)callback, begin, end, user_data); + hook_add((WriteHook)callback, begin, end, user_data); + } + /** * Hook registration for UC_HOOK_MEM_XXX_INVALID and UC_HOOK_MEM_XXX_PROT hooks. * The registered callback function will be invoked whenever a read or write is @@ -529,18 +544,23 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S * @param user_data User data to be passed to the callback function each time the event is triggered */ public void hook_add(EventMemHook callback, int type, Object user_data) throws UnicornException { - Long handle = eventMemHandles.get(type); - if (handle == null) { - eventMemHandles.put(type, registerHook(eng, type)); + //test all of the EventMem related bits in type + for (Integer htype : eventMemMap.keySet()) { + if ((type & htype) != 0) { //the 'htype' bit is set in type + Long handle = eventMemHandles.get(htype); + if (handle == null) { + eventMemHandles.put(htype, registerHook(eng, htype)); + } + int cbType = eventMemMap.get(htype); + ArrayList flist = eventMemLists.get(cbType); + if (flist == null) { + flist = new ArrayList(); + allLists.add(flist); + eventMemLists.put(cbType, flist); + } + flist.add(new Tuple(callback, user_data)); + } } - int cbType = eventMemMap.get(type); - ArrayList flist = eventMemLists.get(cbType); - if (flist == null) { - flist = new ArrayList(); - allLists.add(flist); - eventMemLists.put(cbType, flist); - } - flist.add(new Tuple(callback, user_data)); } /** From 4ebc876bd1d6dfb79c1096e0930d7bd22413b96d Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 24 Sep 2015 09:47:06 -0700 Subject: [PATCH 3/3] file permissions --- bindings/java/unicorn/MemHook.java | 0 bindings/java/unicorn/Unicorn.java | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 bindings/java/unicorn/MemHook.java mode change 100755 => 100644 bindings/java/unicorn/Unicorn.java diff --git a/bindings/java/unicorn/MemHook.java b/bindings/java/unicorn/MemHook.java old mode 100755 new mode 100644 diff --git a/bindings/java/unicorn/Unicorn.java b/bindings/java/unicorn/Unicorn.java old mode 100755 new mode 100644