Reorganize test directories

This commit is contained in:
danghvu
2015-09-21 20:47:45 -05:00
parent 0c67f41ed9
commit 3c1d65ea66
43 changed files with 2 additions and 2 deletions

22
tests/regress/Makefile Normal file
View File

@@ -0,0 +1,22 @@
CFLAGS += -I../include
LDFLAGS += ../libunicorn.a $(shell pkg-config --libs glib-2.0) -lpthread -lm
TESTS = map_crash map_write
TESTS += sigill sigill2
TESTS += block_test
TESTS += ro_mem_test nr_mem_test
TESTS += timeout_segfault
TESTS += rep_movsb
TESTS += mem_unmap
TESTS += mem_protect
TESTS += mem_exec
all: $(TESTS)
clean:
rm -f $(TESTS)
%: %.c
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
.PHONY: all clean

27
tests/regress/arm_bxeq_hang.py Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/python
from unicorn import *
from unicorn.arm_const import *
import regress
class BxHang(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
uc.mem_map(0x1000, 0x1000)
uc.mem_write(0x1000, '1eff2f010000a0e1'.decode('hex'))
uc.count = 0
def hook_block(uc, addr, *args):
print 'enter block 0x%04x' % addr
uc.count += 1
uc.reg_write(UC_ARM_REG_LR, 0x1004)
uc.hook_add(UC_HOOK_BLOCK, hook_block)
print 'block should only run once'
uc.emu_start(0x1000, 0x1004)
self.assertEqual(uc.count, 1)
if __name__ == '__main__':
regress.main()

View File

@@ -0,0 +1,32 @@
#!/usr/bin/python
from unicorn import *
from unicorn.arm_const import *
import regress
class MovHang(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
uc.mem_map(0x1000, 0x1000)
uc.mem_write(0x1000, '00c000e3'.decode('hex')) # movw r12, #0
def hook_block(uc, addr, *args):
print 'enter block 0x%04x' % addr
uc.count += 1
uc.reg_write(UC_ARM_REG_R12, 0x123)
self.assertEquals(uc.reg_read(UC_ARM_REG_R12), 0x123)
uc.hook_add(UC_HOOK_BLOCK, hook_block)
uc.count = 0
#print 'block should only run once'
uc.emu_start(0x1000, 0x1004, timeout=500)
self.assertEquals(uc.reg_read(UC_ARM_REG_R12), 0x0)
self.assertEquals(uc.count, 1)
if __name__ == '__main__':
regress.main()

View File

@@ -0,0 +1,85 @@
#include <sys/types.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <unicorn/unicorn.h>
static int count = 1;
// Callback function for tracing code (UC_HOOK_CODE & UC_HOOK_BLOCK)
// @address: address where the code is being executed
// @size: size of machine instruction being executed
// @user_data: user data passed to tracing APIs.
void cb_hookblock(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) {
fprintf(stderr, "# >>> Tracing basic block at 0x%"PRIx64", block size = 0x%x\n", address, size);
if (address != 0x1000000 && address != 0x1000200) {
fprintf(stderr, "not ok %d - address != 0x1000000 && address != 0x1000200\n", count++);
_exit(1);
}
fprintf(stderr, "ok %d - address (0x%x) is start of basic block\n", count++, (uint32_t)address);
if (size != 0x200) {
fprintf(stderr, "not ok %d - basic block size != 0x200\n", count++);
_exit(1);
}
fprintf(stderr, "ok %d - basic block size is correct\n", count++);
}
int main() {
uc_engine *uc;
fprintf(stderr, "# basic block callback test\n");
fprintf(stderr, "# there are only two basic blocks 0x1000000-0x10001ff and 0x1000200-0x10003ff\n");
uc_err err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
if (err != UC_ERR_OK) {
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
exit(0);
}
fprintf(stderr, "ok %d - uc_open\n", count++);
err = uc_mem_map(uc, 0x1000000, 4096, UC_PROT_ALL);
if (err != UC_ERR_OK) {
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
exit(0);
}
fprintf(stderr, "ok %d - uc_mem_map\n", count++);
uint8_t code[1024];
//build a program that consists of 1019 nops followed by a jump -512
//this program contains exactly 2 basic blocks, a block of 512 nops, followed
//by a loop body containing 507 nops and jump to the top of the loop
//the first basic block begins at address 0x1000000, and the second
//basic block begins at address 0x1000200
memset(code, 0x90, sizeof(code));
memcpy(code + 1024 - 5, "\xe9\x00\xfe\xff\xff", 5);
err = uc_mem_write(uc, 0x1000000, code, sizeof(code));
if (err != UC_ERR_OK) {
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
exit(0);
}
fprintf(stderr, "ok %d - uc_mem_write\n", count++);
uc_hook h1, h2;
err = uc_hook_add(uc, &h1, UC_HOOK_BLOCK, cb_hookblock, NULL, (uint64_t)1, (uint64_t)0);
if (err != UC_ERR_OK) {
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
exit(0);
}
fprintf(stderr, "ok %d - uc_hook_add\n", count++);
err = uc_emu_start(uc, 0x1000000, 0x1000000 + sizeof(code), 0, 1030);
if (err != UC_ERR_OK) {
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
exit(0);
}
fprintf(stderr, "ok %d - uc_emu_start\n", count++);
fprintf(stderr, "ok %d - Done", count++);
return 0;
}

64
tests/regress/callback-pc.py Executable file
View File

@@ -0,0 +1,64 @@
#!/usr/bin/env python
# reg_write() can't modify PC from within trace callbacks
# Pull Request #4
from __future__ import print_function
from unicorn import *
from unicorn.arm_const import *
import regress
BASE_ADDRESS = 0x10000000
# sub sp, #0xc
THUMB_CODE = "\x83\xb0" * 5
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = %u" % (address, size))
mu = user_data
print(">>> Setting PC to 0xffffffff")
mu.reg_write(UC_ARM_REG_PC, 0xffffffff)
# callback for tracing basic blocks
def hook_block(uc, address, size, user_data):
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
mu = user_data
print(">>> Setting PC to 0xffffffff")
mu.reg_write(UC_ARM_REG_PC, 0xffffffff)
class CallBackPCTest(regress.RegressTest):
def runTest(self):
self.instruction_trace_test()
# set up emulation
def instruction_trace_test(self):
try:
# initialize emulator in ARM's Thumb mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
# map some memory
mu.mem_map(BASE_ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(BASE_ADDRESS, THUMB_CODE)
# setup stack
mu.reg_write(UC_ARM_REG_SP, BASE_ADDRESS + 2 * 1024 * 1024)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code, user_data=mu)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, hook_block, user_data=mu)
# emulate machine code in infinite time
mu.emu_start(BASE_ADDRESS, BASE_ADDRESS + len(THUMB_CODE))
except UcError as e:
assertFalse(0, "ERROR: %s" % e)
if __name__ == '__main__':
regress.main()

37
tests/regress/crash_tb.py Executable file
View File

@@ -0,0 +1,37 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
import regress
CODE_ADDR = 0x0
binary1 = b'\xb8\x02\x00\x00\x00'
binary2 = b'\xb8\x01\x00\x00\x00'
class CrashTB(regress.RegressTest):
def runTest(self):
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(CODE_ADDR, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(CODE_ADDR, binary1)
# emu for maximum 1 sec.
mu.emu_start(CODE_ADDR, len(binary1), UC_SECOND_SCALE)
self.assertEqual(0x2, mu.reg_read(UC_X86_REG_RAX))
# write machine code to be emulated to memory
mu.mem_write(CODE_ADDR, binary2)
# emu for maximum 1 sec.
mu.emu_start(CODE_ADDR, len(binary2), UC_SECOND_SCALE)
self.assertEqual(0x1, mu.reg_read(UC_X86_REG_RAX))
if __name__ == '__main__':
regress.main()

20
tests/regress/deadlock_1.py Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/python
# From issue #1 of Ryan Hileman
from unicorn import *
import regress
CODE = b"\x90\x91\x92"
class DeadLock(regress.RegressTest):
def runTest(self):
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0x100000, 4 * 1024)
mu.mem_write(0x100000, CODE)
with self.assertRaises(UcError):
mu.emu_start(0x100000, 0x1000 + len(CODE))
if __name__ == '__main__':
regress.main()

View File

@@ -0,0 +1,20 @@
#!/usr/bin/python
"""See https://github.com/unicorn-engine/unicorn/issues/65"""
import unicorn
import regress
class EmuStopSegFault(regress.RegressTest):
def runTest(self):
ADDR = 0x10101000
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
mu.mem_map(ADDR, 1024 * 4)
mu.mem_write(ADDR, b'\x41')
mu.emu_start(ADDR, ADDR + 1, count=1)
# The following should not trigger a null pointer dereference
self.assertEqual(None, mu.emu_stop())
if __name__ == '__main__':
regress.main()

69
tests/regress/fpu_ip.py Executable file
View File

@@ -0,0 +1,69 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
from capstone import *
import regress
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))
class FpuIP(regress.RegressTest):
def mem_reader(self, mu, addr, size, expected):
tmp = mu.mem_read(addr, size)
for out, exp in zip(tmp, expected):
self.assertEqual(exp, out)
def test_32(self):
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)
self.assertEqual(0x2004, esp)
expected = [0x0, 0x0, 0xa, 0x40]
self.mem_reader(mu, esp + 14, 4, expected)
def test_64(self):
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_ESP, ESP)
mu.hook_add(UC_HOOK_CODE, hook_code)
mu.emu_start(0x4000, 0, 0, 5)
rsp = mu.reg_read(UC_X86_REG_RSP)
self.assertEqual(0x2012, rsp + 10)
expected = [0x0, 0x0, 0xa, 0x40, 0x0, 0x0, 0x0, 0x0]
self.mem_reader(mu, rsp + 10, 4, expected)
if __name__ == '__main__':
regress.main()

