Merge remote-tracking branch 'upstream/master' into change-handle-based-api
# Conflicts: # qemu/target-i386/unicorn.c
This commit is contained in:
@ -6,6 +6,7 @@ TESTS += sigill sigill2
|
||||
TESTS += block_test
|
||||
TESTS += ro_mem_test nr_mem_test
|
||||
TESTS += timeout_segfault
|
||||
TESTS += rep_movsb
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
|
61
regress/fpu_ip.py
Executable file
61
regress/fpu_ip.py
Executable file
@ -0,0 +1,61 @@
|
||||
#!/usr/bin/python
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
from capstone import *
|
||||
|
||||
ESP = 0x2000
|
||||
PAGE_SIZE = 2 * 1024 * 1024
|
||||
|
||||
# mov [esp], DWORD 0x37f
|
||||
# fldcw [esp]
|
||||
# fnop
|
||||
# fnstenv [esp + 8]
|
||||
# pop ecx
|
||||
CODE = b'\xc7\x04\x24\x7f\x03\x00\x00\xd9\x2c\x24\xd9\xd0\xd9\x74\x24\x08\x59'
|
||||
|
||||
class SimpleEngine:
|
||||
def __init__(self):
|
||||
self.capmd = Cs(CS_ARCH_X86, CS_MODE_32)
|
||||
|
||||
def disas_single(self, data):
|
||||
for i in self.capmd.disasm(data, 16):
|
||||
print("\t%s\t%s" % (i.mnemonic, i.op_str))
|
||||
break
|
||||
|
||||
disasm = SimpleEngine()
|
||||
|
||||
def hook_code(uc, addr, size, user_data):
|
||||
mem = uc.mem_read(addr, size)
|
||||
print(" 0x%X:" % (addr)),
|
||||
disasm.disas_single(str(mem))
|
||||
|
||||
def mem_reader(addr, size):
|
||||
tmp = mu.mem_read(addr, size)
|
||||
|
||||
for i in tmp:
|
||||
print(" 0x%x" % i),
|
||||
print("")
|
||||
|
||||
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
mu.mem_map(0x0, PAGE_SIZE)
|
||||
mu.mem_write(0x4000, CODE)
|
||||
mu.reg_write(UC_X86_REG_ESP, ESP)
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
|
||||
mu.emu_start(0x4000, 0, 0, 5)
|
||||
esp = mu.reg_read(UC_X86_REG_ESP)
|
||||
print("value at ESP [0x%X - 4]: " % esp)
|
||||
mem_reader(esp + 14, 4)
|
||||
|
||||
# EXPECTED OUTPUT:
|
||||
# 0x4000: mov dword ptr [esp], 0x37f
|
||||
# 0x4007: fldcw word ptr [esp]
|
||||
# 0x400A: fnop
|
||||
# 0x400C: fnstenv dword ptr [esp + 8]
|
||||
# 0x4010: pop ecx
|
||||
# value at ESP [0x2004 - 4]:
|
||||
# 0x0 0x0 0xa 0x40
|
||||
# ^ this value should match the fnop instuction addr
|
62
regress/fpu_ip64.py
Executable file
62
regress/fpu_ip64.py
Executable file
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/python
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
from capstone import *
|
||||
|
||||
ESP = 0x2000
|
||||
PAGE_SIZE = 2 * 1024 * 1024
|
||||
|
||||
# mov [esp], DWORD 0x37f
|
||||
# fldcw [esp]
|
||||
# fnop
|
||||
# fnstenv [esp + 8]
|
||||
# pop ecx
|
||||
CODE = "C704247F030000D92C24D9D0D974240859".decode('hex')
|
||||
|
||||
class SimpleEngine:
|
||||
def __init__(self):
|
||||
self.capmd = Cs(CS_ARCH_X86, CS_MODE_64)
|
||||
|
||||
def disas_single(self, data):
|
||||
for i in self.capmd.disasm(data, 16):
|
||||
print("\t%s\t%s" % (i.mnemonic, i.op_str))
|
||||
break
|
||||
|
||||
disasm = SimpleEngine()
|
||||
|
||||
def hook_code(uc, addr, size, user_data):
|
||||
mem = uc.mem_read(addr, size)
|
||||
print(" 0x%X:" % (addr)),
|
||||
disasm.disas_single(str(mem))
|
||||
|
||||
def mem_reader(addr, size):
|
||||
tmp = mu.mem_read(addr, size)
|
||||
|
||||
for i in tmp:
|
||||
print(" 0x%x" % i),
|
||||
print("")
|
||||
|
||||
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||
|
||||
mu.mem_map(0x0, PAGE_SIZE)
|
||||
mu.mem_write(0x4000, CODE)
|
||||
mu.reg_write(UC_X86_REG_RSP, ESP)
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
|
||||
mu.emu_start(0x4000, 0, 0, 5)
|
||||
rsp = mu.reg_read(UC_X86_REG_RSP)
|
||||
print("Value of FPIP: [0x%X]" % (rsp + 10))
|
||||
mem_reader(rsp + 10, 8)
|
||||
# EXPECTED OUTPUT:
|
||||
|
||||
# 0x4000: mov dword ptr [rsp], 0x37f
|
||||
# 0x4007: fldcw word ptr [rsp]
|
||||
# 0x400A: fnop
|
||||
# 0x400C: fnstenv dword ptr [rsp + 8]
|
||||
# 0x4010: pop rcx
|
||||
# Value of FPIP: [0x2012]
|
||||
# 0x0 0x0 0xa 0x40 0x0 0x0 0x0 0x0
|
||||
|
||||
# WHERE: the value of FPIP should be the address of fnop
|
37
regress/jmp_ebx_hang.py
Executable file
37
regress/jmp_ebx_hang.py
Executable file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""See https://github.com/unicorn-engine/unicorn/issues/82"""
|
||||
|
||||
import unicorn
|
||||
CODE_ADDR = 0x10101000
|
||||
CODE = b'\xff\xe3' # jmp ebx
|
||||
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
|
||||
mu.mem_map(CODE_ADDR, 1024 * 4)
|
||||
mu.mem_write(CODE_ADDR, CODE)
|
||||
# If EBX is zero then an exception is raised, as expected
|
||||
mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0x0)
|
||||
|
||||
print(">>> jmp ebx (ebx = 0)");
|
||||
try:
|
||||
mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1)
|
||||
except unicorn.UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
assert(e.errno == unicorn.UC_ERR_CODE_INVALID)
|
||||
else:
|
||||
assert(False)
|
||||
|
||||
print(">>> jmp ebx (ebx = 0xaa96a47f)");
|
||||
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
|
||||
mu.mem_map(CODE_ADDR, 1024 * 4)
|
||||
# If we write this address to EBX then the emulator hangs on emu_start
|
||||
mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0xaa96a47f)
|
||||
mu.mem_write(CODE_ADDR, CODE)
|
||||
try:
|
||||
mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1)
|
||||
except unicorn.UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
assert(e.errno == unicorn.UC_ERR_CODE_INVALID)
|
||||
else:
|
||||
assert(False)
|
||||
|
||||
print "Success"
|
12
regress/pshufb.py
Executable file
12
regress/pshufb.py
Executable file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/python
|
||||
# By Ryan Hileman, issue #91
|
||||
|
||||
# Invalid instruction = test failed
|
||||
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
uc = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||
uc.mem_map(0x2000, 0x1000)
|
||||
# pshufb xmm0, xmm1
|
||||
uc.mem_write(0x2000, '660f3800c1'.decode('hex'))
|
||||
uc.emu_start(0x2000, 0x2005)
|
183
regress/rep_movsb.c
Normal file
183
regress/rep_movsb.c
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
|
||||
rep movsb regression
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <unicorn/unicorn.h>
|
||||
|
||||
unsigned char PROGRAM[] =
|
||||
"\xbe\x00\x00\x20\x00\xbf\x00\x10\x20\x00\xb9\x14\x00\x00\x00\xf3"
|
||||
"\xa4\xf4";
|
||||
// total size: 18 bytes
|
||||
|
||||
/*
|
||||
bits 32
|
||||
|
||||
; assumes code section at 0x100000 r-x
|
||||
; assumes data section at 0x200000-0x202000, rw-
|
||||
|
||||
mov esi, 0x200000
|
||||
mov edi, 0x201000
|
||||
mov ecx, 20
|
||||
rep movsb
|
||||
hlt
|
||||
*/
|
||||
|
||||
static int log_num = 1;
|
||||
|
||||
// callback for tracing instruction
|
||||
static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data)
|
||||
{
|
||||
uint8_t opcode;
|
||||
if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) {
|
||||
printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr);
|
||||
_exit(-1);
|
||||
}
|
||||
switch (opcode) {
|
||||
case 0xf4: //hlt
|
||||
printf("# Handling HLT\n");
|
||||
if (uc_emu_stop(handle) != UC_ERR_OK) {
|
||||
printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr);
|
||||
_exit(-1);
|
||||
}
|
||||
else {
|
||||
printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++);
|
||||
}
|
||||
break;
|
||||
default: //all others
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// callback for tracing memory access (READ or WRITE)
|
||||
static void hook_mem_write(uch handle, uc_mem_type type,
|
||||
uint64_t addr, int size, int64_t value, void *user_data)
|
||||
{
|
||||
printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value);
|
||||
if (addr < 0x201000L) {
|
||||
//this is actually a read, we don't write in this range
|
||||
printf("not ok %d - write hook called for read of 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", log_num++, addr, size, value);
|
||||
}
|
||||
else {
|
||||
printf("ok %d - write hook called for write of 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", log_num++, addr, size, value);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
uch handle, trace1, trace2;
|
||||
uc_err err;
|
||||
uint8_t buf1[100], readbuf[100];
|
||||
|
||||
printf("# rep movsb test\n");
|
||||
|
||||
memset(buf1, 'A', 20);
|
||||
|
||||
// Initialize emulator in X86-32bit mode
|
||||
err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle);
|
||||
if (err) {
|
||||
printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
printf("ok %d - uc_open() success\n", log_num++);
|
||||
}
|
||||
|
||||
uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_READ);
|
||||
uc_mem_map(handle, 0x200000, 0x2000, UC_PROT_READ | UC_PROT_WRITE);
|
||||
|
||||
// fill in the data that we want to copy
|
||||
if (uc_mem_write(handle, 0x200000, (uint8_t*)buf1, 20)) {
|
||||
printf("not ok %d - Failed to write read buffer to memory, quit!\n", log_num++);
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
printf("ok %d - Read buffer written to memory\n", log_num++);
|
||||
}
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
if (uc_mem_write(handle, 0x100000, PROGRAM, sizeof(PROGRAM))) {
|
||||
printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++);
|
||||
return 4;
|
||||
}
|
||||
else {
|
||||
printf("ok %d - Program written to memory\n", log_num++);
|
||||
}
|
||||
|
||||
if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) {
|
||||
printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++);
|
||||
return 5;
|
||||
}
|
||||
else {
|
||||
printf("ok %d - UC_HOOK_CODE installed\n", log_num++);
|
||||
}
|
||||
|
||||
// intercept memory write events only, NOT read events
|
||||
if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) {
|
||||
printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++);
|
||||
return 6;
|
||||
}
|
||||
else {
|
||||
printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++);
|
||||
}
|
||||
|
||||
// emulate machine code until told to stop by hook_code
|
||||
printf("# BEGIN execution\n");
|
||||
err = uc_emu_start(handle, 0x100000, 0x101000, 0, 0);
|
||||
if (err != UC_ERR_OK) {
|
||||
printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err));
|
||||
return 8;
|
||||
}
|
||||
else {
|
||||
printf("ok %d - uc_emu_start complete\n", log_num++);
|
||||
}
|
||||
printf("# END execution\n");
|
||||
|
||||
//make sure that data got copied
|
||||
// fill in sections that shouldn't get touched
|
||||
if (uc_mem_read(handle, 0x201000, (uint8_t*)readbuf, 20)) {
|
||||
printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++);
|
||||
}
|
||||
else {
|
||||
printf("ok %d - Random buffer 1 read from memory\n", log_num++);
|
||||
if (memcmp(buf1, readbuf, 20)) {
|
||||
printf("not ok %d - write buffer contents are incorrect\n", log_num++);
|
||||
}
|
||||
else {
|
||||
printf("ok %d - write buffer contents are correct\n", log_num++);
|
||||
}
|
||||
}
|
||||
|
||||
if (uc_close(&handle) == UC_ERR_OK) {
|
||||
printf("ok %d - uc_close complete\n", log_num++);
|
||||
}
|
||||
else {
|
||||
printf("not ok %d - uc_close complete\n", log_num++);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user