Initial checkin of unicorn java binding

This commit is contained in:
Chris Eagle
2015-08-25 03:21:47 -07:00
parent 4127d8ad85
commit 0359c44462
33 changed files with 5582 additions and 0 deletions

View File

@ -0,0 +1,130 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh, 2015 */
/* Sample code to demonstrate how to emulate ARM code */
import unicorn.*;
public class Sample_arm {
// code to be emulated
public static final byte[] ARM_CODE = {55,0,(byte)0xa0,(byte)0xe3,3,16,66,(byte)0xe0}; // mov r0, #0x37; sub r1, r2, r3
public static final byte[] THUMB_CODE = {(byte)0x83, (byte)0xb0}; // sub sp, #0xc
// memory address where emulation starts
public static final int ADDRESS = 0x10000;
public static final long toInt(byte val[]) {
long res = 0;
for (int i = 0; i < val.length; i++) {
long v = val[i] & 0xff;
res = res + (v << (i * 8));
}
return res;
}
private static class MyBlockHook implements BlockHook {
public void hook(Unicorn u, long address, int size, Object user_data)
{
System.out.print(String.format(">>> Tracing basic block at 0x%x, block size = 0x%x\n", address, size));
}
}
// callback for tracing instruction
private static class MyCodeHook implements CodeHook {
public void hook(Unicorn u, long address, int size, Object user_data) {
System.out.print(String.format(">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", address, size));
}
}
static void test_arm()
{
byte[] r0 = {0x34, 0x12, 0, 0}; // R0 register
byte[] r2 = {(byte)0x89, 0x67, 0, 0}; // R1 register
byte[] r3 = {0x33, 0x33, 0, 0}; // R2 register
byte[] r1; // R1 register
System.out.print("Emulate ARM code\n");
// Initialize emulator in ARM mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_ARM, Unicorn.UC_MODE_ARM);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, ARM_CODE);
// initialize machine registers
u.reg_write(Unicorn.UC_ARM_REG_R0, r0);
u.reg_write(Unicorn.UC_ARM_REG_R2, r2);
u.reg_write(Unicorn.UC_ARM_REG_R3, r3);
// tracing all basic blocks with customized callback
u.hook_add(new MyBlockHook(), 1, 0, null);
// tracing one instruction at ADDRESS with customized callback
u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null);
// emulate machine code in infinite time (last param = 0), or when
// finishing all the code.
u.emu_start(ADDRESS, ADDRESS + ARM_CODE.length, 0, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
r0 = u.reg_read(Unicorn.UC_ARM_REG_R0, 4);
r1 = u.reg_read(Unicorn.UC_ARM_REG_R1, 4);
System.out.print(String.format(">>> R0 = 0x%x\n", toInt(r0)));
System.out.print(String.format(">>> R1 = 0x%x\n", toInt(r1)));
u.close();
}
static void test_thumb()
{
byte[] sp = {0x34, 0x12, 0, 0}; // R0 register
System.out.print("Emulate THUMB code\n");
// Initialize emulator in ARM mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_ARM, Unicorn.UC_MODE_THUMB);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, THUMB_CODE);
// initialize machine registers
u.reg_write(Unicorn.UC_ARM_REG_SP, sp);
// tracing all basic blocks with customized callback
u.hook_add(new MyBlockHook(), 1, 0, null);
// tracing one instruction at ADDRESS with customized callback
u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null);
// emulate machine code in infinite time (last param = 0), or when
// finishing all the code.
u.emu_start(ADDRESS, ADDRESS + THUMB_CODE.length, 0, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
sp = u.reg_read(Unicorn.UC_ARM_REG_SP, 4);
System.out.print(String.format(">>> SP = 0x%x\n", toInt(sp)));
u.close();
}
public static void main(String args[])
{
test_arm();
System.out.print("==========================\n");
test_thumb();
}
}

View File

@ -0,0 +1,115 @@
/*
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.
*/
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh, 2015 */
/* Sample code to demonstrate how to emulate ARM64 code */
import unicorn.*;
public class Sample_arm64 {
// code to be emulated
public static final byte[] ARM_CODE = {-85,1,15,-117}; // add x11, x13, x15
// memory address where emulation starts
public static final int ADDRESS = 0x10000;
public static final long toInt(byte val[]) {
long res = 0;
for (int i = 0; i < val.length; i++) {
long v = val[i] & 0xff;
res = res + (v << (i * 8));
}
return res;
}
public static final byte[] toBytes(long val) {
byte[] res = new byte[8];
for (int i = 0; i < 8; i++) {
res[i] = (byte)(val & 0xff);
val >>>= 8;
}
return res;
}
// callback for tracing basic blocks
private static class MyBlockHook implements BlockHook {
public void hook(Unicorn u, long address, int size, Object user_data) {
System.out.print(String.format(">>> Tracing basic block at 0x%x, block size = 0x%x\n", address, size));
}
}
// callback for tracing instruction
private static class MyCodeHook implements CodeHook {
public void hook(Unicorn u, long address, int size, Object user_data) {
System.out.print(String.format(">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", address, size));
}
}
static void test_arm64()
{
byte[] x11 = toBytes(0x1234); // X11 register
byte[] x13 = toBytes(0x6789); // X13 register
byte[] x15 = toBytes(0x3333); // X15 register
System.out.print("Emulate ARM64 code\n");
// Initialize emulator in ARM mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_ARM64, Unicorn.UC_MODE_ARM);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, ARM_CODE);
// initialize machine registers
u.reg_write(Unicorn.UC_ARM64_REG_X11, x11);
u.reg_write(Unicorn.UC_ARM64_REG_X13, x13);
u.reg_write(Unicorn.UC_ARM64_REG_X15, x15);
// tracing all basic blocks with customized callback
u.hook_add(new MyBlockHook(), 1, 0, null);
// tracing one instruction at ADDRESS with customized callback
u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null);
// emulate machine code in infinite time (last param = 0), or when
// finishing all the code.
u.emu_start(ADDRESS, ADDRESS + ARM_CODE.length, 0, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
x11 = u.reg_read(Unicorn.UC_ARM64_REG_X11, 8);
System.out.print(String.format(">>> X11 = 0x%x\n", toInt(x11)));
u.close();
}
public static void main(String args[])
{
test_arm64();
}
}