38
tests/regress/fpu_mem_write.py Executable file
View File

@@ -0,0 +1,38 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
import regress
ESP = 0x2000
PAGE_SIZE = 1 * 1024 * 1024
# wait
# fnstcw word ptr [esp]
# pop ecx
CODE = b'\x9B\xD9\x3C\x24\x59'
def hook_mem_write(uc, access, address, size, value, user_data):
print("mem WRITE: 0x%x, data size = %u, data value = 0x%x" % (address, size, value))
return True
class FpuWrite(regress.RegressTest):
def mem_reader(self, mu, addr, size, expected):
tmp = mu.mem_read(addr, size)
for i, e in zip(tmp, expected):
self.assertEquals(e, i)
def runTest(self):
mu = Uc(UC_ARCH_X86, UC_MODE_32)
mu.mem_map(0, PAGE_SIZE)
mu.mem_write(0, CODE)
mu.reg_write(UC_X86_REG_ESP, ESP)
mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_write)
mu.emu_start(0x0, 5, 0, 2)
esp = mu.reg_read(UC_X86_REG_ESP)
self.mem_reader(mu, esp, 10, [0] * 10)
if __name__ == '__main__':
regress.main()

57
tests/regress/hang.py Executable file
View File

@@ -0,0 +1,57 @@
#!/usr/bin/python
from __future__ import print_function
from unicorn import *
from unicorn.x86_const import *
import regress
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
tmp = uc.mem_read(address, size)
print("[0x%x] =" %(address), end="")
for i in tmp:
print(" %02x" %i, end="")
print("")
# callback for tracing Linux interrupt
def hook_intr(uc, intno, user_data):
# only handle Linux syscall
rip = uc.reg_read(UC_X86_REG_RIP)
if intno != 0x80:
print("=== 0x%x: got interrupt %x, quit" %(rip, intno));
uc.emu_stop()
return
eax = uc.reg_read(UC_X86_REG_EAX)
print(">>> 0x%x: interrupt 0x%x, EAX = 0x%x" %(rip, intno, eax))
class Hang(regress.RegressTest):
def runTest(self):
binary1 = b'\xeb\x1c\x5a\x89\xd6\x8b\x02\x66\x3d\xca\x7d\x75\x06\x66\x05\x03\x03\x89\x02\xfe\xc2\x3d\x41\x41\x41\x41\x75\xe9\xff\xe6\xe8\xdf\xff\xff\xff\x31\xd2\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xca\x7d\x41\x41\x41\x41\x41\x41\x41\x41'
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0, 2 * 1024 * 1024)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code)
# handle interrupt ourself
mu.hook_add(UC_HOOK_INTR, hook_intr)
# setup stack
mu.reg_write(UC_X86_REG_RSP, 1024 * 1024)
# fill in memory with 0xCC (software breakpoint int 3)
for i in xrange(1 * 1024):
mu.mem_write(0 + i, b'\xcc')
# write machine code to be emulated to memory
mu.mem_write(0, binary1)
self.assertEqual(mu.emu_start(0, len(binary1)), None)
if __name__ == '__main__':
regress.main()

39
tests/regress/jmp_ebx_hang.py Executable file
View File

@@ -0,0 +1,39 @@
#!/usr/bin/env python
"""See https://github.com/unicorn-engine/unicorn/issues/82"""
import unicorn
from unicorn import *
import regress
CODE_ADDR = 0x10101000
CODE = b'\xff\xe3' # jmp ebx
class JumEbxHang(regress.RegressTest):
def runTest(self):
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)");
with self.assertRaises(UcError) as m:
mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1)
self.assertEqual(m.exception.errno, unicorn.UC_ERR_CODE_INVALID)
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)
with self.assertRaises(UcError) as m:
mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1)
self.assertEqual(m.exception.errno, unicorn.UC_ERR_CODE_INVALID)
if __name__ == '__main__':
regress.main()

31
tests/regress/map_crash.c Normal file
View File

@@ -0,0 +1,31 @@
#include <unicorn/unicorn.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define UC_BUG_WRITE_SIZE 13000
#define UC_BUG_WRITE_ADDR 0x1000
int main()
{
int size;
uint8_t *buf;
uc_engine *uc;
uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc);
if (err) {
fprintf (stderr, "Cannot initialize unicorn\n");
return 1;
}
size = UC_BUG_WRITE_SIZE;
buf = malloc (size);
if (!buf) {
fprintf (stderr, "Cannot allocate\n");
return 1;
}
memset (buf, 0, size);
if (!uc_mem_map (uc, UC_BUG_WRITE_ADDR, size, UC_PROT_ALL)) {
uc_mem_write (uc, UC_BUG_WRITE_ADDR, buf, size);
}
uc_close(uc);
return 0;
}

50
tests/regress/map_write.c Normal file
View File

@@ -0,0 +1,50 @@
#include <unicorn/unicorn.h>
#include <stdio.h>
#include <stdlib.h>
#define ADDR 0x00400000
#define SIZE 1024*64
#define OVERFLOW 1
int main()
{
uc_engine *uc;
uint8_t *buf, *buf2;
int i;
uc_err err;
err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc);
if (err) {
printf ("uc_open %d\n", err);
return 1;
}
err = uc_mem_map (uc, ADDR, SIZE, UC_PROT_ALL);
if (err) {
printf ("uc_mem_map %d\n", err);
return 1;
}
buf = calloc (SIZE*2, 1);
buf2 = calloc (SIZE, 1);
for (i=0;i<SIZE; i++) {
buf[i] = i & 0xff;
}
/* crash here */
err = uc_mem_write (uc, ADDR, buf, SIZE+OVERFLOW);
if (err) {
printf ("uc_mem_map %d\n", err);
return 1;
}
err = uc_mem_read (uc, ADDR+10, buf2, 4);
if (err) {
printf ("uc_mem_map %d\n", err);
return 1;
}
if (buf2[0] != 0xa) {
printf ("mem contents are wrong\n");
return 1;
}
printf ("OK\n");
free (buf);
free (buf2);
return 0;
}

280
tests/regress/mem_exec.c Normal file
View File

@@ -0,0 +1,280 @@
/*
Executable memory regions demo / unit test
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[] =
"\xeb\x45\x5e\x81\xe6\x00\xf0\xff\xff\x40\x40\x40\x40\x40\x40\x40"
"\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40\x40"
"\x40\x40\x40\x40\x40\x40\x40\x89\xf7\x81\xc7\x00\x00\x10\x00\xb9"
"\x4c\x00\x00\x00\x81\xff\x00\x00\x40\x00\x75\x01\xf4\xf3\xa4\x81"
"\xe7\x00\xf0\xff\xff\xff\xe7\xe8\xb6\xff\xff\xff";
// total size: 76 bytes
/*
bits 32
; assumes r-x section at 0x100000
; assumes rw- section at 0x200000
; assumes r-- section at 0x300000
; also needs an initialized stack
start:
jmp bottom
top:
pop esi
and esi, ~0xfff
times 30 inc eax
mov edi, esi
add edi, 0x100000
mov ecx, end - start
rep movsb
and edi, ~0xfff
cmp edi, 0x400000
jnz next_block
hlt
next_block:
jmp edi
bottom:
call top
end:
*/
int test_num = 0;
uint32_t tests[] = {
0x41414141,
0x43434343,
0x45454545
};
static int log_num = 1;
#define CODE_SECTION 0x100000
#define CODE_SIZE 0x1000
// callback for tracing instruction
static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data)
{
uint8_t opcode;
if (uc_mem_read(uc, 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);
}
// printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr);
switch (opcode) {
case 0xf4: //hlt
printf("# Handling HLT\n");
if (uc_emu_stop(uc) != 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
// printf("# Handling OTHER\n");
break;
}
}
// callback for tracing memory access (READ or WRITE)
static void hook_mem_write(uc_engine *uc, 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);
}
// callback for tracing invalid memory access (READ or WRITE)
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
uint64_t addr, int size, int64_t value, void *user_data)
{
switch(type) {
default:
printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr);
return false;
case UC_MEM_EXEC_PROT:
printf("# Fetch from non-executable memory at 0x%"PRIx64 "\n", addr);
//make page executable
if (uc_mem_protect(uc, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_EXEC) != UC_ERR_OK) {
printf("not ok %d - uc_mem_protect fail for address: 0x%" PRIx64 "\n", log_num++, addr);
} else {
printf("ok %d - uc_mem_protect success at 0x%" PRIx64 "\n", log_num++, addr);
}
return true;
case UC_MEM_WRITE_PROT:
printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value);
if (uc_mem_protect(uc, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) {
printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr);
} else {
printf("ok %d - uc_mem_protect success\n", log_num++);
}
return true;
}
}
int main(int argc, char **argv, char **envp)
{
uc_engine *uc;
uc_hook trace1, trace2;
uc_err err;
uint32_t esp, eip;
int32_t buf1[1024], buf2[1024], readbuf[1024];
int i;
//don't really care about quality of randomness
srand(time(NULL));
for (i = 0; i < 1024; i++) {
buf1[i] = rand();
buf2[i] = rand();
}
printf("# Memory protect test\n");
// Initialize emulator in X86-32bit mode
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
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(uc, 0x100000, 0x1000, UC_PROT_READ | UC_PROT_EXEC);
uc_mem_map(uc, 0x1ff000, 0x2000, UC_PROT_READ | UC_PROT_WRITE);
uc_mem_map(uc, 0x300000, 0x2000, UC_PROT_READ);
uc_mem_map(uc, 0xf00000, 0x1000, UC_PROT_READ | UC_PROT_WRITE);
esp = 0xf00000 + 0x1000;
// Setup stack pointer
if (uc_reg_write(uc, UC_X86_REG_ESP, &esp)) {
printf("not ok %d - Failed to set esp. quit!\n", log_num++);
return 2;
} else {
printf("ok %d - ESP set\n", log_num++);
}
// fill in sections that shouldn't get touched
if (uc_mem_write(uc, 0x1ff000, buf1, sizeof(buf1))) {
printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++);
return 3;
} else {
printf("ok %d - Random buffer 1 written to memory\n", log_num++);
}
if (uc_mem_write(uc, 0x301000, buf2, sizeof(buf2))) {
printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++);
return 4;
} else {
printf("ok %d - Random buffer 2 written to memory\n", log_num++);
}
// write machine code to be emulated to memory
if (uc_mem_write(uc, 0x100000, PROGRAM, sizeof(PROGRAM))) {
printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++);
return 5;
} else {
printf("ok %d - Program written to memory\n", log_num++);
}
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++);
return 6;
} else {
printf("ok %d - UC_HOOK_CODE installed\n", log_num++);
}
// intercept memory write events
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++);
return 7;
} else {
printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++);
}
// intercept invalid memory events
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++);
return 8;
} else {
printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++);
}
// emulate machine code until told to stop by hook_code
printf("# BEGIN execution\n");
err = uc_emu_start(uc, 0x100000, 0x400000, 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 9;
} else {
printf("ok %d - uc_emu_start complete\n", log_num++);
}
printf("# END execution\n");
// get ending EIP
if (uc_reg_read(uc, UC_X86_REG_EIP, &eip)) {
printf("not ok %d - Failed to read eip.\n", log_num++);
} else {
printf("ok %d - Ending EIP 0x%x\n", log_num++, eip);
}
//make sure that random blocks didn't get nuked
// fill in sections that shouldn't get touched
if (uc_mem_read(uc, 0x1ff000, readbuf, sizeof(readbuf))) {
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, 4096)) {
printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++);
} else {
printf("ok %d - Random buffer 1 contents are correct\n", log_num++);
}
}
if (uc_mem_read(uc, 0x301000, readbuf, sizeof(readbuf))) {
printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++);
} else {
printf("ok %d - Random buffer 2 read from memory\n", log_num++);
if (memcmp(buf2, readbuf, 4096)) {
printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++);
} else {
printf("ok %d - Random buffer 2 contents are correct\n", log_num++);
}
}
if (uc_close(uc) == 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;
}

