mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-02-03 23:01:05 +00:00
8adc8afc63
* Remove glib from samples makefile * support new APIs * reimplement register batch mode interface * stop using deprecated java API
826 lines
30 KiB
Java
826 lines
30 KiB
Java
/*
|
|
|
|
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;
|
|
|
|
import java.util.*;
|
|
|
|
public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, SparcConst, MipsConst, X86Const {
|
|
|
|
private long eng;
|
|
private int arch;
|
|
private int mode;
|
|
|
|
private long blockHandle = 0;
|
|
private long interruptHandle = 0;
|
|
private long codeHandle = 0;
|
|
|
|
private Hashtable<Integer, Long> eventMemHandles = new Hashtable<Integer, Long>();
|
|
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 inHandle = 0;
|
|
private long outHandle = 0;
|
|
private long syscallHandle = 0;
|
|
|
|
private class Tuple {
|
|
public Hook function;
|
|
public Object data;
|
|
public Tuple(Hook f, Object d) {
|
|
function = f;
|
|
data = d;
|
|
}
|
|
}
|
|
|
|
private ArrayList<Tuple> blockList = new ArrayList<Tuple>();
|
|
private ArrayList<Tuple> intrList = new ArrayList<Tuple>();
|
|
private ArrayList<Tuple> codeList = new ArrayList<Tuple>();
|
|
private ArrayList<Tuple> readList = new ArrayList<Tuple>();
|
|
private ArrayList<Tuple> writeList = new ArrayList<Tuple>();
|
|
private ArrayList<Tuple> inList = new ArrayList<Tuple>();
|
|
private ArrayList<Tuple> outList = new ArrayList<Tuple>();
|
|
private ArrayList<Tuple> syscallList = new ArrayList<Tuple>();
|
|
|
|
private Hashtable<Integer, ArrayList<Tuple> > eventMemLists = new Hashtable<Integer, ArrayList<Tuple> >();
|
|
|
|
private ArrayList<ArrayList<Tuple>> allLists = new ArrayList<ArrayList<Tuple>>();
|
|
|
|
private static Hashtable<Integer,Integer> eventMemMap = new Hashtable<Integer,Integer>();
|
|
private static Hashtable<Long,Unicorn> unicorns = new Hashtable<Long,Unicorn>();
|
|
|
|
//required to load native method implementations
|
|
static {
|
|
System.loadLibrary("unicorn_java"); //loads unicorn.dll or libunicorn.so
|
|
eventMemMap.put(UC_HOOK_MEM_READ_UNMAPPED, UC_MEM_READ_UNMAPPED);
|
|
eventMemMap.put(UC_HOOK_MEM_WRITE_UNMAPPED, UC_MEM_WRITE_UNMAPPED);
|
|
eventMemMap.put(UC_HOOK_MEM_FETCH_UNMAPPED, UC_MEM_FETCH_UNMAPPED);
|
|
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);
|
|
eventMemMap.put(UC_HOOK_MEM_READ, UC_MEM_READ);
|
|
eventMemMap.put(UC_HOOK_MEM_WRITE, UC_MEM_WRITE);
|
|
eventMemMap.put(UC_HOOK_MEM_FETCH, UC_MEM_FETCH);
|
|
eventMemMap.put(UC_HOOK_MEM_READ_AFTER, UC_MEM_READ_AFTER);
|
|
}
|
|
|
|
/**
|
|
* Invoke all UC_HOOK_BLOCK callbacks registered for a specific Unicorn.
|
|
* This function gets invoked from the native C callback registered for
|
|
* for UC_HOOK_BLOCK
|
|
*
|
|
* @param eng A Unicorn uc_engine* eng returned by uc_open
|
|
* @param address The address of the instruction being executed
|
|
* @param size The size of the basic block being executed
|
|
* @see hook_add, unicorn.BlockHook
|
|
*/
|
|
private static void invokeBlockCallbacks(long eng, long address, int size) {
|
|
Unicorn u = unicorns.get(eng);
|
|
if (u != null) {
|
|
for (Tuple p : u.blockList) {
|
|
BlockHook bh = (BlockHook)p.function;
|
|
bh.hook(u, address, size, p.data);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invoke all UC_HOOK_INTR callbacks registered for a specific Unicorn.
|
|
* This function gets invoked from the native C callback registered for
|
|
* for UC_HOOK_INTR
|
|
*
|
|
* @param eng A Unicorn uc_engine* eng returned by uc_open
|
|
* @param intno The interrupt number
|
|
* @see hook_add, unicorn.InterruptHook
|
|
*/
|
|
private static void invokeInterruptCallbacks(long eng, int intno) {
|
|
Unicorn u = unicorns.get(eng);
|
|
if (u != null) {
|
|
for (Tuple p : u.intrList) {
|
|
InterruptHook ih = (InterruptHook)p.function;
|
|
ih.hook(u, intno, p.data);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invoke all UC_HOOK_CODE callbacks registered for a specific Unicorn.
|
|
* This function gets invoked from the native C callback registered for
|
|
* for UC_HOOK_CODE
|
|
*
|
|
* @param eng A Unicorn uc_engine* eng returned by uc_open
|
|
* @param address The address of the instruction being executed
|
|
* @param size The size of the instruction being executed
|
|
* @see hook_add, unicorn.CodeHook
|
|
*/
|
|
private static void invokeCodeCallbacks(long eng, long address, int size) {
|
|
Unicorn u = unicorns.get(eng);
|
|
if (u != null) {
|
|
for (Tuple p : u.codeList) {
|
|
CodeHook ch = (CodeHook)p.function;
|
|
ch.hook(u, address, size, p.data);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invoke all UC_HOOK_MEM_XXX_UNMAPPED and/or 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_XXX_UNMAPPED or UC_HOOK_MEM_XXX_PROT
|
|
*
|
|
* @param eng A Unicorn uc_engine* eng returned by uc_open
|
|
* @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.EventMemHook
|
|
*/
|
|
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) {
|
|
ArrayList<Tuple> 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;
|
|
}
|
|
|
|
/**
|
|
* Invoke all UC_HOOK_MEM_READ callbacks registered for a specific Unicorn.
|
|
* This function gets invoked from the native C callback registered for
|
|
* for UC_HOOK_MEM_READ
|
|
*
|
|
* @param eng A Unicorn uc_engine* eng returned by uc_open
|
|
* @param address Address of instruction being executed
|
|
* @param size Size of data being read
|
|
* @see hook_add, unicorn.ReadHook
|
|
*/
|
|
private static void invokeReadCallbacks(long eng, long address, int size) {
|
|
Unicorn u = unicorns.get(eng);
|
|
if (u != null) {
|
|
for (Tuple p : u.readList) {
|
|
ReadHook rh = (ReadHook)p.function;
|
|
rh.hook(u, address, size, p.data);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invoke all UC_HOOK_MEM_WRITE callbacks registered for a specific Unicorn.
|
|
* This function gets invoked from the native C callback registered for
|
|
* for UC_HOOK_MEM_WRITE
|
|
*
|
|
* @param eng A Unicorn uc_engine* eng returned by uc_open
|
|
* @param address Address of instruction being executed
|
|
* @param size Size of data being read
|
|
* @param value value being written
|
|
* @see hook_add, unicorn.WriteHook
|
|
*/
|
|
private static void invokeWriteCallbacks(long eng, long address, int size, long value) {
|
|
Unicorn u = unicorns.get(eng);
|
|
if (u != null) {
|
|
for (Tuple p : u.writeList) {
|
|
WriteHook wh = (WriteHook)p.function;
|
|
wh.hook(u, address, size, value, p.data);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invoke all UC_HOOK_INSN callbacks registered for a specific Unicorn.
|
|
* This is specifically for the x86 IN instruction.
|
|
* This function gets invoked from the native C callback registered for
|
|
* for UC_HOOK_INSN
|
|
*
|
|
* @param eng A Unicorn uc_engine* eng returned by uc_open
|
|
* @param port I/O Port number
|
|
* @param size Data size (1/2/4) to be read from this port
|
|
* @return Data supplied from the input port
|
|
* @see hook_add, unicorn.InHook
|
|
*/
|
|
private static int invokeInCallbacks(long eng, int port, int size) {
|
|
Unicorn u = unicorns.get(eng);
|
|
int result = 0;
|
|
if (u != null) {
|
|
for (Tuple p : u.inList) {
|
|
InHook ih = (InHook)p.function;
|
|
result = ih.hook(u, port, size, p.data);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Invoke all UC_HOOK_INSN callbacks registered for a specific Unicorn.
|
|
* This is specifically for the x86 OUT instruction.
|
|
* This function gets invoked from the native C callback registered for
|
|
* for UC_HOOK_INSN
|
|
*
|
|
* @param eng A Unicorn uc_engine* eng returned by uc_open
|
|
* @param port I/O Port number
|
|
* @param size Data size (1/2/4) to be written to this port
|
|
* @see hook_add, unicorn.OutHook
|
|
*/
|
|
private static void invokeOutCallbacks(long eng, int port, int size, int value) {
|
|
Unicorn u = unicorns.get(eng);
|
|
int result = 0;
|
|
if (u != null) {
|
|
for (Tuple p : u.outList) {
|
|
OutHook oh = (OutHook)p.function;
|
|
oh.hook(u, port, size, value, p.data);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invoke all UC_HOOK_INSN callbacks registered for a specific Unicorn.
|
|
* This is specifically for the x86 SYSCALL and SYSENTER instruction.
|
|
* This function gets invoked from the native C callback registered for
|
|
* for UC_HOOK_INSN
|
|
*
|
|
* @param eng A Unicorn uc_engine* eng returned by uc_open
|
|
* @see hook_add, unicorn.SyscallHook
|
|
*/
|
|
private static void invokeSyscallCallbacks(long eng) {
|
|
Unicorn u = unicorns.get(eng);
|
|
int result = 0;
|
|
if (u != null) {
|
|
for (Tuple p : u.syscallList) {
|
|
SyscallHook sh = (SyscallHook)p.function;
|
|
sh.hook(u, p.data);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Write to register.
|
|
*
|
|
* @param regid Register ID that is to be modified.
|
|
* @param value Number containing the new register value
|
|
*/
|
|
private native void reg_write_num(int regid, Number value) throws UnicornException;
|
|
|
|
/**
|
|
* Write to register.
|
|
*
|
|
* @param regid Register ID that is to be modified.
|
|
* @param value X86 specific memory management register containing the new register value
|
|
*/
|
|
private native void reg_write_mmr(int regid, X86_MMR value) throws UnicornException;
|
|
|
|
/**
|
|
* Read register value.
|
|
*
|
|
* @param regid Register ID that is to be retrieved.
|
|
* @return Number containing the requested register value.
|
|
*/
|
|
private native Number reg_read_num(int regid) throws UnicornException;
|
|
|
|
/**
|
|
* Read register value.
|
|
*
|
|
* @param regid Register ID that is to be retrieved.
|
|
* @return X86_MMR containing the requested register value.
|
|
*/
|
|
private native Number reg_read_mmr(int regid) throws UnicornException;
|
|
|
|
/**
|
|
* Native access to uc_open
|
|
*
|
|
* @param arch Architecture type (UC_ARCH_*)
|
|
* @param mode Hardware mode. This is combined of UC_MODE_*
|
|
*/
|
|
private native long open(int arch, int mode) throws UnicornException;
|
|
|
|
/**
|
|
* Create a new Unicorn object
|
|
*
|
|
* @param arch Architecture type (UC_ARCH_*)
|
|
* @param mode Hardware mode. This is combined of UC_MODE_*
|
|
* @see unicorn.UnicornConst
|
|
*
|
|
*/
|
|
public Unicorn(int arch, int mode) throws UnicornException {
|
|
//remember these in case we need arch specific code
|
|
this.arch = arch;
|
|
this.mode = mode;
|
|
eng = open(arch, mode);
|
|
unicorns.put(eng, this);
|
|
allLists.add(blockList);
|
|
allLists.add(intrList);
|
|
allLists.add(codeList);
|
|
allLists.add(readList);
|
|
allLists.add(writeList);
|
|
allLists.add(inList);
|
|
allLists.add(outList);
|
|
allLists.add(syscallList);
|
|
}
|
|
|
|
/**
|
|
* Perform native cleanup tasks associated with a Unicorn object
|
|
*
|
|
*/
|
|
protected void finalize() {
|
|
unicorns.remove(eng);
|
|
close();
|
|
}
|
|
|
|
/**
|
|
* Return combined API version & major and minor version numbers.
|
|
*
|
|
* @return hexadecimal number as (major << 8 | minor), which encodes both major & minor versions.
|
|
*
|
|
* For example Unicorn version 1.2 whould yield 0x0102
|
|
*/
|
|
public native static int version();
|
|
|
|
/**
|
|
* Determine if the given architecture is supported by this library.
|
|
*
|
|
* @param arch Architecture type (UC_ARCH_*)
|
|
* @return true if this library supports the given arch.
|
|
* @see unicorn.UnicornConst
|
|
*/
|
|
public native static boolean arch_supported(int arch);
|
|
|
|
/**
|
|
* Close the underlying uc_engine* eng associated with this Unicorn object
|
|
*
|
|
*/
|
|
public native void close() throws UnicornException;
|
|
|
|
/**
|
|
* Query internal status of engine.
|
|
*
|
|
* @param type query type. See UC_QUERY_*
|
|
* @param result save the internal status queried
|
|
*
|
|
* @return: error code. see UC_ERR_*
|
|
* @see unicorn.UnicornConst
|
|
*/
|
|
public native int query(int type) throws UnicornException;
|
|
|
|
/**
|
|
* Report the last error number when some API function fail.
|
|
* Like glibc's errno, uc_errno might not retain its old value once accessed.
|
|
*
|
|
* @return Error code of uc_err enum type (UC_ERR_*, see above)
|
|
* @see unicorn.UnicornConst
|
|
*/
|
|
public native int errno();
|
|
|
|
/**
|
|
* Return a string describing given error code.
|
|
*
|
|
* @param code Error code (see UC_ERR_* above)
|
|
* @return Returns a String that describes the error code
|
|
* @see unicorn.UnicornConst
|
|
*/
|
|
public native static String strerror(int code);
|
|
|
|
/**
|
|
* Write to register.
|
|
*
|
|
* @deprecated use reg_write(int regid, Object value) instead
|
|
* @param regid Register ID that is to be modified.
|
|
* @param value Array containing value that will be written into register @regid
|
|
*/
|
|
@Deprecated
|
|
public native void reg_write(int regid, byte[] value) throws UnicornException;
|
|
|
|
/**
|
|
* Write to register.
|
|
*
|
|
* @param regid Register ID that is to be modified.
|
|
* @param value Object containing the new register value. Long, BigInteger, or
|
|
* other custom class used to represent register values
|
|
*/
|
|
public void reg_write(int regid, Object value) throws UnicornException {
|
|
if (value instanceof Number) {
|
|
reg_write_num(regid, (Number)value);
|
|
}
|
|
else if (arch == UC_ARCH_X86 && value instanceof X86_MMR) {
|
|
if (regid >= UC_X86_REG_IDTR && regid <= UC_X86_REG_TR) {
|
|
reg_write_mmr(regid, (X86_MMR)value);
|
|
}
|
|
}
|
|
else {
|
|
throw new ClassCastException("Invalid value type");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Read register value.
|
|
*
|
|
* @deprecated use Object reg_read(int regid) instead
|
|
* @param regid Register ID that is to be retrieved.
|
|
* @param regsz Size of the register being retrieved.
|
|
* @return Byte array containing the requested register value.
|
|
*/
|
|
@Deprecated
|
|
public native byte[] reg_read(int regid, int regsz) throws UnicornException;
|
|
|
|
/**
|
|
* Read register value.
|
|
*
|
|
* @param regid Register ID that is to be retrieved.
|
|
* @return Object containing the requested register value. Long, BigInteger, or
|
|
* other custom class used to represent register values
|
|
*/
|
|
public Object reg_read(int regid) throws UnicornException {
|
|
if (arch == UC_ARCH_X86 && regid >= UC_X86_REG_IDTR && regid <= UC_X86_REG_TR) {
|
|
return reg_read_mmr(regid);
|
|
}
|
|
else {
|
|
return reg_read_num(regid);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Batch write register values. regids.length == vals.length or UC_ERR_ARG
|
|
*
|
|
* @param regids Array of register IDs to be written.
|
|
* @param vals Array of register values to be written.
|
|
*/
|
|
public void reg_write_batch(int regids[], Object vals[]) throws UnicornException {
|
|
if (regids.length != vals.length) {
|
|
throw new UnicornException(strerror(UC_ERR_ARG));
|
|
}
|
|
for (int i = 0; i < regids.length; i++) {
|
|
reg_write(regids[i], vals[i]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Batch read register values.
|
|
*
|
|
* @param regids Array of register IDs to be read.
|
|
* @return Array containing the requested register values.
|
|
*/
|
|
public Object[] reg_read_batch(int regids[]) throws UnicornException {
|
|
Object[] vals = new Object[regids.length];
|
|
for (int i = 0; i < regids.length; i++) {
|
|
vals[i] = reg_read(regids[i]);
|
|
}
|
|
return vals;
|
|
}
|
|
|
|
/**
|
|
* Write to memory.
|
|
*
|
|
* @param address Start addres of the memory region to be written.
|
|
* @param bytes The values to be written into memory. bytes.length bytes will be written.
|
|
*/
|
|
public native void mem_write(long address, byte[] bytes) throws UnicornException;
|
|
|
|
/**
|
|
* Read memory contents.
|
|
*
|
|
* @param address Start addres of the memory region to be read.
|
|
* @param size Number of bytes to be retrieved.
|
|
* @return Byte array containing the contents of the requested memory range.
|
|
*/
|
|
public native byte[] mem_read(long address, long size) throws UnicornException;
|
|
|
|
/**
|
|
* Emulate machine code in a specific duration of time.
|
|
*
|
|
* @param begin Address where emulation starts
|
|
* @param until Address where emulation stops (i.e when this address is hit)
|
|
* @param timeout Duration to emulate the code (in microseconds). When this value is 0, we will emulate the code in infinite time, until the code is finished.
|
|
* @param count The number of instructions to be emulated. When this value is 0, we will emulate all the code available, until the code is finished.
|
|
*/
|
|
public native void emu_start(long begin, long until, long timeout, long count) throws UnicornException;
|
|
|
|
/**
|
|
* Stop emulation (which was started by emu_start() ).
|
|
* This is typically called from callback functions registered via tracing APIs.
|
|
* NOTE: for now, this will stop the execution only after the current block.
|
|
*/
|
|
public native void emu_stop() throws UnicornException;
|
|
|
|
/**
|
|
* Hook registration helper for hook types that require no additional arguments.
|
|
*
|
|
* @param eng Internal unicorn uc_engine* eng associated with hooking Unicorn object
|
|
* @param type UC_HOOK_* hook type
|
|
* @return Unicorn uch returned for registered hook function
|
|
*/
|
|
private native static long registerHook(long eng, int type);
|
|
|
|
/**
|
|
* Hook registration helper for hook types that require one additional argument.
|
|
*
|
|
* @param eng Internal unicorn uc_engine* eng associated with hooking Unicorn object
|
|
* @param type UC_HOOK_* hook type
|
|
* @param arg1 Additional varargs argument
|
|
* @return Unicorn uch returned for registered hook function
|
|
*/
|
|
private native static long registerHook(long eng, int type, int arg1);
|
|
|
|
/**
|
|
* Hook registration helper for hook types that require two additional arguments.
|
|
*
|
|
* @param eng Internal unicorn uc_engine* eng associated with hooking Unicorn object
|
|
* @param type UC_HOOK_* hook type
|
|
* @param arg1 First additional varargs argument
|
|
* @param arg2 Second additional varargs argument
|
|
* @return Unicorn uch returned for registered hook function
|
|
*/
|
|
private native static long registerHook(long eng, int type, long arg1, long arg2);
|
|
|
|
/**
|
|
* Hook registration for UC_HOOK_BLOCK hooks. The registered callback function will be
|
|
* invoked when a basic block is entered and the address of the basic block (BB) falls in the
|
|
* range begin <= BB <= end. For the special case in which begin > end, the callback will be
|
|
* invoked whenver any basic block is entered.
|
|
*
|
|
* @param callback Implementation of a BlockHook interface
|
|
* @param begin Start address of hooking range
|
|
* @param end End address of hooking range
|
|
* @param user_data User data to be passed to the callback function each time the event is triggered
|
|
*/
|
|
public void hook_add(BlockHook callback, long begin, long end, Object user_data) throws UnicornException {
|
|
if (blockHandle == 0) {
|
|
blockHandle = registerHook(eng, UC_HOOK_BLOCK, begin, end);
|
|
}
|
|
blockList.add(new Tuple(callback, user_data));
|
|
}
|
|
|
|
/**
|
|
* Hook registration for UC_HOOK_INTR hooks. The registered callback function will be
|
|
* invoked whenever an interrupt instruction is executed.
|
|
*
|
|
* @param callback Implementation of a InterruptHook interface
|
|
* @param user_data User data to be passed to the callback function each time the event is triggered
|
|
*/
|
|
public void hook_add(InterruptHook callback, Object user_data) throws UnicornException {
|
|
if (interruptHandle == 0) {
|
|
interruptHandle = registerHook(eng, UC_HOOK_INTR);
|
|
}
|
|
intrList.add(new Tuple(callback, user_data));
|
|
}
|
|
|
|
/**
|
|
* Hook registration for UC_HOOK_CODE hooks. The registered callback function will be
|
|
* invoked when an instruction is executed from the address range begin <= PC <= end. For
|
|
* the special case in which begin > end, the callback will be invoked for ALL instructions.
|
|
*
|
|
* @param callback Implementation of a CodeHook interface
|
|
* @param begin Start address of hooking range
|
|
* @param end End address of hooking range
|
|
* @param user_data User data to be passed to the callback function each time the event is triggered
|
|
*/
|
|
public void hook_add(CodeHook callback, long begin, long end, Object user_data) throws UnicornException {
|
|
if (codeHandle == 0) {
|
|
codeHandle = registerHook(eng, UC_HOOK_CODE, begin, end);
|
|
}
|
|
codeList.add(new Tuple(callback, user_data));
|
|
}
|
|
|
|
/**
|
|
* Hook registration for UC_HOOK_MEM_READ hooks. The registered callback function will be
|
|
* invoked whenever a memory read is performed within the address range begin <= read_addr <= end. For
|
|
* the special case in which begin > end, the callback will be invoked for ALL memory reads.
|
|
*
|
|
* @param callback Implementation of a ReadHook interface
|
|
* @param begin Start address of memory read range
|
|
* @param end End address of memory read range
|
|
* @param user_data User data to be passed to the callback function each time the event is triggered
|
|
*/
|
|
public void hook_add(ReadHook callback, long begin, long end, Object user_data) throws UnicornException {
|
|
if (readHandle == 0) {
|
|
readHandle = registerHook(eng, UC_HOOK_MEM_READ, begin, end);
|
|
}
|
|
readList.add(new Tuple(callback, user_data));
|
|
}
|
|
|
|
/**
|
|
* Hook registration for UC_HOOK_MEM_WRITE hooks. The registered callback function will be
|
|
* invoked whenever a memory write is performed within the address range begin <= write_addr <= end. For
|
|
* the special case in which begin > end, the callback will be invoked for ALL memory writes.
|
|
*
|
|
* @param callback Implementation of a WriteHook interface
|
|
* @param begin Start address of memory write range
|
|
* @param end End address of memory write range
|
|
* @param user_data User data to be passed to the callback function each time the event is triggered
|
|
*/
|
|
public void hook_add(WriteHook callback, long begin, long end, Object user_data) throws UnicornException {
|
|
if (writeHandle == 0) {
|
|
writeHandle = registerHook(eng, UC_HOOK_MEM_WRITE, begin, end);
|
|
}
|
|
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_UNMAPPED 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 EventMemHook interface
|
|
* @param type Type of memory event being hooked such as UC_HOOK_MEM_READ_UNMAPPED 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(EventMemHook callback, int type, Object user_data) throws UnicornException {
|
|
//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<Tuple> flist = eventMemLists.get(cbType);
|
|
if (flist == null) {
|
|
flist = new ArrayList<Tuple>();
|
|
allLists.add(flist);
|
|
eventMemLists.put(cbType, flist);
|
|
}
|
|
flist.add(new Tuple(callback, user_data));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hook registration for UC_HOOK_INSN hooks (x86 IN instruction only). The registered callback
|
|
* function will be invoked whenever an x86 IN instruction is executed.
|
|
*
|
|
* @param callback Implementation of a InHook interface
|
|
* @param user_data User data to be passed to the callback function each time the event is triggered
|
|
*/
|
|
public void hook_add(InHook callback, Object user_data) throws UnicornException {
|
|
if (inHandle == 0) {
|
|
inHandle = registerHook(eng, UC_HOOK_INSN, Unicorn.UC_X86_INS_IN);
|
|
}
|
|
inList.add(new Tuple(callback, user_data));
|
|
}
|
|
|
|
/**
|
|
* Hook registration for UC_HOOK_INSN hooks (x86 OUT instruction only). The registered callback
|
|
* function will be invoked whenever an x86 OUT instruction is executed.
|
|
*
|
|
* @param callback Implementation of a OutHook interface
|
|
* @param user_data User data to be passed to the callback function each time the event is triggered
|
|
*/
|
|
public void hook_add(OutHook callback, Object user_data) throws UnicornException {
|
|
if (outHandle == 0) {
|
|
outHandle = registerHook(eng, UC_HOOK_INSN, Unicorn.UC_X86_INS_OUT);
|
|
}
|
|
outList.add(new Tuple(callback, user_data));
|
|
}
|
|
|
|
/**
|
|
* Hook registration for UC_HOOK_INSN hooks (x86 SYSCALL/SYSENTER instruction only). The registered callback
|
|
* function will be invoked whenever an x86 SYSCALL or SYSENTER instruction is executed.
|
|
*
|
|
* @param callback Implementation of a SyscallHook interface
|
|
* @param user_data User data to be passed to the callback function each time the event is triggered
|
|
*/
|
|
public void hook_add(SyscallHook callback, Object user_data) throws UnicornException {
|
|
if (syscallHandle == 0) {
|
|
syscallHandle = registerHook(eng, UC_HOOK_INSN, Unicorn.UC_X86_INS_SYSCALL);
|
|
}
|
|
syscallList.add(new Tuple(callback, user_data));
|
|
}
|
|
|
|
public void hook_del(Hook hook) throws UnicornException {
|
|
for (ArrayList<Tuple> l : allLists) {
|
|
for (Tuple t : l) {
|
|
if (t.function.equals(hook)) {
|
|
allLists.remove(t);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Map a range of memory.
|
|
*
|
|
* @param address Base address of the memory range
|
|
* @param size Size of the memory block.
|
|
* @param perms Permissions on the memory block. A combination of UC_PROT_READ, UC_PROT_WRITE, UC_PROT_EXEC
|
|
*/
|
|
public native void mem_map(long address, long size, int perms) throws UnicornException;
|
|
|
|
/**
|
|
* Map existing host memory in for emulation.
|
|
* This API adds a memory region that can be used by emulation.
|
|
*
|
|
* @param address Base address of the memory range
|
|
* @param size Size of the memory block.
|
|
* @param perms Permissions on the memory block. A combination of UC_PROT_READ, UC_PROT_WRITE, UC_PROT_EXEC
|
|
* @param ptr Block of host memory backing the newly mapped memory. This block is
|
|
* expected to be an equal or larger size than provided, and be mapped with at
|
|
* least PROT_READ | PROT_WRITE. If it is not, the resulting behavior is undefined.
|
|
*/
|
|
public native void mem_map_ptr(long address, long size, int perms, byte[] block) throws UnicornException;
|
|
|
|
/**
|
|
* Unmap a range of memory.
|
|
*
|
|
* @param address Base address of the memory range
|
|
* @param size Size of the memory block.
|
|
*/
|
|
public native void mem_unmap(long address, long size) throws UnicornException;
|
|
|
|
/**
|
|
* Change permissions on a range of memory.
|
|
*
|
|
* @param address Base address of the memory range
|
|
* @param size Size of the memory block.
|
|
* @param perms New permissions on the memory block. A combination of UC_PROT_READ, UC_PROT_WRITE, UC_PROT_EXEC
|
|
*/
|
|
public native void mem_protect(long address, long size, int perms) throws UnicornException;
|
|
|
|
/**
|
|
* Retrieve all memory regions mapped by mem_map() and mem_map_ptr()
|
|
* NOTE: memory regions may be split by mem_unmap()
|
|
*
|
|
* @return list of mapped regions.
|
|
*/
|
|
public native MemRegion[] mem_regions() throws UnicornException;
|
|
|
|
/**
|
|
* Allocate a region that can be used with uc_context_{save,restore} to perform
|
|
* quick save/rollback of the CPU context, which includes registers and some
|
|
* internal metadata. Contexts may not be shared across engine instances with
|
|
* differing arches or modes.
|
|
*
|
|
* @return context handle for use with save/restore.
|
|
*/
|
|
public native long context_alloc();
|
|
|
|
/**
|
|
* Free a resource allocated within Unicorn. Use for handles
|
|
* allocated by context_alloc.
|
|
*
|
|
* @param Previously allocated Unicorn object handle.
|
|
*/
|
|
public native void free(long handle);
|
|
|
|
/**
|
|
* Save a copy of the internal CPU context.
|
|
* This API should be used to efficiently make or update a saved copy of the
|
|
* internal CPU state.
|
|
*
|
|
* @param context handle previously returned by context_alloc.
|
|
*/
|
|
public native void context_save(long context);
|
|
|
|
/**
|
|
* Restore the current CPU context from a saved copy.
|
|
* This API should be used to roll the CPU context back to a previous
|
|
* state saved by uc_context_save().
|
|
*
|
|
* @param context handle previously returned by context_alloc.
|
|
*/
|
|
public native void context_restore(long context);
|
|
|
|
}
|
|
|