diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h old mode 100644 new mode 100755 index 7d18c96d..ab5a0481 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -8,6 +8,15 @@ extern "C" { #endif +//Memory-Management Register fields (idtr, gdtr, ldtr, tr) +//borrow from SegmentCache in qemu/target-i386/cpu.h +typedef struct x86_mmr { + uint32_t selector; + uint64_t base; /* handle 32 or 64 bit CPUs */ + uint32_t limit; + uint32_t flags; +} x86_mmr; + // Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr()) // @user_data: user data passed to tracing APIs. typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data); @@ -64,9 +73,7 @@ typedef enum uc_x86_reg { UC_X86_REG_R9D, UC_X86_REG_R10D, UC_X86_REG_R11D, UC_X86_REG_R12D, UC_X86_REG_R13D, UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, - UC_X86_REG_IDTR_LIMIT, UC_X86_REG_IDTR_BASE, UC_X86_REG_GDTR_LIMIT, UC_X86_REG_GDTR_BASE, - UC_X86_REG_LDTR_SS, UC_X86_REG_LDTR_LIMIT, UC_X86_REG_LDTR_BASE, UC_X86_REG_LDTR_ATTR, - UC_X86_REG_TR_SS, UC_X86_REG_TR_LIMIT, UC_X86_REG_TR_BASE, UC_X86_REG_TR_ATTR, + UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_ENDING // <-- mark the end of the list of registers } uc_x86_reg; diff --git a/qemu/target-i386/cpu.h b/qemu/target-i386/cpu.h old mode 100644 new mode 100755 index 4628a8df..68f802f9 --- a/qemu/target-i386/cpu.h +++ b/qemu/target-i386/cpu.h @@ -699,7 +699,7 @@ typedef enum { typedef struct SegmentCache { uint32_t selector; - target_ulong base; + uint64_t base; /* handle 32 or 64 bit CPUs */ uint32_t limit; uint32_t flags; } SegmentCache; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c old mode 100644 new mode 100755 index ce495c36..89ccdb6d --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -277,41 +277,25 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_GS: *(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base; break; - case UC_X86_REG_IDTR_LIMIT: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.idt.limit); + case UC_X86_REG_IDTR: + ((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit; + ((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.idt.base; break; - case UC_X86_REG_IDTR_BASE: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.idt.base; + case UC_X86_REG_GDTR: + ((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit; + ((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.gdt.base; break; - case UC_X86_REG_GDTR_LIMIT: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.gdt.limit); + case UC_X86_REG_LDTR: + ((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit; + ((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.ldt.base; + ((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector; + ((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags; break; - case UC_X86_REG_GDTR_BASE: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.gdt.base; - break; - case UC_X86_REG_LDTR_SS: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.ldt.selector); - break; - case UC_X86_REG_LDTR_LIMIT: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.limit; - break; - case UC_X86_REG_LDTR_BASE: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.base; - break; - case UC_X86_REG_LDTR_ATTR: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.flags; - break; - case UC_X86_REG_TR_SS: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.tr.selector); - break; - case UC_X86_REG_TR_LIMIT: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.limit; - break; - case UC_X86_REG_TR_BASE: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.base; - break; - case UC_X86_REG_TR_ATTR: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.flags; + case UC_X86_REG_TR: + ((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit; + ((SegmentCache *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.tr.base; + ((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; + ((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; break; } break; @@ -561,41 +545,25 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_R15B: *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15]); break; - case UC_X86_REG_IDTR_LIMIT: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.idt.limit); + case UC_X86_REG_IDTR: + ((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit; + ((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.idt.base; break; - case UC_X86_REG_IDTR_BASE: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.idt.base; + case UC_X86_REG_GDTR: + ((SegmentCache *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit; + ((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.gdt.base; break; - case UC_X86_REG_GDTR_LIMIT: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.gdt.limit); + case UC_X86_REG_LDTR: + ((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit; + ((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.ldt.base; + ((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector; + ((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags; break; - case UC_X86_REG_GDTR_BASE: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.gdt.base; - break; - case UC_X86_REG_LDTR_SS: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.ldt.selector); - break; - case UC_X86_REG_LDTR_LIMIT: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.limit; - break; - case UC_X86_REG_LDTR_BASE: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.ldt.base; - break; - case UC_X86_REG_LDTR_ATTR: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.ldt.flags; - break; - case UC_X86_REG_TR_SS: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.tr.selector); - break; - case UC_X86_REG_TR_LIMIT: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.limit; - break; - case UC_X86_REG_TR_BASE: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.tr.base; - break; - case UC_X86_REG_TR_ATTR: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.tr.flags; + case UC_X86_REG_TR: + ((SegmentCache *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit; + ((SegmentCache *)value)->base = X86_CPU(uc, mycpu)->env.tr.base; + ((SegmentCache *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; + ((SegmentCache *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; break; } break; @@ -756,41 +724,25 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) case UC_X86_REG_GS: X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint32_t *)value; break; - case UC_X86_REG_IDTR_LIMIT: - WRITE_WORD(X86_CPU(uc, mycpu)->env.idt.limit, *(uint16_t *)value); + case UC_X86_REG_IDTR: + X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.idt.base = (uint32_t)((SegmentCache *)value)->base; break; - case UC_X86_REG_IDTR_BASE: - X86_CPU(uc, mycpu)->env.idt.base = *(uint32_t *)value; + case UC_X86_REG_GDTR: + X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.gdt.base = (uint32_t)((SegmentCache *)value)->base; break; - case UC_X86_REG_GDTR_LIMIT: - WRITE_WORD(X86_CPU(uc, mycpu)->env.gdt.limit, *(uint16_t *)value); + case UC_X86_REG_LDTR: + X86_CPU(uc, mycpu)->env.ldt.limit = ((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.ldt.base = (uint32_t)((SegmentCache *)value)->base; + X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((SegmentCache *)value)->selector; + X86_CPU(uc, mycpu)->env.ldt.flags = ((SegmentCache *)value)->flags; break; - case UC_X86_REG_GDTR_BASE: - X86_CPU(uc, mycpu)->env.gdt.base = *(uint32_t *)value; - break; - case UC_X86_REG_LDTR_SS: - WRITE_WORD(X86_CPU(uc, mycpu)->env.ldt.selector, *(uint16_t *)value); - break; - case UC_X86_REG_LDTR_LIMIT: - X86_CPU(uc, mycpu)->env.ldt.limit = *(uint32_t *)value; - break; - case UC_X86_REG_LDTR_BASE: - X86_CPU(uc, mycpu)->env.ldt.base = *(uint32_t *)value; - break; - case UC_X86_REG_LDTR_ATTR: - X86_CPU(uc, mycpu)->env.ldt.flags = *(uint32_t *)value; - break; - case UC_X86_REG_TR_SS: - WRITE_WORD(X86_CPU(uc, mycpu)->env.tr.selector, *(uint16_t *)value); - break; - case UC_X86_REG_TR_LIMIT: - X86_CPU(uc, mycpu)->env.tr.limit = *(uint32_t *)value; - break; - case UC_X86_REG_TR_BASE: - X86_CPU(uc, mycpu)->env.tr.base = *(uint32_t *)value; - break; - case UC_X86_REG_TR_ATTR: - X86_CPU(uc, mycpu)->env.tr.flags = *(uint32_t *)value; + case UC_X86_REG_TR: + X86_CPU(uc, mycpu)->env.tr.limit = ((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.tr.base = (uint32_t)((SegmentCache *)value)->base; + X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((SegmentCache *)value)->selector; + X86_CPU(uc, mycpu)->env.tr.flags = ((SegmentCache *)value)->flags; break; } break; @@ -1050,41 +1002,25 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) case UC_X86_REG_R15B: WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15], *(uint8_t *)value); break; - case UC_X86_REG_IDTR_LIMIT: - WRITE_WORD(X86_CPU(uc, mycpu)->env.idt.limit, *(uint16_t *)value); + case UC_X86_REG_IDTR: + X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.idt.base = ((SegmentCache *)value)->base; break; - case UC_X86_REG_IDTR_BASE: - X86_CPU(uc, mycpu)->env.idt.base = *(uint64_t *)value; + case UC_X86_REG_GDTR: + X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.gdt.base = ((SegmentCache *)value)->base; break; - case UC_X86_REG_GDTR_LIMIT: - WRITE_WORD(X86_CPU(uc, mycpu)->env.gdt.limit, *(uint16_t *)value); + case UC_X86_REG_LDTR: + X86_CPU(uc, mycpu)->env.ldt.limit = ((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.ldt.base = ((SegmentCache *)value)->base; + X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((SegmentCache *)value)->selector; + X86_CPU(uc, mycpu)->env.ldt.flags = ((SegmentCache *)value)->flags; break; - case UC_X86_REG_GDTR_BASE: - X86_CPU(uc, mycpu)->env.gdt.base = *(uint64_t *)value; - break; - case UC_X86_REG_LDTR_SS: - WRITE_WORD(X86_CPU(uc, mycpu)->env.ldt.selector, *(uint16_t *)value); - break; - case UC_X86_REG_LDTR_LIMIT: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.ldt.limit, *(uint32_t *)value); - break; - case UC_X86_REG_LDTR_BASE: - X86_CPU(uc, mycpu)->env.ldt.base = *(uint64_t *)value; - break; - case UC_X86_REG_LDTR_ATTR: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.ldt.flags, *(uint32_t *)value); - break; - case UC_X86_REG_TR_SS: - WRITE_WORD(X86_CPU(uc, mycpu)->env.tr.selector, *(uint16_t *)value); - break; - case UC_X86_REG_TR_LIMIT: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.tr.limit, *(uint32_t *)value); - break; - case UC_X86_REG_TR_BASE: - X86_CPU(uc, mycpu)->env.tr.base = *(uint64_t *)value; - break; - case UC_X86_REG_TR_ATTR: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.tr.flags, *(uint32_t *)value); + case UC_X86_REG_TR: + X86_CPU(uc, mycpu)->env.tr.limit = ((SegmentCache *)value)->limit; + X86_CPU(uc, mycpu)->env.tr.base = ((SegmentCache *)value)->base; + X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((SegmentCache *)value)->selector; + X86_CPU(uc, mycpu)->env.tr.flags = ((SegmentCache *)value)->flags; break; } break; diff --git a/tests/unit/test_gdt_idt_x86.c b/tests/unit/test_gdt_idt_x86.c index 03c66bb9..27183f0e 100755 --- a/tests/unit/test_gdt_idt_x86.c +++ b/tests/unit/test_gdt_idt_x86.c @@ -47,16 +47,30 @@ static void test_idt_gdt_i386(/*void **state*/) uc_engine *uc; uc_err err; uint8_t buf[6]; + x86_mmr idt; + x86_mmr gdt; + x86_mmr ldt; + x86_mmr tr; const uint8_t code[] = "\x0f\x01\x0c\x24\x0f\x01\x44\x24\x06"; // sidt [esp]; sgdt [esp+6] const uint64_t address = 0x1000000; int r_esp = address + 0x1000 - 0x100; // initial esp - int idt_base = 0x12345678; - int idt_limit = 0xabcd; - int gdt_base = 0x87654321; - int gdt_limit = 0xdcba; + idt.base = 0x12345678; + idt.limit = 0xabcd; + gdt.base = 0x87654321; + gdt.limit = 0xdcba; + + ldt.base = 0xfedcba98; + ldt.limit = 0x11111111; + ldt.selector = 0x3333; + ldt.flags = 0x55555555; + + tr.base = 0x22222222; + tr.limit = 0x33333333; + tr.selector = 0x4444; + tr.flags = 0x66666666; // Initialize emulator in X86-32bit mode err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); @@ -73,36 +87,44 @@ static void test_idt_gdt_i386(/*void **state*/) // initialize machine registers err = uc_reg_write(uc, UC_X86_REG_ESP, &r_esp); uc_assert_success(err); - err = uc_reg_write(uc, UC_X86_REG_IDTR_BASE, &idt_base); + err = uc_reg_write(uc, UC_X86_REG_IDTR, &idt); uc_assert_success(err); - err = uc_reg_write(uc, UC_X86_REG_IDTR_LIMIT, &idt_limit); - uc_assert_success(err); - err = uc_reg_write(uc, UC_X86_REG_GDTR_BASE, &gdt_base); - uc_assert_success(err); - err = uc_reg_write(uc, UC_X86_REG_GDTR_LIMIT, &gdt_limit); + err = uc_reg_write(uc, UC_X86_REG_GDTR, &gdt); uc_assert_success(err); - idt_base = 0; - idt_limit = 0; - gdt_base = 0; - gdt_limit = 0; + idt.base = 0; + idt.limit = 0; + gdt.base = 0; + gdt.limit = 0; // emulate machine code in infinite time err = uc_emu_start(uc, address, address+sizeof(code)-1, 0, 0); uc_assert_success(err); - uc_reg_read(uc, UC_X86_REG_IDTR_BASE, &idt_base); - assert(idt_base == 0x12345678); - - uc_reg_read(uc, UC_X86_REG_IDTR_LIMIT, &idt_limit); - assert(idt_limit == 0xabcd); + uc_reg_read(uc, UC_X86_REG_IDTR, &idt); + assert(idt.base == 0x12345678); + assert(idt.limit == 0xabcd); - uc_reg_read(uc, UC_X86_REG_GDTR_BASE, &gdt_base); - assert(gdt_base == 0x87654321); + uc_reg_read(uc, UC_X86_REG_GDTR, &gdt); + assert(gdt.base == 0x87654321); + assert(gdt.limit == 0xdcba); - uc_reg_read(uc, UC_X86_REG_GDTR_LIMIT, &gdt_limit); - assert(gdt_limit == 0xdcba); + //userspace can only set ldt selector, remainder are loaded from + //GDT/LDT, but we allow all to emulator user + uc_reg_read(uc, UC_X86_REG_LDTR, &ldt); + assert(ldt.base == 0xfedcba98); + assert(ldt.limit == 0x11111111); + assert(ldt.selector == 0x3333); + assert(ldt.flags = 0x55555555); + + //userspace can only set tr selector, remainder are loaded from + //GDT/LDT, but we allow all to emulator user + uc_reg_read(uc, UC_X86_REG_TR, &tr); + assert(tr.base == 0x22222222); + assert(tr.limit == 0x33333333); + assert(tr.selector == 0x4444); + assert(tr.flags = 0x66666666); // read from memory err = uc_mem_read(uc, r_esp, buf, 6);