302
tests/regress/mem_protect.c Normal file
View File

@@ -0,0 +1,302 @@
/*
uc_mem_protect demo / unit test
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[] =
"\xc7\x05\x00\x00\x20\x00\x41\x41\x41\x41\x90\xc7\x05\x00\x00\x20"
"\x00\x42\x42\x42\x42\xc7\x05\x00\x00\x30\x00\x43\x43\x43\x43\x90"
"\xc7\x05\x00\x00\x30\x00\x44\x44\x44\x44\xc7\x05\x00\x00\x40\x00"
"\x45\x45\x45\x45\x90\xc7\x05\x00\x00\x40\x00\x46\x46\x46\x46\xc7"
"\x05\x00\xf8\x3f\x00\x47\x47\x47\x47\xc7\x05\x00\x18\x40\x00\x48"
"\x48\x48\x48\xf4";
// total size: 84 bytes
/*
bits 32
; assumes code section at 0x100000
; assumes data section at 0x200000, initially rw
; assumes data section at 0x300000, initially rw
; assumes data section at 0x400000, initially rw
; with installed hooks unmaps or maps on each nop
mov dword [0x200000], 0x41414141
nop ; mark it RO
mov dword [0x200000], 0x42424242
mov dword [0x300000], 0x43434343
nop ; mark it RO
mov dword [0x300000], 0x44444444
mov dword [0x400000], 0x45454545
nop ; mark it RO
mov dword [0x400000], 0x46464646
mov dword [0x3ff800], 0x47474747 ; make sure surrounding areas remained RW
mov dword [0x401800], 0x48484848 ; make sure surrounding areas remained RW
hlt ; tell hook function we are done
*/
int test_num = 0;
uint32_t tests[] = {
0x41414141,
0x43434343,
0x45454545
};
static int log_num = 1;
#define CODE_SECTION 0x100000
#define CODE_SIZE 0x1000
// callback for tracing instruction
static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data)
{
uint8_t opcode;
uint32_t testval;
if (uc_mem_read(uc, 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);
}
printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr);
switch (opcode) {
case 0x90: //nop
printf("# Handling NOP\n");
if (uc_mem_read(uc, 0x200000 + test_num * 0x100000, &testval, sizeof(testval)) != UC_ERR_OK) {
printf("not ok %d - uc_mem_read fail for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000);
} else {
printf("ok %d - good uc_mem_read for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000);
printf("# uc_mem_read for test %d\n", test_num);
if (testval == tests[test_num]) {
printf("ok %d - passed test %d\n", log_num++, test_num);
} else {
printf("not ok %d - failed test %d\n", log_num++, test_num);
printf("# Expected: 0x%x\n",tests[test_num]);
printf("# Received: 0x%x\n", testval);
}
}
if (uc_mem_protect(uc, 0x200000 + test_num * 0x100000, 0x1000, UC_PROT_READ) != UC_ERR_OK) {
printf("not ok %d - uc_mem_protect fail during hook_code callback, addr: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000);
} else {
printf("ok %d - uc_mem_protect success\n", log_num++);
}
test_num++;
break;
case 0xf4: //hlt
printf("# Handling HLT\n");
if (uc_emu_stop(uc) != 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
printf("# Handling OTHER\n");
break;
}
}
// callback for tracing memory access (READ or WRITE)
static void hook_mem_write(uc_engine *uc, 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);
}
// callback for tracing invalid memory access (READ or WRITE)
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
uint64_t addr, int size, int64_t value, void *user_data)
{
uint32_t testval;
switch(type) {
default:
printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr);
return false;
case UC_MEM_WRITE_PROT:
printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value);
if (uc_mem_read(uc, addr, &testval, sizeof(testval)) != UC_ERR_OK) {
printf("not ok %d - uc_mem_read fail for address: 0x%" PRIx64 "\n", log_num++, addr);
} else {
printf("ok %d - uc_mem_read success after mem_protect at test %d\n", log_num++, test_num - 1);
}
if (uc_mem_protect(uc, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) {
printf("not ok %d - uc_mem_protect fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr);
} else {
printf("ok %d - uc_mem_protect success\n", log_num++);
}
return true;
}
}
int main(int argc, char **argv, char **envp)
{
uc_engine *uc;
uc_hook trace1, trace2;
uc_err err;
uint32_t addr, testval;
int32_t buf1[1024], buf2[1024], readbuf[1024];
int i;
//don't really care about quality of randomness
srand(time(NULL));
for (i = 0; i < 1024; i++) {
buf1[i] = rand();
buf2[i] = rand();
}
printf("# Memory protect test\n");
// Initialize emulator in X86-32bit mode
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
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(uc, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC);
uc_mem_map(uc, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE);
uc_mem_map(uc, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE);
uc_mem_map(uc, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE);
// fill in sections that shouldn't get touched
if (uc_mem_write(uc, 0x3ff000, buf1, sizeof(buf1))) {
printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++);
return 2;
} else {
printf("ok %d - Random buffer 1 written to memory\n", log_num++);
}
if (uc_mem_write(uc, 0x401000, buf2, sizeof(buf2))) {
printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++);
return 3;
} else {
printf("ok %d - Random buffer 2 written to memory\n", log_num++);
}
// write machine code to be emulated to memory
if (uc_mem_write(uc, CODE_SECTION, 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(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++);
return 5;
} else {
printf("ok %d - UC_HOOK_CODE installed\n", log_num++);
}
// intercept memory write events
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++);
return 6;
} else {
printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++);
}
// intercept invalid memory events
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++);
return 7;
} else {
printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++);
}
// emulate machine code until told to stop by hook_code
printf("# BEGIN execution\n");
err = uc_emu_start(uc, CODE_SECTION, CODE_SECTION + CODE_SIZE, 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");
//read from the remapped memory
testval = 0x42424242;
for (addr = 0x200000; addr <= 0x400000; addr += 0x100000) {
uint32_t val;
if (uc_mem_read(uc, addr, &val, sizeof(val)) != UC_ERR_OK) {
printf("not ok %d - Failed uc_mem_read for address 0x%x\n", log_num++, addr);
} else {
printf("ok %d - Good uc_mem_read from 0x%x\n", log_num++, addr);
}
if (val != testval) {
printf("not ok %d - Read 0x%x, expected 0x%x\n", log_num++, val, testval);
} else {
printf("ok %d - Correct value retrieved\n", log_num++);
}
testval += 0x02020202;
}
//account for the two mods made by the machine code
buf1[512] = 0x47474747;
buf2[512] = 0x48484848;
//make sure that random blocks didn't get nuked
// fill in sections that shouldn't get touched
if (uc_mem_read(uc, 0x3ff000, readbuf, sizeof(readbuf))) {
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, 4096)) {
printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++);
} else {
printf("ok %d - Random buffer 1 contents are correct\n", log_num++);
}
}
if (uc_mem_read(uc, 0x401000, readbuf, sizeof(readbuf))) {
printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++);
} else {
printf("ok %d - Random buffer 2 read from memory\n", log_num++);
if (memcmp(buf2, readbuf, 4096)) {
printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++);
} else {
printf("ok %d - Random buffer 2 contents are correct\n", log_num++);
}
}
if (uc_close(uc) == 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;
}

