Merge branch 'master' into memleak2

This commit is contained in:
Nguyen Anh Quynh
2016-02-15 15:52:10 +08:00
26 changed files with 1117 additions and 91 deletions

View File

@ -37,6 +37,7 @@ TESTS += mips_branch_likely_issue
TESTS += hook_extrainvoke
TESTS += sysenter_hook_x86
TESTS += emu_clear_errors
TESTS += mem_fuzz
TESTS += memleak_x86
TESTS += memleak_arm

View File

@ -0,0 +1,109 @@
#!/usr/bin/env python
# Sample code for ARM of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
#
from __future__ import print_function
from unicorn import *
from unicorn.arm_const import *
# code to be emulated
ARM_CODE = "\x37\x00\xa0\xe3\x03\x10\x42\xe0" # mov r0, #0x37; sub r1, r2, r3
THUMB_CODE = "\x83\xb0" # sub sp, #0xc
# memory address where emulation starts
ADDRESS = 0xF0000000
# 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))
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
# Test ARM
def test_arm():
print("Emulate ARM code")
try:
# Initialize emulator in ARM mode
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
mem_size = 2 * (1024 * 1024)
mu.mem_map(ADDRESS, mem_size)
stack_address = ADDRESS + mem_size
stack_size = stack_address # >>> here huge memory size
mu.mem_map(stack_address, stack_size)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, ARM_CODE)
# initialize machine registers
mu.reg_write(UC_ARM_REG_R0, 0x1234)
mu.reg_write(UC_ARM_REG_R2, 0x6789)
mu.reg_write(UC_ARM_REG_R3, 0x3333)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, hook_block)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE))
# now print out some registers
print(">>> Emulation done. Below is the CPU context")
r0 = mu.reg_read(UC_ARM_REG_R0)
r1 = mu.reg_read(UC_ARM_REG_R1)
print(">>> R0 = 0x%x" %r0)
print(">>> R1 = 0x%x" %r1)
except UcError as e:
print("ERROR: %s" % e)
def test_thumb():
print("Emulate THUMB code")
try:
# Initialize emulator in thumb mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, THUMB_CODE)
# initialize machine registers
mu.reg_write(UC_ARM_REG_SP, 0x1234)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, hook_block)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + len(THUMB_CODE))
# now print out some registers
print(">>> Emulation done. Below is the CPU context")
sp = mu.reg_read(UC_ARM_REG_SP)
print(">>> SP = 0x%x" %sp)
except UcError as e:
print("ERROR: %s" % e)
if __name__ == '__main__':
test_arm()
print("=" * 20)
test_thumb()

119
tests/regress/mem_fuzz.c Normal file
View File

