Port sample_x86_32_gdt_and_seg_regs over to Sample_x86_mmr
This commit is contained in:
parent
4f563490e2
commit
edd80ddeda
@ -23,11 +23,83 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||||||
|
|
||||||
package samples;
|
package samples;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import unicorn.*;
|
import unicorn.*;
|
||||||
|
|
||||||
public class Sample_x86_mmr implements UnicornConst, X86Const {
|
public class Sample_x86_mmr implements UnicornConst, X86Const {
|
||||||
|
|
||||||
|
private static final MemHook hook_mem =
|
||||||
|
(uc, type, address, size, value, user_data) -> {
|
||||||
|
switch (type) {
|
||||||
|
case UC_MEM_WRITE:
|
||||||
|
System.out.format(
|
||||||
|
"mem write at 0x%x, size = %d, value = 0x%x\n",
|
||||||
|
address, size, value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private static final CodeHook hook_code =
|
||||||
|
(uc, address, size, user_data) -> {
|
||||||
|
System.out.format("Executing at 0x%x, ilen = 0x%x\n", address,
|
||||||
|
size);
|
||||||
|
};
|
||||||
|
|
||||||
|
public static class SegmentDescriptor {
|
||||||
|
public static final int BYTES = 8;
|
||||||
|
|
||||||
|
int base;
|
||||||
|
int limit;
|
||||||
|
|
||||||
|
byte type; // 4 bits
|
||||||
|
byte system; // 1 bit: S flag
|
||||||
|
byte dpl; // 2 bits
|
||||||
|
byte present; // 1 bit: P flag
|
||||||
|
byte avail; // 1 bit
|
||||||
|
byte is_64_code; // 1 bit: L flag
|
||||||
|
byte db; // 1 bit: DB flag
|
||||||
|
byte granularity; // 1 bit: G flag
|
||||||
|
|
||||||
|
public SegmentDescriptor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// VERY basic descriptor init function, sets many fields to user space sane
|
||||||
|
// defaults
|
||||||
|
public SegmentDescriptor(int base, int limit, boolean is_code) {
|
||||||
|
this.base = base;
|
||||||
|
if (limit > 0xfffff) {
|
||||||
|
// need Giant granularity
|
||||||
|
limit >>= 12;
|
||||||
|
this.granularity = 1;
|
||||||
|
}
|
||||||
|
this.limit = limit;
|
||||||
|
|
||||||
|
// some sane defaults
|
||||||
|
this.dpl = 3;
|
||||||
|
this.present = 1;
|
||||||
|
this.db = 1; // 32 bit
|
||||||
|
this.type = is_code ? (byte) 0xb : 3;
|
||||||
|
this.system = 1; // code or data
|
||||||
|
}
|
||||||
|
|
||||||
|
public void appendToBuffer(ByteBuffer buf) {
|
||||||
|
buf.putShort((short) limit);
|
||||||
|
buf.putShort((short) base);
|
||||||
|
buf.put((byte) (base >>> 16));
|
||||||
|
buf.put(
|
||||||
|
(byte) (type | (system << 4) | (dpl << 5) | (present << 7)));
|
||||||
|
buf.put((byte) (((limit >>> 16) & 0xf) | (avail << 4) |
|
||||||
|
(is_64_code << 5) | (db << 6) | (granularity << 7)));
|
||||||
|
buf.put((byte) (base >>> 24));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void test_x86_mmr() {
|
public static void test_x86_mmr() {
|
||||||
|
System.out.println("Test x86 MMR read/write");
|
||||||
// Initialize emulator in X86-32bit mode
|
// Initialize emulator in X86-32bit mode
|
||||||
Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32);
|
Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32);
|
||||||
|
|
||||||
@ -41,7 +113,7 @@ public class Sample_x86_mmr implements UnicornConst, X86Const {
|
|||||||
(short) 0xaaaa);
|
(short) 0xaaaa);
|
||||||
X86_MMR gdtr2;
|
X86_MMR gdtr2;
|
||||||
|
|
||||||
int eax;
|
long eax;
|
||||||
|
|
||||||
// initialize machine registers
|
// initialize machine registers
|
||||||
|
|
||||||
@ -50,7 +122,7 @@ public class Sample_x86_mmr implements UnicornConst, X86Const {
|
|||||||
uc.reg_write(UC_X86_REG_EAX, 0xddddddddL);
|
uc.reg_write(UC_X86_REG_EAX, 0xddddddddL);
|
||||||
|
|
||||||
// read the registers back out
|
// read the registers back out
|
||||||
eax = (int) uc.reg_read(UC_X86_REG_EAX);
|
eax = uc.reg_read(UC_X86_REG_EAX);
|
||||||
ldtr2 = (X86_MMR) uc.reg_read(UC_X86_REG_LDTR, null);
|
ldtr2 = (X86_MMR) uc.reg_read(UC_X86_REG_LDTR, null);
|
||||||
gdtr2 = (X86_MMR) uc.reg_read(UC_X86_REG_GDTR, null);
|
gdtr2 = (X86_MMR) uc.reg_read(UC_X86_REG_GDTR, null);
|
||||||
|
|
||||||
@ -65,8 +137,103 @@ public class Sample_x86_mmr implements UnicornConst, X86Const {
|
|||||||
System.out.printf(">>> GDTR.limit = 0x%x\n", gdtr2.limit);
|
System.out.printf(">>> GDTR.limit = 0x%x\n", gdtr2.limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void gdt_demo() {
|
||||||
|
System.out.println("Demonstrate GDT usage");
|
||||||
|
/*
|
||||||
|
bits 32
|
||||||
|
|
||||||
|
push dword 0x01234567
|
||||||
|
push dword 0x89abcdef
|
||||||
|
|
||||||
|
mov dword [fs:0], 0x01234567
|
||||||
|
mov dword [fs:4], 0x89abcdef
|
||||||
|
*/
|
||||||
|
final byte[] code =
|
||||||
|
Utils.hexToBytes("686745230168efcdab8964c70500000000" +
|
||||||
|
"6745230164c70504000000efcdab89");
|
||||||
|
final long code_address = 0x1000000L;
|
||||||
|
final long stack_address = 0x120000L;
|
||||||
|
final long gdt_address = 0xc0000000L;
|
||||||
|
final long fs_address = 0x7efdd000L;
|
||||||
|
|
||||||
|
SegmentDescriptor[] gdt = new SegmentDescriptor[31];
|
||||||
|
|
||||||
|
int r_esp = (int) stack_address + 0x1000; // initial esp
|
||||||
|
int r_cs = 0x73;
|
||||||
|
int r_ss = 0x88; // ring 0
|
||||||
|
int r_ds = 0x7b;
|
||||||
|
int r_es = 0x7b;
|
||||||
|
int r_fs = 0x83;
|
||||||
|
|
||||||
|
X86_MMR gdtr =
|
||||||
|
new X86_MMR(gdt_address, gdt.length * SegmentDescriptor.BYTES - 1);
|
||||||
|
|
||||||
|
gdt[14] = new SegmentDescriptor(0, 0xfffff000, true); // code segment
|
||||||
|
gdt[15] = new SegmentDescriptor(0, 0xfffff000, false); // data segment
|
||||||
|
gdt[16] = new SegmentDescriptor((int) fs_address, 0xfff, false); // one page data segment simulate fs
|
||||||
|
gdt[17] = new SegmentDescriptor(0, 0xfffff000, false); // ring 0 data
|
||||||
|
gdt[17].dpl = 0; // set descriptor privilege level
|
||||||
|
|
||||||
|
// Initialize emulator in X86-32bit mode
|
||||||
|
Unicorn uc = new Unicorn(UC_ARCH_X86, UC_MODE_32);
|
||||||
|
uc.hook_add(hook_code, code_address, code_address + code.length, null);
|
||||||
|
uc.hook_add(hook_mem, UC_HOOK_MEM_WRITE, 1, 0, null);
|
||||||
|
|
||||||
|
// map 1 page of code for this emulation
|
||||||
|
uc.mem_map(code_address, 0x1000, UC_PROT_ALL);
|
||||||
|
// map 1 page of stack for this emulation
|
||||||
|
uc.mem_map(stack_address, 0x1000, UC_PROT_READ | UC_PROT_WRITE);
|
||||||
|
// map 64k for a GDT
|
||||||
|
uc.mem_map(gdt_address, 0x10000, UC_PROT_WRITE | UC_PROT_READ);
|
||||||
|
// set up a GDT BEFORE you manipulate any segment registers
|
||||||
|
uc.reg_write(UC_X86_REG_GDTR, gdtr);
|
||||||
|
// write gdt to be emulated to memory
|
||||||
|
ByteBuffer gdt_buf =
|
||||||
|
ByteBuffer.allocate(gdt.length * SegmentDescriptor.BYTES)
|
||||||
|
.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
for (SegmentDescriptor desc : gdt) {
|
||||||
|
if (desc == null) {
|
||||||
|
gdt_buf.put(new byte[SegmentDescriptor.BYTES]);
|
||||||
|
} else {
|
||||||
|
desc.appendToBuffer(gdt_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uc.mem_write(gdt_address, gdt_buf.array());
|
||||||
|
// map 1 page for FS
|
||||||
|
uc.mem_map(fs_address, 0x1000, UC_PROT_WRITE | UC_PROT_READ);
|
||||||
|
// write machine code to be emulated to memory
|
||||||
|
uc.mem_write(code_address, code);
|
||||||
|
// initialize machine registers
|
||||||
|
uc.reg_write(UC_X86_REG_ESP, r_esp);
|
||||||
|
// when setting SS, need rpl == cpl && dpl == cpl
|
||||||
|
// emulator starts with cpl == 0, so we need a dpl 0 descriptor and rpl 0
|
||||||
|
// selector
|
||||||
|
uc.reg_write(UC_X86_REG_SS, r_ss);
|
||||||
|
uc.reg_write(UC_X86_REG_CS, r_cs);
|
||||||
|
uc.reg_write(UC_X86_REG_DS, r_ds);
|
||||||
|
uc.reg_write(UC_X86_REG_ES, r_es);
|
||||||
|
uc.reg_write(UC_X86_REG_FS, r_fs);
|
||||||
|
// emulate machine code in infinite time
|
||||||
|
uc.emu_start(code_address, code_address + code.length, 0, 0);
|
||||||
|
|
||||||
|
// read from memory
|
||||||
|
byte[] buf = uc.mem_read(r_esp - 8, 8);
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
System.out.format("%02x", buf[i] & 0xff);
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
assert Arrays.equals(buf, Utils.hexToBytes("efcdab8967452301"));
|
||||||
|
|
||||||
|
// read from memory
|
||||||
|
buf = uc.mem_read(fs_address, 8);
|
||||||
|
assert Arrays.equals(buf, Utils.hexToBytes("67452301efcdab89"));
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
test_x86_mmr();
|
test_x86_mmr();
|
||||||
|
System.out.println("===================================");
|
||||||
|
gdt_demo();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1172,4 +1172,40 @@ public class TestSamples implements UnicornConst {
|
|||||||
">>> We have to add a map at 0x10000 before continue execution!\n",
|
">>> We have to add a map at 0x10000 before continue execution!\n",
|
||||||
outContent.toString());
|
outContent.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testX86Mmr() {
|
||||||
|
assumeTrue(Unicorn.arch_supported(UC_ARCH_X86));
|
||||||
|
samples.Sample_x86_mmr.test_x86_mmr();
|
||||||
|
assertEquals(
|
||||||
|
"Test x86 MMR read/write\n" +
|
||||||
|
">>> EAX = 0xdddddddd\n" +
|
||||||
|
">>> LDTR.base = 0x22222222\n" +
|
||||||
|
">>> LDTR.limit = 0x33333333\n" +
|
||||||
|
">>> LDTR.flags = 0x44444444\n" +
|
||||||
|
">>> LDTR.selector = 0x5555\n" +
|
||||||
|
"\n" +
|
||||||
|
">>> GDTR.base = 0x77777777\n" +
|
||||||
|
">>> GDTR.limit = 0x8888\n",
|
||||||
|
outContent.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testX86Gdt() {
|
||||||
|
assumeTrue(Unicorn.arch_supported(UC_ARCH_X86));
|
||||||
|
samples.Sample_x86_mmr.gdt_demo();
|
||||||
|
assertEquals(
|
||||||
|
"Demonstrate GDT usage\n" +
|
||||||
|
"Executing at 0x1000000, ilen = 0x5\n" +
|
||||||
|
"mem write at 0x120ffc, size = 4, value = 0x1234567\n" +
|
||||||
|
"Executing at 0x1000005, ilen = 0x5\n" +
|
||||||
|
"mem write at 0x120ff8, size = 4, value = 0x89abcdef\n" +
|
||||||
|
"Executing at 0x100000a, ilen = 0xb\n" +
|
||||||
|
"mem write at 0x7efdd000, size = 4, value = 0x1234567\n" +
|
||||||
|
"Executing at 0x1000015, ilen = 0xb\n" +
|
||||||
|
"mem write at 0x7efdd004, size = 4, value = 0x89abcdef\n" +
|
||||||
|
"efcdab8967452301\n",
|
||||||
|
outContent.toString());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user