View File

@ -0,0 +1,177 @@
/*
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.
*/
/* Unicorn Emulator Engine */
/* By Loi Anh Tuan, 2015 */
/* Sample code to demonstrate how to emulate m68k code */
import unicorn.*;
public class Sample_m68k {
// code to be emulated
public static final byte[] M68K_CODE = {118,-19}; // movq #-19, %d3
// memory address where emulation starts
public static final int ADDRESS = 0x10000;
public static final long toInt(byte val[]) {
long res = 0;
for (int i = 0; i < val.length; i++) {
long v = val[i] & 0xff;
res = res + (v << (i * 8));
}
return res;
}
public static final byte[] toBytes(long val) {
byte[] res = new byte[8];
for (int i = 0; i < 8; i++) {
res[i] = (byte)(val & 0xff);
val >>>= 8;
}
return res;
}
// callback for tracing basic blocks
private static class MyBlockHook implements BlockHook {
public void hook(Unicorn u, long address, int size, Object user_data) {
System.out.print(String.format(">>> Tracing basic block at 0x%x, block size = 0x%x\n", address, size));
}
}
// callback for tracing instruction
private static class MyCodeHook implements CodeHook {
public void hook(Unicorn u, long address, int size, Object user_data) {
System.out.print(String.format(">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", address, size));
}
}
static void test_m68k()
{
byte[] d0 = toBytes(0x0000); // d0 data register
byte[] d1 = toBytes(0x0000); // d1 data register
byte[] d2 = toBytes(0x0000); // d2 data register
byte[] d3 = toBytes(0x0000); // d3 data register
byte[] d4 = toBytes(0x0000); // d4 data register
byte[] d5 = toBytes(0x0000); // d5 data register
byte[] d6 = toBytes(0x0000); // d6 data register
byte[] d7 = toBytes(0x0000); // d7 data register
byte[] a0 = toBytes(0x0000); // a0 address register
byte[] a1 = toBytes(0x0000); // a1 address register
byte[] a2 = toBytes(0x0000); // a2 address register
byte[] a3 = toBytes(0x0000); // a3 address register
byte[] a4 = toBytes(0x0000); // a4 address register
byte[] a5 = toBytes(0x0000); // a5 address register
byte[] a6 = toBytes(0x0000); // a6 address register
byte[] a7 = toBytes(0x0000); // a6 address register
byte[] pc = toBytes(0x0000); // program counter
byte[] sr = toBytes(0x0000); // status register
System.out.print("Emulate M68K code\n");
// Initialize emulator in M68K mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_M68K, Unicorn.UC_MODE_BIG_ENDIAN);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, M68K_CODE);
// initialize machine registers
u.reg_write(Unicorn.UC_M68K_REG_D0, d0);
u.reg_write(Unicorn.UC_M68K_REG_D1, d1);
u.reg_write(Unicorn.UC_M68K_REG_D2, d2);
u.reg_write(Unicorn.UC_M68K_REG_D3, d3);
u.reg_write(Unicorn.UC_M68K_REG_D4, d4);
u.reg_write(Unicorn.UC_M68K_REG_D5, d5);
u.reg_write(Unicorn.UC_M68K_REG_D6, d6);
u.reg_write(Unicorn.UC_M68K_REG_D7, d7);
u.reg_write(Unicorn.UC_M68K_REG_A0, a0);
u.reg_write(Unicorn.UC_M68K_REG_A1, a1);
u.reg_write(Unicorn.UC_M68K_REG_A2, a2);
u.reg_write(Unicorn.UC_M68K_REG_A3, a3);
u.reg_write(Unicorn.UC_M68K_REG_A4, a4);
u.reg_write(Unicorn.UC_M68K_REG_A5, a5);
u.reg_write(Unicorn.UC_M68K_REG_A6, a6);
u.reg_write(Unicorn.UC_M68K_REG_A7, a7);
u.reg_write(Unicorn.UC_M68K_REG_PC, pc);
u.reg_write(Unicorn.UC_M68K_REG_SR, sr);
// tracing all basic blocks with customized callback
u.hook_add(new MyBlockHook(), 1, 0, null);
// tracing all instruction
u.hook_add(new MyCodeHook(), 1, 0, null);
// emulate machine code in infinite time (last param = 0), or when
// finishing all the code.
u.emu_start(ADDRESS, ADDRESS + M68K_CODE.length, 0, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
d0 = u.reg_read(Unicorn.UC_M68K_REG_D0, 4);
d1 = u.reg_read(Unicorn.UC_M68K_REG_D1, 4);
d2 = u.reg_read(Unicorn.UC_M68K_REG_D2, 4);
d3 = u.reg_read(Unicorn.UC_M68K_REG_D3, 4);
d4 = u.reg_read(Unicorn.UC_M68K_REG_D4, 4);
d5 = u.reg_read(Unicorn.UC_M68K_REG_D5, 4);
d6 = u.reg_read(Unicorn.UC_M68K_REG_D6, 4);
d7 = u.reg_read(Unicorn.UC_M68K_REG_D7, 4);
a0 = u.reg_read(Unicorn.UC_M68K_REG_A0, 4);
a1 = u.reg_read(Unicorn.UC_M68K_REG_A1, 4);
a2 = u.reg_read(Unicorn.UC_M68K_REG_A2, 4);
a3 = u.reg_read(Unicorn.UC_M68K_REG_A3, 4);
a4 = u.reg_read(Unicorn.UC_M68K_REG_A4, 4);
a5 = u.reg_read(Unicorn.UC_M68K_REG_A5, 4);
a6 = u.reg_read(Unicorn.UC_M68K_REG_A6, 4);
a7 = u.reg_read(Unicorn.UC_M68K_REG_A7, 4);
pc = u.reg_read(Unicorn.UC_M68K_REG_PC, 4);
sr = u.reg_read(Unicorn.UC_M68K_REG_SR, 4);
System.out.print(String.format(">>> A0 = 0x%x\t\t>>> D0 = 0x%x\n", toInt(a0), toInt(d0)));
System.out.print(String.format(">>> A1 = 0x%x\t\t>>> D1 = 0x%x\n", toInt(a1), toInt(d1)));
System.out.print(String.format(">>> A2 = 0x%x\t\t>>> D2 = 0x%x\n", toInt(a2), toInt(d2)));
System.out.print(String.format(">>> A3 = 0x%x\t\t>>> D3 = 0x%x\n", toInt(a3), toInt(d3)));
System.out.print(String.format(">>> A4 = 0x%x\t\t>>> D4 = 0x%x\n", toInt(a4), toInt(d4)));
System.out.print(String.format(">>> A5 = 0x%x\t\t>>> D5 = 0x%x\n", toInt(a5), toInt(d5)));
System.out.print(String.format(">>> A6 = 0x%x\t\t>>> D6 = 0x%x\n", toInt(a6), toInt(d6)));
System.out.print(String.format(">>> A7 = 0x%x\t\t>>> D7 = 0x%x\n", toInt(a7), toInt(d7)));
System.out.print(String.format(">>> PC = 0x%x\n", toInt(pc)));
System.out.print(String.format(">>> SR = 0x%x\n", toInt(sr)));
u.close();
}
public static void main(String args[])
{
test_m68k();
}
}

View File

@ -0,0 +1,151 @@
/*
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.
*/
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh, 2015 */
/* Sample code to demonstrate how to emulate Mips code (big endian) */
import unicorn.*;
public class Sample_mips {
// code to be emulated
public static final byte[] MIPS_CODE_EB = {52,33,52,86};
public static final byte[] MIPS_CODE_EL = {86,52,33,52};
// memory address where emulation starts
public static final int ADDRESS = 0x10000;
public static final long toInt(byte val[]) {
long res = 0;
for (int i = 0; i < val.length; i++) {
long v = val[i] & 0xff;
res = res + (v << (i * 8));
}
return res;
}
public static final byte[] toBytes(long val) {
byte[] res = new byte[8];
for (int i = 0; i < 8; i++) {
res[i] = (byte)(val & 0xff);
val >>>= 8;
}
return res;
}
// callback for tracing basic blocks
private static class MyBlockHook implements BlockHook {
public void hook(Unicorn u, long address, int size, Object user_data) {
System.out.print(String.format(">>> Tracing basic block at 0x%x, block size = 0x%x\n", address, size));
}
}
// callback for tracing instruction
private static class MyCodeHook implements CodeHook {
public void hook(Unicorn u, long address, int size, Object user_data) {
System.out.print(String.format(">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", address, size));
}
}
static void test_mips_eb()
{
byte[] r1 = toBytes(0x6789); // R1 register
System.out.print("Emulate MIPS code (big-endian)\n");
// Initialize emulator in MIPS mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_MIPS, Unicorn.UC_MODE_MIPS32 + Unicorn.UC_MODE_BIG_ENDIAN);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, MIPS_CODE_EB);
// initialize machine registers
u.reg_write(Unicorn.UC_MIPS_REG_1, r1);
// tracing all basic blocks with customized callback
u.hook_add(new MyBlockHook(), 1, 0, null);
// tracing one instruction at ADDRESS with customized callback
u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null);
// emulate machine code in infinite time (last param = 0), or when
// finishing all the code.
u.emu_start(ADDRESS, ADDRESS + MIPS_CODE_EB.length, 0, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
r1 = u.reg_read(Unicorn.UC_MIPS_REG_1, 4);
System.out.print(String.format(">>> R1 = 0x%x\n", toInt(r1)));
u.close();
}
static void test_mips_el()
{
byte[] r1 = toBytes(0x6789); // R1 register
System.out.print("===========================\n");
System.out.print("Emulate MIPS code (little-endian)\n");
// Initialize emulator in MIPS mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_MIPS, Unicorn.UC_MODE_MIPS32);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, MIPS_CODE_EL);
// initialize machine registers
u.reg_write(Unicorn.UC_MIPS_REG_1, r1);
// tracing all basic blocks with customized callback
u.hook_add(new MyBlockHook(), 1, 0, null);
// tracing one instruction at ADDRESS with customized callback
u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null);
// emulate machine code in infinite time (last param = 0), or when
// finishing all the code.
u.emu_start(ADDRESS, ADDRESS + MIPS_CODE_EL.length, 0, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
r1 = u.reg_read(Unicorn.UC_MIPS_REG_1, 4);
System.out.print(String.format(">>> R1 = 0x%x\n", toInt(r1)));
u.close();
}
public static void main(String args[])
{
test_mips_eb();
test_mips_el();
}
}

View File

@ -0,0 +1,115 @@
/*
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.
*/
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh, 2015 */
/* Sample code to demonstrate how to emulate Sparc code */
import unicorn.*;
public class Sample_sparc {
// code to be emulated
public static final byte[] SPARC_CODE = {-122,0,64,2};
//public static final byte[] SPARC_CODE = {-69,112,0,0}; //illegal code
// memory address where emulation starts
public static final int ADDRESS = 0x10000;
public static final long toInt(byte val[]) {
long res = 0;
for (int i = 0; i < val.length; i++) {
long v = val[i] & 0xff;
res = res + (v << (i * 8));
}
return res;
}
public static final byte[] toBytes(long val) {
byte[] res = new byte[8];
for (int i = 0; i < 8; i++) {
res[i] = (byte)(val & 0xff);
val >>>= 8;
}
return res;
}
// callback for tracing basic blocks
private static class MyBlockHook implements BlockHook {
public void hook(Unicorn u, long address, int size, Object user_data) {
System.out.print(String.format(">>> Tracing basic block at 0x%x, block size = 0x%x\n", address, size));
}
}
// callback for tracing instruction
private static class MyCodeHook implements CodeHook {
public void hook(Unicorn u, long address, int size, Object user_data) {
System.out.print(String.format(">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", address, size));
}
}
static void test_sparc()
{
byte[] g1 = toBytes(0x1230); // G1 register
byte[] g2 = toBytes(0x6789); // G2 register
byte[] g3 = toBytes(0x5555); // G3 register
System.out.print("Emulate SPARC code\n");
// Initialize emulator in Sparc mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_SPARC, Unicorn.UC_MODE_BIG_ENDIAN);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, SPARC_CODE);
// initialize machine registers
u.reg_write(Unicorn.UC_SPARC_REG_G1, g1);
u.reg_write(Unicorn.UC_SPARC_REG_G2, g2);
u.reg_write(Unicorn.UC_SPARC_REG_G3, g3);
// tracing all basic blocks with customized callback
u.hook_add(new MyBlockHook(), 1, 0, null);
// tracing one instruction at ADDRESS with customized callback
u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null);
// emulate machine code in infinite time (last param = 0), or when
// finishing all the code.
u.emu_start(ADDRESS, ADDRESS + SPARC_CODE.length, 0, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
g3 = u.reg_read(Unicorn.UC_SPARC_REG_G3, 4);
System.out.print(String.format(">>> G3 = 0x%x\n", toInt(g3)));
u.close();
}
public static void main(String args[])
{
test_sparc();
}
}

View File

@ -0,0 +1,618 @@
/*
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.
*/
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh & Dang Hoang Vu, 2015 */
/* Sample code to demonstrate how to emulate X86 code */
import unicorn.*;
public class Sample_x86 {
// code to be emulated
public static final byte[] X86_CODE32 = {65,74};
public static final byte[] X86_CODE32_JUMP = {-21,2,-112,-112,-112,-112,-112,-112};
public static final byte[] X86_CODE32_SELF = {-21,28,90,-119,-42,-117,2,102,61,-54,125,117,6,102,5,3,3,-119,2,-2,-62,61,65,65,65,65,117,-23,-1,-26,-24,-33,-1,-1,-1,49,-46,106,11,88,-103,82,104,47,47,115,104,104,47,98,105,110,-119,-29,82,83,-119,-31,-54,125,65,65,65,65};
public static final byte[] X86_CODE32_LOOP = {65,74,-21,-2};
public static final byte[] X86_CODE32_MEM_WRITE = {-119,13,-86,-86,-86,-86,65,74};
public static final byte[] X86_CODE32_MEM_READ = {-117,13,-86,-86,-86,-86,65,74};
public static final byte[] X86_CODE32_JMP_INVALID = {-23,-23,-18,-18,-18,65,74};
public static final byte[] X86_CODE32_INOUT = {65,-28,63,74,-26,70,67};
public static final byte[] X86_CODE64 = {65,-68,59,-80,40,42,73,15,-55,-112,77,15,-83,-49,73,-121,-3,-112,72,-127,-46,-118,-50,119,53,72,-9,-39,77,41,-12,73,-127,-55,-10,-118,-58,83,77,-121,-19,72,15,-83,-46,73,-9,-44,72,-9,-31,77,25,-59,77,-119,-59,72,-9,-42,65,-72,79,-115,107,89,77,-121,-48,104,106,30,9,60,89};
// memory address where emulation starts
public static final int ADDRESS = 0x1000000;
public static final long toInt(byte val[]) {
long res = 0;
for (int i = 0; i < val.length; i++) {
long v = val[i] & 0xff;
res = res + (v << (i * 8));
}
return res;
}
public static final byte[] toBytes(long val) {
byte[] res = new byte[8];
for (int i = 0; i < 8; i++) {
res[i] = (byte)(val & 0xff);
val >>>= 8;
}
return res;
}
// callback for tracing basic blocks
// callback for tracing instruction
private static class MyBlockHook implements BlockHook {
public void hook(Unicorn u, long address, int size, Object user_data)
{
System.out.print(String.format(">>> Tracing basic block at 0x%x, block size = 0x%x\n", address, size));
}
}
// callback for tracing instruction
private static class MyCodeHook implements CodeHook {
public void hook(Unicorn u, long address, int size, Object user_data) {
System.out.print(String.format(">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", address, size));
byte eflags[] = u.reg_read(Unicorn.UC_X86_REG_EFLAGS, 4);
System.out.print(String.format(">>> --- EFLAGS is 0x%x\n", toInt(eflags)));
// Uncomment below code to stop the emulation using uc_emu_stop()
// if (address == 0x1000009)
// u.emu_stop();
}
}
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.print(String.format(">>> 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);
// return true to indicate we want to continue
return true;
}
return false;
}
}
// callback for tracing instruction
private static class MyCode64Hook implements CodeHook {
public void hook(Unicorn u, long address, int size, Object user_data) {
byte[] r_rip = u.reg_read(Unicorn.UC_X86_REG_RIP, 8);
System.out.print(String.format(">>> Tracing instruction at 0x%x, instruction size = 0x%x\n", address, size));
System.out.print(String.format(">>> RIP is 0x%x\n", toInt(r_rip)));
// Uncomment below code to stop the emulation using uc_emu_stop()
// if (address == 0x1000009)
// uc_emu_stop(handle);
}
}
private static class MyRead64Hook implements ReadHook {
public void hook(Unicorn u, long address, int size, Object user) {
System.out.print(String.format(">>> Memory is being READ at 0x%x, data size = %d\n", address, size));
}
}
private static class MyWrite64Hook implements WriteHook {
public void hook(Unicorn u, long address, int size, long value, Object user) {
System.out.print(String.format(">>> Memory is being WRITE at 0x%x, data size = %d, data value = 0x%x\n",
address, size, value));
}
}
// callback for IN instruction (X86).
// this returns the data read from the port
private static class MyInHook implements InHook {
public int hook(Unicorn u, int port, int size, Object user_data)
{
byte[] r_eip = u.reg_read(Unicorn.UC_X86_REG_EIP, 4);
System.out.print(String.format("--- reading from port 0x%x, size: %d, address: 0x%x\n", port, size, toInt(r_eip)));
switch(size) {
case 1:
// read 1 byte to AL
return 0xf1;
case 2:
// read 2 byte to AX
return 0xf2;
case 4:
// read 4 byte to EAX
return 0xf4;
}
return 0;
}
}
// callback for OUT instruction (X86).
private static class MyOutHook implements OutHook {
public void hook(Unicorn u, int port, int size, int value, Object user) {
byte[] eip = u.reg_read(Unicorn.UC_X86_REG_EIP, 4);
byte[] tmp = null;
System.out.print(String.format("--- writing to port 0x%x, size: %d, value: 0x%x, address: 0x%x\n", port, size, value, toInt(eip)));
// confirm that value is indeed the value of AL/AX/EAX
switch(size) {
default:
return; // should never reach this
case 1:
tmp = u.reg_read(Unicorn.UC_X86_REG_AL, 1);
break;
case 2:
tmp = u.reg_read(Unicorn.UC_X86_REG_AX, 2);
break;
case 4:
tmp = u.reg_read(Unicorn.UC_X86_REG_EAX, 4);
break;
}
System.out.print(String.format("--- register value = 0x%x\n", toInt(tmp)));
}
}
static void test_i386()
{
byte r_ecx[] = {(byte)0x34, (byte)0x12, 0, 0}; //0x1234; // ECX register
byte r_edx[] = {(byte)0x90, (byte)0x78, 0, 0}; //0x7890; // EDX register
System.out.print("Emulate i386 code\n");
// Initialize emulator in X86-32bit mode
Unicorn uc;
try {
uc = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
} catch (UnicornException uex) {
System.out.println("Failed on uc_open() with error returned: " + uex);
return;
}
// map 2MB memory for this emulation
uc.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
try {
uc.mem_write(ADDRESS, X86_CODE32);
} catch (UnicornException uex) {
System.out.println("Failed to write emulation code to memory, quit!\n");
return;
}
// initialize machine registers
uc.reg_write(Unicorn.UC_X86_REG_ECX, r_ecx);
uc.reg_write(Unicorn.UC_X86_REG_EDX, r_edx);
// tracing all basic blocks with customized callback
uc.hook_add(new MyBlockHook(), 1, 0, null);
// tracing all instruction by having @begin > @end
uc.hook_add(new MyCodeHook(), 1, 0, null);
// emulate machine code in infinite time
try {
uc.emu_start(ADDRESS, ADDRESS + X86_CODE32.length, 0, 0);
} catch (UnicornException uex) {
System.out.print(String.format("Failed on uc_emu_start() with error : %s\n",
uex.getMessage()));
}
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
r_ecx = uc.reg_read(Unicorn.UC_X86_REG_ECX, 4);
r_edx = uc.reg_read(Unicorn.UC_X86_REG_EDX, 4);
System.out.print(String.format(">>> ECX = 0x%x\n", toInt(r_ecx)));
System.out.print(String.format(">>> EDX = 0x%x\n", toInt(r_edx)));
// read from memory
try {
byte tmp[] = uc.mem_read(ADDRESS, 4);
System.out.print(String.format(">>> Read 4 bytes from [0x%x] = 0x%x\n", ADDRESS, toInt(tmp)));
} catch (UnicornException ex) {
System.out.print(String.format(">>> Failed to read 4 bytes from [0x%x]\n", ADDRESS));
}
uc.close();
}
static void test_i386_inout()
{
byte[] r_eax = {0x34, 0x12, 0, 0}; //0x1234; // EAX register
byte[] r_ecx = {(byte)0x89, 0x67, 0, 0}; //0x6789; // ECX register
System.out.print("===================================\n");
System.out.print("Emulate i386 code with IN/OUT instructions\n");
// Initialize emulator in X86-32bit mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, X86_CODE32_INOUT);
// initialize machine registers
u.reg_write(Unicorn.UC_X86_REG_EAX, r_eax);
u.reg_write(Unicorn.UC_X86_REG_ECX, r_ecx);
// tracing all basic blocks with customized callback
u.hook_add(new MyBlockHook(), 1, 0, null);
// tracing all instructions
u.hook_add(new MyCodeHook(), 1, 0, null);
// handle IN instruction
u.hook_add(new MyInHook(), null);
// handle OUT instruction
u.hook_add(new MyOutHook(), null);
// emulate machine code in infinite time
u.emu_start(ADDRESS, ADDRESS + X86_CODE32_INOUT.length, 0, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
r_eax = u.reg_read(Unicorn.UC_X86_REG_EAX, 4);
r_ecx = u.reg_read(Unicorn.UC_X86_REG_ECX, 4);
System.out.print(String.format(">>> EAX = 0x%x\n", toInt(r_eax)));
System.out.print(String.format(">>> ECX = 0x%x\n", toInt(r_ecx)));
u.close();
}
static void test_i386_jump()
{
System.out.print("===================================\n");
System.out.print("Emulate i386 code with jump\n");
// Initialize emulator in X86-32bit mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, X86_CODE32_JUMP);
// tracing 1 basic block with customized callback
u.hook_add(new MyBlockHook(), ADDRESS, ADDRESS, null);
// tracing 1 instruction at ADDRESS
u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null);
// emulate machine code in infinite time
u.emu_start(ADDRESS, ADDRESS + X86_CODE32_JUMP.length, 0, 0);
System.out.print(">>> Emulation done. Below is the CPU context\n");
u.close();
}
// emulate code that loop forever
static void test_i386_loop()
{
byte r_ecx[] = {(byte)0x34, (byte)0x12, 0, 0}; //0x1234; // ECX register
byte r_edx[] = {(byte)0x90, (byte)0x78, 0, 0}; //0x7890; // EDX register
System.out.print("===================================\n");
System.out.print("Emulate i386 code that loop forever\n");
// Initialize emulator in X86-32bit mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, X86_CODE32_LOOP);
// initialize machine registers
u.reg_write(Unicorn.UC_X86_REG_ECX, r_ecx);
u.reg_write(Unicorn.UC_X86_REG_EDX, r_edx);
// emulate machine code in 2 seconds, so we can quit even
// if the code loops
u.emu_start(ADDRESS, ADDRESS + X86_CODE32_LOOP.length, 2 * Unicorn.UC_SECOND_SCALE, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
r_ecx = u.reg_read(Unicorn.UC_X86_REG_ECX, 4);
r_edx = u.reg_read(Unicorn.UC_X86_REG_EDX, 4);
System.out.print(String.format(">>> ECX = 0x%x\n", toInt(r_ecx)));
System.out.print(String.format(">>> EDX = 0x%x\n", toInt(r_edx)));
u.close();
}
// emulate code that read invalid memory
static void test_i386_invalid_mem_read()
{
byte r_ecx[] = {(byte)0x34, (byte)0x12, 0, 0}; //0x1234; // ECX register
byte r_edx[] = {(byte)0x90, (byte)0x78, 0, 0}; //0x7890; // EDX register
System.out.print("===================================\n");
System.out.print("Emulate i386 code that read from invalid memory\n");
// Initialize emulator in X86-32bit mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, X86_CODE32_MEM_READ);
// initialize machine registers
u.reg_write(Unicorn.UC_X86_REG_ECX, r_ecx);
u.reg_write(Unicorn.UC_X86_REG_EDX, r_edx);
// tracing all basic blocks with customized callback
u.hook_add(new MyBlockHook(), 1, 0, null);
// tracing all instruction by having @begin > @end
u.hook_add(new MyCodeHook(), 1, 0, null);
// emulate machine code in infinite time
u.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_READ.length, 0, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
r_ecx = u.reg_read(Unicorn.UC_X86_REG_ECX, 4);
r_edx = u.reg_read(Unicorn.UC_X86_REG_EDX, 4);
System.out.print(String.format(">>> ECX = 0x%x\n", toInt(r_ecx)));
System.out.print(String.format(">>> EDX = 0x%x\n", toInt(r_edx)));
u.close();
}
// emulate code that read invalid memory
static void test_i386_invalid_mem_write()
{
byte r_ecx[] = {(byte)0x34, (byte)0x12, 0, 0}; //0x1234; // ECX register
byte r_edx[] = {(byte)0x90, (byte)0x78, 0, 0}; //0x7890; // EDX register
System.out.print("===================================\n");
System.out.print("Emulate i386 code that write to invalid memory\n");
// Initialize emulator in X86-32bit mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, X86_CODE32_MEM_WRITE);
// initialize machine registers
u.reg_write(Unicorn.UC_X86_REG_ECX, r_ecx);
u.reg_write(Unicorn.UC_X86_REG_EDX, r_edx);
// tracing all basic blocks with customized callback
u.hook_add(new MyBlockHook(), 1, 0, null);
// tracing all instruction by having @begin > @end
u.hook_add(new MyCodeHook(), 1, 0, null);
// intercept invalid memory events
u.hook_add(new MyMemInvalidHook(), null);
// emulate machine code in infinite time
u.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_WRITE.length, 0, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
r_ecx = u.reg_read(Unicorn.UC_X86_REG_ECX, 4);
r_edx = u.reg_read(Unicorn.UC_X86_REG_EDX, 4);
System.out.print(String.format(">>> ECX = 0x%x\n", toInt(r_ecx)));
System.out.print(String.format(">>> EDX = 0x%x\n", toInt(r_edx)));
// read from memory
byte tmp[] = u.mem_read(0xaaaaaaaa, 4);
System.out.print(String.format(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xaaaaaaaa, toInt(tmp)));
u.mem_read(0xffffffaa, 4);
System.out.print(String.format(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xffffffaa, toInt(tmp)));
u.close();
}
// emulate code that jump to invalid memory
static void test_i386_jump_invalid()
{
byte r_ecx[] = {(byte)0x34, (byte)0x12, 0, 0}; //0x1234; // ECX register
byte r_edx[] = {(byte)0x90, (byte)0x78, 0, 0}; //0x7890; // EDX register
System.out.print("===================================\n");
System.out.print("Emulate i386 code that jumps to invalid memory\n");
// Initialize emulator in X86-32bit mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, X86_CODE32_JMP_INVALID);
// initialize machine registers
u.reg_write(Unicorn.UC_X86_REG_ECX, r_ecx);
u.reg_write(Unicorn.UC_X86_REG_EDX, r_edx);
// tracing all basic blocks with customized callback
u.hook_add(new MyBlockHook(), 1, 0, null);
// tracing all instructions by having @begin > @end
u.hook_add(new MyCodeHook(), 1, 0, null);
// emulate machine code in infinite time
u.emu_start(ADDRESS, ADDRESS + X86_CODE32_JMP_INVALID.length, 0, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
r_ecx = u.reg_read(Unicorn.UC_X86_REG_ECX, 4);
r_edx = u.reg_read(Unicorn.UC_X86_REG_EDX, 4);
System.out.print(String.format(">>> ECX = 0x%x\n", toInt(r_ecx)));
System.out.print(String.format(">>> EDX = 0x%x\n", toInt(r_edx)));
u.close();
}
static void test_x86_64()
{
long rax = 0x71f3029efd49d41dL;
long rbx = 0xd87b45277f133ddbL;
long rcx = 0xab40d1ffd8afc461L;
long rdx = 0x919317b4a733f01L;
long rsi = 0x4c24e753a17ea358L;
long rdi = 0xe509a57d2571ce96L;
long r8 = 0xea5b108cc2b9ab1fL;
long r9 = 0x19ec097c8eb618c1L;
long r10 = 0xec45774f00c5f682L;
long r11 = 0xe17e9dbec8c074aaL;
long r12 = 0x80f86a8dc0f6d457L;
long r13 = 0x48288ca5671c5492L;
long r14 = 0x595f72f6e4017f6eL;
long r15 = 0x1efd97aea331ccccL;
long rsp = ADDRESS + 0x200000;
System.out.print("Emulate x86_64 code\n");
// Initialize emulator in X86-64bit mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_64);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, X86_CODE64);
// initialize machine registers
u.reg_write(Unicorn.UC_X86_REG_RSP, toBytes(rsp));
u.reg_write(Unicorn.UC_X86_REG_RAX, toBytes(rax));
u.reg_write(Unicorn.UC_X86_REG_RBX, toBytes(rbx));
u.reg_write(Unicorn.UC_X86_REG_RCX, toBytes(rcx));
u.reg_write(Unicorn.UC_X86_REG_RDX, toBytes(rdx));
u.reg_write(Unicorn.UC_X86_REG_RSI, toBytes(rsi));
u.reg_write(Unicorn.UC_X86_REG_RDI, toBytes(rdi));
u.reg_write(Unicorn.UC_X86_REG_R8, toBytes(r8));
u.reg_write(Unicorn.UC_X86_REG_R9, toBytes(r9));
u.reg_write(Unicorn.UC_X86_REG_R10, toBytes(r10));
u.reg_write(Unicorn.UC_X86_REG_R11, toBytes(r11));
u.reg_write(Unicorn.UC_X86_REG_R12, toBytes(r12));
u.reg_write(Unicorn.UC_X86_REG_R13, toBytes(r13));
u.reg_write(Unicorn.UC_X86_REG_R14, toBytes(r14));
u.reg_write(Unicorn.UC_X86_REG_R15, toBytes(r15));
// tracing all basic blocks with customized callback
u.hook_add(new MyBlockHook(), 1, 0, null);
// tracing all instructions in the range [ADDRESS, ADDRESS+20]
u.hook_add(new MyCode64Hook(), ADDRESS, ADDRESS+20, null);
// tracing all memory WRITE access (with @begin > @end)
u.hook_add(new MyWrite64Hook(), 1, 0, null);
// tracing all memory READ access (with @begin > @end)
u.hook_add(new MyRead64Hook(), 1, 0, null);
// emulate machine code in infinite time (last param = 0), or when
// finishing all the code.
u.emu_start(ADDRESS, ADDRESS + X86_CODE64.length, 0, 0);
// now print out some registers
System.out.print(">>> Emulation done. Below is the CPU context\n");
byte[] r_rax = u.reg_read(Unicorn.UC_X86_REG_RAX, 8);
byte[] r_rbx = u.reg_read(Unicorn.UC_X86_REG_RBX, 8);
byte[] r_rcx = u.reg_read(Unicorn.UC_X86_REG_RCX, 8);
byte[] r_rdx = u.reg_read(Unicorn.UC_X86_REG_RDX, 8);
byte[] r_rsi = u.reg_read(Unicorn.UC_X86_REG_RSI, 8);
byte[] r_rdi = u.reg_read(Unicorn.UC_X86_REG_RDI, 8);
byte[] r_r8 = u.reg_read(Unicorn.UC_X86_REG_R8, 8);
byte[] r_r9 = u.reg_read(Unicorn.UC_X86_REG_R9, 8);
byte[] r_r10 = u.reg_read(Unicorn.UC_X86_REG_R10, 8);
byte[] r_r11 = u.reg_read(Unicorn.UC_X86_REG_R11, 8);
byte[] r_r12 = u.reg_read(Unicorn.UC_X86_REG_R12, 8);
byte[] r_r13 = u.reg_read(Unicorn.UC_X86_REG_R13, 8);
byte[] r_r14 = u.reg_read(Unicorn.UC_X86_REG_R14, 8);
byte[] r_r15 = u.reg_read(Unicorn.UC_X86_REG_R15, 8);
System.out.print(String.format(">>> RAX = 0x%x\n", toInt(r_rax)));
System.out.print(String.format(">>> RBX = 0x%x\n", toInt(r_rbx)));
System.out.print(String.format(">>> RCX = 0x%x\n", toInt(r_rcx)));
System.out.print(String.format(">>> RDX = 0x%x\n", toInt(r_rdx)));
System.out.print(String.format(">>> RSI = 0x%x\n", toInt(r_rsi)));
System.out.print(String.format(">>> RDI = 0x%x\n", toInt(r_rdi)));
System.out.print(String.format(">>> R8 = 0x%x\n", toInt(r_r8)));
System.out.print(String.format(">>> R9 = 0x%x\n", toInt(r_r9)));
System.out.print(String.format(">>> R10 = 0x%x\n", toInt(r_r10)));
System.out.print(String.format(">>> R11 = 0x%x\n", toInt(r_r11)));
System.out.print(String.format(">>> R12 = 0x%x\n", toInt(r_r12)));
System.out.print(String.format(">>> R13 = 0x%x\n", toInt(r_r13)));
System.out.print(String.format(">>> R14 = 0x%x\n", toInt(r_r14)));
System.out.print(String.format(">>> R15 = 0x%x\n", toInt(r_r15)));
u.close();
}
public static void main(String args[])
{
if (args.length == 1) {
if (args[0].equals("-32")) {
test_i386();
test_i386_inout();
test_i386_jump();
test_i386_loop();
test_i386_invalid_mem_read();
test_i386_invalid_mem_write();
test_i386_jump_invalid();
}
if (args[0].equals("-64")) {
test_x86_64();
}
// test memleak
if (args[0].equals("-0")) {
while(true) {
test_i386();
// test_x86_64();
}
}
} else {
System.out.print("Syntax: java Sample_x86 <-32|-64>\n");
}
}
}

View File

@ -0,0 +1,161 @@
/*
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.
*/
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh & Dang Hoang Vu, 2015 */
/* Sample code to trace code with Linux code with syscall */
import unicorn.*;
import java.math.*;
public class Shellcode {
public static final byte[] X86_CODE32 = {-21,25,49,-64,49,-37,49,-46,49,-55,-80,4,-77,1,89,-78,5,-51,-128,49,-64,-80,1,49,-37,-51,-128,-24,-30,-1,-1,-1,104,101,108,108,111};
public static final byte[] X86_CODE32_SELF = {-21,28,90,-119,-42,-117,2,102,61,-54,125,117,6,102,5,3,3,-119,2,-2,-62,61,65,65,65,65,117,-23,-1,-26,-24,-33,-1,-1,-1,49,-46,106,11,88,-103,82,104,47,47,115,104,104,47,98,105,110,-119,-29,82,83,-119,-31,-54,125,65,65,65,65,65,65,65,65};
// memory address where emulation starts
public static final int ADDRESS = 0x1000000;
public static final long toInt(byte val[]) {
long res = 0;
for (int i = 0; i < val.length; i++) {
long v = val[i] & 0xff;
res = res + (v << (i * 8));
}
return res;
}
public static final byte[] toBytes(long val) {
byte[] res = new byte[8];
for (int i = 0; i < 8; i++) {
res[i] = (byte)(val & 0xff);
val >>>= 8;
}
return res;
}
public static class MyCodeHook implements CodeHook {
public void hook(Unicorn u, long address, int size, Object user) {
System.out.print(String.format("Tracing instruction at 0x%x, instruction size = 0x%x\n", address, size));
byte[] r_eip = u.reg_read(Unicorn.UC_X86_REG_EIP, 4);
System.out.print(String.format("*** EIP = %x ***: ", toInt(r_eip)));
size = Math.min(16, size);
byte[] tmp = u.mem_read(address, size);
for (int i = 0; i < tmp.length; i++) {
System.out.print(String.format("%x ", 0xff & tmp[i]));
}
System.out.print("\n");
}
};
public static class MyInterruptHook implements InterruptHook {
public void hook(Unicorn u, int intno, Object user) {
long r_ecx;
long r_edx;
int size;
// only handle Linux syscall
if (intno != 0x80) {
return;
}
long r_eax = toInt(u.reg_read(Unicorn.UC_X86_REG_EAX, 4));
long r_eip = toInt(u.reg_read(Unicorn.UC_X86_REG_EIP, 4));
switch ((int)r_eax) {
default:
System.out.print(String.format(">>> 0x%x: interrupt 0x%x, EAX = 0x%x\n", r_eip, intno, r_eax));
break;
case 1: // sys_exit
System.out.print(String.format(">>> 0x%x: interrupt 0x%x, SYS_EXIT. quit!\n\n", r_eip, intno));
u.emu_stop();
break;
case 4: // sys_write
// ECX = buffer address
r_ecx = toInt(u.reg_read(Unicorn.UC_X86_REG_ECX, 4));
// EDX = buffer size
r_edx = toInt(u.reg_read(Unicorn.UC_X86_REG_EDX, 4));
// read the buffer in
size = (int)Math.min(256, r_edx);
byte[] buffer = u.mem_read(r_ecx, size);
System.out.print(String.format(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = '%s'\n",
r_eip, intno, r_ecx, r_edx, new String(buffer)));
break;
}
}
}
static void test_i386()
{
long r_esp = ADDRESS + 0x200000; // ESP register
System.out.print("Emulate i386 code\n");
// Initialize emulator in X86-32bit mode
Unicorn u = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, X86_CODE32_SELF);
// initialize machine registers
u.reg_write(Unicorn.UC_X86_REG_ESP, toBytes(r_esp));
// tracing all instructions by having @begin > @end
u.hook_add(new MyCodeHook(), 1, 0, null);
// handle interrupt ourself
u.hook_add(new MyInterruptHook(), null);
System.out.print("\n>>> Start tracing this Linux code\n");
// emulate machine code in infinite time
// u.emu_start(ADDRESS, ADDRESS + X86_CODE32_SELF.length, 0, 12); <--- emulate only 12 instructions
u.emu_start(ADDRESS, ADDRESS + X86_CODE32_SELF.length, 0, 0);
System.out.print("\n>>> Emulation done.\n");
u.close();
}
public static void main(String args[])
{
if (args.length == 1) {
if ("-32".equals(args[0])) {
test_i386();
}
} else {
System.out.print("Syntax: java Shellcode <-32|-64>\n");
}
}
}