293
tests/regress/mem_unmap.c Normal file
View File

@@ -0,0 +1,293 @@
/*
uc_mem_unmap demo / unit test
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[] =
"\xc7\x05\x00\x00\x20\x00\x41\x41\x41\x41\x90\xc7\x05\x00\x00\x20"
"\x00\x42\x42\x42\x42\xc7\x05\x00\x00\x30\x00\x43\x43\x43\x43\x90"
"\xc7\x05\x00\x00\x30\x00\x44\x44\x44\x44\xc7\x05\x00\x00\x40\x00"
"\x45\x45\x45\x45\x90\xc7\x05\x00\x00\x40\x00\x46\x46\x46\x46\xf4";
// total size: 64 bytes
/*
; assumes code section at 0x100000
; assumes data section at 0x200000, initially rw
; assumes data section at 0x300000, initially rw
; assumes data section at 0x400000, initially rw
; with installed hooks unmaps or maps on each nop
mov dword [0x200000], 0x41414141
nop ; unmap it
mov dword [0x200000], 0x42424242
mov dword [0x300000], 0x43434343
nop ; unmap it
mov dword [0x300000], 0x44444444
mov dword [0x400000], 0x45454545
nop ; unmap it
mov dword [0x400000], 0x46464646
hlt ; tell hook function we are done
*/
int test_num = 0;
uint32_t tests[] = {
0x41414141,
0x43434343,
0x45454545
};
static int log_num = 1;
#define CODE_SECTION 0x100000
#define CODE_SIZE 0x1000
// callback for tracing instruction
static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data)
{
uint8_t opcode;
uint32_t testval;
if (uc_mem_read(uc, 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);
}
printf("ok %d - uc_mem_read for opcode at address 0x%" PRIx64 "\n", log_num++, addr);
switch (opcode) {
case 0x90: //nop
printf("# Handling NOP\n");
if (uc_mem_read(uc, 0x200000 + test_num * 0x100000, &testval, sizeof(testval)) != UC_ERR_OK) {
printf("not ok %d - uc_mem_read fail for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000);
} else {
printf("ok %d - good uc_mem_read for address: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000);
printf("# uc_mem_read for test %d\n", test_num);
if (testval == tests[test_num]) {
printf("ok %d - passed test %d\n", log_num++, test_num);
} else {
printf("not ok %d - failed test %d\n", log_num++, test_num);
printf("# Expected: 0x%x\n",tests[test_num]);
printf("# Received: 0x%x\n", testval);
}
}
if (uc_mem_unmap(uc, 0x200000 + test_num * 0x100000, 0x1000) != UC_ERR_OK) {
printf("not ok %d - uc_mem_unmap fail during hook_code callback, addr: 0x%x\n", log_num++, 0x200000 + test_num * 0x100000);
} else {
printf("ok %d - uc_mem_unmap success\n", log_num++);
}
test_num++;
break;
case 0xf4: //hlt
printf("# Handling HLT\n");
if (uc_emu_stop(uc) != 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
printf("# Handling OTHER\n");
break;
}
}
// callback for tracing memory access (READ or WRITE)
static void hook_mem_write(uc_engine *uc, 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);
}
// callback for tracing invalid memory access (READ or WRITE)
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
uint64_t addr, int size, int64_t value, void *user_data)
{
uint32_t testval;
switch(type) {
default:
printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr);
return false;
case UC_MEM_WRITE:
printf("# write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value);
if (uc_mem_read(uc, addr, &testval, sizeof(testval)) != UC_ERR_OK) {
printf("ok %d - uc_mem_read fail for address: 0x%" PRIx64 "\n", log_num++, addr);
} else {
printf("not ok %d - uc_mem_read success after unmap at test %d\n", log_num++, test_num - 1);
}
if (uc_mem_map(uc, addr & ~0xfffL, 0x1000, UC_PROT_READ | UC_PROT_WRITE) != UC_ERR_OK) {
printf("not ok %d - uc_mem_map fail during hook_mem_invalid callback, addr: 0x%" PRIx64 "\n", log_num++, addr);
} else {
printf("ok %d - uc_mem_map success\n", log_num++);
}
return true;
}
}
int main(int argc, char **argv, char **envp)
{
uc_engine *uc;
uc_hook trace1, trace2;
uc_err err;
uint32_t addr, testval;
int32_t buf1[1024], buf2[1024], readbuf[1024];
int i;
//don't really care about quality of randomness
srand(time(NULL));
for (i = 0; i < 1024; i++) {
buf1[i] = rand();
buf2[i] = rand();
}
printf("# Memory unmapping test\n");
// Initialize emulator in X86-32bit mode
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
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(uc, CODE_SECTION, CODE_SIZE, UC_PROT_READ | UC_PROT_EXEC);
uc_mem_map(uc, 0x200000, 0x1000, UC_PROT_READ | UC_PROT_WRITE);
uc_mem_map(uc, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE);
uc_mem_map(uc, 0x3ff000, 0x3000, UC_PROT_READ | UC_PROT_WRITE);
// fill in sections that shouldn't get touched
if (uc_mem_write(uc, 0x3ff000, buf1, sizeof(buf1))) {
printf("not ok %d - Failed to write random buffer 1 to memory, quit!\n", log_num++);
return 2;
} else {
printf("ok %d - Random buffer 1 written to memory\n", log_num++);
}
if (uc_mem_write(uc, 0x401000, buf2, sizeof(buf1))) {
printf("not ok %d - Failed to write random buffer 2 to memory, quit!\n", log_num++);
return 3;
} else {
printf("ok %d - Random buffer 2 written to memory\n", log_num++);
}
// write machine code to be emulated to memory
if (uc_mem_write(uc, CODE_SECTION, 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(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++);
return 5;
} else {
printf("ok %d - UC_HOOK_CODE installed\n", log_num++);
}
// intercept memory write events
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++);
return 6;
} else {
printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++);
}
// intercept invalid memory events
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++);
return 7;
} else {
printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++);
}
// emulate machine code until told to stop by hook_code
printf("# BEGIN execution\n");
err = uc_emu_start(uc, CODE_SECTION, CODE_SECTION + CODE_SIZE, 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");
//read from the remapped memory
testval = 0x42424242;
for (addr = 0x200000; addr <= 0x400000; addr += 0x100000) {
uint32_t val;
if (uc_mem_read(uc, addr, &val, sizeof(val)) != UC_ERR_OK) {
printf("not ok %d - Failed uc_mem_read for address 0x%x\n", log_num++, addr);
} else {
printf("ok %d - Good uc_mem_read from 0x%x\n", log_num++, addr);
}
if (val != testval) {
printf("not ok %d - Read 0x%x, expected 0x%x\n", log_num++, val, testval);
} else {
printf("ok %d - Correct value retrieved\n", log_num++);
}
testval += 0x02020202;
}
//make sure that random blocks didn't get nuked
// fill in sections that shouldn't get touched
if (uc_mem_read(uc, 0x3ff000, readbuf, sizeof(readbuf))) {
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, 4096)) {
printf("not ok %d - Random buffer 1 contents are incorrect\n", log_num++);
} else {
printf("ok %d - Random buffer 1 contents are correct\n", log_num++);
}
}
if (uc_mem_read(uc, 0x401000, readbuf, sizeof(readbuf))) {
printf("not ok %d - Failed to read random buffer 2 from memory\n", log_num++);
} else {
printf("ok %d - Random buffer 2 read from memory\n", log_num++);
if (memcmp(buf2, readbuf, 4096)) {
printf("not ok %d - Random buffer 2 contents are incorrect\n", log_num++);
} else {
printf("ok %d - Random buffer 2 contents are correct\n", log_num++);
}
}
if (uc_close(uc) == 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;
}

40
tests/regress/memmap.py Executable file
View File

@@ -0,0 +1,40 @@
#!/usr/bin/python
# By Ryan Hileman, issue #9
# this prints out 2 lines and the contents must be the same
from unicorn import *
import regress
class MemMap(regress.RegressTest):
def test_mmap_write(self):
uc = Uc(UC_ARCH_X86, UC_MODE_64)
uc.mem_map(0x8048000, 0x2000)
uc.mem_write(0x8048000, 'test')
s1 = str(uc.mem_read(0x8048000, 4)).encode('hex')
self.assertEqual('test'.encode('hex'), s1)
uc.mem_map(0x804a000, 0x8000)
s2 = str(uc.mem_read(0x8048000, 4)).encode('hex')
self.assertEqual(s1, s2)
def test_mmap_invalid(self):
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
with self.assertRaises(UcError):
u.mem_map(0x2000, 0)
with self.assertRaises(UcError):
u.mem_map(0x4000, 1)
def test_mmap_weird(self):
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
for i in xrange(20):
with self.assertRaises(UcError):
u.mem_map(i*0x1000, 5)
u.mem_read(i*0x1000+6, 1)
if __name__ == '__main__':
regress.main()

View File