@ -0,0 +1,119 @@
#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>
uint64_t baseranges[] = {0,0,0,0};
int step =0;
uint64_t urnd(){
uint64_t rnd = rand();
rnd = rnd << 32;
rnd += rand();
return rnd;
}
uint64_t get_addr(){
uint64_t base = ((uint64_t)urnd())%4;
uint64_t addr= baseranges[base] + urnd()%(4096*10);
return addr;
}
uint64_t get_aligned_addr(){
uint64_t addr = get_addr();
return addr - (addr % 4096);
}
uint64_t get_len(){
uint64_t len = (urnd() % (4096*5))+1;
return len;
}
uint64_t get_aligned_len(){
uint64_t len = get_len();
len = len - (len %4096);
len = ((len == 0) ? 4096 : len);
return len;
}
void perform_map_step(uc_engine *uc){
uint64_t addr = get_aligned_addr();
uint64_t len = get_aligned_len();
printf("map(uc,0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step);
uc_mem_map(uc, addr, len, UC_PROT_READ | UC_PROT_WRITE);
}
void perform_unmap_step(uc_engine *uc){
uint64_t addr = get_aligned_addr();
uint64_t len = get_aligned_len();
printf("unmap(uc,0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step);
uc_mem_unmap(uc, addr, len);
}
void perform_write_step(uc_engine *uc){
char* buff[4096*4];
memset(buff, 0, 4096*4);
uint64_t addr = get_addr();
uint64_t len = get_len()%(4096*3);
printf("write(uc,0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step);
uc_mem_write(uc, addr, buff, len);
}
void perform_read_step(uc_engine *uc){
char* buff[4096*4];
uint64_t addr = get_addr();
uint64_t len = get_len()%(4096*3);
printf("read(uc,0x%"PRIx64",0x%"PRIx64"); //%d\n", addr, len, step);
uc_mem_read(uc, addr, buff, len);
}
void perform_fuzz_step(uc_engine *uc){
switch( ((uint32_t)rand())%4 ){
case 0: perform_map_step(uc); break;
case 1: perform_unmap_step(uc); break;
case 2: perform_read_step(uc); break;
case 3: perform_write_step(uc); break;
}
}
int main(int argc, char **argv, char **envp)
{
uc_engine *uc;
uc_hook trace1, trace2;
uc_err err;
if(argc<2){
printf("usage: mem_fuzz $seed\n");
return 1;
}
int seed = atoi(argv[1]);
int i = 0;
//don't really care about quality of randomness
srand(seed);
printf("running with seed %d\n",seed);
// Initialize emulator in X86-32bit mode
err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc);
if (err) {
printf("Failed on uc_open() with error returned: %u\n", err);
return 1;
}
for(i = 0; i < 2048; i++){
step++;
perform_fuzz_step(uc);
}
// fill in sections that shouldn't get touched
if (uc_close(uc) != UC_ERR_OK) {
printf("Failed on uc_close\n");
return 1;
}
return 0;
}

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

@ -0,0 +1,27 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
import regress
class VldrPcInsn(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_X86, UC_MODE_32)
uc.mem_map(0x1000, 0x1000)
# mov gs, eax; mov eax, 1
code = '8ee8b801000000'.decode('hex')
uc.mem_write(0x1000, code)
uc.reg_write(UC_X86_REG_EAX, 0xFFFFFFFF)
# this should throw an error
# the eax test is just to prove the second instruction doesn't execute
try:
uc.emu_start(0x1000, len(code))
except UcError:
return
self.assertEqual(uc.reg_read(UC_X86_REG_EAX), 1)
if __name__ == '__main__':
regress.main()

View File

@ -0,0 +1,163 @@
#include <unicorn/unicorn.h>
#include <inttypes.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
/**
* Assert that err matches expect
*/
#define uc_assert_err(expect, err) \
do { \
uc_err __err = err; \
if (__err != expect) { \
fprintf(stderr, "%s", uc_strerror(__err)); \
exit(1); \
} \
} while (0)
/**
* Assert that err is UC_ERR_OK
*/
#define uc_assert_success(err) uc_assert_err(UC_ERR_OK, err)
/**
* Assert that err is anything but UC_ERR_OK
*
* Note: Better to use uc_assert_err(<specific error>, err),
* as this serves to document which errors a function will return
* in various scenarios.
*/
#define uc_assert_fail(err) \
do { \
uc_err __err = err; \
if (__err == UC_ERR_OK) { \
fprintf(stderr, "%s", uc_strerror(__err)); \
exit(1); \
} \
} while (0)
#define OK(x) uc_assert_success(x)
/******************************************************************************/
static void test_idt_gdt_i386(/*void **state*/)
{
uc_engine *uc;
uc_err err;
uint8_t buf[6];
uc_x86_mmr idt;
uc_x86_mmr gdt;
uc_x86_mmr ldt;
uc_x86_mmr tr;
const uint8_t code[] = "\x0f\x01\x0c\x24\x0f\x01\x44\x24\x06"; // sidt [esp]; sgdt [esp+6]
const uint64_t address = 0x1000000;
int r_esp = address + 0x1000 - 0x100; // initial esp
idt.base = 0x12345678;
idt.limit = 0xabcd;
gdt.base = 0x87654321;
gdt.limit = 0xdcba;
ldt.base = 0xfedcba98;
ldt.limit = 0x11111111;
ldt.selector = 0x3333;
ldt.flags = 0x55555555;
tr.base = 0x22222222;
tr.limit = 0x33333333;
tr.selector = 0x4444;
tr.flags = 0x66666666;
// Initialize emulator in X86-32bit mode
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
uc_assert_success(err);
// map 1 page memory for this emulation
err = uc_mem_map(uc, address, 0x1000, UC_PROT_ALL);
uc_assert_success(err);
// write machine code to be emulated to memory
err = uc_mem_write(uc, address, code, sizeof(code)-1);
uc_assert_success(err);
// initialize machine registers
err = uc_reg_write(uc, UC_X86_REG_ESP, &r_esp);
uc_assert_success(err);
err = uc_reg_write(uc, UC_X86_REG_IDTR, &idt);
uc_assert_success(err);
err = uc_reg_write(uc, UC_X86_REG_GDTR, &gdt);
uc_assert_success(err);
err = uc_reg_write(uc, UC_X86_REG_LDTR, &ldt);
uc_assert_success(err);
err = uc_reg_write(uc, UC_X86_REG_TR, &tr);
uc_assert_success(err);
memset(&idt, 0, sizeof(idt));
memset(&gdt, 0, sizeof(gdt));
memset(&ldt, 0, sizeof(ldt));
memset(&tr, 0, sizeof(tr));
// emulate machine code in infinite time
err = uc_emu_start(uc, address, address+sizeof(code)-1, 0, 0);
uc_assert_success(err);
uc_reg_read(uc, UC_X86_REG_IDTR, &idt);
assert(idt.base == 0x12345678);
assert(idt.limit == 0xabcd);
uc_reg_read(uc, UC_X86_REG_GDTR, &gdt);
assert(gdt.base == 0x87654321);
assert(gdt.limit == 0xdcba);
//userspace can only set ldt selector, remainder are loaded from
//GDT/LDT, but we allow all to emulator user
uc_reg_read(uc, UC_X86_REG_LDTR, &ldt);
assert(ldt.base == 0xfedcba98);
assert(ldt.limit == 0x11111111);
assert(ldt.selector == 0x3333);
assert(ldt.flags = 0x55555555);
//userspace can only set tr selector, remainder are loaded from
//GDT/LDT, but we allow all to emulator user
uc_reg_read(uc, UC_X86_REG_TR, &tr);
assert(tr.base == 0x22222222);
assert(tr.limit == 0x33333333);
assert(tr.selector == 0x4444);
assert(tr.flags = 0x66666666);
// read from memory
err = uc_mem_read(uc, r_esp, buf, 6);
uc_assert_success(err);
assert(memcmp(buf, "\xcd\xab\x78\x56\x34\x12", 6) == 0);
// read from memory
err = uc_mem_read(uc, r_esp + 6, buf, 6);
uc_assert_success(err);
assert(memcmp(buf, "\xba\xdc\x21\x43\x65\x87", 6) == 0);
uc_close(uc);
}
/******************************************************************************/
int main(void) {
/*
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_idt_gdt_i386)
};
return cmocka_run_group_tests(tests, NULL, NULL);
*/
test_idt_gdt_i386();
fprintf(stderr, "success\n");
return 0;
}

View File

@ -138,15 +138,88 @@ static void test_unmap_double_map(void **state)
uc_assert_fail(uc_mem_map(uc, 0x0000, 0x1000, 0)); /* 0x1000 - 0x1000 */
}
static void test_overlap_unmap_double_map(void **state)
{
uc_engine *uc = *state;
uc_mem_map( uc, 0x1000, 0x2000, 0);
uc_mem_map( uc, 0x1000, 0x1000, 0);
uc_mem_unmap(uc, 0x2000, 0x1000);
}
static void test_strange_map(void **state)
{
uc_engine *uc = *state;
uc_mem_map( uc, 0x0,0x3000,0);
uc_mem_unmap(uc, 0x1000,0x1000);
uc_mem_map( uc, 0x3000,0x1000,0);
uc_mem_map( uc, 0x4000,0x1000,0);
uc_mem_map( uc, 0x1000,0x1000,0);
uc_mem_map( uc, 0x5000,0x1000,0);
uc_mem_unmap(uc, 0x0,0x1000);
}
void write(uc_engine* uc, uint64_t addr, uint64_t len){
uint8_t* buff = alloca(len);
memset(buff,0,len);
uc_mem_write(uc, addr, buff, len);
}
void read(uc_engine* uc, uint64_t addr, uint64_t len){
uint8_t* buff = alloca(len);
uc_mem_read(uc, addr, buff, len);
}
void map(uc_engine* uc, uint64_t addr, uint64_t len){
uc_mem_map(uc, addr, len, UC_PROT_READ | UC_PROT_WRITE);
}
void unmap(uc_engine* uc, uint64_t addr, uint64_t len){
uc_mem_unmap(uc, addr, len);
}
//most likely same bug as in test_strange_map, but looked different in fuzzer (sefault instead of assertion fail)
static void test_assertion_fail(void **state){
uc_engine *uc = *state;
map(uc,0x2000,0x4000); //5
unmap(uc,0x3000,0x2000); //11
map(uc,0x0,0x2000); //23
map(uc,0x3000,0x2000); //24
map(uc,0x9000,0x4000); //32
map(uc,0x8000,0x1000); //34
unmap(uc,0x1000,0x4000); //35
}
static void test_bad_offset(void **state){
uc_engine *uc = *state;
map(uc,0x9000,0x4000); //17
map(uc,0x4000,0x2000); //32
unmap(uc,0x5000,0x1000); //35
map(uc,0x0,0x1000); //42
map(uc,0x5000,0x4000); //51
map(uc,0x2000,0x1000); //53
map(uc,0x1000,0x1000); //55
unmap(uc,0x7000,0x3000); //58
unmap(uc,0x5000,0x1000); //59
unmap(uc,0x4000,0x2000); //70
}
int main(void) {
#define test(x) cmocka_unit_test_setup_teardown(x, setup, teardown)
const struct CMUnitTest tests[] = {
test(test_basic),
//test(test_bad_read),
//test(test_bad_write),
test(test_bad_offset),
test(test_assertion_fail),
test(test_bad_unmap),
test(test_rw_across_boundaries),
test(test_unmap_double_map),
test(test_overlap_unmap_double_map),
test(test_strange_map),
};
#undef test
return cmocka_run_group_tests(tests, NULL, NULL);