Files
unicorn/bindings/java/samples/Shellcode.java
2023-06-17 14:17:57 -07:00

174 lines
5.8 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 */
import unicorn.*;
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));
Long r_eip = (Long) u.reg_read(Unicorn.UC_X86_REG_EIP);
System.out.print(
String.format("*** EIP = %x ***: ", r_eip.intValue()));
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 = (Long) u.reg_read(Unicorn.UC_X86_REG_EAX);
Long r_eip = (Long) u.reg_read(Unicorn.UC_X86_REG_EIP);
switch (r_eax.intValue()) {
default:
System.out.print(
String.format(">>> 0x%x: interrupt 0x%x, EAX = 0x%x\n",
r_eip.intValue(), intno, r_eax.intValue()));
break;
case 1: // sys_exit
System.out.print(String.format(
">>> 0x%x: interrupt 0x%x, SYS_EXIT. quit!\n\n",
r_eip.intValue(), intno));
u.emu_stop();
break;
case 4: // sys_write
// ECX = buffer address
r_ecx = (Long) u.reg_read(Unicorn.UC_X86_REG_ECX);
// EDX = buffer size
r_edx = (Long) u.reg_read(Unicorn.UC_X86_REG_EDX);
// 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.intValue(), intno, r_ecx.intValue(),
r_edx.intValue(), new String(buffer)));
break;
}
}
}
static void test_i386() {
Long r_esp = ADDRESS + 0x200000L; // 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, Unicorn.UC_PROT_ALL);
// 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, 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");
}
}
}