@@ -0,0 +1,35 @@
#!/usr/bin/env python
import unicorn
from unicorn import *
import regress
class MmapSeg(regress.RegressTest):
def test_seg1(self):
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
u.mem_map(0x2000, 0x1000)
u.mem_read(0x2000, 1)
for i in range(50):
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
u.mem_map(i*0x1000, 0x1000)
u.mem_read(i*0x1000, 1)
for i in range(20):
with self.assertRaises(UcError):
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
u.mem_map(i*0x1000, 5)
u.mem_read(i*0x1000, 1)
def test_seg2(self):
uc = Uc(UC_ARCH_X86, UC_MODE_32)
uc.mem_map(0x0000, 0x2000)
uc.mem_map(0x2000, 0x4000)
uc.mem_write(0x1000, 0x1004 * ' ')
self.assertTrue(1,
'If not reached, then we have BUG (crash on x86_64 Linux).')
if __name__ == '__main__':
regress.main()

View File

@@ -0,0 +1,37 @@
#!/usr/bin/python
from capstone import *
from unicorn import *
from unicorn.mips_const import *
import regress
class MipsBranchDelay(regress.RegressTest):
def runTest(self):
md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_LITTLE_ENDIAN)
def disas(code, addr):
for i in md.disasm(code, addr):
print '0x%x: %s %s' % (i.address, str(i.bytes).encode('hex'), i.op_str)
def hook_code(uc, addr, size, _):
mem = str(uc.mem_read(addr, size))
disas(mem, addr)
CODE = 0x400000
asm = '0000a4126a00822800000000'.decode('hex')
print 'Input instructions:'
disas(asm, CODE)
print
print 'Hooked instructions:'
uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN)
uc.hook_add(UC_HOOK_CODE, hook_code)
uc.mem_map(CODE, 0x1000)
uc.mem_write(CODE, asm)
self.assertEqual(None, uc.emu_start(CODE, CODE + len(asm)))
if __name__ == '__main__':
regress.main()

41
tests/regress/mips_except.py Executable file
View File

@@ -0,0 +1,41 @@
#!/usr/bin/python
from unicorn import *
from unicorn.mips_const import *
import regress
def hook_intr(uc, intno, _):
print 'interrupt', intno
CODE = 0x400000
asm = '0000a48f'.decode('hex') # lw $a0, ($sp)
class MipsExcept(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN)
uc.hook_add(UC_HOOK_INTR, hook_intr)
uc.mem_map(CODE, 0x1000)
uc.mem_write(CODE, asm)
with self.assertRaises(UcError) as m:
uc.reg_write(UC_MIPS_REG_SP, 0x400001)
uc.emu_start(CODE, CODE + len(asm), 300)
self.assertEqual(UC_ERR_READ_UNALIGNED, m.exception.errno)
with self.assertRaises(UcError) as m:
uc.reg_write(UC_MIPS_REG_SP, 0xFFFFFFF0)
uc.emu_start(CODE, CODE + len(asm), 200)
self.assertEqual(UC_ERR_READ_INVALID, m.exception.errno)
with self.assertRaises(UcError) as m:
uc.reg_write(UC_MIPS_REG_SP, 0x80000000)
uc.emu_start(CODE, CODE + len(asm), 100)
self.assertEqual(UC_ERR_READ_INVALID, m.exception.errno)
if __name__ == '__main__':
regress.main()

35
tests/regress/movsd.py Executable file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/python
# By Ryan Hileman, issue #3
from capstone import *
from unicorn import *
from unicorn.x86_const import *
import regress
code = 'f20f1005aa120000'.decode('hex')
def dis(mem, addr):
md = Cs(CS_ARCH_X86, CS_MODE_64)
return '\n'.join([
'%s %s' % (i.mnemonic, i.op_str)
for i in md.disasm(str(mem), addr)
])
def hook_code(uc, addr, size, user_data):
mem = uc.mem_read(addr, size)
print 'instruction size:', size
print 'instruction:', str(mem).encode('hex'), dis(mem, addr)
print 'reference: ', code.encode('hex'), dis(code, addr)
class Movsd(regress.RegressTest):
def runTest(self):
addr = 0x400000
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.hook_add(UC_HOOK_CODE, hook_code)
mu.mem_map(addr, 8 * 1024 * 1024)
mu.mem_write(addr, code)
mu.emu_start(addr, addr + len(code))
if __name__ == '__main__':
regress.main()

110
tests/regress/nr_mem_test.c Normal file
View File

@@ -0,0 +1,110 @@
/*
Non-readable memory test case
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.
*/
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <unicorn/unicorn.h>
const uint8_t PROGRAM[] =
"\x8b\x1d\x00\x00\x30\x00\xa1\x00\x00\x40\x00";
// total size: 11 bytes
/*
bits 32
mov ebx, [0x300000]
mov eax, [0x400000]
*/
// callback for tracing memory access (READ or WRITE)
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
uint64_t address, int size, int64_t value, void *user_data)
{
switch(type) {
default:
// return false to indicate we want to stop emulation
return false;
case UC_MEM_READ_PROT:
printf(">>> non-readable memory is being read at 0x%"PRIx64 ", data size = %u\n",
address, size);
return false;
}
}
int main(int argc, char **argv, char **envp)
{
uc_engine *uc;
uc_hook trace1, trace2;
uc_err err;
uint32_t eax, ebx;
printf("Memory protections test\n");
// 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: %u\n", err);
return 1;
}
uc_mem_map(uc, 0x100000, 0x1000, UC_PROT_READ);
uc_mem_map(uc, 0x300000, 0x1000, UC_PROT_READ | UC_PROT_WRITE);
uc_mem_map(uc, 0x400000, 0x1000, UC_PROT_WRITE);
// write machine code to be emulated to memory
if (uc_mem_write(uc, 0x100000, PROGRAM, sizeof(PROGRAM))) {
printf("Failed to write emulation code to memory, quit!\n");
return 2;
} else {
printf("Allowed to write to read only memory via uc_mem_write\n");
}
uc_mem_write(uc, 0x300000, (const uint8_t*)"\x41\x41\x41\x41", 4);
uc_mem_write(uc, 0x400000, (const uint8_t*)"\x42\x42\x42\x42", 4);
//uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff);
// intercept invalid memory events
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL);
// emulate machine code in infinite time
printf("BEGIN execution\n");
err = uc_emu_start(uc, 0x100000, 0x100000 + sizeof(PROGRAM), 0, 2);
if (err) {
printf("Expected failure on uc_emu_start() with error returned %u: %s\n",
err, uc_strerror(err));
} else {
printf("UNEXPECTED uc_emu_start returned UC_ERR_OK\n");
}
printf("END execution\n");
uc_reg_read(uc, UC_X86_REG_EAX, &eax);
printf("Final eax = 0x%x\n", eax);
uc_reg_read(uc, UC_X86_REG_EBX, &ebx);
printf("Final ebx = 0x%x\n", ebx);
uc_close(uc);
return 0;
}

21
tests/regress/pshufb.py Executable file
View File

@@ -0,0 +1,21 @@
#!/usr/bin/python
# By Ryan Hileman, issue #91
# Invalid instruction = test failed
from unicorn import *
from unicorn.x86_const import *
import regress
class Pshufb(regress.RegressTest):
def runTest(self):
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)
if __name__ == '__main__':
regress.main()

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env python
"""See https://github.com/unicorn-engine/unicorn/issues/98"""
import unicorn
import regress
ADDR = 0xffaabbcc
def hook_mem_invalid(mu, access, address, size, value, user_data):
print ">>> Access type: %u, expected value: 0x%x, actual value: 0x%x" % (access, ADDR, address)
assert(address == ADDR)
mu.mem_map(address & 0xfffff000, 4 * 1024)
mu.mem_write(address, b'\xcc')
return True
class RegWriteSignExt(regress.RegressTest):
def runTest(self):
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, ADDR)
mu.mem_map(0x10000000, 1024 * 4)
# jmp ebx
mu.mem_write(0x10000000, b'\xff\xe3')
mu.hook_add(unicorn.UC_HOOK_MEM_INVALID, hook_mem_invalid)
mu.emu_start(0x10000000, 0x10000000 + 2, count=1)
if __name__ == '__main__':
regress.main()

34
tests/regress/regress.py Executable file
View File

@@ -0,0 +1,34 @@
#!/usr/bin/python
import unittest
from os.path import dirname, basename, isfile
import glob
# Find all unittest type in this directory and run it.
class RegressTest(unittest.TestCase):
pass
def main():
unittest.main()
if __name__ == '__main__':
directory = dirname(__file__)
if directory == '':
directory = '.'
modules = glob.glob(directory+"/*.py")
__all__ = [ basename(f)[:-3] for f in modules if isfile(f)]
suite = unittest.TestSuite()
for module in __all__:
m = __import__(module)
for cl in dir(m):
try:
realcl = getattr(m,cl)
if issubclass(realcl, unittest.TestCase):
suite.addTest(realcl())
except Exception as e:
pass
unittest.TextTestRunner().run(suite)

184
tests/regress/rep_movsb.c Normal file
View File

