Merge branch 'master' of https://github.com/unicorn-engine/unicorn
This commit is contained in:
commit
b3dfde8a17
1
.gitignore
vendored
1
.gitignore
vendored
@ -107,6 +107,7 @@ timeout_segfault
|
|||||||
rep_movsb
|
rep_movsb
|
||||||
mem_double_unmap
|
mem_double_unmap
|
||||||
mips_kseg0_1
|
mips_kseg0_1
|
||||||
|
eflags_nosync
|
||||||
|
|
||||||
|
|
||||||
#################
|
#################
|
||||||
|
@ -328,12 +328,7 @@ void helper_write_eflags(CPUX86State *env, target_ulong t0,
|
|||||||
|
|
||||||
target_ulong helper_read_eflags(CPUX86State *env)
|
target_ulong helper_read_eflags(CPUX86State *env)
|
||||||
{
|
{
|
||||||
uint32_t eflags;
|
return cpu_compute_eflags(env);
|
||||||
|
|
||||||
eflags = cpu_cc_compute_all(env, CC_OP);
|
|
||||||
eflags |= (env->df & DF_MASK);
|
|
||||||
eflags |= env->eflags & ~(VM_MASK | RF_MASK);
|
|
||||||
return eflags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_clts(CPUX86State *env)
|
void helper_clts(CPUX86State *env)
|
||||||
|
@ -839,6 +839,7 @@ typedef struct CPUX86State {
|
|||||||
/* standard registers */
|
/* standard registers */
|
||||||
target_ulong regs[CPU_NB_REGS];
|
target_ulong regs[CPU_NB_REGS];
|
||||||
target_ulong eip;
|
target_ulong eip;
|
||||||
|
target_ulong eflags0; // copy of eflags that does not change thru the BB
|
||||||
target_ulong eflags; /* eflags register. During CPU emulation, CC
|
target_ulong eflags; /* eflags register. During CPU emulation, CC
|
||||||
flags and DF are set to zero because they are
|
flags and DF are set to zero because they are
|
||||||
stored elsewhere */
|
stored elsewhere */
|
||||||
@ -1314,7 +1315,7 @@ void update_fp_status(CPUX86State *env);
|
|||||||
|
|
||||||
static inline uint32_t cpu_compute_eflags(CPUX86State *env)
|
static inline uint32_t cpu_compute_eflags(CPUX86State *env)
|
||||||
{
|
{
|
||||||
return env->eflags | cpu_cc_compute_all(env, CC_OP) | (env->df & DF_MASK);
|
return env->eflags0 | cpu_cc_compute_all(env, CC_OP) | (env->df & DF_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: the translator must set DisasContext.cc_op to CC_OP_EFLAGS
|
/* NOTE: the translator must set DisasContext.cc_op to CC_OP_EFLAGS
|
||||||
|
@ -1141,4 +1141,5 @@ void x86_cpu_exec_exit(CPUState *cs)
|
|||||||
CPUX86State *env = &cpu->env;
|
CPUX86State *env = &cpu->env;
|
||||||
|
|
||||||
env->eflags = cpu_compute_eflags(env);
|
env->eflags = cpu_compute_eflags(env);
|
||||||
|
env->eflags0 = env->eflags;
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ void x86_reg_reset(struct uc_struct *uc)
|
|||||||
|
|
||||||
env->eip = 0;
|
env->eip = 0;
|
||||||
env->eflags = 0;
|
env->eflags = 0;
|
||||||
|
env->eflags0 = 0;
|
||||||
|
|
||||||
env->fpstt = 0; /* top of stack index */
|
env->fpstt = 0; /* top of stack index */
|
||||||
env->fpus = 0;
|
env->fpus = 0;
|
||||||
@ -580,6 +581,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
|||||||
break;
|
break;
|
||||||
case UC_X86_REG_EFLAGS:
|
case UC_X86_REG_EFLAGS:
|
||||||
X86_CPU(uc, mycpu)->env.eflags = *(uint32_t *)value;
|
X86_CPU(uc, mycpu)->env.eflags = *(uint32_t *)value;
|
||||||
|
X86_CPU(uc, mycpu)->env.eflags0 = *(uint32_t *)value;
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_EAX:
|
case UC_X86_REG_EAX:
|
||||||
X86_CPU(uc, mycpu)->env.regs[R_EAX] = *(uint32_t *)value;
|
X86_CPU(uc, mycpu)->env.regs[R_EAX] = *(uint32_t *)value;
|
||||||
@ -693,6 +695,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
|||||||
break;
|
break;
|
||||||
case UC_X86_REG_EFLAGS:
|
case UC_X86_REG_EFLAGS:
|
||||||
X86_CPU(uc, mycpu)->env.eflags = *(uint64_t *)value;
|
X86_CPU(uc, mycpu)->env.eflags = *(uint64_t *)value;
|
||||||
|
X86_CPU(uc, mycpu)->env.eflags0 = *(uint64_t *)value;
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_RAX:
|
case UC_X86_REG_RAX:
|
||||||
X86_CPU(uc, mycpu)->env.regs[R_EAX] = *(uint64_t *)value;
|
X86_CPU(uc, mycpu)->env.regs[R_EAX] = *(uint64_t *)value;
|
||||||
|
@ -12,6 +12,7 @@ TESTS += mem_double_unmap
|
|||||||
TESTS += mem_protect
|
TESTS += mem_protect
|
||||||
TESTS += mem_exec
|
TESTS += mem_exec
|
||||||
TESTS += mips_kseg0_1
|
TESTS += mips_kseg0_1
|
||||||
|
TESTS += eflags_nosync
|
||||||
|
|
||||||
all: $(TESTS)
|
all: $(TESTS)
|
||||||
|
|
||||||
|
184
tests/regress/eflags_nosync.c
Normal file
184
tests/regress/eflags_nosync.c
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <unicorn/unicorn.h>
|
||||||
|
|
||||||
|
#define X86_CODE32 "\x33\xD2\x8A\xD4\x8B\xC8\x81\xE1\xFF\x00\x00\x00" // XOR edx,edx; MOV dl,ah; MOV ecx,eax; AND ecx,FF
|
||||||
|
#define ADDRESS 0x1000000
|
||||||
|
#define PAGE_8K (1 << 13)
|
||||||
|
#define PAGE_4K (1 << 12)
|
||||||
|
#define TARGET_PAGE_MASK ~(PAGE_4K - 1)
|
||||||
|
#define TARGET_PAGE_PREPARE(addr) (((addr) + PAGE_4K - 1) & TARGET_PAGE_MASK)
|
||||||
|
#define TARGET_PAGE_ALIGN(addr) (addr - (TARGET_PAGE_PREPARE(addr) - addr) & TARGET_PAGE_MASK)
|
||||||
|
|
||||||
|
static uint64_t instructions = 0;
|
||||||
|
|
||||||
|
static void hook_ins(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
||||||
|
{
|
||||||
|
instructions++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hook_invalid_mem(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data)
|
||||||
|
{
|
||||||
|
uc_err err;
|
||||||
|
uint64_t address_align = TARGET_PAGE_ALIGN(address);
|
||||||
|
|
||||||
|
if(address == 0)
|
||||||
|
{
|
||||||
|
printf("Address is 0, proof 0x%" PRIx64 "\n", address);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case UC_MEM_WRITE_UNMAPPED:
|
||||||
|
printf("Mapping write address 0x%" PRIx64 " to aligned 0x%" PRIx64 "\n", address, address_align);
|
||||||
|
|
||||||
|
err = uc_mem_map(uc, address_align, PAGE_8K, UC_PROT_ALL);
|
||||||
|
if(err != UC_ERR_OK)
|
||||||
|
{
|
||||||
|
printf("Failed to map memory on UC_MEM_WRITE_UNMAPPED %s\n", uc_strerror(err));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case UC_MEM_READ_UNMAPPED:
|
||||||
|
|
||||||
|
printf("Mapping read address 0x%" PRIx64 " to aligned 0x%" PRIx64 "\n", address, address_align);
|
||||||
|
|
||||||
|
|
||||||
|
err = uc_mem_map(uc, address_align, PAGE_8K, UC_PROT_ALL);
|
||||||
|
if(err != UC_ERR_OK)
|
||||||
|
{
|
||||||
|
printf("Failed to map memory on UC_MEM_READ_UNMAPPED %s\n", uc_strerror(err));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VM_exec()
|
||||||
|
{
|
||||||
|
uc_engine *uc;
|
||||||
|
uc_err err;
|
||||||
|
uint32_t tmp;
|
||||||
|
uc_hook trace1, trace2;
|
||||||
|
unsigned int r_eax, r_ebx, r_ecx, r_edx, r_ebp, r_esp, r_esi, r_edi, r_eip, eflags;
|
||||||
|
unsigned int tr_eax, tr_ebx, tr_ecx, tr_edx, tr_ebp, tr_esp, tr_esi, tr_edi, tr_eip, t_eflags;
|
||||||
|
|
||||||
|
|
||||||
|
r_eax = tr_eax = 0x1DB10106;
|
||||||
|
r_ebx = tr_ebx = 0x7EFDE000;
|
||||||
|
r_ecx = tr_ecx = 0x7EFDE000;
|
||||||
|
r_edx = tr_edx = 0x00001DB1;
|
||||||
|
r_ebp = tr_ebp = 0x0018FF88;
|
||||||
|
r_esp = tr_esp = 0x0018FF14;
|
||||||
|
r_esi = tr_esi = 0x0;
|
||||||
|
r_edi = tr_edi = 0x0;
|
||||||
|
r_eip = tr_eip = 0x004939F3;
|
||||||
|
t_eflags = eflags = 0x00000206;
|
||||||
|
|
||||||
|
// Initialize emulator in X86-32bit mode
|
||||||
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
||||||
|
if(err)
|
||||||
|
{
|
||||||
|
printf("Failed on uc_open() with error returned: %s", uc_strerror(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = uc_mem_map(uc, ADDRESS, (4 * 1024 * 1024), UC_PROT_ALL);
|
||||||
|
if(err != UC_ERR_OK)
|
||||||
|
{
|
||||||
|
printf("Failed to map memory %s", uc_strerror(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write machine code to be emulated to memory
|
||||||
|
err = uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1);
|
||||||
|
if(err != UC_ERR_OK)
|
||||||
|
{
|
||||||
|
printf("Failed to write emulation code to memory, quit!: %s(len %lu)", uc_strerror(err), sizeof(X86_CODE32) - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize machine registers
|
||||||
|
uc_reg_write(uc, UC_X86_REG_EAX, &r_eax);
|
||||||
|
uc_reg_write(uc, UC_X86_REG_EBX, &r_ebx);
|
||||||
|
uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
|
||||||
|
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
||||||
|
uc_reg_write(uc, UC_X86_REG_EBP, &r_ebp);
|
||||||
|
uc_reg_write(uc, UC_X86_REG_ESP, &r_esp);
|
||||||
|
uc_reg_write(uc, UC_X86_REG_ESI, &r_esi);
|
||||||
|
uc_reg_write(uc, UC_X86_REG_EDI, &r_edi);
|
||||||
|
uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags);
|
||||||
|
|
||||||
|
uc_hook_add(uc, &trace1, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, (void *)hook_invalid_mem, NULL);
|
||||||
|
|
||||||
|
// tracing all instruction by having @begin > @end
|
||||||
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, (void *)hook_ins, NULL, (uint64_t)1, (uint64_t)0);
|
||||||
|
|
||||||
|
// emulate machine code in infinite time
|
||||||
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + (sizeof(X86_CODE32) - 1), 0, 0);
|
||||||
|
if(err)
|
||||||
|
{
|
||||||
|
printf("Failed on uc_emu_start() with error returned %u: %s", err, uc_strerror(err));
|
||||||
|
instructions = 0;
|
||||||
|
|
||||||
|
uc_close(uc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EBX, &r_ebx);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EBP, &r_ebp);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_ESP, &r_esp);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_ESI, &r_esi);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EDI, &r_edi);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EIP, &r_eip);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags);
|
||||||
|
|
||||||
|
uc_close(uc);
|
||||||
|
|
||||||
|
printf(">>> Emulation done. Below is the CPU context\n");
|
||||||
|
printf(">>> EAX = 0x%08X %s\n", r_eax, (r_eax == tr_eax ? "" : "(m)"));
|
||||||
|
printf(">>> EBX = 0x%08X %s\n", r_ebx, (r_ebx == tr_ebx ? "" : "(m)"));
|
||||||
|
printf(">>> ECX = 0x%08X %s\n", r_ecx, (r_ecx == tr_ecx ? "" : "(m)"));
|
||||||
|
printf(">>> EDX = 0x%08X %s\n", r_edx, (r_edx == tr_edx ? "" : "(m)"));
|
||||||
|
printf(">>> EBP = 0x%08X %s\n", r_ebp, (r_ebp == tr_ebp ? "" : "(m)"));
|
||||||
|
printf(">>> ESP = 0x%08X %s\n", r_esp, (r_esp == tr_esp ? "" : "(m)"));
|
||||||
|
printf(">>> ESI = 0x%08X %s\n", r_esi, (r_esi == tr_esi ? "" : "(m)"));
|
||||||
|
printf(">>> EDI = 0x%08X %s\n", r_edi, (r_edi == tr_edi ? "" : "(m)"));
|
||||||
|
printf(">>> EIP = 0x%08X %s\n", (r_eip - ADDRESS) + tr_eip, (r_eip == tr_eip ? "" : "(m)\n"));
|
||||||
|
printf(">>> EFLAGS = 0x%08X %s\n", eflags, (eflags == t_eflags ? "" : "(m)"));
|
||||||
|
|
||||||
|
printf(">>> Instructions executed %" PRIu64 "\n", instructions);
|
||||||
|
|
||||||
|
assert(r_eax == 0x1DB10106);
|
||||||
|
assert(r_ebx == 0x7EFDE000);
|
||||||
|
assert(r_ecx == 0x00000006);
|
||||||
|
assert(r_edx == 0x00000001);
|
||||||
|
assert(r_ebp == 0x0018FF88);
|
||||||
|
assert(r_esp == 0x0018FF14);
|
||||||
|
assert(r_esi == 0x00000000);
|
||||||
|
assert(r_edi == 0x00000000);
|
||||||
|
assert(eflags == 0x00000206); //we shouldn't fail this assert, eflags should be 0x00000206 because the last AND instruction produces a non-zero result.
|
||||||
|
|
||||||
|
instructions = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
VM_exec();
|
||||||
|
return 0;
|
||||||
|
}
|
68
tests/regress/init.py
Normal file
68
tests/regress/init.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# By Mariano Graziano
|
||||||
|
|
||||||
|
from unicorn import *
|
||||||
|
from unicorn.x86_const import *
|
||||||
|
|
||||||
|
import regress, struct
|
||||||
|
|
||||||
|
mu = 0
|
||||||
|
|
||||||
|
class Init(regress.RegressTest):
|
||||||
|
|
||||||
|
def init_unicorn(self, ip, sp, counter):
|
||||||
|
global mu
|
||||||
|
print "[+] Emulating IP: %x SP: %x - Counter: %x" % (ip, sp, counter)
|
||||||
|
mu = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||||
|
mu.mem_map(0x1000000, 2 * 1024 * 1024)
|
||||||
|
mu.mem_write(0x1000000, "\x90")
|
||||||
|
mu.mem_map(0x8000000, 8 * 1024 * 1024)
|
||||||
|
mu.reg_write(UC_X86_REG_RSP, sp)
|
||||||
|
content = self.generate_value(counter)
|
||||||
|
mu.mem_write(sp, content)
|
||||||
|
self.set_hooks()
|
||||||
|
|
||||||
|
def generate_value(self, counter):
|
||||||
|
start = 0xffff880026f02000
|
||||||
|
offset = counter * 8
|
||||||
|
address = start + offset
|
||||||
|
return struct.pack("<Q", address)
|
||||||
|
|
||||||
|
def set_hooks(self):
|
||||||
|
global mu
|
||||||
|
mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, self.hook_mem_invalid)
|
||||||
|
mu.hook_add(UC_HOOK_MEM_FETCH_UNMAPPED, self.hook_mem_fetch_unmapped)
|
||||||
|
|
||||||
|
def hook_mem_invalid(self, uc, access, address, size, value, user_data):
|
||||||
|
global mu
|
||||||
|
print "[ HOOK_MEM_INVALID - Address: %s ]" % hex(address)
|
||||||
|
if access == UC_MEM_WRITE_UNMAPPED:
|
||||||
|
print ">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" %(address, size, value)
|
||||||
|
address_page = address & 0xFFFFFFFFFFFFF000
|
||||||
|
mu.mem_map(address_page, 2 * 1024 * 1024)
|
||||||
|
mu.mem_write(address, str(value))
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def hook_mem_fetch_unmapped(self, uc, access, address, size, value, user_data):
|
||||||
|
global mu
|
||||||
|
print "[ HOOK_MEM_FETCH - Address: %s ]" % hex(address).strip("L")
|
||||||
|
print "[ mem_fetch_unmapped: faulting address at %s ]" % hex(address).strip("L")
|
||||||
|
mu.mem_write(0x1000003, "\x90")
|
||||||
|
mu.reg_write(UC_X86_REG_RIP, 0x1000001)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
global mu
|
||||||
|
ips = list(xrange(0x1000000, 0x1001000, 0x1))
|
||||||
|
sps = list(xrange(0x8000000, 0x8001000, 0x1))
|
||||||
|
j = 0
|
||||||
|
for i in ips:
|
||||||
|
j += 1
|
||||||
|
index = ips.index(i)
|
||||||
|
self.init_unicorn(i, sps[index], j)
|
||||||
|
mu.emu_start(0x1000000, 0x1000000 + 0x1)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
regress.main()
|
13
tests/regress/segfault_on_stop.py
Executable file
13
tests/regress/segfault_on_stop.py
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import regress
|
||||||
|
import unicorn
|
||||||
|
|
||||||
|
|
||||||
|
class SegfaultOnStop(regress.RegressTest):
|
||||||
|
def test(self):
|
||||||
|
unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_64).emu_stop()
|
||||||
|
self.assertTrue(True, "If not reached, then we have a crashing bug.")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
regress.main()
|
6
uc.c
6
uc.c
@ -525,8 +525,10 @@ uc_err uc_emu_stop(uc_engine *uc)
|
|||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
|
|
||||||
uc->stop_request = true;
|
uc->stop_request = true;
|
||||||
// exit the current TB
|
if (uc->current_cpu) {
|
||||||
cpu_exit(uc->current_cpu);
|
// exit the current TB
|
||||||
|
cpu_exit(uc->current_cpu);
|
||||||
|
}
|
||||||
|
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user