Update Java samples to match C samples.
Also add all of the samples as Java tests, referencing the output of the C samples.
This commit is contained in:
@@ -26,94 +26,262 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
package samples;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import unicorn.*;
|
||||
|
||||
public class Sample_arm64 {
|
||||
public class Sample_arm64 implements UnicornConst, Arm64Const {
|
||||
|
||||
// code to be emulated
|
||||
public static final byte[] ARM_CODE = { -85, 1, 15, -117 }; // add x11, x13, x15
|
||||
/** code to be emulated {@code str w11, [x13], #0; ldrb w15, [x13], #0} */
|
||||
private static final byte[] ARM64_CODE =
|
||||
Utils.hexToBytes("ab0500b8af054038");
|
||||
|
||||
/** code to be emulated {@code str w11, [x13]; ldrb w15, [x13]} */
|
||||
//private static final byte[] ARM64_CODE_EB = Utils.hexToBytes("b80005ab384005af"); // str w11, [x13];
|
||||
|
||||
private static final byte[] ARM64_CODE_EB = ARM64_CODE;
|
||||
|
||||
/** code to be emulated {@code mrs x2, tpidrro_el0} */
|
||||
private static final byte[] ARM64_MRS_CODE = Utils.hexToBytes("62d03bd5");
|
||||
|
||||
/** code to be emulated {@code paciza x1} */
|
||||
private static final byte[] ARM64_PAC_CODE = Utils.hexToBytes("e123c1da");
|
||||
|
||||
// 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 final BlockHook hook_block =
|
||||
(uc, address, size, user_data) -> {
|
||||
System.out.format(
|
||||
">>> Tracing basic block at 0x%x, block size = 0x%x\n",
|
||||
address, size);
|
||||
};
|
||||
|
||||
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(
|
||||
private static final CodeHook hook_code =
|
||||
(uc, address, size, user_data) -> {
|
||||
System.out.format(
|
||||
">>> Tracing instruction at 0x%x, instruction size = 0x%x\n",
|
||||
address, size));
|
||||
}
|
||||
address, size);
|
||||
};
|
||||
|
||||
public static void test_arm64_mem_fetch() {
|
||||
// msr x0, CurrentEL
|
||||
byte[] shellcode0 = { 64, 66, 56, (byte) 213 };
|
||||
// .text:00000000004002C0 LDR X1, [SP,#arg_0]
|
||||
byte[] shellcode = { (byte) 0xE1, 0x03, 0x40, (byte) 0xF9 };
|
||||
long shellcode_address = 0x4002C0L;
|
||||
long data_address = 0x10000000000000L;
|
||||
|
||||
System.out.format(
|
||||
">>> Emulate ARM64 fetching stack data from high address %x\n",
|
||||
data_address);
|
||||
|
||||
// Initialize emulator in ARM mode
|
||||
Unicorn uc = new Unicorn(UC_ARCH_ARM64, UC_MODE_ARM);
|
||||
|
||||
uc.mem_map(data_address, 0x30000, UC_PROT_ALL);
|
||||
uc.mem_map(0x400000, 0x1000, UC_PROT_ALL);
|
||||
|
||||
uc.reg_write(UC_ARM64_REG_SP, data_address);
|
||||
byte[] data = new byte[8];
|
||||
Arrays.fill(data, (byte) 0xc8);
|
||||
uc.mem_write(data_address, data);
|
||||
uc.mem_write(shellcode_address, shellcode0);
|
||||
uc.mem_write(shellcode_address + 4, shellcode);
|
||||
|
||||
uc.emu_start(shellcode_address, shellcode_address + 4, 0, 0);
|
||||
|
||||
long x0 = uc.reg_read(UC_ARM64_REG_X0);
|
||||
System.out.format(">>> x0(Exception Level)=%x\n", x0 >> 2);
|
||||
|
||||
uc.emu_start(shellcode_address + 4, shellcode_address + 8, 0, 0);
|
||||
|
||||
long x1 = uc.reg_read(UC_ARM64_REG_X1);
|
||||
|
||||
System.out.format(">>> X1 = 0x%x\n", x1);
|
||||
}
|
||||
|
||||
public static void test_arm64() {
|
||||
long x11 = 0x12345678; // X11 register
|
||||
long x13 = 0x10000 + 0x8; // X13 register
|
||||
long x15 = 0x33; // X15 register
|
||||
|
||||
long x11 = 0x1234L; // X11 register
|
||||
long x13 = 0x6789L; // X13 register
|
||||
long x15 = 0x3333L; // X15 register
|
||||
|
||||
System.out.print("Emulate ARM64 code\n");
|
||||
System.out.println("Emulate ARM64 code");
|
||||
|
||||
// Initialize emulator in ARM mode
|
||||
Unicorn u = new Unicorn(Unicorn.UC_ARCH_ARM64, Unicorn.UC_MODE_ARM);
|
||||
Unicorn uc = new Unicorn(UC_ARCH_ARM64, UC_MODE_ARM);
|
||||
|
||||
// map 2MB memory for this emulation
|
||||
u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL);
|
||||
uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
u.mem_write(ADDRESS, ARM_CODE);
|
||||
uc.mem_write(ADDRESS, ARM64_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);
|
||||
uc.reg_write(UC_ARM64_REG_X11, x11);
|
||||
uc.reg_write(UC_ARM64_REG_X13, x13);
|
||||
uc.reg_write(UC_ARM64_REG_X15, x15);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
u.hook_add(new MyBlockHook(), 1, 0, null);
|
||||
uc.hook_add(hook_block, 1, 0, null);
|
||||
|
||||
// tracing one instruction at ADDRESS with customized callback
|
||||
u.hook_add(new MyCodeHook(), ADDRESS, ADDRESS, null);
|
||||
uc.hook_add(hook_code, 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);
|
||||
uc.emu_start(ADDRESS, ADDRESS + ARM64_CODE.length, 0, 0);
|
||||
|
||||
// now print out some registers
|
||||
System.out.print(">>> Emulation done. Below is the CPU context\n");
|
||||
System.out.println(">>> Emulation done. Below is the CPU context");
|
||||
System.out.println(">>> As little endian, X15 should be 0x78:");
|
||||
System.out.format(">>> X15 = 0x%x\n", uc.reg_read(UC_ARM64_REG_X15));
|
||||
}
|
||||
|
||||
x11 = u.reg_read(Unicorn.UC_ARM64_REG_X11);
|
||||
System.out.print(String.format(">>> X11 = 0x%x\n", x11));
|
||||
public static void test_arm64eb() {
|
||||
long x11 = 0x12345678; // X11 register
|
||||
long x13 = 0x10000 + 0x8; // X13 register
|
||||
long x15 = 0x33; // X15 register
|
||||
|
||||
u.close();
|
||||
System.out.println("Emulate ARM64 Big-Endian code");
|
||||
|
||||
// Initialize emulator in ARM mode
|
||||
Unicorn uc =
|
||||
new Unicorn(UC_ARCH_ARM64, UC_MODE_ARM + UC_MODE_BIG_ENDIAN);
|
||||
|
||||
// map 2MB memory for this emulation
|
||||
uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
uc.mem_write(ADDRESS, ARM64_CODE_EB);
|
||||
|
||||
// initialize machine registers
|
||||
uc.reg_write(UC_ARM64_REG_X11, x11);
|
||||
uc.reg_write(UC_ARM64_REG_X13, x13);
|
||||
uc.reg_write(UC_ARM64_REG_X15, x15);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc.hook_add(hook_block, 1, 0, null);
|
||||
|
||||
// tracing one instruction at ADDRESS with customized callback
|
||||
uc.hook_add(hook_code, ADDRESS, ADDRESS, null);
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
uc.emu_start(ADDRESS, ADDRESS + ARM64_CODE_EB.length, 0, 0);
|
||||
|
||||
// now print out some registers
|
||||
System.out.println(">>> Emulation done. Below is the CPU context");
|
||||
System.out.println(">>> As big endian, X15 should be 0x78:");
|
||||
System.out.format(">>> X15 = 0x%x\n", uc.reg_read(UC_ARM64_REG_X15));
|
||||
}
|
||||
|
||||
public static void test_arm64_sctlr() {
|
||||
long val;
|
||||
System.out.println("Read the SCTLR register.");
|
||||
|
||||
Unicorn uc =
|
||||
new Unicorn(UC_ARCH_ARM64, UC_MODE_LITTLE_ENDIAN | UC_MODE_ARM);
|
||||
|
||||
// SCTLR_EL1. See arm reference.
|
||||
Arm64_CP reg = new Arm64_CP(1, 0, 3, 0, 0);
|
||||
|
||||
val = (long) uc.reg_read(UC_ARM64_REG_CP_REG, reg);
|
||||
System.out.format(">>> SCTLR_EL1 = 0x%x\n", val);
|
||||
|
||||
reg.op1 = 0b100;
|
||||
val = (long) uc.reg_read(UC_ARM64_REG_CP_REG, reg);
|
||||
System.out.format(">>> SCTLR_EL2 = 0x%x\n", val);
|
||||
}
|
||||
|
||||
private static final Arm64SysHook hook_mrs =
|
||||
(uc, reg, cp_reg, user_data) -> {
|
||||
System.out
|
||||
.println(">>> Hook MSR instruction. Write 0x114514 to X2.");
|
||||
|
||||
uc.reg_write(reg, 0x114514L);
|
||||
|
||||
// Skip
|
||||
return 1;
|
||||
};
|
||||
|
||||
public static void test_arm64_hook_mrs() {
|
||||
System.out.println("Hook MRS instruction.");
|
||||
|
||||
Unicorn uc =
|
||||
new Unicorn(UC_ARCH_ARM64, UC_MODE_LITTLE_ENDIAN | UC_MODE_ARM);
|
||||
uc.mem_map(0x1000, 0x1000, UC_PROT_ALL);
|
||||
uc.mem_write(0x1000, ARM64_MRS_CODE);
|
||||
uc.hook_add(hook_mrs, UC_ARM64_INS_MRS, 1, 0, null);
|
||||
uc.emu_start(0x1000, 0x1000 + ARM64_MRS_CODE.length, 0, 0);
|
||||
System.out.format(">>> X2 = 0x%x\n", uc.reg_read(UC_ARM64_REG_X2));
|
||||
}
|
||||
|
||||
public static void test_arm64_pac() {
|
||||
long x1 = 0x0000aaaabbbbccccL;
|
||||
|
||||
System.out.println("Try ARM64 PAC");
|
||||
|
||||
// Initialize emulator in ARM mode
|
||||
Unicorn uc = new Unicorn(UC_ARCH_ARM64, UC_MODE_ARM);
|
||||
uc.ctl_set_cpu_model(UC_CPU_ARM64_MAX);
|
||||
uc.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||
uc.mem_write(ADDRESS, ARM64_PAC_CODE);
|
||||
uc.reg_write(UC_ARM64_REG_X1, x1);
|
||||
|
||||
/** Initialize PAC support **/
|
||||
Arm64_CP reg;
|
||||
|
||||
// SCR_EL3
|
||||
reg = new Arm64_CP(1, 1, 3, 6, 0);
|
||||
reg.val = (Long) uc.reg_read(UC_ARM64_REG_CP_REG, reg);
|
||||
// NS && RW && API
|
||||
reg.val |= (1 | (1L << 10) | (1L << 17));
|
||||
uc.reg_write(UC_ARM64_REG_CP_REG, reg);
|
||||
|
||||
// SCTLR_EL1
|
||||
reg = new Arm64_CP(1, 0, 3, 0, 0);
|
||||
reg.val = (Long) uc.reg_read(UC_ARM64_REG_CP_REG, reg);
|
||||
// EnIA && EnIB
|
||||
reg.val |= (1L << 31) | (1L << 30);
|
||||
uc.reg_write(UC_ARM64_REG_CP_REG, reg);
|
||||
|
||||
// HCR_EL2
|
||||
reg = new Arm64_CP(1, 1, 3, 4, 0);
|
||||
reg.val = (Long) uc.reg_read(UC_ARM64_REG_CP_REG, reg);
|
||||
// HCR.API
|
||||
reg.val |= (1L << 41);
|
||||
uc.reg_write(UC_ARM64_REG_CP_REG, reg);
|
||||
|
||||
/** Check that PAC worked **/
|
||||
uc.emu_start(ADDRESS, ADDRESS + ARM64_PAC_CODE.length, 0, 0);
|
||||
long new_x1 = uc.reg_read(UC_ARM64_REG_X1);
|
||||
|
||||
System.out.format("X1 = 0x%x\n", new_x1);
|
||||
if (new_x1 == x1) {
|
||||
System.out.println("FAIL: No PAC tag added!");
|
||||
} else {
|
||||
// Expect 0x1401aaaabbbbccccULL with the default key
|
||||
System.out.println("SUCCESS: PAC tag found.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
test_arm64_mem_fetch();
|
||||
|
||||
System.out.println("-------------------------");
|
||||
test_arm64();
|
||||
|
||||
System.out.println("-------------------------");
|
||||
test_arm64eb();
|
||||
|
||||
System.out.println("-------------------------");
|
||||
test_arm64_sctlr();
|
||||
|
||||
System.out.println("-------------------------");
|
||||
test_arm64_hook_mrs();
|
||||
|
||||
System.out.println("-------------------------");
|
||||
test_arm64_pac();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user