@@ -0,0 +1,184 @@
/*
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(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data)
{
uint8_t opcode;
if (uc_mem_read(uc, 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(uc) != 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(uc_engine *uc, 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)
{
uc_engine *uc;
uc_hook 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, &uc);
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(uc, 0x100000, 0x1000, UC_PROT_READ);
uc_mem_map(uc, 0x200000, 0x2000, UC_PROT_READ | UC_PROT_WRITE);
// fill in the data that we want to copy
if (uc_mem_write(uc, 0x200000, 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(uc, 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(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)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(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != 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(uc, 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(uc, 0x201000, 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(uc) == 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;
}

211
tests/regress/ro_mem_test.c Normal file
View File

@@ -0,0 +1,211 @@
/*
Non-writable memory test case
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.
*/
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <unicorn/unicorn.h>
const uint8_t PROGRAM[] =
"\xeb\x1a\x58\x83\xc0\x04\x83\xe0\xfc\x83\xc0\x01\xc7\x00\x78\x56"
"\x34\x12\x83\xc0\x07\xc7\x00\x21\x43\x65\x87\x90\xe8\xe1\xff\xff"
"\xff" "xxxxAAAAxxxBBBB";
// total size: 33 bytes
/*
jmp short bottom
top:
pop eax
add eax, 4
and eax, 0xfffffffc
add eax, 1 ; unaligned
mov dword [eax], 0x12345678 ; try to write into code section
add eax, 7 ; aligned
mov dword [eax], 0x87654321 ; try to write into code section
nop
bottom:
call top
*/
// callback for tracing instruction
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
{
uint32_t esp;
printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
uc_reg_read(uc, UC_X86_REG_ESP, &esp);
printf(">>> --- ESP is 0x%x\n", esp);
}
// callback for tracing memory access (READ or WRITE)
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
uint64_t address, int size, int64_t value, void *user_data)
{
uint32_t esp;
uc_reg_read(uc, UC_X86_REG_ESP, &esp);
switch(type) {
default:
// return false to indicate we want to stop emulation
return false;
case UC_MEM_WRITE:
//if this is a push, esp has not been adjusted yet
if (esp == (address + size)) {
uint32_t upper;
upper = (esp + 0xfff) & ~0xfff;
printf(">>> Stack appears to be missing at 0x%"PRIx64 ", allocating now\n", address);
// map this memory in with 2MB in size
uc_mem_map(uc, upper - 0x8000, 0x8000, UC_PROT_READ | UC_PROT_WRITE);
// return true to indicate we want to continue
return true;
}
printf(">>> Missing memory is being WRITTEN at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n",
address, size, value);
return false;
case UC_MEM_WRITE_PROT:
printf(">>> RO memory is being WRITTEN at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n",
address, size, value);
return false;
}
}
#define STACK 0x500000
#define STACK_SIZE 0x5000
int main(int argc, char **argv, char **envp)
{
uc_engine *uc;
uc_hook trace1, trace2;
uc_err err;
uint8_t bytes[8];
uint32_t esp;
int result;
int map_stack = 0;
if (argc == 2 && strcmp(argv[1], "--map-stack") == 0) {
map_stack = 1;
}
printf("Memory mapping test\n");
// 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: %u\n", err);
return 1;
}
uc_mem_map(uc, 0x100000, 0x1000, UC_PROT_ALL);
uc_mem_map(uc, 0x200000, 0x2000, UC_PROT_ALL);
uc_mem_map(uc, 0x300000, 0x3000, UC_PROT_ALL);
uc_mem_map(uc, 0x400000, 0x4000, UC_PROT_READ);
if (map_stack) {
printf("Pre-mapping stack\n");
uc_mem_map(uc, STACK, STACK_SIZE, UC_PROT_READ | UC_PROT_WRITE);
} else {
printf("Mapping stack on first invalid memory access\n");
}
esp = STACK + STACK_SIZE;
uc_reg_write(uc, UC_X86_REG_ESP, &esp);
// write machine code to be emulated to memory
if (uc_mem_write(uc, 0x400000, PROGRAM, sizeof(PROGRAM))) {
printf("Failed to write emulation code to memory, quit!\n");
return 2;
} else {
printf("Allowed to write to read only memory via uc_mem_write\n");
}
//uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff);
// intercept invalid memory events
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL);
// emulate machine code in infinite time
printf("BEGIN execution - 1\n");
err = uc_emu_start(uc, 0x400000, 0x400000 + sizeof(PROGRAM), 0, 10);
if (err) {
printf("Expected failue on uc_emu_start() with error returned %u: %s\n",
err, uc_strerror(err));
} else {
printf("UNEXPECTED uc_emu_start returned UC_ERR_OK\n");
}
printf("END execution - 1\n");
// emulate machine code in infinite time
printf("BEGIN execution - 2\n");
//update eax to point to aligned memory (same as add eax,7 above)
uint32_t eax = 0x40002C;
uc_reg_write(uc, UC_X86_REG_EAX, &eax);
//resume execution at the mov dword [eax], 0x87654321
//to test an aligned write as well
err = uc_emu_start(uc, 0x400015, 0x400000 + sizeof(PROGRAM), 0, 2);
if (err) {
printf("Expected failure on uc_emu_start() with error returned %u: %s\n",
err, uc_strerror(err));
} else {
printf("UNEXPECTED uc_emu_start returned UC_ERR_OK\n");
}
printf("END execution - 2\n");
printf("Verifying content at 0x400025 is unchanged\n");
if (!uc_mem_read(uc, 0x400025, bytes, 4)) {
printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)0x400025, *(uint32_t*) bytes);
if (0x41414141 != *(uint32_t*) bytes) {
printf("ERROR content in read only memory changed\n");
} else {
printf("SUCCESS content in read only memory unchanged\n");
}
} else {
printf(">>> Failed to read 4 bytes from [0x%x]\n", (uint32_t)(esp - 4));
return 4;
}
printf("Verifying content at 0x40002C is unchanged\n");
if (!uc_mem_read(uc, 0x40002C, bytes, 4)) {
printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)0x40002C, *(uint32_t*) bytes);
if (0x42424242 != *(uint32_t*) bytes) {
printf("ERROR content in read only memory changed\n");
} else {
printf("SUCCESS content in read only memory unchanged\n");
}
} else {
printf(">>> Failed to read 4 bytes from [0x%x]\n", (uint32_t)(esp - 4));
return 4;
}
printf("Verifying content at bottom of stack is readable and correct\n");
if (!uc_mem_read(uc, esp - 4, bytes, 4)) {
printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", (uint32_t)(esp - 4), *(uint32_t*) bytes);
} else {
printf(">>> Failed to read 4 bytes from [0x%x]\n", (uint32_t)(esp - 4));
return 4;
}
uc_close(uc);
return 0;
}

46
tests/regress/sigill.c Normal file
View File

