Files
unicorn/bindings/java/samples/Shellcode.java
Robert Xiao 4f563490e2 Update Java samples to match C samples.
Also add all of the samples as Java tests, referencing the output of the C
samples.
2023-06-17 14:19:10 -07:00

146 lines
4.6 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.
*/
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh & Dang Hoang Vu, 2015 */
/* Sample code to trace code with Linux code with syscall */
package samples;
import unicorn.*;
public class Shellcode implements UnicornConst, X86Const {
public static final byte[] X86_CODE32_SELF = Utils.hexToBytes(
"eb1c5a89d68b02663dca7d75066605030389" +
"02fec23d4141414175e9ffe6e8dfffffff31" +
"d26a0b589952682f2f7368682f62696e89e3" +
"525389e1ca7d4141414141414141");
// memory address where emulation starts
public static final int ADDRESS = 0x1000000;
public static CodeHook hook_code = (u, address, size, user) -> {
System.out.format(
"Tracing instruction at 0x%x, instruction size = 0x%x\n",
address, size);
long r_eip = u.reg_read(UC_X86_REG_EIP);
System.out.format("*** EIP = %x ***: ", r_eip);
byte[] tmp = u.mem_read(address, size);
for (int i = 0; i < tmp.length; i++) {
System.out.format("%x ", 0xff & tmp[i]);
}
System.out.println();
};
public static InterruptHook hook_intr = (u, intno, user) -> {
// only handle Linux syscall
if (intno != 0x80) {
return;
}
long r_eax = u.reg_read(UC_X86_REG_EAX);
long r_eip = u.reg_read(UC_X86_REG_EIP);
switch ((int) r_eax) {
default:
System.out.format(">>> 0x%x: interrupt 0x%x, EAX = 0x%x\n",
r_eip, intno, r_eax);
break;
case 1: // sys_exit
System.out.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
long r_ecx = u.reg_read(UC_X86_REG_ECX);
// EDX = buffer size
long r_edx = u.reg_read(UC_X86_REG_EDX);
// read the buffer in
int size = (int) Math.min(256, r_edx);
try {
byte[] buffer = u.mem_read(r_ecx, size);
System.out.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));
} catch (UnicornException e) {
System.out.format(
">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u (cannot get content)\n",
r_eip, intno, r_ecx, r_edx);
}
break;
}
}
};
public static void test_i386() {
long r_esp = ADDRESS + 0x200000L; // ESP register
System.out.println("Emulate i386 code");
// Initialize emulator in X86-32bit mode
Unicorn u = new Unicorn(UC_ARCH_X86, UC_MODE_32);
// map 2MB memory for this emulation
u.mem_map(ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
// write machine code to be emulated to memory
u.mem_write(ADDRESS, X86_CODE32_SELF);
// initialize machine registers
u.reg_write(UC_X86_REG_ESP, r_esp);
// tracing all instructions by having @begin > @end
u.hook_add(hook_code, 1, 0, null);
// handle interrupt ourself
u.hook_add(hook_intr, null);
System.out.println("\n>>> Start tracing this Linux code");
// 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.println("\n>>> Emulation done.");
}
public static void main(String args[]) {
if (args.length == 1) {
if ("-32".equals(args[0])) {
test_i386();
}
} else {
System.out.println("Syntax: java Shellcode <-32|-64>");
}
}
}