package samples; import java.util.Arrays; import unicorn.*; public class Sample_ctl implements UnicornConst, X86Const { /** Code to be emulated *
* cmp eax, 0;
* jg lb;
* inc eax;
* nop;
* lb:
* inc ebx;
* nop;
*
*/
private static final byte[] X86_JUMP_CODE =
Utils.hexToBytes("83f8007f0240904390");
/** memory address where emulation starts */
private static final long ADDRESS = 0x10000;
public static void test_uc_ctl_read() {
System.out.println("Reading some properties by uc_ctl.");
// Initialize emulator in X86-32bit mode
Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32);
// Let's query some properties by uc_ctl.
int mode = uc.ctl_get_mode();
int arch = uc.ctl_get_arch();
long timeout = uc.ctl_get_timeout();
int pagesize = uc.ctl_get_page_size();
System.out.format(">>> mode = %d, arch = %d, timeout=%d, pagesize=%d\n",
mode, arch, timeout, pagesize);
}
private static final EdgeGeneratedHook trace_new_edge =
(uc, cur, prev, data) -> {
System.out.format(">>> Getting a new edge from 0x%x to 0x%x.\n",
prev.pc + prev.size - 1, cur.pc);
};
public static void test_uc_ctl_exits() {
long r_eax, r_ebx;
long exits[] = { ADDRESS + 6, ADDRESS + 8 };
System.out.println("Using multiple exits by uc_ctl.");
// Initialize emulator in X86-32bit mode
Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32);
uc.mem_map(ADDRESS, 0x1000, UC_PROT_ALL);
// Write our code to the memory.
uc.mem_write(ADDRESS, X86_JUMP_CODE);
// We trace if any new edge is generated.
uc.hook_add(trace_new_edge, 1, 0, null);
// Enable multiple exits.
uc.ctl_exits_enabled(true);
uc.ctl_set_exits(exits);
// This should stop at ADDRESS + 6 and increase eax, even thouhg we don't
// provide an exit.
uc.emu_start(ADDRESS, 0, 0, 0);
r_eax = uc.reg_read(UC_X86_REG_EAX);
r_ebx = uc.reg_read(UC_X86_REG_EBX);
System.out.format(
">>> eax = %d and ebx = %d after the first emulation\n",
r_eax, r_ebx);
// This should stop at ADDRESS + 8, even though we don't provide an exit.
uc.emu_start(ADDRESS, 0, 0, 0);
r_eax = uc.reg_read(UC_X86_REG_EAX);
r_ebx = uc.reg_read(UC_X86_REG_EBX);
System.out.format(
">>> eax = %d and ebx = %d after the second emulation\n",
r_eax, r_ebx);
}
private static final int TB_COUNT = 8;
private static final int TCG_MAX_INSNS = 512; // from tcg.h
private static final int CODE_LEN = TB_COUNT * TCG_MAX_INSNS;
private static double time_emulation(Unicorn uc, long start, long end) {
long t1 = System.nanoTime();
uc.emu_start(start, end, 0, 0);
long t2 = System.nanoTime();
return (t2 - t1) / 1000000.0;
}
public static void test_uc_ctl_tb_cache() {
byte[] code = new byte[CODE_LEN];
double standard, cached, evicted;
System.out.println(
"Controlling the TB cache in a finer granularity by uc_ctl.");
// Fill the code buffer with NOP.
Arrays.fill(code, (byte) 0x90);
// Initialize emulator in X86-32bit mode
Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32);
uc.mem_map(ADDRESS, 0x10000, UC_PROT_ALL);
// Write our code to the memory.
uc.mem_write(ADDRESS, code);
// We trace if any new edge is generated.
// Note: In this sample, there is only **one** basic block while muliple
// translation blocks is generated due to QEMU tcg buffer limit. In this
// case, we don't consider it as a new edge.
uc.hook_add(trace_new_edge, 1, 0, null);
// Do emulation without any cache.
standard = time_emulation(uc, ADDRESS, ADDRESS + CODE_LEN);
// Now we request cache for all TBs.
for (int i = 0; i < TB_COUNT; i++) {
TranslationBlock tb =
uc.ctl_request_cache(ADDRESS + i * TCG_MAX_INSNS);
System.out.format(
">>> TB is cached at 0x%x which has %d instructions with %d bytes.\n",
tb.pc, tb.icount, tb.size);
}
// Do emulation with all TB cached.
cached = time_emulation(uc, ADDRESS, ADDRESS + CODE_LEN);
// Now we clear cache for all TBs.
for (int i = 0; i < TB_COUNT; i++) {
uc.ctl_remove_cache(ADDRESS + i * TCG_MAX_INSNS,
ADDRESS + i * TCG_MAX_INSNS + 1);
}
// Do emulation with all TB cache evicted.
evicted = time_emulation(uc, ADDRESS, ADDRESS + CODE_LEN);
System.out.format(
">>> Run time: First time: %fms, Cached: %fms, Cache evicted: %fms\n",
standard, cached, evicted);
}
public static final void main(String[] args) {
test_uc_ctl_read();
System.out.println("====================");
test_uc_ctl_exits();
System.out.println("====================");
test_uc_ctl_tb_cache();
}
}