@@ -0,0 +1,46 @@
#include <unicorn/unicorn.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define UC_BUG_WRITE_SIZE 128
#define UC_BUG_WRITE_ADDR 0x1000 // fix this by change this to 0x2000
int got_sigill = 0;
void _interrupt(uc_engine *uc, uint32_t intno, void *user_data)
{
if (intno == 6) {
uc_emu_stop(uc);
got_sigill = 1;
}
}
int main()
{
int size;
uint8_t *buf;
uc_engine *uc;
uc_hook uh_trap;
uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc);
if (err) {
fprintf (stderr, "Cannot initialize unicorn\n");
return 1;
}
size = UC_BUG_WRITE_SIZE;
buf = malloc (size);
if (!buf) {
fprintf (stderr, "Cannot allocate\n");
return 1;
}
memset (buf, 0, size);
if (!uc_mem_map(uc, UC_BUG_WRITE_ADDR, size, UC_PROT_ALL)) {
uc_mem_write(uc, UC_BUG_WRITE_ADDR,
(const uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff", 8);
}
uc_hook_add(uc, &uh_trap, UC_HOOK_INTR, _interrupt, NULL);
uc_emu_start(uc, UC_BUG_WRITE_ADDR, UC_BUG_WRITE_ADDR+8, 0, 1);
uc_close(uc);
printf ("Correct: %s\n", got_sigill? "YES": "NO");
return got_sigill? 0: 1;
}

29
tests/regress/sigill2.c Normal file
View File

@@ -0,0 +1,29 @@
#include <unicorn/unicorn.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define UC_BUG_WRITE_SIZE 128
#define UC_BUG_WRITE_ADDR 0x2000
int main()
{
int size;
uint8_t *buf;
uc_engine *uc;
uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc);
if (err) {
fprintf (stderr, "Cannot initialize unicorn\n");
return 1;
}
size = UC_BUG_WRITE_SIZE;
if (!uc_mem_map (uc, UC_BUG_WRITE_ADDR, size, UC_PROT_ALL)) {
uc_mem_write (uc, UC_BUG_WRITE_ADDR,
(const uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff", 8);
}
err = uc_emu_start(uc, UC_BUG_WRITE_ADDR, UC_BUG_WRITE_ADDR+8, 0, 1);
uc_close(uc);
printf ("Error = %u (%s)\n", err, uc_strerror(err));
return err? -1: 0;
}

24
tests/regress/sparc64.py Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/python
from unicorn import *
from unicorn.sparc_const import *
PAGE_SIZE = 1 * 1024 * 1024
uc = Uc(UC_ARCH_SPARC, UC_MODE_64)
uc.reg_write(UC_SPARC_REG_SP, 100)
print 'writing sp = 100'
# 0: b0 06 20 01 inc %i0
# 4: b2 06 60 01 inc %i1
CODE = "\xb0\x06\x20\x01" \
"\xb2\x06\x60\x01"
uc.mem_map(0, PAGE_SIZE)
uc.mem_write(0, CODE)
uc.emu_start(0, len(CODE), 0, 2)
print 'sp =', uc.reg_read(UC_SPARC_REG_SP)
print 'i0 =', uc.reg_read(UC_SPARC_REG_I0)
print 'i1 =', uc.reg_read(UC_SPARC_REG_I1)

205
tests/regress/sparc_reg.py Executable file
View File

@@ -0,0 +1,205 @@
#!/usr/bin/python
from unicorn import *
from unicorn.sparc_const import *
PAGE_SIZE = 1 * 1024 * 1024
uc = Uc(UC_ARCH_SPARC, UC_MODE_32)
uc.reg_write(UC_SPARC_REG_SP, 100)
uc.reg_write(UC_SPARC_REG_FP, 200)
# 0x0: \x80\x00\x20\x01 add %g0, 1, %g0
# 0x4: \x82\x00\x60\x01 add %g1, 1, %g1
# 0x8: \x84\x00\xA0\x01 add %g2, 1, %g2
# 0xc: \x86\x00\xE0\x01 add %g3, 1, %g3
# 0x10: \x88\x01\x20\x01 add %g4, 1, %g4
# 0x14: \x8A\x01\x60\x01 add %g5, 1, %g5
# 0x18: \x8C\x01\xA0\x01 add %g6, 1, %g6
# 0x1c: \x8E\x01\xE0\x01 add %g7, 1, %g7
# 0x20: \x90\x02\x20\x01 add %o0, 1, %o0
# 0x24: \x92\x02\x60\x01 add %o1, 1, %o1
# 0x28: \x94\x02\xA0\x01 add %o2, 1, %o2
# 0x2c: \x96\x02\xE0\x01 add %o3, 1, %o3
# 0x30: \x98\x03\x20\x01 add %o4, 1, %o4
# 0x34: \x9A\x03\x60\x01 add %o5, 1, %o5
# 0x38: \x9C\x03\xA0\x01 add %sp, 1, %sp
# 0x3c: \x9E\x03\xE0\x01 add %o7, 1, %o7
# 0x40: \xA0\x04\x20\x01 add %l0, 1, %l0
# 0x44: \xA2\x04\x60\x01 add %l1, 1, %l1
# 0x48: \xA4\x04\xA0\x01 add %l2, 1, %l2
# 0x4c: \xA6\x04\xE0\x01 add %l3, 1, %l3
# 0x50: \xA8\x05\x20\x01 add %l4, 1, %l4
# 0x54: \xAA\x05\x60\x01 add %l5, 1, %l5
# 0x58: \xAC\x05\xA0\x01 add %l6, 1, %l6
# 0x5c: \xAE\x05\xE0\x01 add %l7, 1, %l7
# 0x0: \xB0\x06\x20\x01 add %i0, 1, %i0
# 0x4: \xB2\x06\x60\x01 add %i1, 1, %i1
# 0x8: \xB4\x06\xA0\x01 add %i2, 1, %i2
# 0xc: \xB6\x06\xE0\x01 add %i3, 1, %i3
# 0x10: \xB8\x07\x20\x01 add %i4, 1, %i4
# 0x14: \xBA\x07\x60\x01 add %i5, 1, %i5
# 0x18: \xBC\x07\xA0\x01 add %fp, 1, %fp
# 0x1c: \xBE\x07\xE0\x01 add %i7, 1, %i7
CODE = "\x80\x00\x20\x01" \
"\x82\x00\x60\x01" \
"\x84\x00\xA0\x01" \
"\x86\x00\xE0\x01" \
"\x88\x01\x20\x01" \
"\x8A\x01\x60\x01" \
"\x8C\x01\xA0\x01" \
"\x8E\x01\xE0\x01" \
"\x90\x02\x20\x01" \
"\x92\x02\x60\x01" \
"\x94\x02\xA0\x01" \
"\x96\x02\xE0\x01" \
"\x98\x03\x20\x01" \
"\x9A\x03\x60\x01" \
"\x9C\x03\xA0\x01" \
"\x9E\x03\xE0\x01" \
"\xA0\x04\x20\x01" \
"\xA2\x04\x60\x01" \
"\xA4\x04\xA0\x01" \
"\xA6\x04\xE0\x01" \
"\xA8\x05\x20\x01" \
"\xAA\x05\x60\x01" \
"\xAC\x05\xA0\x01" \
"\xAE\x05\xE0\x01" \
"\xB0\x06\x20\x01" \
"\xB2\x06\x60\x01" \
"\xB4\x06\xA0\x01" \
"\xB6\x06\xE0\x01" \
"\xB8\x07\x20\x01" \
"\xBA\x07\x60\x01" \
"\xBC\x07\xA0\x01" \
"\xBE\x07\xE0\x01"
uc.mem_map(0, PAGE_SIZE)
uc.mem_write(0, CODE)
uc.emu_start(0, len(CODE), 0, 32)
def print_registers(mu):
g0 = mu.reg_read(UC_SPARC_REG_G0)
g1 = mu.reg_read(UC_SPARC_REG_G1)
g2 = mu.reg_read(UC_SPARC_REG_G2)
g3 = mu.reg_read(UC_SPARC_REG_G3)
g4 = mu.reg_read(UC_SPARC_REG_G4)
g5 = mu.reg_read(UC_SPARC_REG_G5)
g6 = mu.reg_read(UC_SPARC_REG_G6)
g7 = mu.reg_read(UC_SPARC_REG_G7)
o0 = mu.reg_read(UC_SPARC_REG_O0)
o1 = mu.reg_read(UC_SPARC_REG_O1)
o2 = mu.reg_read(UC_SPARC_REG_O2)
o3 = mu.reg_read(UC_SPARC_REG_O3)
o4 = mu.reg_read(UC_SPARC_REG_O4)
o5 = mu.reg_read(UC_SPARC_REG_O5)
o6 = mu.reg_read(UC_SPARC_REG_O6)
o7 = mu.reg_read(UC_SPARC_REG_O7)
l0 = mu.reg_read(UC_SPARC_REG_L0)
l1 = mu.reg_read(UC_SPARC_REG_L1)
l2 = mu.reg_read(UC_SPARC_REG_L2)
l3 = mu.reg_read(UC_SPARC_REG_L3)
l4 = mu.reg_read(UC_SPARC_REG_L4)
l5 = mu.reg_read(UC_SPARC_REG_L5)
l6 = mu.reg_read(UC_SPARC_REG_L6)
l7 = mu.reg_read(UC_SPARC_REG_L7)
i0 = mu.reg_read(UC_SPARC_REG_I0)
i1 = mu.reg_read(UC_SPARC_REG_I1)
i2 = mu.reg_read(UC_SPARC_REG_I2)
i3 = mu.reg_read(UC_SPARC_REG_I3)
i4 = mu.reg_read(UC_SPARC_REG_I4)
i5 = mu.reg_read(UC_SPARC_REG_I5)
i6 = mu.reg_read(UC_SPARC_REG_I6)
i7 = mu.reg_read(UC_SPARC_REG_I7)
pc = mu.reg_read(UC_SPARC_REG_PC)
sp = mu.reg_read(UC_SPARC_REG_SP)
fp = mu.reg_read(UC_SPARC_REG_FP)
print(" G0 = %d" % g0)
print(" G1 = %d" % g1)
print(" G2 = %d" % g2)
print(" G3 = %d" % g3)
print(" G4 = %d" % g4)
print(" G5 = %d" % g5)
print(" G6 = %d" % g6)
print(" G7 = %d" % g7)
print("")
print(" O0 = %d" % o0)
print(" O1 = %d" % o1)
print(" O2 = %d" % o2)
print(" O3 = %d" % o3)
print(" O4 = %d" % o4)
print(" O5 = %d" % o5)
print(" O6 = %d" % o6)
print(" O7 = %d" % o7)
print("")
print(" L0 = %d" % l0)
print(" L1 = %d" % l1)
print(" L2 = %d" % l2)
print(" L3 = %d" % l3)
print(" L4 = %d" % l4)
print(" L5 = %d" % l5)
print(" L6 = %d" % l6)
print(" L7 = %d" % l7)
print("")
print(" I0 = %d" % i0)
print(" I1 = %d" % i1)
print(" I2 = %d" % i2)
print(" I3 = %d" % i3)
print(" I4 = %d" % i4)
print(" I5 = %d" % i5)
print(" I6 = %d" % i6)
print(" I7 = %d" % i7)
print("")
print(" PC = %d" % pc)
print(" SP = %d" % sp)
print(" FP = %d" % fp)
print("")
print_registers(uc)
assert uc.reg_read(UC_SPARC_REG_PC) == 128 # make sure we executed all instructions
assert uc.reg_read(UC_SPARC_REG_SP) == 101
assert uc.reg_read(UC_SPARC_REG_FP) == 201
assert uc.reg_read(UC_SPARC_REG_G0) == 0 # G0 is always zero
assert uc.reg_read(UC_SPARC_REG_G1) == 1
assert uc.reg_read(UC_SPARC_REG_G2) == 1
assert uc.reg_read(UC_SPARC_REG_G3) == 1
assert uc.reg_read(UC_SPARC_REG_G4) == 1
assert uc.reg_read(UC_SPARC_REG_G5) == 1
assert uc.reg_read(UC_SPARC_REG_G6) == 1
assert uc.reg_read(UC_SPARC_REG_G7) == 1
assert uc.reg_read(UC_SPARC_REG_O0) == 1
assert uc.reg_read(UC_SPARC_REG_O1) == 1
assert uc.reg_read(UC_SPARC_REG_O2) == 1
assert uc.reg_read(UC_SPARC_REG_O3) == 1
assert uc.reg_read(UC_SPARC_REG_O4) == 1
assert uc.reg_read(UC_SPARC_REG_O5) == 1
assert uc.reg_read(UC_SPARC_REG_O6) == 101
assert uc.reg_read(UC_SPARC_REG_O7) == 1
assert uc.reg_read(UC_SPARC_REG_L0) == 1
assert uc.reg_read(UC_SPARC_REG_L1) == 1
assert uc.reg_read(UC_SPARC_REG_L2) == 1
assert uc.reg_read(UC_SPARC_REG_L3) == 1
assert uc.reg_read(UC_SPARC_REG_L4) == 1
assert uc.reg_read(UC_SPARC_REG_L5) == 1
assert uc.reg_read(UC_SPARC_REG_L6) == 1
assert uc.reg_read(UC_SPARC_REG_L7) == 1
assert uc.reg_read(UC_SPARC_REG_I0) == 1
assert uc.reg_read(UC_SPARC_REG_I1) == 1
assert uc.reg_read(UC_SPARC_REG_I2) == 1
assert uc.reg_read(UC_SPARC_REG_I3) == 1
assert uc.reg_read(UC_SPARC_REG_I4) == 1
assert uc.reg_read(UC_SPARC_REG_I5) == 1
assert uc.reg_read(UC_SPARC_REG_I6) == 201
assert uc.reg_read(UC_SPARC_REG_I7) == 1

View File

@@ -0,0 +1,149 @@
/*
timeout_segfault.c
This program shows a case where the emulation timer keeps running after
emulation has ended. It triggers an intermittent segfault when _timeout_fn()
tries to call uc_emu_stop() after emulation has already been cleaned up. This
code is the same as samples/sample_arm.c, except that it adds a timeout on each
call to uc_emu_start(). See issue #78 for more details:
https://github.com/unicorn-engine/unicorn/issues/78
*/
#include <inttypes.h>
#include <unicorn/unicorn.h>
// code to be emulated
#define ARM_CODE "\x37\x00\xa0\xe3\x03\x10\x42\xe0" // mov r0, #0x37; sub r1, r2, r3
#define THUMB_CODE "\x83\xb0" // sub sp, #0xc
// memory address where emulation starts
#define ADDRESS 0x10000
// number of seconds to wait before timeout
#define TIMEOUT 5
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
{
printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size);
}
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
{
printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
}
static void test_arm(void)
{
uc_engine *uc;
uc_err err;
uc_hook trace1, trace2;
int r0 = 0x1234; // R0 register
int r2 = 0x6789; // R1 register
int r3 = 0x3333; // R2 register
int r1; // R1 register
printf("Emulate ARM code\n");
// Initialize emulator in ARM mode
err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc);
if (err) {
printf("Failed on uc_open() with error returned: %u (%s)\n",
err, uc_strerror(err));
return;
}
// map 2MB memory for this emulation
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
// write machine code to be emulated to memory
uc_mem_write(uc, ADDRESS, ARM_CODE, sizeof(ARM_CODE) - 1);
// initialize machine registers
uc_reg_write(uc, UC_ARM_REG_R0, &r0);
uc_reg_write(uc, UC_ARM_REG_R2, &r2);
uc_reg_write(uc, UC_ARM_REG_R3, &r3);
// tracing all basic blocks with customized callback
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
// tracing one instruction at ADDRESS with customized callback
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS);
// emulate machine code in infinite time (last param = 0), or when
// finishing all the code.
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, UC_SECOND_SCALE * TIMEOUT, 0);
if (err) {
printf("Failed on uc_emu_start() with error returned: %u\n", err);
}
// now print out some registers
printf(">>> Emulation done. Below is the CPU context\n");
uc_reg_read(uc, UC_ARM_REG_R0, &r0);
uc_reg_read(uc, UC_ARM_REG_R1, &r1);
printf(">>> R0 = 0x%x\n", r0);
printf(">>> R1 = 0x%x\n", r1);
uc_close(uc);
}
static void test_thumb(void)
{
uc_engine *uc;
uc_err err;
uc_hook trace1, trace2;
int sp = 0x1234; // R0 register
printf("Emulate THUMB code\n");
// Initialize emulator in ARM mode
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &uc);
if (err) {
printf("Failed on uc_open() with error returned: %u (%s)\n",
err, uc_strerror(err));
return;
}
// map 2MB memory for this emulation
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
// write machine code to be emulated to memory
uc_mem_write(uc, ADDRESS, THUMB_CODE, sizeof(THUMB_CODE) - 1);
// initialize machine registers
uc_reg_write(uc, UC_ARM_REG_SP, &sp);
// tracing all basic blocks with customized callback
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
// tracing one instruction at ADDRESS with customized callback
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS);
// emulate machine code in infinite time (last param = 0), or when
// finishing all the code.
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(THUMB_CODE) -1, UC_SECOND_SCALE * TIMEOUT, 0);
if (err) {
printf("Failed on uc_emu_start() with error returned: %u\n", err);
}
// now print out some registers
printf(">>> Emulation done. Below is the CPU context\n");
uc_reg_read(uc, UC_ARM_REG_SP, &sp);
printf(">>> SP = 0x%x\n", sp);
uc_close(uc);
}
int main(int argc, char **argv, char **envp)
{
test_arm();
printf("==========================\n");
test_thumb();
return 0;
}

71
tests/regress/wrong_rip.py Executable file
View File

@@ -0,0 +1,71 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
import regress
binary1 = b'\xb8\x02\x00\x00\x00' # mov eax, 2
binary2 = b'\xb8\x01\x00\x00\x00' # mov eax, 1
class WrongRIP(regress.RegressTest):
def test_step(self):
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(0, binary1 + binary2)
# emu for maximum 1 instruction.
mu.emu_start(0, 5, 0, 1)
self.assertEqual(0x2, mu.reg_read(UC_X86_REG_RAX))
self.assertEqual(0x5, mu.reg_read(UC_X86_REG_RIP))
mu.emu_start(5, 10, 0, 1)
self.assertEqual(0xa, mu.reg_read(UC_X86_REG_RIP))
self.assertEqual(0x1, mu.reg_read(UC_X86_REG_RAX))
def test_step2(self):
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(0, binary1 + binary2)
# emu for maximum 1 instruction.
mu.emu_start(0, 10, 0, 1)
self.assertEqual(0x2, mu.reg_read(UC_X86_REG_RAX))
self.assertEqual(0x5, mu.reg_read(UC_X86_REG_RIP))
mu.emu_start(5, 10, 0, 1)
self.assertEqual(0x1, mu.reg_read(UC_X86_REG_RAX))
self.assertEqual(0xa, mu.reg_read(UC_X86_REG_RIP))
def test_step3(self):
bin3 = b'\x40\x01\xc1\x31\xf6' # inc eax; add ecx, eax; xor esi, esi
mu = Uc(UC_ARCH_X86, UC_MODE_32)
mu.mem_map(0, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(0, bin3)
# emu for maximum 1 instruction.
mu.emu_start(0, 10, 0, 1)
self.assertEqual(0x1, mu.reg_read(UC_X86_REG_EAX))
self.assertEqual(0x1, mu.reg_read(UC_X86_REG_EIP))
def test_step_then_fin(self):
bin4 = b'\x40\x01\xc1\x31\xf6\x90\x90\x90' # inc eax; add ecx, eax; xor esi, esi
mu = Uc(UC_ARCH_X86, UC_MODE_32)
mu.mem_map(0, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(0, bin4)
# emu for maximum 1 instruction.
mu.emu_start(0, len(binary1), 0, 1)
self.assertEqual(0x1, mu.reg_read(UC_X86_REG_EAX))
self.assertEqual(0x1, mu.reg_read(UC_X86_REG_EIP))
# emu to the end
mu.emu_start(1, len(bin4))
self.assertEqual(0x1, mu.reg_read(UC_X86_REG_EAX))
self.assertEqual(len(bin4), mu.reg_read(UC_X86_REG_EIP))
if __name__ == '__main__':
regress.main()

38
tests/regress/wrong_rip_arm.py Executable file
View File

@@ -0,0 +1,38 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
from unicorn.arm_const import *
import regress
# adds r1, #0x48
# ldrsb r7, [r7, r7]
# ldrsh r7, [r2, r1]
# ldr r0, [pc, #0x168]
# cmp r7, #0xbf
# str r7, [r5, #0x20]
# ldr r1, [r5, #0x64]
# strb r7, [r5, #0xc]
# ldr r0, [pc, #0x1a0]
binary1 = b'\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05'
# binary1 = b'\x48\x31\xff\x57'
#adds r1, #0x48
#ldrsb r7, [r7, r7]
class WrongRIPArm(regress.RegressTest):
def runTest(self):
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
mu.mem_map(0, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(0, binary1)
mu.reg_write(UC_ARM_REG_R13, 1 * 1024 * 1024)
# emu for maximum 1 instruction.
mu.emu_start(0, len(binary1), 0, 1)
self.assertEqual(0x48, mu.reg_read(UC_ARM_REG_R1))
pos = mu.reg_read(UC_ARM_REG_R15)
self.assertEqual(0x2, pos)
if __name__ == '__main__':
regress.main()

28
tests/regress/wrong_sp_arm.py Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/python
# By Ryan Hileman, issue #16
from unicorn import *
from unicorn.arm_const import *
from unicorn.arm64_const import *
import regress
class WrongSPArm(regress.RegressTest):
def test_32(self):
with self.assertRaises(UcError):
uc = Uc(UC_ARCH_ARM, UC_MODE_32)
uc.reg_write(UC_ARM_REG_SP, 4)
def test_64(self):
uc = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
uc.reg_write(UC_ARM64_REG_SP, 4)
self.assertEqual(0x4, uc.reg_read(UC_ARM64_REG_SP))
def test_arm(self):
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
uc.reg_write(UC_ARM_REG_SP, 4)
self.assertEqual(0x4, uc.reg_read(UC_ARM_REG_SP))
if __name__ == '__main__':
regress.main()