Revamp Python regression tests suite (#2022)

* Fix Python regression test suite (partial)

* Fix Python regression test suite

* Add a test for mapping at high addresses

* Add ctl tests
This commit is contained in:
Eli 2024-10-13 08:14:10 +03:00 committed by mio
parent 1742486319
commit 429dbf3012
No known key found for this signature in database
GPG Key ID: DFF27E34A47CB873
58 changed files with 1903 additions and 1455 deletions

View File

@ -1,93 +1,111 @@
from __future__ import print_function
from unicorn import *
from unicorn.arm_const import *
import regress
# code to be emulated
'''
ins = {
0x00008cd4: """
push {r11}
add r11, sp, #0
mov r3, pc
mov r0, r3
sub sp, r11, #0
pop {r11}
bx lr
""",
0x00008cf0: """
push {r11}
add r11, sp, #0
push {r6}
add r6, pc, $1
bx r6
.code 16
mov r3, pc
add r3, $0x4
push {r3}
pop {pc}
.code 32
pop {r6}
mov r0, r3
sub sp, r11, #0
pop {r11}
bx lr
""",
0x00008d20: """
push {r11}
add r11, sp, #0
mov r3, lr
mov r0, r3
sub sp, r11, #0
pop {r11}
bx lr
""",
0x00008d68: "bl 0x8cd4\n"
"mov r4, r0\n"
"bl 0x8cf0\n"
"mov r3, r0\n"
"add r4, r4, r3\n"
"bl 0x8d20\n"
"mov r3, r0\n"
"add r2, r4, r3",
}
'''
from unicorn import *
from unicorn.arm_const import *
MAIN_ADDRESS = 0x8d68
ADDRESS = MAIN_ADDRESS & ~(0x1000 - 1)
STACK_ADDR = ADDRESS + 0x1000
class BxTwiceTest(regress.RegressTest):
def runTest(self):
ADDRESS = 0x8000
MAIN_ADDRESS = 0x8d68
STACK_ADDR = ADDRESS + 0x1000
# code to be emulated
code = {
0x8cf0: '\x04\xb0-\xe5\x00\xb0\x8d\xe2\x04`-\xe5\x01`\x8f\xe2\x16\xff/\xe1{F\x03\xf1\x04\x03\x08\xb4\x00\xbd\x00\x00\x04`\x9d\xe4\x03\x00\xa0\xe1\x00\xd0K\xe2\x04\xb0\x9d\xe4\x1e\xff/\xe1',
0x8d20: '\x04\xb0-\xe5\x00\xb0\x8d\xe2\x0e0\xa0\xe1\x03\x00\xa0\xe1\x00\xd0K\xe2\x04\xb0\x9d\xe4\x1e\xff/\xe1',
0x8cd4: '\x04\xb0-\xe5\x00\xb0\x8d\xe2\x0f0\xa0\xe1\x03\x00\xa0\xe1\x00\xd0K\xe2\x04\xb0\x9d\xe4\x1e\xff/\xe1',
0x8d68: '\xd9\xff\xff\xeb\x00@\xa0\xe1\xde\xff\xff\xeb\x000\xa0\xe1\x03@\x84\xe0\xe7\xff\xff\xeb\x000\xa0\xe1\x03 \x84\xe0'
0x8cd4: (
b'\x04\xb0\x2d\xe5' # 8cd4 push {r11}
b'\x00\xb0\x8d\xe2' # 8cd8 add r11, sp, #0
b'\x0f\x30\xa0\xe1' # 8cdc mov r3, pc
b'\x03\x00\xa0\xe1' # 8ce0 mov r0, r3
b'\x00\xd0\x4b\xe2' # 8ce4 sub sp, r11, #0
b'\x04\xb0\x9d\xe4' # 8ce8 pop {r11}
b'\x1e\xff\x2f\xe1' # 8cec bx lr
),
0x8cf0: (
b'\x04\xb0\x2d\xe5' # 8cf0 push {r11}
b'\x00\xb0\x8d\xe2' # 8cf4 add r11, sp, #0
b'\x04\x60\x2d\xe5' # 8cf8 push {r6}
b'\x01\x60\x8f\xe2' # 8cfc add r6, pc, $1
b'\x16\xff\x2f\xe1' # 8d00 bx r6
# .thumb
b'\x7b\x46' # 8d04 mov r3, pc
b'\x03\xf1\x08\x03' # 8d06 add r3, $0x8 # elicn: used to be $0x4 but it kept failing
b'\x08\xb4' # 8d0a push {r3}
b'\x00\xbd' # 8d0c pop {pc}
b'\x00\x00' # 8d0e (alignment)
# .arm
b'\x04\x60\x9d\xe4' # 8d10 pop {r6}
b'\x03\x00\xa0\xe1' # 8d14 mov r0, r3
b'\x00\xd0\x4b\xe2' # 8d18 sub sp, r11, #0
b'\x04\xb0\x9d\xe4' # 8d1c pop {r11}
b'\x1e\xff\x2f\xe1' # 8d20 bx lr
),
0x8d24: ( # elicn: used to be 0x8d20 but it caused this block to overlap with the previous one
b'\x04\xb0\x2d\xe5' # 8d24 push {r11}
b'\x00\xb0\x8d\xe2' # 8d28 add r11, sp, #0
b'\x0e\x30\xa0\xe1' # 8d2c mov r3, lr
b'\x03\x00\xa0\xe1' # 8d20 mov r0, r3
b'\x00\xd0\x4b\xe2' # 8d34 sub sp, r11, #0
b'\x04\xb0\x9d\xe4' # 8d38 pop {r11}
b'\x1e\xff\x2f\xe1' # 8d3c bx lr
),
0x8d68: (
b'\xd9\xff\xff\xeb' # 8d68 bl 0x8cd4 <-- MAIN_ADDRESS
b'\x00\x40\xa0\xe1' # 8d6c mov r4, r0
b'\xde\xff\xff\xeb' # 8d70 bl 0x8cf0
b'\x00\x30\xa0\xe1' # 8d74 mov r3, r0
b'\x03\x40\x84\xe0' # 8d78 add r4, r4, r3
b'\xe8\xff\xff\xeb' # 8d7c bl 0x8d24
b'\x00\x30\xa0\xe1' # 8d80 mov r3, r0
b'\x03\x20\x84\xe0' # 8d84 add r2, r4, r3
)
}
try:
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
# write machine code to be emulated to memory
for addr, c in code.items():
print("Writing chunk to 0x{:x}".format(addr))
mu.mem_write(addr, c)
mu.mem_map(ADDRESS, 0x1000)
# initialize machine registers
mu.reg_write(UC_ARM_REG_SP, STACK_ADDR)
# write machine code to be emulated to memory
for addr, c in code.items():
regress.logger.debug("Writing %d bytes to %#x", len(c), addr)
mu.mem_write(addr, c)
print("Starting emulation")
# initialize machine registers
mu.reg_write(UC_ARM_REG_PC, MAIN_ADDRESS)
mu.reg_write(UC_ARM_REG_SP, STACK_ADDR)
# emulate code in infinite time & unlimited instructions
mu.emu_start(MAIN_ADDRESS, MAIN_ADDRESS + len(code[MAIN_ADDRESS]))
regress.logger.debug("Starting emulation")
print("Emulation done")
# trace code only if we are debugging it
if regress.logger.isEnabledFor(regress.logging.DEBUG):
def __hook_code(uc, addr, size, _):
cpsr, r0, r3, r4, r6 = uc.reg_read_batch((
UC_ARM_REG_CPSR,
UC_ARM_REG_R0,
UC_ARM_REG_R3,
UC_ARM_REG_R4,
UC_ARM_REG_R6
))
r2 = mu.reg_read(UC_ARM_REG_R2)
print(">>> r2: 0x{:08x}".format(r2))
is_thumb = (cpsr >> 5) & 0b1
except UcError as e:
self.fail("ERROR: %s" % e)
opcode = uc.mem_read(addr, size).hex()
regress.logger.debug(
"%-2s PC = %#06x | opcode = %-8s [R0 = %#06x, R3 = %#06x, R4 = %#07x, R6 = %#06x]",
"T" if is_thumb else "", addr, opcode, r0, r3, r4, r6
)
mu.hook_add(UC_HOOK_CODE, __hook_code)
mu.emu_start(MAIN_ADDRESS, MAIN_ADDRESS + len(code[MAIN_ADDRESS]))
regress.logger.debug("Emulation done")
self.assertEqual(0x8ce4 + 0x8d10 + 0x8d80, mu.reg_read(UC_ARM_REG_R2))
if __name__ == '__main__':
regress.main()

View File

@ -1,28 +1,30 @@
#!/usr/bin/python
import regress
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')) # bxeq lr; mov r0, r0
uc.mem_write(0x1000, b'\x1e\xff\x2f\x01\x00\x00\xa0\xe1') # bxeq lr; mov r0, r0
uc.count = 0
def hook_block(uc, addr, *args):
print 'enter block 0x%04x' % addr
regress.logger.debug('enter block %#06x', 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'
regress.logger.debug('block should only run once')
uc.emu_start(0x1000, 0x1004)
self.assertEqual(uc.count, 1)
if __name__ == '__main__':
regress.main()

View File

@ -1,44 +1,41 @@
#!/usr/bin/python
# coding=utf8
# Added by Peter Mackay, relating to issue 571
# "ARM NEON/VFP support seems to exist but is disabled by default"
# https://github.com/unicorn-engine/unicorn/issues/571
import regress
from unicorn import *
from unicorn.arm_const import *
import regress
CODE = (
b'\x11\xEE\x50\x1F' # MRC p15, #0, r1, c1, c0, #2
b'\x41\xF4\x70\x01' # ORR r1, r1, #(0xf << 20)
b'\x01\xEE\x50\x1F' # MCR p15, #0, r1, c1, c0, #2
b'\x4F\xF0\x00\x01' # MOV r1, #0
b'\x07\xEE\x95\x1F' # MCR p15, #0, r1, c7, c5, #4
b'\x4F\xF0\x80\x40' # MOV r0,#0x40000000
b'\xE8\xEE\x10\x0A' # FMXR FPEXC, r0
b'\x2d\xed\x02\x8b' # vpush {d8}
)
BASE = 0x1000
class FpVfpDisabled(regress.RegressTest):
def runTest(self):
# MRC p15, #0, r1, c1, c0, #2
# ORR r1, r1, #(0xf << 20)
# MCR p15, #0, r1, c1, c0, #2
# MOV r1, #0
# MCR p15, #0, r1, c7, c5, #4
# MOV r0,#0x40000000
# FMXR FPEXC, r0
code = '11EE501F'
code += '41F47001'
code += '01EE501F'
code += '4FF00001'
code += '07EE951F'
code += '4FF08040'
code += 'E8EE100A'
# vpush {d8}
code += '2ded028b'
address = 0x1000
mem_size = 0x1000
code_bytes = code.decode('hex')
uc = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
uc.mem_map(address, mem_size)
uc.mem_write(address, code_bytes)
uc.reg_write(UC_ARM_REG_SP, address + mem_size)
uc.emu_start(address + 1, address + len(code_bytes))
uc.mem_map(BASE, mem_size)
uc.mem_write(BASE, CODE)
uc.reg_write(UC_ARM_REG_SP, BASE + mem_size - 4)
uc.emu_start(BASE + 1, BASE + len(CODE))
if __name__ == '__main__':
regress.main()

View File

@ -3,39 +3,44 @@
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
#
import regress
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
ARM_CODE = (
b"\x37\x00\xa0\xe3" # mov r0, #0x37
b"\x03\x10\x42\xe0" # sub r1, r2, r3
)
THUMB_CODE = b"\x83\xb0" # sub sp, #0xc
# memory address where emulation starts
ADDRESS = 0xF0000000
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))
regress.logger.debug(">>> Tracing basic block at %#x, block size = %#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))
regress.logger.debug(">>> Tracing instruction at %#x, instruction size = %u", address, size)
# Test ARM
def test_arm():
print("Emulate ARM code")
try:
class TestInitInputCrash(regress.RegressTest):
def test_arm(self):
regress.logger.debug("Emulate ARM code")
# 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)
@ -58,20 +63,16 @@ def test_arm():
mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE))
# now print out some registers
print(">>> Emulation done. Below is the CPU context")
regress.logger.debug(">>> 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)
regress.logger.debug(">>> R0 = %#x", r0)
regress.logger.debug(">>> R1 = %#x", r1)
except UcError as e:
print("ERROR: %s" % e)
def test_thumb(self):
regress.logger.debug("Emulate THUMB code")
def test_thumb():
print("Emulate THUMB code")
try:
# Initialize emulator in thumb mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
@ -91,19 +92,14 @@ def test_thumb():
mu.hook_add(UC_HOOK_CODE, hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + len(THUMB_CODE))
mu.emu_start(ADDRESS | 0b1, ADDRESS + len(THUMB_CODE))
# now print out some registers
print(">>> Emulation done. Below is the CPU context")
regress.logger.debug(">>> 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)
regress.logger.debug(">>> SP = %#x", sp)
if __name__ == '__main__':
test_arm()
print("=" * 20)
test_thumb()
regress.main()

View File

@ -1,3 +1,6 @@
import regress
from unicorn import *
from unicorn.arm_const import *
@ -32,37 +35,42 @@ BASE = 0x1F894
COPY_SRC = 0x1000
COPY_DST = 0x2000
COPY_LEN = 8
bs = b'c8' * COPY_LEN
DATA = b'c8' * COPY_LEN
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
class ArmMemcpy(regress.RegressTest):
uc.mem_map(COPY_SRC, 0x1000)
uc.mem_map(COPY_DST, 0x1000)
uc.mem_map(BASE & ~(0x1000 - 1), 0x1000)
uc.mem_write(COPY_SRC, bs)
uc.mem_write(BASE, bytes(SHELLCODE))
def test_arm_memcpy(self):
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
uc.reg_write_batch((
(UC_ARM_REG_R12, COPY_DST),
(UC_ARM_REG_R1, COPY_SRC),
(UC_ARM_REG_R2, COPY_LEN),
(UC_ARM_REG_R3, 0x24)
))
uc.mem_map(COPY_SRC, 0x1000)
uc.mem_map(COPY_DST, 0x1000)
uc.mem_map(BASE & ~(0x1000 - 1), 0x1000)
uc.mem_write(COPY_SRC, DATA)
uc.mem_write(BASE, bytes(SHELLCODE))
# enable_vfp
uc.reg_write_batch((
(UC_ARM_REG_R12, COPY_DST),
(UC_ARM_REG_R1, COPY_SRC),
(UC_ARM_REG_R2, COPY_LEN),
(UC_ARM_REG_R3, 0x24)
))
# coproc=15, is64=0, sec=0, CRn=1, CRm=0, opc1=0, opc2=2
CPACR = (15, 0, 0, 1, 0, 0, 2)
# enable_vfp
cpacr = uc.reg_read(UC_ARM_REG_CP_REG, CPACR)
uc.reg_write(UC_ARM_REG_CP_REG, CPACR + (cpacr | (0b11 << 20) | (0b11 << 22),))
uc.reg_write(UC_ARM_REG_FPEXC, (0b1 << 30))
# coproc=15, is64=0, sec=0, CRn=1, CRm=0, opc1=0, opc2=2
CPACR = (15, 0, 0, 1, 0, 0, 2)
uc.emu_start(BASE, BASE + len(SHELLCODE))
src = uc.mem_read(COPY_SRC, len(bs))
dst = uc.mem_read(COPY_DST, len(bs))
cpacr = uc.reg_read(UC_ARM_REG_CP_REG, CPACR)
uc.reg_write(UC_ARM_REG_CP_REG, CPACR + (cpacr | (0b11 << 20) | (0b11 << 22),))
uc.reg_write(UC_ARM_REG_FPEXC, (0b1 << 30))
print(f'''memcpy result:
from: {bytes(src)}
to: {bytes(dst)}
''')
uc.emu_start(BASE, BASE + len(SHELLCODE))
src = uc.mem_read(COPY_SRC, len(DATA))
dst = uc.mem_read(COPY_DST, len(DATA))
self.assertEqual(DATA, src)
self.assertEqual(DATA, dst)
if __name__ == '__main__':
regress.main()

View File

@ -1,23 +1,24 @@
#!/usr/bin/python
import regress
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
uc.mem_write(0x1000, b'\x00\xc0\x00\xe3') # movw r12, #0
def hook_block(uc, addr, *args):
print 'enter block 0x%04x' % addr
regress.logger.debug('enter block 0x%#06x', addr)
uc.count += 1
uc.reg_write(UC_ARM_REG_R12, 0x123)
self.assertEquals(uc.reg_read(UC_ARM_REG_R12), 0x123)
self.assertEqual(0x123, uc.reg_read(UC_ARM_REG_R12))
uc.hook_add(UC_HOOK_BLOCK, hook_block)
uc.count = 0
@ -25,8 +26,9 @@ class MovHang(regress.RegressTest):
#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)
self.assertEqual(0x0, uc.reg_read(UC_ARM_REG_R12))
self.assertEqual(uc.count, 1)
if __name__ == '__main__':
regress.main()

View File

@ -1,18 +1,24 @@
#!/usr/bin/python
import regress
from unicorn import *
from unicorn.arm_const import *
import regress
class VldrPcInsn(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
uc.mem_map(0x1000, 0x1000)
uc.mem_write(0x1000, 'ed9f8a3d'.decode('hex')) # vldr s16, [pc, #244]
# this will raise invalid insn
uc.emu_start(0x1000, 0x1004)
uc.mem_write(0x1000, b'\xed\x9f\x8a\x3d') # vldr s16, [pc, #244]
with self.assertRaises(UcError) as ex:
uc.emu_start(0x1000, 0x1004)
self.assertEqual(UC_ERR_INSN_INVALID, ex.exception.errno)
if __name__ == '__main__':
regress.main()

View File

@ -1,15 +1,28 @@
import regress
from unicorn import *
from unicorn.arm_const import *
# ADD R0, R10, R0;
# B L0;
# L0:
# ADD R0, R10, R0; <--- we stop at here, the first instruction of the next TB.
code = b'\x00\x00\x8a\xe0\xff\xff\xff\xea\x00\x00\x8a\xe0'
address = 0x1000
CODE = (
b'\x00\x00\x8a\xe0' # ADD R0, R10, R0
b'\xff\xff\xff\xea' # B L0
b'\x00\x00\x8a\xe0' # L0: ADD R0, R10, R0 <-- we stop here, the first instruction of the next TB
)
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
mu.mem_map(address, 0x1000)
mu.mem_write(address, code)
mu.emu_start(address, address + len(code) - 4)
BASE = 0x1000
class TestARMFirstInsn(regress.RegressTest):
def runTest(self):
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
mu.mem_map(BASE, 0x1000)
mu.mem_write(BASE, CODE)
mu.emu_start(BASE, BASE + len(CODE) - 4)
if __name__ == '__main__':
regress.main()

View File

@ -1,29 +1,33 @@
#!/usr/bin/python
import regress
from unicorn import *
from unicorn.x86_const import *
import regress
class Hang(regress.RegressTest):
def runTest(self):
PAGE_SIZE = 0x5000
CODE_ADDR = 0x400000
RSP_ADDR = 0x200000
binary1 = "\xCA\x24\x5D" # retf 0x5d24
CODE = b"\xCA\x24\x5D" # retf 0x5d24
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(CODE_ADDR, PAGE_SIZE)
mu.mem_map(RSP_ADDR, PAGE_SIZE)
mu.mem_write(CODE_ADDR, binary1)
mu.mem_write(CODE_ADDR, CODE)
mu.reg_write(UC_X86_REG_RSP, RSP_ADDR)
try:
self.assertEqual(mu.emu_start(CODE_ADDR, CODE_ADDR + PAGE_SIZE, 0), UC_ERR_FETCH_INVALID)
except UcError as e:
print("ERROR: %s" % e)
# make sure we bump into an exception
with self.assertRaises(UcError) as raisedEx:
mu.emu_start(CODE_ADDR, CODE_ADDR + PAGE_SIZE)
# make sure it is an exception with the errno we expect
self.assertEqual(raisedEx.exception.errno, UC_ERR_READ_UNMAPPED)
if __name__ == '__main__':

View File

@ -3,88 +3,85 @@
# reg_write() can't modify PC from within trace callbacks
# issue #210
from __future__ import print_function
import regress
from unicorn import *
from unicorn.arm_const import *
import regress
BASE_ADDRESS = 0x10000000
THUMB_CODE = b"\x83\xb0" * 5 # sub sp, #0xc
TARGET_PC = 0xffffffff
# 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 test_instruction_trace(self):
try:
# initialize emulator in ARM's Thumb mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
# 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)
# 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)
# 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)
# 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)
def __hook_callback(uc, address, size, user_data):
regress.logger.debug(">>> Tracing instruction at 0x%x, instruction size = %u", address, size)
regress.logger.debug(">>> Setting PC to %#x", TARGET_PC)
# emulate one instruction
uc.reg_write(UC_ARM_REG_PC, TARGET_PC)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, __hook_callback)
# emulate one instruction. since pc was modified to point to an unmapped
# area, this is expected to fail
with self.assertRaises(UcError) as raisedEx:
mu.emu_start(BASE_ADDRESS, BASE_ADDRESS + len(THUMB_CODE), count=1)
# the instruction trace callback set PC to 0xffffffff, so at this
# point, the PC value should be 0xffffffff.
pc = mu.reg_read(UC_ARM_REG_PC)
self.assertEqual(pc, 0xffffffff, "PC not set to 0xffffffff by instruction trace callback")
self.assertEqual(UC_ERR_FETCH_UNMAPPED, raisedEx.exception.errno)
except UcError as e:
self.assertFalse(0, "ERROR: %s" % e)
# the block callback set PC to 0xffffffff, so at this point, the PC
# value should be 0xffffffff.
self.assertEqual(TARGET_PC, mu.reg_read(UC_ARM_REG_PC) | 0b1)
def test_block_trace(self):
try:
# initialize emulator in ARM's Thumb mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
# 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)
# 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)
# 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)
# setup stack
mu.reg_write(UC_ARM_REG_SP, BASE_ADDRESS + 2 * 1024 * 1024)
# trace blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, hook_block, user_data=mu)
def __hook_callback(uc, address, size, user_data):
regress.logger.debug(">>> Tracing basic block at 0x%x, block size = 0x%x", address, size)
regress.logger.debug(">>> Setting PC to %#x", TARGET_PC)
# emulate one instruction
uc.reg_write(UC_ARM_REG_PC, TARGET_PC)
# trace blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, __hook_callback)
# emulate one instruction. since pc was modified to point to an unmapped
# area, this is expected to fail
with self.assertRaises(UcError) as raisedEx:
mu.emu_start(BASE_ADDRESS, BASE_ADDRESS + len(THUMB_CODE), count=1)
# the block callback set PC to 0xffffffff, so at this point, the PC
# value should be 0xffffffff.
pc = mu.reg_read(UC_ARM_REG_PC)
self.assertEqual(pc, 0xffffffff, "PC not set to 0xffffffff by block callback")
self.assertEqual(UC_ERR_FETCH_UNMAPPED, raisedEx.exception.errno)
# the block callback set PC to 0xffffffff, so at this point, the PC
# value should be 0xffffffff.
self.assertEqual(TARGET_PC, mu.reg_read(UC_ARM_REG_PC) | 0b1)
except UcError as e:
self.assertFalse(0, "ERROR: %s" % e)
if __name__ == '__main__':
regress.main()

177
tests/regress/core_ctl.py Normal file
View File

@ -0,0 +1,177 @@
#!/usr/bin/env python
import regress
from unicorn import *
from unicorn.arm_const import *
from unicorn.x86_const import *
# count down from maxint to zero
_VALID_CODE = (
b'\x31\xc9' # xor ecx, ecx
b'\x49' # _top: dec ecx
b'\xf3\x90' # pause
b'\xe3\xfb' # jecxz _top
b'\xf4' # _end: hlt
)
_INVALID_CODE = (
b'\xff\xff' # (invalid)
)
CODE = _VALID_CODE + _INVALID_CODE
BASE = 0x100000
class TestCtl(regress.RegressTest):
def test_mode(self):
uc = Uc(UC_ARCH_ARM, UC_MODE_BIG_ENDIAN)
# changing cpu model to one that supports EB
uc.ctl_set_cpu_model(UC_CPU_ARM_CORTEX_M0)
# changing cpu model to one that does not support EB; this is expected to fail
with self.assertRaises(UcError) as ex:
uc.ctl_set_cpu_model(UC_CPU_ARM_CORTEX_A8)
self.assertEqual(UC_ERR_ARG, ex.exception.errno)
# make sure we stay with the configuration we set beforehand
self.assertEqual(UC_ARCH_ARM, uc.ctl_get_arch())
self.assertEqual(UC_MODE_BIG_ENDIAN, uc.ctl_get_mode())
self.assertEqual(UC_CPU_ARM_CORTEX_M0, uc.ctl_get_cpu_model())
def test_page_size(self):
SIZE_4KB = 4 * 1024 ** 1
SIZE_2MB = 2 * 1024 ** 2
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
# set page size to 2 MiB; this should work
uc.ctl_set_page_size(SIZE_2MB)
# BUG! was it set properly?
# self.assertEqual(SIZE_2MB, uc.ctl_get_page_size())
# set a page size which is not a power of 2
with self.assertRaises(UcError) as ex:
uc.ctl_set_page_size(SIZE_2MB + 0xbad)
self.assertEqual(UC_ERR_ARG, ex.exception.errno)
# BUG! are we still with the valid value?
# self.assertEqual(SIZE_2MB, uc.ctl_get_page_size())
# force uc to complete its initialization by triggering a random api
uc.ctl_flush_tb()
# set a page size after uc has completed its initialization
with self.assertRaises(UcError) as ex:
uc.ctl_set_page_size(SIZE_4KB)
self.assertEqual(UC_ERR_ARG, ex.exception.errno)
# BUG! are we still with the valid value?
# self.assertEqual(SIZE_2MB, uc.ctl_get_page_size())
def test_timeout(self):
MILLIS_1S = 1000
uc = Uc(UC_ARCH_X86, UC_MODE_32)
uc.mem_map(BASE, 0x1000)
uc.mem_write(BASE, CODE)
# start a long emulation bound by timeout
uc.emu_start(BASE, BASE + len(CODE), timeout=MILLIS_1S)
# was timeout set properly? uc returns timeout in nanoseconds
self.assertEqual(MILLIS_1S * 1000, uc.ctl_get_timeout())
# no way we made it all the way down to zero
self.assertNotEqual(0, uc.reg_read(UC_X86_REG_ECX))
def test_exits(self):
WRONG_EXIT = BASE + len(CODE)
GOOD_EXIT = BASE + len(_VALID_CODE)
uc = Uc(UC_ARCH_X86, UC_MODE_32)
uc.mem_map(BASE, 0x1000)
uc.mem_write(BASE, CODE)
def __hook_code(uc, *args):
ecx = uc.reg_read(UC_X86_REG_ECX)
# 16 down to the count
if ecx == 0xfffffff0:
# fast-forward the counter and let it run for another 16 iterations
uc.reg_write(UC_X86_REG_ECX, 0x10)
uc.hook_add(UC_HOOK_CODE, __hook_code)
# enable exits
uc.ctl_exits_enabled(True)
# fix the exit point so we don't reach invalid code
uc.ctl_set_exits([GOOD_EXIT])
# start emulation, setting a wrong stopping point that will get us to invalid code
# since we enabled exits, the stopping point should be ignored
uc.emu_start(BASE, WRONG_EXIT, count=1)
# only one exit point was set
self.assertEqual(1, uc.ctl_get_exits_cnt())
# only one exit point, and it is the wrong one
self.assertSequenceEqual([GOOD_EXIT], uc.ctl_get_exits(), int)
# resume execution; rely on code hook to fast-forward the emulation
# stopping point is ignored due to enabled exits
uc.emu_start(BASE, WRONG_EXIT)
# did we exit on the right place?
# not failing on an invalid instruction is another good indication for that
self.assertEqual(GOOD_EXIT, uc.reg_read(UC_X86_REG_EIP))
def test_tlb_mode(self):
MAPPING_LO = 0x0000000001000000
MAPPING_HI = 0x0010000000000000
NOPSLED = b'\x90' * 8
uc = Uc(UC_ARCH_X86, UC_MODE_64)
uc.mem_map(MAPPING_LO, 0x1000)
uc.mem_write(MAPPING_LO, NOPSLED)
uc.emu_start(MAPPING_LO, MAPPING_LO + len(NOPSLED))
# # we should be fine here
# uc.emu_start(BASE, BASE + len(_VALID_CODE), count=1)
uc.mem_map(MAPPING_HI, 0x1000)
uc.mem_write(MAPPING_HI, NOPSLED)
# this should prevents us from mapping to high addresses
uc.ctl_tlb_mode(UC_TLB_CPU)
# this should fail
with self.assertRaises(UcError) as ex:
uc.emu_start(MAPPING_HI, MAPPING_HI + len(NOPSLED))
self.assertEqual(UC_ERR_FETCH_UNMAPPED, ex.exception.errno)
# ------------------------------------------------------
# this should allow us mapping to high addresses
uc.ctl_tlb_mode(UC_TLB_VIRTUAL)
# this should ok now
uc.emu_start(MAPPING_HI, MAPPING_HI + len(NOPSLED))
if __name__ == '__main__':
regress.main()

View File

@ -1,6 +1,5 @@
#!/usr/bin/python
from __future__ import print_function
import binascii
import regress
@ -8,21 +7,18 @@ from unicorn import *
from unicorn.x86_const import *
CODE = binascii.unhexlify(b"".join([
b"8B 74 01 28", # mov esi, dword ptr [ecx + eax + 0x28] mapped: 0x1000
b"03 F0", # add esi, eax 0x1004
b"8D 45 FC", # lea eax, dword ptr [ebp - 4] 0x1006
b"50", # push eax 0x1009
b"6A 40", # push 0x40 0x100A
b"6A 10", # push 0x10 0x100C
b"56", # push esi 0x100E
b"FF 15 20 20 00 10" # call some address 0x100F
]).replace(" ", ""))
CODE = binascii.unhexlify((
"8B 74 01 28" # mov esi, dword ptr [ecx + eax + 0x28] mapped: 0x1000
"03 F0" # add esi, eax 0x1004
"8D 45 FC" # lea eax, dword ptr [ebp - 4] 0x1006
"50" # push eax 0x1009
"6A 40" # push 0x40 0x100A
"6A 10" # push 0x10 0x100C
"56" # push esi 0x100E
).replace(' ', ''))
def showpc(mu):
pc = mu.reg_read(UC_X86_REG_EIP)
print("pc: 0x%x" % (pc))
BASE = 0x1000
STACK = 0x4000
class HookCodeStopEmuTest(regress.RegressTest):
@ -30,38 +26,32 @@ class HookCodeStopEmuTest(regress.RegressTest):
mu = Uc(UC_ARCH_X86, UC_MODE_32)
# base of CODE
mu.mem_map(0x1000, 0x1000)
mu.mem_write(0x1000, CODE)
mu.reg_write(UC_X86_REG_EIP, 0x1000)
mu.mem_map(BASE, 0x1000)
mu.mem_write(BASE, CODE)
# base of STACK
mu.mem_map(0x4000, 0x4000)
mu.mem_write(0x4000, "\x00" * 0x4000)
mu.reg_write(UC_X86_REG_ESP, 0x6000)
mu.reg_write(UC_X86_REG_EBP, 0x6000)
mu.mem_map(STACK, 0x1000)
mu.mem_write(STACK, b"\x00" * 0x1000)
mu.reg_write(UC_X86_REG_EIP, BASE)
mu.reg_write(UC_X86_REG_ESP, STACK + 0x1000 - 8)
mu.reg_write(UC_X86_REG_EBP, STACK + 0x1000 - 8)
mu.reg_write(UC_X86_REG_ECX, 0x0)
mu.reg_write(UC_X86_REG_EAX, 0x0)
def _hook(_, access, address, length, value, context):
pc = mu.reg_read(UC_X86_REG_EIP)
print("mem unmapped: pc: %x access: %x address: %x length: %x value: %x" % (
pc, access, address, length, value))
mu.emu_stop()
return True
mu.hook_add(UC_HOOK_MEM_UNMAPPED, _hook)
# we only expect the following instruction to execute,
# and it will fail, because it accesses unmapped memory.
# mov esi, dword ptr [ecx + eax + 0x28] mapped: 0x1000
mu.emu_start(0x1000, 0x100F)
showpc(mu)
with self.assertRaises(UcError) as ex:
mu.emu_start(BASE, BASE + len(CODE), count=1)
self.assertEqual(UC_ERR_READ_UNMAPPED, ex.exception.errno)
regress.logger.debug("pc: %#x", mu.reg_read(UC_X86_REG_EIP))
# now, we want to reuse the emulator, and keep executing
# from the next instruction
mu.reg_write(UC_X86_REG_EIP, 0x1004)
self.assertEqual(0x1004, mu.reg_read(UC_X86_REG_EIP))
# we expect the following instructions to execute
# add esi, eax 0x1004
@ -70,10 +60,9 @@ class HookCodeStopEmuTest(regress.RegressTest):
# push 0x40 0x100A
# push 0x10 0x100C
# push esi 0x100E
#
# currently, a UC_ERR_READ_UNMAPPED exception is raised here
mu.emu_start(0x1004, 0x100F)
showpc(mu)
mu.emu_start(BASE + 0x4, BASE + len(CODE))
regress.logger.debug("pc: %#x", mu.reg_read(UC_X86_REG_EIP))
if __name__ == '__main__':

View File

@ -7,9 +7,19 @@ are included in the bindings by the script for autogenerating mappings for
constants.
"""
import regress
import unicorn
try:
unicorn.UC_HOOK_MEM_UNMAPPED
except AttributeError:
assert(False and "Definition for UC_HOOK_MEM_UNMAPPED not generated")
class TestTypedefs(regress.RegressTest):
def runTest(self):
prop = 'UC_HOOK_MEM_UNMAPPED'
try:
getattr(unicorn, prop)
except AttributeError:
self.fail("Definition for %s not generated" % prop)
if __name__ == '__main__':
regress.main()

View File

@ -1,69 +1,62 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
from capstone import *
import regress
ESP = 0x2000
PAGE_SIZE = 2 * 1024 * 1024
from unicorn import *
from unicorn.x86_const import *
from capstone import Cs, CS_ARCH_X86, CS_ARCH_X86, CS_MODE_64, CS_MODE_32
# 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)
CODE = (
b'\xc7\x04\x24\x7f\x03\x00\x00' # mov DWORD PTR [rsp],0x37f
b'\xd9\x2c\x24' # fldcw WORD PTR [rsp]
b'\xd9\xd0' # fnop
b'\xd9\x74\x24\x08' # fnstenv [rsp+0x8]
b'\x59' # pop rcx
)
def disas_single(self, data):
for i in self.capmd.disasm(data, 16):
print("\t%s\t%s" % (i.mnemonic, i.op_str))
break
BASE = 0x00000000
STACK = 0x00000f00
disasm = SimpleEngine()
def hook_code(uc, addr, size, user_data):
mem = uc.mem_read(addr, size)
print(" 0x%X:" % (addr)),
disasm.disas_single(bytes(mem))
cs = user_data
data = uc.mem_read(addr, size)
mnem, ops = next((insn.mnemonic, insn.op_str) for insn in cs.disasm(data, addr))
regress.logger.debug("0x%x: %-12s %-24s", addr, mnem, ops)
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)
cs = Cs(CS_ARCH_X86, CS_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.mem_map(BASE, 0x1000)
mu.mem_write(BASE, CODE)
mu.reg_write(UC_X86_REG_ESP, STACK)
mu.hook_add(UC_HOOK_CODE, hook_code, cs)
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)
mu.emu_start(BASE, BASE + len(CODE), count=5)
self.assertSequenceEqual(b'\x7f\x03\x00\x00\x00\x00\x00\x00', mu.mem_read(STACK + 8, 8))
self.assertSequenceEqual(b'\x55\x55\x00\x00\x00\x00\x00\x00', mu.mem_read(STACK + 16, 8))
def test_64(self):
mu = Uc(UC_ARCH_X86, UC_MODE_64)
cs = Cs(CS_ARCH_X86, CS_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.mem_map(BASE, 0x1000)
mu.mem_write(BASE, CODE)
mu.reg_write(UC_X86_REG_RSP, STACK)
mu.hook_add(UC_HOOK_CODE, hook_code, cs)
mu.emu_start(BASE, BASE + len(CODE), count=5)
self.assertSequenceEqual(b'\x7f\x03\x00\x00\x00\x00\x00\x00', mu.mem_read(STACK + 8, 8))
self.assertSequenceEqual(b'\x55\x55\x00\x00\x00\x00\x00\x00', mu.mem_read(STACK + 16, 8))
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()

View File

@ -1,38 +1,40 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
import regress
ESP = 0x2000
PAGE_SIZE = 1 * 1024 * 1024
from unicorn import *
from unicorn.x86_const import *
CODE = (
b'\x9b\xd9\x3c\x24' # fstcw WORD PTR [esp]
b'\x59' # pop ecx
)
BASE = 0x00000000
STACK = 0x00000f00
# 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))
regress.logger.debug("mem WRITE to: %#x, size = %u, value = %#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.mem_map(BASE, 0x1000)
mu.mem_write(BASE, CODE)
mu.reg_write(UC_X86_REG_ESP, STACK)
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)
mu.emu_start(BASE, BASE + len(CODE), count=2)
self.assertSequenceEqual(b'\x00' * 2, mu.mem_read(STACK, 2))
if __name__ == '__main__':
regress.main()

View File

@ -1,39 +1,71 @@
#!/usr/bin/python
from __future__ import print_function
import binascii
import regress
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("")
# invalid instruction?
if size == 0xf1f1f1f1:
return
regress.logger.debug("[%#x] = %s" , address, binascii.hexlify(uc.mem_read(address, size)))
# 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))
regress.logger.debug("[%#x]: got interrupt %#x", rip, intno)
regress.logger.debug(" EAX = %#010x", uc.reg_read(UC_X86_REG_EAX))
regress.logger.debug(" EBX = %#010x", uc.reg_read(UC_X86_REG_EBX))
regress.logger.debug(" ECX = %#010x", uc.reg_read(UC_X86_REG_ECX))
regress.logger.debug(" EDX = %#010x", uc.reg_read(UC_X86_REG_EDX))
uc.emu_stop()
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'
# self modifying shellcode execve('/bin/sh')
shellcode = (
b'\xeb\x1c' # 00: jmp 0x1e
b'\x5a' # 02: pop rdx
b'\x89\xd6' # 03: mov esi, edx
b'\x8b\x02' # 05: mov eax, [rdx]
b'\x66\x3d\xca\x7d' # 07: cmp ax, 0x7dca
b'\x75\x06' # 0b: jne 0x13
b'\x66\x05\x03\x03' # 0d: add ax,0x303
b'\x89\x02' # 11: mov [rdx], eax
b'\xfe\xc2' # 13: inc dl
b'\x3d\x41\x41\x41\x41' # 15: cmp eax, 0x41414141
b'\x75\xe9' # 1a: jne 0x5
b'\xff\xe6' # 1c: jmp rsi
b'\xe8\xdf\xff\xff\xff' # 1e: call 0x2
b'\x31\xd2' # 23: xor edx, edx
b'\x6a\x0b' # 25: push 0xb
b'\x58' # 27: pop rax
b'\x99' # 28: cdq
b'\x52' # 29: push rdx
b'\x68\x2f\x2f\x73\x68' # 2a: push 0x68732f2f
b'\x68\x2f\x62\x69\x6e' # 2f: push 0x6e69622f
b'\x89\xe3' # 34: mov ebx, esp
b'\x52' # 36: push rdx
b'\x53' # 37: push rbx
b'\x89\xe1' # 38: mov ecx, esp
b'\xca\x7d\x41\x41\x41\x41\x41\x41\x41\x41' # 3a: .db ca 7d 41 41 41 41 41 41 41 41
)
address = 0x00000000
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0, 2 * 1024 * 1024)
mu.mem_map(address, 0x1000)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code)
@ -42,16 +74,15 @@ class Hang(regress.RegressTest):
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')
mu.reg_write(UC_X86_REG_RSP, 0x1000 - 8)
# write machine code to be emulated to memory
mu.mem_write(0, binary1)
mu.mem_write(address, shellcode)
regress.logger.debug('Starting emulation')
mu.emu_start(address, address + len(shellcode))
self.assertEqual(mu.emu_start(0, len(binary1)), None)
if __name__ == '__main__':
regress.main()

66
tests/regress/high_mem.py Normal file
View File

@ -0,0 +1,66 @@
#!/usr/bin/env python3
import regress
from unicorn import Uc, UcError, UC_ARCH_X86, UC_MODE_64
from unicorn.unicorn_const import UC_TLB_VIRTUAL, UC_TLB_CPU, UC_ERR_FETCH_UNMAPPED
MAX_INTEL_INSN_SIZE = 15
class TestMem(regress.RegressTest):
# 0x0008fffffffff000 : mappings till this point work ok
# 0x0010000000000000 : mappings beyond this point will fail if tlb is not set to virtual
def setUp(self):
self.uc = Uc(UC_ARCH_X86, UC_MODE_64)
def map_code_page(self, address, payload):
regress.logger.debug('attempting to map code at %#018x', address)
self.uc.mem_map(address, 0x1000)
self.uc.mem_write(address, payload)
def test_virt_high_mapping(self):
"""Mapping memory at high addresses should work when TLB mode
is set to VIRTUAL.
"""
base = 0x0010000000000000
self.uc.ctl_tlb_mode(UC_TLB_VIRTUAL)
for i in range(12):
code = base << i
self.map_code_page(code, b'\xf4')
try:
self.uc.emu_start(code, code + MAX_INTEL_INSN_SIZE, count=1)
except UcError:
self.fail('high mapping failed at %#018x' % code)
def test_cpu_high_mapping(self):
"""Mapping memory at high addresses should work fail TLB mode
is set to CPU (default).
"""
base = 0x0010000000000000
self.uc.ctl_tlb_mode(UC_TLB_CPU)
for i in range(12):
code = base << i
self.map_code_page(code, b'\xf4')
with self.assertRaises(UcError) as ex:
self.uc.emu_start(code, code + MAX_INTEL_INSN_SIZE, count=1)
self.assertEqual(UC_ERR_FETCH_UNMAPPED, ex.exception.errno)
if __name__ == '__main__':
regress.main()

View File

@ -2,15 +2,21 @@
"""https://github.com/unicorn-engine/unicorn/issues/165"""
import unicorn
import regress
from unicorn import *
def hook_mem_read_unmapped(mu, access, address, size, value, user_data):
pass
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
class TestHook(regress.RegressTest):
def test_excessive_hooks(self):
mu = Uc(UC_ARCH_X86, UC_MODE_32)
try:
for x in range(0, 1000):
mu.hook_add(unicorn.UC_HOOK_MEM_READ_UNMAPPED, hook_mem_read_unmapped, None)
except unicorn.UcError as e:
print("ERROR: %s" % e)
for _ in range(1337):
mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED, hook_mem_read_unmapped)
if __name__ == '__main__':
regress.main()

View File

@ -11,38 +11,41 @@ from unicorn.x86_const import *
ADDRESS = 0x8048000
STACK_ADDRESS = 0xffff000
STACK_SIZE = 4096
'''
31 DB xor ebx, ebx
53 push ebx
43 inc ebx
53 push ebx
6A 02 push 2
6A 66 push 66h
58 pop eax
89 E1 mov ecx, esp
CD 80 int 80h
'''
CODE = "\x31\xDB\x53\x43\x53\x6A\x02\x6A\x66\x58\x89\xE1\xCD\x80"
CODE = (
b'\x31\xDB' # xor ebx, ebx
b'\x53' # push ebx
b'\x43' # inc ebx
b'\x53' # push ebx
b'\x6A\x02' # push 2
b'\x6A\x66' # push 66h
b'\x58' # pop eax
b'\x89\xE1' # mov ecx, esp
b'\xCD\x80' # int 80h
)
EP = ADDRESS + 0x54
def hook_code(mu, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
class HookCodeAddDelTest(regress.RegressTest):
def runTest(self):
emu = Uc(UC_ARCH_X86, UC_MODE_32)
emu.mem_map(ADDRESS, 0x1000)
emu.mem_write(EP, CODE)
regress.logger.debug(">>> Tracing instruction at %#x, instruction size = %u", address, size)
class HookCodeAddDelTest(regress.RegressTest):
def runTest(self):
emu = Uc(UC_ARCH_X86, UC_MODE_32)
emu.mem_map(ADDRESS, 0x1000)
emu.mem_write(EP, CODE)
emu.mem_map(STACK_ADDRESS, STACK_SIZE)
emu.reg_write(UC_X86_REG_ESP, STACK_ADDRESS + STACK_SIZE)
# UC_HOOK_CODE hook will work even after deletion
i = emu.hook_add(UC_HOOK_CODE, hook_code, None)
emu.hook_del(i)
emu.emu_start(EP, EP + len(CODE), count = 3)
regress.logger.debug("EIP: %#x", emu.reg_read(UC_X86_REG_EIP))
emu.mem_map(STACK_ADDRESS, STACK_SIZE)
emu.reg_write(UC_X86_REG_ESP, STACK_ADDRESS + STACK_SIZE)
# UC_HOOK_CODE hook will work even after deletion
i = emu.hook_add(UC_HOOK_CODE, hook_code, None)
emu.hook_del(i)
emu.emu_start(EP, EP + len(CODE), count = 3)
print("EIP: 0x%x" % emu.reg_read(UC_X86_REG_EIP))
if __name__ == '__main__':
regress.main()
regress.main()

View File

@ -1,90 +1,77 @@
#!/usr/bin/python
from __future__ import print_function
import binascii
import regress
from unicorn import *
from unicorn.x86_const import *
CODE = binascii.unhexlify(b"".join([
b"48c7c003000000", # mov rax, 3 mapped: 0x1000
b"0f05", # syscall mapped: 0x1007
b"48c7c700400000", # mov rdi, 0x4000 mapped: 0x1009
b"488907", # mov [rdi], rdx mapped: 0x1010
b"488b07", # mov rdx, [rdi] mapped: 0x1013
b"4883c201", # add rdx, 1 mapped: 0x1016
]))
CODE = (
b'\x48\xc7\xc0\x03\x00\x00\x00' # 0x1000: mov rax, 3
b'\x0f\x05' # 0x1007: syscall
b'\x48\xc7\xc7\x00\x40\x00\x00' # 0x1009: mov rdi, 0x4000
b'\x48\x89\x07' # 0x1010: mov [rdi], rdx
b'\x48\x8b\x07' # 0x1013: mov rdx, [rdi]
b'\x48\x83\xc2\x01' # 0x1016: add rdx, 1
)
BASE = 0x00001000
SCRATCH = 0x00004000
class SingleStepper:
def __init__(self, emu, test):
self._emu = emu
self._hit_count = 0
self._test = test
def __init__(self, uc, test):
self.uc = uc
self.hits = 0
self.test = test
def _stop_hook(self, uc, address, *args, **kwargs):
if self._hit_count == 0:
self._hit_count += 1
else:
self._test.assertEqual(1, self._hit_count, "HOOK_CODE invoked too many times")
self.hits += 1
if self.hits > 1:
self.test.assertEqual(2, self.hits, "HOOK_CODE invoked too many times")
uc.emu_stop()
def step(self):
self._hit_count = 0
h = self._emu.hook_add(UC_HOOK_CODE, self._stop_hook)
self.hits = 0
h = self.uc.hook_add(UC_HOOK_CODE, self._stop_hook)
try:
pc = self._emu.reg_read(UC_X86_REG_RIP)
self._emu.emu_start(pc, pc+0x20)
pc = self.uc.reg_read(UC_X86_REG_RIP)
self.uc.emu_start(pc, pc + 0x20)
finally:
self._emu.hook_del(h)
self.uc.hook_del(h)
def showpc(mu):
pc = mu.reg_read(UC_X86_REG_RIP)
print("pc: 0x%x" % (pc))
regress.logger.debug("pc: %#x", mu.reg_read(UC_X86_REG_RIP))
class HookCodeStopEmuTest(regress.RegressTest):
def test_hook_code_stop_emu(self):
try:
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu = Uc(UC_ARCH_X86, UC_MODE_64)
# base of CODE
mu.mem_map(0x1000, 0x1000)
mu.mem_write(0x1000, CODE)
# base of CODE
mu.mem_map(BASE, 0x1000)
mu.mem_write(BASE, CODE)
# scratch, used by CODE
mu.mem_map(0x4000, 0x1000)
# scratch, used by CODE
mu.mem_map(SCRATCH, 0x1000)
mu.reg_write(UC_X86_REG_RDX, 0x1)
mu.reg_write(UC_X86_REG_RIP, 0x1000)
mu.reg_write(UC_X86_REG_RDX, 0x1)
mu.reg_write(UC_X86_REG_RIP, BASE)
# 0x1000: 48c7c003000000 mov rax, 3
# 0x1007: 0f05 syscall
# 0x1009: 48c7c700400000 mov rdi, 0x4000
# 0x1010: 488907 mov [rdi], rdx
# 0x1013: 488b07 mov rdx, [rdi]
# 0x1016: 4883c201 add rdx, 1
stepper = SingleStepper(mu, self)
showpc(mu)
self.assertEqual(0x1000, mu.reg_read(UC_X86_REG_RIP), "Unexpected PC")
stepper = SingleStepper(mu, self)
showpc(mu)
self.assertEqual(BASE + 0x0, mu.reg_read(UC_X86_REG_RIP), "Unexpected starting PC")
stepper.step()
showpc(mu)
self.assertEqual(BASE + 0x7, mu.reg_read(UC_X86_REG_RIP), "Emulator failed to stop after one instruction")
stepper.step()
showpc(mu)
self.assertEqual(0x1007, mu.reg_read(UC_X86_REG_RIP),
"Emulator failed to stop after one instruction")
stepper.step()
showpc(mu)
self.assertEqual(0x1009, mu.reg_read(UC_X86_REG_RIP),
"Emulator failed to stop after one instruction")
except UcError as e:
self.assertFalse(0, "ERROR: %s" % e)
stepper.step()
showpc(mu)
self.assertEqual(BASE + 0x9, mu.reg_read(UC_X86_REG_RIP), "Emulator failed to stop after one instruction")
if __name__ == '__main__':

View File

@ -1,30 +1,41 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
import regress
PAGE_SIZE = 4 * 1024
from unicorn import *
from unicorn.x86_const import *
PAGE_SIZE = 0x1000
ACCESS_ADDR = 0x1000
# mov eax, [0x1000]
# mov eax, [0x1000]
CODE = b'\xA1\x00\x10\x00\x00\xA1\x00\x10\x00\x00'
CODE = (
b'\xA1\x00\x10\x00\x00' # mov eax, [0x1000]
b'\xA1\x00\x10\x00\x00' # mov eax, [0x1000]
)
BASE = 0x00000000
def hook_mem_read(uc, access, address, size, value, data):
print("Reading at " + str(address))
regress.logger.debug("Reading at %#x", address)
# BUG: unicorn will segfault when calling "uc.mem_write" to write to a location that was mapped only as UC_PROT_READ
uc.mem_write(address, CODE)
class REP(regress.RegressTest):
def test_rep(self):
class REP(regress.RegressTest):
@regress.unittest.skip('writing to a UC_PROT_READ area will segfault Unicorn')
def runTest(self):
mu = Uc(UC_ARCH_X86, UC_MODE_32)
mu.mem_map(0, PAGE_SIZE)
mu.mem_write(0, CODE)
mu.mem_map(BASE, PAGE_SIZE)
mu.mem_write(BASE, CODE)
mu.mem_map(ACCESS_ADDR, PAGE_SIZE, UC_PROT_READ)
mu.hook_add(UC_HOOK_MEM_READ, hook_mem_read, begin = ACCESS_ADDR, end = ACCESS_ADDR + PAGE_SIZE)
mu.emu_start(0, len(CODE))
mu.emu_start(BASE, BASE + len(CODE))
self.assertEqual(0x001000a1, mu.reg_read(UC_X86_REG_EAX))
if __name__ == '__main__':
regress.main()

View File

@ -1,10 +1,17 @@
#!/usr/bin/python
# By Mariano Graziano
import regress
import struct
import sys
from unicorn import *
from unicorn.x86_const import *
import regress, struct
if sys.version_info.major == 2:
range = xrange
mu = 0
@ -15,54 +22,61 @@ class Init(regress.RegressTest):
#print "[+] Emulating IP: %x SP: %x - Counter: %x" % (ip, sp, counter)
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0x1000000, 2 * 1024 * 1024)
mu.mem_write(0x1000000, "\x90")
mu.mem_write(0x1000000, b"\x90")
mu.mem_map(0x8000000, 8 * 1024 * 1024)
mu.reg_write(UC_X86_REG_RSP, sp)
content = self.generate_value(counter)
mu.mem_write(sp, content)
self.set_hooks()
def generate_value(self, counter):
start = 0xffff880026f02000
offset = counter * 8
address = start + offset
return struct.pack("<Q", address)
def set_hooks(self):
global mu
mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, self.hook_mem_invalid)
mu.hook_add(UC_HOOK_MEM_FETCH_UNMAPPED, self.hook_mem_fetch_unmapped)
def hook_mem_invalid(self, uc, access, address, size, value, user_data):
global mu
print "[ HOOK_MEM_INVALID - Address: %s ]" % hex(address)
regress.logger.debug("[ HOOK_MEM_INVALID - Address: 0x%x ]", address)
if access == UC_MEM_WRITE_UNMAPPED:
print ">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" %(address, size, value)
regress.logger.debug(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x", address, size, value)
address_page = address & 0xFFFFFFFFFFFFF000
mu.mem_map(address_page, 2 * 1024 * 1024)
mu.mem_write(address, str(value))
return True
else:
return False
def hook_mem_fetch_unmapped(self, uc, access, address, size, value, user_data):
global mu
print "[ HOOK_MEM_FETCH - Address: %s ]" % hex(address).strip("L")
print "[ mem_fetch_unmapped: faulting address at %s ]" % hex(address).strip("L")
mu.mem_write(0x1000003, "\x90")
regress.logger.debug("[ HOOK_MEM_FETCH - Address: 0x%x ]", address)
regress.logger.debug("[ mem_fetch_unmapped: faulting address at 0x%x ]", address)
mu.mem_write(0x1000003, b"\x90")
mu.reg_write(UC_X86_REG_RIP, 0x1000001)
return True
def runTest(self):
global mu
ips = list(xrange(0x1000000, 0x1001000, 0x1))
sps = list(xrange(0x8000000, 0x8001000, 0x1))
j = 0
for i in ips:
j += 1
index = ips.index(i)
self.init_unicorn(i, sps[index], j)
ips = range(0x1000000, 0x1001000)
sps = range(0x8000000, 0x8001000)
for i, (ip, sp) in enumerate(zip(ips, sps)):
self.init_unicorn(ip, sp, i)
mu.emu_start(0x1000000, 0x1000000 + 0x1)
if __name__ == '__main__':
regress.main()

View File

@ -2,38 +2,42 @@
"""See https://github.com/unicorn-engine/unicorn/issues/82"""
import unicorn
from unicorn import *
import regress
from unicorn import *
from unicorn.x86_const import *
CODE_ADDR = 0x10101000
CODE = b'\xff\xe3' # jmp ebx
class JumEbxHang(regress.RegressTest):
def runTest(self):
mu = unicorn.Uc(UC_ARCH_X86, UC_MODE_32)
mu = Uc(UC_ARCH_X86, 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)
mu.reg_write(UC_X86_REG_EBX, 0x0)
print(">>> jmp ebx (ebx = 0)")
regress.logger.debug(">>> 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, UC_ERR_FETCH_UNMAPPED)
print(">>> jmp ebx (ebx = 0xaa96a47f)")
mu = unicorn.Uc(UC_ARCH_X86, UC_MODE_32)
regress.logger.debug(">>> jmp ebx (ebx = 0xaa96a47f)")
mu = Uc(UC_ARCH_X86, 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.reg_write(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, UC_ERR_FETCH_UNMAPPED)
if __name__ == '__main__':
regress.main()

View File

@ -1,166 +1,126 @@
#!/usr/bin/env python
# Mariano Graziano
import binascii
import regress
from unicorn import *
from unicorn.x86_const import *
import regress
#echo -ne "\x48\x31\xc0\x48\xb8\x04\x00\x00\x00\x00\x00\x00\x00\x48\x3d\x05\x00\x00\x00\x74\x05\xe9\x0f\x00\x00\x00\x48\xba\xbe\xba\x00\x00\x00\x00\x00\x00\xe9\x0f\x00\x00\x00\x48\xba\xca\xc0\x00\x00\x00\x00\x00\x00\xe9\x00\x00\x00\x00\x90" | ndisasm - -b64
#00000000 4831C0 xor rax,rax
#00000003 48B8040000000000 mov rax,0x4
# -0000
#0000000D 483D05000000 cmp rax,0x5
#00000013 7405 jz 0x1a
#00000015 E90F000000 jmp qword 0x29
#0000001A 48BABEBA00000000 mov rdx,0xbabe
# -0000
#00000024 E90F000000 jmp qword 0x38
#00000029 48BACAC000000000 mov rdx,0xc0ca
# -0000
#00000033 E900000000 jmp qword 0x38
#00000038 90 nop
# set rdx to either 0xbabe or 0xc0ca, based on a comparison.
# rdx would never be set to 0xbabe unless we set zf to 1
CODE = (
b"\x48\x31\xc0" # xor rax, rax
b"\x48\xb8\x04\x00\x00\x00\x00\x00\x00\x00" # movabs rax, 0x4
b"\x48\x3d\x05\x00\x00\x00" # cmp rax, 0x5 <-- never true, zf is cleared
b"\x74\x05" # je 0x1a
b"\xe9\x0f\x00\x00\x00" # jmp 0x29
b"\x48\xba\xbe\xba\x00\x00\x00\x00\x00\x00" # 1a: movabs rdx, 0xbabe <-- never reached unless we set zf
b"\xe9\x0f\x00\x00\x00" # jmp 0x38
b"\x48\xba\xca\xc0\x00\x00\x00\x00\x00\x00" # 29: movabs rdx, 0xc0ca
b"\xe9\x00\x00\x00\x00" # jmp 0x38
b"\xf4" # 38: hlt
)
BASE = 0x1000000
mu = 0
zf = 1 # (0:clear, 1:set)
class Init(regress.RegressTest):
class Jumping(regress.RegressTest):
def clear_zf(self):
eflags_cur = mu.reg_read(UC_X86_REG_EFLAGS)
eflags = eflags_cur & ~(1 << 6)
#eflags = 0x0
print "[clear_zf] - eflags from %x to %x" % (eflags_cur, eflags)
if eflags != eflags_cur:
print "[clear_zf] - writing new eflags..."
mu.reg_write(UC_X86_REG_EFLAGS, eflags)
eflags = self.uc.reg_read(UC_X86_REG_EFLAGS)
if (eflags >> 6) & 0b1 == 0b1:
eflags &= ~(0b1 << 6)
regress.logger.debug("[clear_zf] clearing zero flag")
self.uc.reg_write(UC_X86_REG_EFLAGS, eflags)
else:
regress.logger.debug("[clear_zf] no change needed")
def set_zf(self):
eflags_cur = mu.reg_read(UC_X86_REG_EFLAGS)
eflags = eflags_cur | (1 << 6)
#eflags = 0xFFFFFFFF
print "[set_zf] - eflags from %x to %x" % (eflags_cur, eflags)
if eflags != eflags_cur:
print "[set_zf] - writing new eflags..."
mu.reg_write(UC_X86_REG_EFLAGS, eflags)
eflags = self.uc.reg_read(UC_X86_REG_EFLAGS)
def handle_zf(self, zf):
print "[handle_zf] - eflags " , zf
if zf == 0: self.clear_zf()
else: self.set_zf()
if (eflags >> 6) & 0b1 == 0b0:
eflags |= (0b1 << 6)
regress.logger.debug("[set_zf] setting zero flag")
self.uc.reg_write(UC_X86_REG_EFLAGS, eflags)
else:
regress.logger.debug("[set_zf] no change needed")
def multipath(self):
print "[multipath] - handling ZF (%s) - default" % zf
self.handle_zf(zf)
regress.logger.debug("[multipath] - handling ZF (%s) - default", self.fixed_zf)
if self.fixed_zf:
self.set_zf()
else:
self.clear_zf()
# BUG: eflags changes do not get reflected unless re-writing eip
# callback for tracing basic blocks
def hook_block(self, uc, address, size, user_data):
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
def hook_block(self, uc, address, size, _):
regress.logger.debug("Reached a new basic block at %#x (%d bytes in size)", address, size)
# callback for tracing instructions
def hook_code(self, uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
rax = mu.reg_read(UC_X86_REG_RAX)
rbx = mu.reg_read(UC_X86_REG_RBX)
rcx = mu.reg_read(UC_X86_REG_RCX)
rdx = mu.reg_read(UC_X86_REG_RDX)
rsi = mu.reg_read(UC_X86_REG_RSI)
rdi = mu.reg_read(UC_X86_REG_RDI)
r8 = mu.reg_read(UC_X86_REG_R8)
r9 = mu.reg_read(UC_X86_REG_R9)
r10 = mu.reg_read(UC_X86_REG_R10)
r11 = mu.reg_read(UC_X86_REG_R11)
r12 = mu.reg_read(UC_X86_REG_R12)
r13 = mu.reg_read(UC_X86_REG_R13)
r14 = mu.reg_read(UC_X86_REG_R14)
r15 = mu.reg_read(UC_X86_REG_R15)
eflags = mu.reg_read(UC_X86_REG_EFLAGS)
print(">>> RAX = %x" %rax)
print(">>> RBX = %x" %rbx)
print(">>> RCX = %x" %rcx)
print(">>> RDX = %x" %rdx)
print(">>> RSI = %x" %rsi)
print(">>> RDI = %x" %rdi)
print(">>> R8 = %x" %r8)
print(">>> R9 = %x" %r9)
print(">>> R10 = %x" %r10)
print(">>> R11 = %x" %r11)
print(">>> R12 = %x" %r12)
print(">>> R13 = %x" %r13)
print(">>> R14 = %x" %r14)
print(">>> R15 = %x" %r15)
print(">>> ELAGS = %x" %eflags)
print "-"*11
def hook_code(self, uc, address, size, _):
insn = uc.mem_read(address, size)
regress.logger.debug(">>> Tracing instruction at %#x : %s", address, binascii.hexlify(insn))
regs = uc.reg_read_batch((
UC_X86_REG_RAX, UC_X86_REG_RBX, UC_X86_REG_RCX, UC_X86_REG_RDX,
UC_X86_REG_RSI, UC_X86_REG_RDI, UC_X86_REG_RBP, UC_X86_REG_RSP,
UC_X86_REG_R8, UC_X86_REG_R9, UC_X86_REG_R10, UC_X86_REG_R11,
UC_X86_REG_R12, UC_X86_REG_R13, UC_X86_REG_R14, UC_X86_REG_R15,
UC_X86_REG_EFLAGS
))
zf = (regs[16] >> 6) & 0b1
regress.logger.debug(" RAX = %08x, R8 = %08x", regs[0], regs[ 8])
regress.logger.debug(" RBX = %08x, R9 = %08x", regs[1], regs[ 9])
regress.logger.debug(" RCX = %08x, R10 = %08x", regs[2], regs[10])
regress.logger.debug(" RDX = %08x, R11 = %08x", regs[3], regs[11])
regress.logger.debug(" RSI = %08x, R12 = %08x", regs[4], regs[12])
regress.logger.debug(" RDI = %08x, R13 = %08x", regs[5], regs[13])
regress.logger.debug(" RBP = %08x, R14 = %08x", regs[6], regs[14])
regress.logger.debug(" RSP = %08x, R15 = %08x", regs[7], regs[15])
regress.logger.debug(" EFLAGS = %08x (ZF = %d)", regs[16], zf)
regress.logger.debug("-" * 32)
self.multipath()
print "-"*11
# callback for tracing memory access (READ or WRITE)
def hook_mem_access(self, uc, access, address, size, value, user_data):
if access == UC_MEM_WRITE:
print(">>> Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \
%(address, size, value))
else: # READ
print(">>> Memory is being READ at 0x%x, data size = %u" \
%(address, size))
# callback for tracing invalid memory access (READ or WRITE)
def hook_mem_invalid(self, uc, access, address, size, value, user_data):
print("[ HOOK_MEM_INVALID - Address: %s ]" % hex(address))
if access == UC_MEM_WRITE_UNMAPPED:
print(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" %(address, size, value))
return True
else:
print(">>> Missing memory is being READ at 0x%x, data size = %u, data value = 0x%x" %(address, size, value))
return True
regress.logger.debug("-" * 32)
def hook_mem_fetch_unmapped(self, uc, access, address, size, value, user_data):
print("[ HOOK_MEM_FETCH - Address: %s ]" % hex(address))
print("[ mem_fetch_unmapped: faulting address at %s ]" % hex(address).strip("L"))
return True
def setUp(self):
# decide how to fixate zf value: 0 to clear, 1 to set
self.fixed_zf = 1
def runTest(self):
global mu
JUMP = "\x48\x31\xc0\x48\xb8\x04\x00\x00\x00\x00\x00\x00\x00\x48\x3d\x05\x00\x00\x00\x74\x05\xe9\x0f\x00\x00\x00\x48\xba\xbe\xba\x00\x00\x00\x00\x00\x00\xe9\x0f\x00\x00\x00\x48\xba\xca\xc0\x00\x00\x00\x00\x00\x00\xe9\x00\x00\x00\x00\x90"
ADDRESS = 0x1000000
print("Emulate x86_64 code")
# Initialize emulator in X86-64bit mode
mu = Uc(UC_ARCH_X86, UC_MODE_64)
uc = Uc(UC_ARCH_X86, UC_MODE_64)
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# map one page for this emulation
uc.mem_map(BASE, 0x1000)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, JUMP)
uc.mem_write(BASE, CODE)
# setup stack
mu.reg_write(UC_X86_REG_RSP, ADDRESS + 0x200000)
self.uc = uc
def runTest(self):
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, self.hook_block)
self.uc.hook_add(UC_HOOK_BLOCK, self.hook_block)
# tracing all instructions in range [ADDRESS, ADDRESS+0x60]
mu.hook_add(UC_HOOK_CODE, self.hook_code, None, ADDRESS, ADDRESS+0x60)
self.uc.hook_add(UC_HOOK_CODE, self.hook_code, begin=BASE, end=BASE + 0x60)
# tracing all memory READ & WRITE access
mu.hook_add(UC_HOOK_MEM_WRITE, self.hook_mem_access)
mu.hook_add(UC_HOOK_MEM_READ, self.hook_mem_access)
mu.hook_add(UC_HOOK_MEM_FETCH_UNMAPPED, self.hook_mem_fetch_unmapped)
mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, self.hook_mem_invalid)
# emulate machine code in infinite time
self.uc.emu_start(BASE, BASE + len(CODE))
try:
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + len(JUMP))
except UcError as e:
print("ERROR: %s" % e)
rdx = mu.reg_read(UC_X86_REG_RDX)
self.assertEqual(rdx, 0xbabe, "RDX contains the wrong value. Eflags modification failed.")
self.assertEqual(self.uc.reg_read(UC_X86_REG_RDX), 0xbabe, "rdx contains the wrong value. eflags modification failed")
if __name__ == '__main__':

View File

@ -1,63 +1,74 @@
#!/usr/bin/python
from __future__ import print_function
import time
import gc
import regress
import weakref
from unicorn import *
from unicorn.x86_const import *
import objgraph
import regress
ADDRESS = 0x8048000
STACK_ADDRESS = 0xffff000
STACK_SIZE = 4096
'''
31 DB xor ebx, ebx
53 push ebx
43 inc ebx
53 push ebx
6A 02 push 2
6A 66 push 66h
58 pop eax
89 E1 mov ecx, esp
CD 80 int 80h
'''
CODE = "\x31\xDB\x53\x43\x53\x6A\x02\x6A\x66\x58\x89\xE1\xCD\x80"
STACK_SIZE = 0x1000
CODE = (
b"\x31\xDB" # xor ebx, ebx
b"\x53" # push ebx
b"\x43" # inc ebx
b"\x53" # push ebx
b"\x6A\x02" # push 2
b"\x6A\x66" # push 66h
b"\x58" # pop eax
b"\x89\xE1" # mov ecx, esp
b"\xCD\x80" # int 80h
)
EP = ADDRESS + 0x54
# Dictionary to keep weak references to instances
instances = weakref.WeakValueDictionary()
def create_instance(key, *args, **kwargs):
obj = Uc(*args, **kwargs)
instances[key] = obj
return obj
def hook_code(mu, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
def emu_loop():
emu = Uc(UC_ARCH_X86, UC_MODE_32)
regress.logger.debug(">>> Tracing instruction at %#x, instruction size = %u", address, size)
def emu_loop(key):
emu = create_instance(key, UC_ARCH_X86, UC_MODE_32)
emu.mem_map(ADDRESS, 0x1000)
emu.mem_write(EP, CODE)
emu.mem_map(STACK_ADDRESS, STACK_SIZE)
emu.reg_write(UC_X86_REG_ESP, STACK_ADDRESS + STACK_SIZE)
i = emu.hook_add(UC_HOOK_CODE, hook_code, None)
emu.hook_del(i)
emu.emu_start(EP, EP + len(CODE), count = 3)
print("EIP: 0x%x" % emu.reg_read(UC_X86_REG_EIP))
regress.logger.debug("EIP: %#x", emu.reg_read(UC_X86_REG_EIP))
def debugMem():
import gc
gc.collect() # don't care about stuff that would be garbage collected properly
#print("Orphaned objects in gc.garbage:", gc.garbage)
assert(len(objgraph.by_type("Uc")) == 0)
#assert(len(objgraph.get_leaking_objects()) == 0)
assert(len(instances) == 0)
class EmuLoopReferenceTest(regress.RegressTest):
def runTest(self):
for i in range(5):
emu_loop()
emu_loop('obj%d' % i)
debugMem()
if __name__ == '__main__':
regress.main()
regress.main()

View File

@ -3,38 +3,45 @@
# this prints out 2 lines and the contents must be the same
from unicorn import *
import regress
from unicorn import *
from unicorn.x86_const import *
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')
uc.mem_write(0x8048000, b'test')
s1 = uc.mem_read(0x8048000, 4)
self.assertEqual('test'.encode('hex'), s1)
self.assertEqual(b'test', s1)
uc.mem_map(0x804a000, 0x8000)
s2 = str(uc.mem_read(0x8048000, 4)).encode('hex')
s2 = uc.mem_read(0x8048000, 4)
self.assertEqual(s1, s2)
def test_mmap_invalid(self):
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
u = Uc(UC_ARCH_X86, 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)
u = Uc(UC_ARCH_X86, UC_MODE_32)
for i in xrange(20):
for i in range(20):
with self.assertRaises(UcError):
u.mem_map(i*0x1000, 5)
u.mem_read(i*0x1000+6, 1)
u.mem_map(i * 0x1000, 5)
u.mem_read(i * 0x1000+6, 1)
if __name__ == '__main__':
regress.main()

View File

@ -1,35 +1,38 @@
#!/usr/bin/env python
import unicorn
from unicorn import *
import regress
class MmapSeg(regress.RegressTest):
from unicorn import *
from unicorn.x86_const import *
def test_seg1(self):
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
class MmapSeg1(regress.RegressTest):
def runTest(self):
u = Uc(UC_ARCH_X86, 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)
u = Uc(UC_ARCH_X86, 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)
u = Uc(UC_ARCH_X86, UC_MODE_32)
u.mem_map(i * 0x1000, 5)
u.mem_read(i * 0x1000, 1)
def test_seg2(self):
class MmapSeg2(regress.RegressTest):
def runTest(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).')
uc.mem_write(0x1000, b' ' * 0x1004)
self.assertTrue(True, 'If not reached, then we have BUG (crash on x86_64 Linux).')
if __name__ == '__main__':
regress.main()

View File

@ -1,8 +1,19 @@
#!/usr/bin/python
import regress
from capstone import *
from unicorn import *
import regress
CODE = (
b'\x00\x00\xa4\x12' # beq $a0, $s5, 0x4008a0
b'\x6a\x00\x82\x28' # slti $v0, $a0, 0x6a
b'\x00\x00\x00\x00' # nop
)
BASE = 0x400000
class MipsBranchDelay(regress.RegressTest):
@ -10,27 +21,24 @@ class MipsBranchDelay(regress.RegressTest):
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 %-6s %s' % (i.address, str(i.bytes).encode('hex'), i.mnemonic, i.op_str)
for insn in md.disasm(code, addr):
regress.logger.debug('%#x: %-8s %s', insn.address, insn.mnemonic, insn.op_str)
def hook_code(uc, addr, size, _):
mem = str(uc.mem_read(addr, size))
disas(mem, addr)
disas(uc.mem_read(addr, size), addr)
CODE = 0x400000
asm = '0000a4126a00822800000000'.decode('hex') # beq $a0, $s5, 0x4008a0; slti $v0, $a0, 0x6a; nop
regress.logger.debug('Input instructions:')
disas(CODE, BASE)
print 'Input instructions:'
disas(asm, CODE)
print
print 'Hooked instructions:'
regress.logger.debug('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)))
uc.mem_map(BASE, 0x1000)
uc.mem_write(BASE, CODE)
self.assertEqual(None, uc.emu_start(BASE, BASE + len(CODE)))
if __name__ == '__main__':
regress.main()

View File

@ -1,13 +1,29 @@
import regress
from unicorn import *
from unicorn.mips_const import *
CODE = b'\x44\x43\xF8\x00' # cfc1 $v1, FCSR
BASE = 0x416CB0
# .text:00416CB0 cfc1 $v1, FCSR
shellcode = [0x44, 0x43, 0xF8, 0x00]
base = 0x416CB0
uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN)
uc.mem_map(0x416000, 0x1000)
uc.mem_write(base, bytes(shellcode))
uc.emu_start(base, base + len(shellcode))
class TestMipsCp1(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN)
uc.mem_map(BASE & ~(0x1000 - 1), 0x1000)
uc.mem_write(BASE, CODE)
# set a wrong value in v1
uc.reg_write(UC_MIPS_REG_V1, 0x0badc0de)
uc.emu_start(BASE, BASE + len(CODE))
# default FCSR value should be 0
self.assertEqual(0x0000, uc.reg_read(UC_MIPS_REG_V1))
if __name__ == '__main__':
regress.main()

View File

@ -1,41 +1,59 @@
#!/usr/bin/python
from unicorn import *
from unicorn.mips_const import *
import regress
def hook_intr(uc, intno, _):
print 'interrupt', intno
from unicorn import *
from unicorn.mips_const import *
CODE = (
b'\x00\x00\x00\x00' # nop
b'\x00\x00\xa4\x8f' # lw $a0, 0($sp)
)
BASE = 0x20000000
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)
uc.mem_map(BASE, 0x1000)
uc.mem_write(BASE, CODE)
# execute nop. we should be ok
uc.emu_start(BASE, BASE + len(CODE), count=1)
# ----------------------------------------
# set sp to a mapped but unaligned address to read from
uc.reg_write(UC_MIPS_REG_SP, BASE + 0x801)
with self.assertRaises(UcError) as m:
uc.reg_write(UC_MIPS_REG_SP, 0x400001)
uc.emu_start(CODE, CODE + len(asm), 300)
uc.emu_start(BASE + 4, BASE + len(CODE), count=1)
self.assertEqual(UC_ERR_READ_UNALIGNED, m.exception.errno)
# ----------------------------------------
# set sp to an umapped address to read from
uc.reg_write(UC_MIPS_REG_SP, 0xfffffff0)
with self.assertRaises(UcError) as m:
uc.reg_write(UC_MIPS_REG_SP, 0xFFFFFFF0)
uc.emu_start(CODE, CODE + len(asm), 200)
uc.emu_start(BASE + 4, BASE + len(CODE), count=1)
self.assertEqual(UC_ERR_READ_UNMAPPED, m.exception.errno)
# ----------------------------------------
uc.reg_write(UC_MIPS_REG_SP, 0x40000000)
with self.assertRaises(UcError) as m:
uc.reg_write(UC_MIPS_REG_SP, 0x80000000)
uc.emu_start(CODE, CODE + len(asm), 100)
uc.emu_start(BASE + 4, BASE + len(CODE), count=1)
self.assertEqual(UC_ERR_READ_UNMAPPED, m.exception.errno)
if __name__ == '__main__':
regress.main()

View File

@ -1,23 +1,26 @@
#!/usr/bin/python
import regress
from unicorn import *
from unicorn.mips_const import *
import regress
CODE = b'\x34\x21\x34\x56' # ori $at, $at, 0x3456
BASE = 0x10000000
class MipsSyscall(regress.RegressTest):
def test(self):
addr = 0x80000000
code = '34213456'.decode('hex') # ori $at, $at, 0x3456
def test_syscall(self):
uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN)
uc.mem_map(addr, 0x1000)
uc.mem_write(addr, code)
uc.mem_map(BASE, 0x1000)
uc.mem_write(BASE, CODE)
uc.reg_write(UC_MIPS_REG_AT, 0)
uc.emu_start(addr, addr + len(code))
uc.emu_start(BASE, BASE + len(CODE))
self.assertEqual(uc.reg_read(UC_MIPS_REG_AT), 0x3456)
self.assertEqual(0x3456, uc.reg_read(UC_MIPS_REG_AT))
if __name__ == '__main__':

View File

@ -1,51 +1,56 @@
#!/usr/bin/python
import regress
from unicorn import *
from unicorn.mips_const import *
import regress
CODE = (
b'\xf8\xff\x01\x24' # addiu $at, $zero, -8
b'\x24\xe8\xa1\x03' # and $sp, $sp, $at
b'\x09\xf8\x20\x03' # jalr $t9
b'\xe8\xff\xbd\x23' # addi $sp, $sp, -0x18
b'\xb8\xff\xbd\x27' # addiu $sp, $sp, -0x48
b'\x00\x00\x00\x00' # nop
)
BASE = 0x4010dc
def code_hook(uc, addr, size, user_data):
print 'code hook: pc=%08x sp=%08x' % (addr, uc.reg_read(UC_MIPS_REG_SP))
regress.logger.debug('code hook: pc=%08x sp=%08x', addr, uc.reg_read(UC_MIPS_REG_SP))
def run(step=False):
addr = 0x4010dc
code = (
'f8ff0124' # addiu $at, $zero, -8
'24e8a103' # and $sp, $sp, $at
'09f82003' # jalr $t9
'e8ffbd23' # addi $sp, $sp, -0x18
'b8ffbd27' # addiu $sp, $sp, -0x48
'00000000' # nop
).decode('hex')
def run(step) -> int:
uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN)
if step:
uc.hook_add(UC_HOOK_CODE, code_hook)
uc.reg_write(UC_MIPS_REG_SP, 0x60800000)
uc.reg_write(UC_MIPS_REG_T9, addr + len(code) - 8)
uc.reg_write(UC_MIPS_REG_T9, BASE + len(CODE) - 8)
print 'sp =', hex(uc.reg_read(UC_MIPS_REG_SP))
print 'at =', hex(uc.reg_read(UC_MIPS_REG_AT))
print '<run> (single step: %s)' % (str(step))
regress.logger.debug('sp = %08x', uc.reg_read(UC_MIPS_REG_SP))
regress.logger.debug('at = %08x', uc.reg_read(UC_MIPS_REG_AT))
regress.logger.debug('<run> (single step: %s)', str(step))
uc.mem_map(addr & ~(0x1000 - 1), 0x2000)
uc.mem_write(addr, code)
uc.emu_start(addr, addr + len(code))
uc.mem_map(BASE & ~(0x1000 - 1), 0x2000)
uc.mem_write(BASE, CODE)
uc.emu_start(BASE, BASE + len(CODE))
regress.logger.debug('sp = %08x', uc.reg_read(UC_MIPS_REG_SP))
regress.logger.debug('at = %08x', uc.reg_read(UC_MIPS_REG_AT))
print 'sp =', hex(uc.reg_read(UC_MIPS_REG_SP))
print 'at =', hex(uc.reg_read(UC_MIPS_REG_AT))
print
return uc.reg_read(UC_MIPS_REG_SP)
class MipsSingleStep(regress.RegressTest):
def test(self):
def runTest(self):
sp1 = run(step=False)
sp2 = run(step=True)
self.assertEqual(sp1, sp2)
if __name__ == '__main__':
regress.main()

View File

@ -1,25 +1,29 @@
#!/usr/bin/python
import regress
from unicorn import *
from unicorn.mips_const import *
import regress
CODE = b'\x0c\x00\x00\x00' # syscall
BASE = 0x40000
def intr_hook(uc, intno, data):
print 'interrupt=%d, v0=%d, pc=0x%08x' % (intno, uc.reg_read(UC_MIPS_REG_V0), uc.reg_read(UC_MIPS_REG_PC))
regress.logger.debug('interrupt=%d, v0=%d, pc=%#010x', intno, uc.reg_read(UC_MIPS_REG_V0), uc.reg_read(UC_MIPS_REG_PC))
class MipsSyscall(regress.RegressTest):
def test(self):
addr = 0x40000
code = '0c000000'.decode('hex') # syscall
uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN)
uc.mem_map(addr, 0x1000)
uc.mem_write(addr, code)
uc.mem_map(BASE, 0x1000)
uc.mem_write(BASE, CODE)
uc.reg_write(UC_MIPS_REG_V0, 100)
uc.hook_add(UC_HOOK_INTR, intr_hook)
uc.emu_start(addr, addr+len(code))
uc.emu_start(BASE, BASE+len(CODE))
self.assertEqual(0x40004, uc.reg_read(UC_MIPS_REG_PC))

View File

@ -1,24 +1,34 @@
#!/usr/bin/python
import regress
from unicorn import *
from unicorn.x86_const import *
import regress
CODE = (
b'\x8e\xe8' # mov gs, eax
b'\xb8\x01\x00\x00\x00' # mov eax, 1
)
BASE = 0x1000
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.mem_map(BASE, 0x1000)
uc.mem_write(BASE, CODE)
uc.reg_write(UC_X86_REG_EAX, 0xFFFFFFFF)
with self.assertRaises(UcError) as ex_ctx:
uc.emu_start(0x1000, 0x1000 + len(code))
uc.emu_start(BASE, BASE + len(CODE))
self.assertEqual(UC_ERR_EXCEPTION, ex_ctx.exception.errno)
self.assertEquals(ex_ctx.exception.errno, UC_ERR_EXCEPTION)
if __name__ == '__main__':
regress.main()

View File

@ -1,35 +1,39 @@
#!/usr/bin/python
# By Ryan Hileman, issue #3
from capstone import *
import regress
from capstone import Cs, CS_ARCH_X86, CS_MODE_64
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)
])
CODE = b'\xf2\x0f\x10\x05\xaa\x12\x00\x00'
def hook_code(uc, addr, size, user_data):
def dis(md, mem, addr):
return '\n'.join(('%-16s %s' % (insn.mnemonic, insn.op_str) for insn in md.disasm(mem, addr)))
def hook_code(uc, addr, size, md):
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)
regress.logger.debug('instruction size: %d', size)
regress.logger.debug('instruction: %s %s', mem, dis(md, mem, addr))
regress.logger.debug('reference: %s %s', CODE, dis(md, 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)
md = Cs(CS_ARCH_X86, CS_MODE_64)
mu.hook_add(UC_HOOK_CODE, hook_code, md)
mu.mem_map(addr, 8 * 1024 * 1024)
mu.mem_write(addr, code)
mu.emu_start(addr, addr + len(code))
mu.mem_write(addr, CODE)
mu.emu_start(addr, addr + len(CODE))
if __name__ == '__main__':
regress.main()

View File

@ -1,20 +1,18 @@
#!/usr/bin/env python
import platform
import resource
import regress
from unicorn import *
import regress
# OS X: OK with 2047 iterations.
# OS X: Crashes at 2048:th iteration ("qemu: qemu_thread_create: Resource temporarily unavailable").
# Linux: No crashes observed.
class ThreadCreateCrash(regress.RegressTest):
def test(self):
for i in xrange(2048):
for _ in range(2048):
Uc(UC_ARCH_X86, UC_MODE_64)
self.assertTrue(True, "If not reached, then we have a crashing bug.")
if __name__ == '__main__':
regress.main()

View File

@ -2,10 +2,12 @@
import platform
import resource
import regress
from unicorn import *
import regress
ITERATIONS = 10000
class MemoryLeak(regress.RegressTest):
def test(self):
@ -15,15 +17,20 @@ class MemoryLeak(regress.RegressTest):
rusage_multiplier = 1024
else:
# resource.getrusage(...) is platform dependent. Only tested under OS X and Linux.
return
self.skipTest('not OSx neither Linux')
max_rss_before = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss * rusage_multiplier
for i in xrange(10000):
for _ in range(ITERATIONS):
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0, 4096)
mu.mem_map(0, 0x1000)
mu.emu_start(0, 0)
max_rss_after = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss * rusage_multiplier
rss_increase_per_iteration = (max_rss_after - max_rss_before) / i
self.assertLess(rss_increase_per_iteration, 8000)
rss_increase_per_iteration = (max_rss_after - max_rss_before) / ITERATIONS
self.assertLess(rss_increase_per_iteration, 8000.0)
if __name__ == '__main__':
regress.main()

View File

@ -1,21 +1,25 @@
#!/usr/bin/python
# By Ryan Hileman, issue #91
# Invalid instruction = test failed
import regress
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.ctl_set_cpu_model(UC_CPU_X86_HASWELL)
uc.mem_map(0x2000, 0x1000)
# pshufb xmm0, xmm1
uc.mem_write(0x2000, '660f3800c1'.decode('hex'))
uc.mem_write(0x2000, b'\x66\x0f\x38\x00\xc1') # pshufb xmm0, xmm1
# Invalid instruction -> test failed
uc.emu_start(0x2000, 0x2005)
if __name__ == '__main__':
regress.main()

View File

@ -2,30 +2,37 @@
"""See https://github.com/unicorn-engine/unicorn/issues/98"""
import unicorn
import regress
from unicorn import *
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)
regress.logger.debug(">>> 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 = Uc(UC_ARCH_X86, UC_MODE_32)
mu.reg_write(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_FETCH_UNMAPPED | unicorn.UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid)
mu.hook_add(UC_HOOK_MEM_FETCH_UNMAPPED | UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid)
mu.emu_start(0x10000000, 0x10000000 + 2, count=1)
if __name__ == '__main__':
regress.main()

View File

@ -1,34 +1,64 @@
#!/usr/bin/python
#!/usr/bin/env python
import glob
import logging
import os
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
"""Regress test case dummy class.
"""
def __setup_logger(name):
"""Set up a unified logger for all tests.
"""
instance = logging.getLogger(name)
instance.propagate = False
handler = logging.StreamHandler()
formatter = logging.Formatter('[%(levelname)s] %(message)s')
if not instance.hasHandlers():
handler.setFormatter(formatter)
instance.addHandler(handler)
return instance
logger = __setup_logger('UnicornRegress')
logger.setLevel(logging.INFO)
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
logger.info('starting discovery')
# Find all unittest type in this directory and run it.
directory = os.path.dirname(__file__) or '.'
pyfiles = glob.glob(directory + '/*.py')
modules = [os.path.splitext(os.path.basename(f))[0] for f in pyfiles if os.path.isfile(f) and f != __file__]
logger.info('%d test modules found', len(modules))
for mname in modules:
try:
module = __import__(mname)
except ImportError as ex:
logger.error('could not load %s: %s is missing', mname, ex.name)
else:
tests = unittest.defaultTestLoader.loadTestsFromModule(module)
suite.addTests(tests)
logger.debug('found %d test cases in %s', tests.countTestCases(), mname)
logger.info('%d test cases were added', suite.countTestCases())
unittest.TextTestRunner().run(suite)

View File

@ -1,28 +1,36 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
import regress
PAGE_SIZE = 4 * 1024
from unicorn import *
from unicorn.x86_const import *
PAGE_SIZE = 0x1000
CODE = b'\xf3\xaa' # rep stosb
BASE = 0x00000000
def hook_code(uc, addr, size, user_data):
print("hook called at %x" %addr)
class TestRep(regress.RegressTest):
class REP(regress.RegressTest):
def test_rep(self):
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_ECX, 3)
mu.reg_write(UC_X86_REG_EDI, 0x100)
mu.hook_add(UC_HOOK_CODE, hook_code)
mu.mem_map(BASE, PAGE_SIZE)
mu.mem_write(BASE, CODE)
mu.reg_write(UC_X86_REG_ECX, 8)
mu.reg_write(UC_X86_REG_ESI, 0x10)
mu.reg_write(UC_X86_REG_EDI, 0x20)
def __hook_code(uc, addr, size, ud):
regress.logger.debug('iterations remaining: %d', uc.reg_read(UC_X86_REG_ECX))
mu.hook_add(UC_HOOK_CODE, __hook_code)
mu.emu_start(BASE, len(CODE))
mu.emu_start(0, len(CODE))
self.assertEqual(0, mu.reg_read(UC_X86_REG_ECX))

View File

@ -3,33 +3,31 @@
# This test demonstrates emulation behavior within and across
# basic blocks.
from __future__ import print_function
import binascii
import regress
import struct
import regress
from unicorn import *
from unicorn.x86_const import *
CODE = binascii.unhexlify(b"".join([
b"b800000000", # 1000: b8 00 00 00 00 mov eax,0x0
b"40", # 1005: 40 inc eax
b"40", # 1006: 40 inc eax
b"6810100000", # 1007: 68 10 10 00 00 push 0x1010
b"c3", # 100c: c3 ret
b"cc", # 100d: cc int3
b"cc", # 100e: cc int3
b"cc", # 100f: cc int3
b"b800000000", # 1010: b8 00 00 00 00 mov eax,0x0
b"40", # 1015: 40 inc eax
b"40", # 1016: 40 inc eax
]))
CODE = (
b"\xb8\x00\x00\x00\x00" # 1000: mov eax,0x0
b"\x40" # 1005: inc eax
b"\x40" # 1006: inc eax
b"\x68\x10\x10\x00\x00" # 1007: push 0x1010
b"\xc3" # 100c: ret
b"\xcc" # 100d: int3
b"\xcc" # 100e: int3
b"\xcc" # 100f: int3
b"\xb8\x00\x00\x00\x00" # 1010: mov eax,0x0
b"\x40" # 1015: inc eax
b"\x40" # 1016: inc eax
)
def showpc(mu):
pc = mu.reg_read(UC_X86_REG_EIP)
print("pc: 0x%x" % (pc))
regress.logger.debug("pc: 0x%x", mu.reg_read(UC_X86_REG_EIP))
class RunAcrossBBTest(regress.RegressTest):
@ -38,13 +36,13 @@ class RunAcrossBBTest(regress.RegressTest):
#######################################################################
# emu SETUP
#######################################################################
print("\n---- test: run_all ----")
regress.logger.debug("\n---- test: run_all ----")
mu = Uc(UC_ARCH_X86, UC_MODE_32)
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
regress.logger.debug(">>> Tracing instruction at 0x%x, instruction size = %u", address, size)
mu.hook_add(UC_HOOK_CODE, hook_code)
# base of CODE
@ -73,33 +71,34 @@ class RunAcrossBBTest(regress.RegressTest):
# 1010: b8 00 00 00 00 mov eax,0x0 <-+
# 1015: 40 inc eax <
# 1016: 40 inc eax <
self.assertEqual(0x1016, mu.reg_read(UC_X86_REG_EIP), "unexpected PC (2)")
self.assertEqual(0x2800, mu.reg_read(UC_X86_REG_ESP), "unexpected SP (2)")
showpc(mu)
except UcError as e:
eip = mu.reg_read(UC_X86_REG_EIP)
if e.errno == UC_ERR_FETCH_UNMAPPED:
# during initial test dev, bad fetch at 0x1010, but the data is there,
# and this proves it
print("!!! about to bail due to bad fetch... here's the data at PC:")
print(binascii.hexlify(mu.mem_read(mu.reg_read(UC_X86_REG_EIP), 0x8)))
self.assertFalse(True, "ERROR: %s @ 0x%x" % (e, mu.reg_read(UC_X86_REG_EIP)))
# during initial test dev, bad fetch at 0x1010, but the data is there, and this proves it
regress.logger.error("!!! about to bail due to bad fetch... here's the data at PC:")
regress.logger.error(binascii.hexlify(mu.mem_read(eip, 8)))
self.fail("ERROR: %s @ 0x%x" % (e, eip))
def test_run_across_bb(self):
try:
#######################################################################
# emu SETUP
#######################################################################
print("\n---- test: run_across_bb ----")
regress.logger.debug("\n---- test: run_across_bb ----")
mu = Uc(UC_ARCH_X86, UC_MODE_32)
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
regress.logger.debug(">>> Tracing instruction at 0x%x, instruction size = %u", address, size)
mu.hook_add(UC_HOOK_CODE, hook_code)
# base of CODE
@ -111,8 +110,10 @@ class RunAcrossBBTest(regress.RegressTest):
mu.reg_write(UC_X86_REG_EIP, 0x1000)
mu.reg_write(UC_X86_REG_ESP, 0x2800)
self.assertEqual(0x1000, mu.reg_read(UC_X86_REG_EIP), "unexpected PC")
self.assertEqual(0x2800, mu.reg_read(UC_X86_REG_ESP), "unexpected SP")
showpc(mu)
@ -182,13 +183,14 @@ class RunAcrossBBTest(regress.RegressTest):
showpc(mu)
except UcError as e:
if e.errno == UC_ERR_FETCH_UNMAPPED:
# during initial test dev, bad fetch at 0x1010, but the data is there,
# and this proves it
print("!!! about to bail due to bad fetch... here's the data at PC:")
print(binascii.hexlify(mu.mem_read(mu.reg_read(UC_X86_REG_EIP), 0x8)))
eip = mu.reg_read(UC_X86_REG_EIP)
self.assertFalse(True, "ERROR: %s @ 0x%x" % (e, mu.reg_read(UC_X86_REG_EIP)))
if e.errno == UC_ERR_FETCH_UNMAPPED:
# during initial test dev, bad fetch at 0x1010, but the data is there, and this proves it
regress.logger.error("!!! about to bail due to bad fetch... here's the data at PC:")
regress.logger.error(binascii.hexlify(mu.mem_read(eip, 8)))
self.fail("ERROR: %s @ 0x%x" % (e, eip))
if __name__ == '__main__':

View File

@ -1,24 +1,33 @@
#!/usr/bin/python
import regress
from unicorn import *
from unicorn.sparc_const import *
PAGE_SIZE = 1 * 1024 * 1024
uc = Uc(UC_ARCH_SPARC, UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN)
uc.reg_write(UC_SPARC_REG_SP, 100)
print 'writing sp = 100'
CODE = (
b"\xb0\x06\x20\x01" # 0: b0 06 20 01 inc %i0
b"\xb2\x06\x60\x01" # 4: b2 06 60 01 inc %i1
)
# 0: b0 06 20 01 inc %i0
# 4: b2 06 60 01 inc %i1
BASE = 0x00000000
CODE = "\xb0\x06\x20\x01" \
"\xb2\x06\x60\x01"
class TestSparcRegRead(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_SPARC, UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN)
uc.mem_map(0, PAGE_SIZE)
uc.mem_write(0, CODE)
uc.emu_start(0, len(CODE), 0, 2)
uc.mem_map(BASE, 0x1000 ** 2)
uc.mem_write(BASE, CODE)
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)
uc.reg_write(UC_SPARC_REG_SP, 100)
uc.emu_start(BASE, BASE + len(CODE), count=2)
regress.logger.debug('sp = %#x', uc.reg_read(UC_SPARC_REG_SP))
regress.logger.debug('i0 = %#x', uc.reg_read(UC_SPARC_REG_I0))
regress.logger.debug('i1 = %#x', uc.reg_read(UC_SPARC_REG_I1))
if __name__ == '__main__':
regress.main()

View File

@ -1,205 +1,109 @@
#!/usr/bin/python
import regress
from unicorn import *
from unicorn.sparc_const import *
PAGE_SIZE = 1 * 1024 * 1024
uc = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN)
uc.reg_write(UC_SPARC_REG_SP, 100)
uc.reg_write(UC_SPARC_REG_FP, 200)
CODE =(
b"\x80\x00\x20\x01" # add %g0, 1, %g0
b"\x82\x00\x60\x01" # add %g1, 1, %g1
b"\x84\x00\xA0\x01" # add %g2, 1, %g2
b"\x86\x00\xE0\x01" # add %g3, 1, %g3
b"\x88\x01\x20\x01" # add %g4, 1, %g4
b"\x8A\x01\x60\x01" # add %g5, 1, %g5
b"\x8C\x01\xA0\x01" # add %g6, 1, %g6
b"\x8E\x01\xE0\x01" # add %g7, 1, %g7
b"\x90\x02\x20\x01" # add %o0, 1, %o0
b"\x92\x02\x60\x01" # add %o1, 1, %o1
b"\x94\x02\xA0\x01" # add %o2, 1, %o2
b"\x96\x02\xE0\x01" # add %o3, 1, %o3
b"\x98\x03\x20\x01" # add %o4, 1, %o4
b"\x9A\x03\x60\x01" # add %o5, 1, %o5
b"\x9C\x03\xA0\x01" # add %sp, 1, %sp
b"\x9E\x03\xE0\x01" # add %o7, 1, %o7
b"\xA0\x04\x20\x01" # add %l0, 1, %l0
b"\xA2\x04\x60\x01" # add %l1, 1, %l1
b"\xA4\x04\xA0\x01" # add %l2, 1, %l2
b"\xA6\x04\xE0\x01" # add %l3, 1, %l3
b"\xA8\x05\x20\x01" # add %l4, 1, %l4
b"\xAA\x05\x60\x01" # add %l5, 1, %l5
b"\xAC\x05\xA0\x01" # add %l6, 1, %l6
b"\xAE\x05\xE0\x01" # add %l7, 1, %l7
b"\xB0\x06\x20\x01" # add %i0, 1, %i0
b"\xB2\x06\x60\x01" # add %i1, 1, %i1
b"\xB4\x06\xA0\x01" # add %i2, 1, %i2
b"\xB6\x06\xE0\x01" # add %i3, 1, %i3
b"\xB8\x07\x20\x01" # add %i4, 1, %i4
b"\xBA\x07\x60\x01" # add %i5, 1, %i5
b"\xBC\x07\xA0\x01" # add %fp, 1, %fp
b"\xBE\x07\xE0\x01" # add %i7, 1, %i7
)
# 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
BASE = 0x00000000
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"
def hook_code(uc, addr, size, ud):
regress.logger.debug("executing at 0x%04x", uc.reg_read(UC_SPARC_REG_PC))
uc.mem_map(0, PAGE_SIZE)
uc.mem_write(0, CODE)
uc.emu_start(0, len(CODE), 0, 32)
class TestSparcRegRead(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32 | UC_MODE_BIG_ENDIAN)
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)
uc.reg_write(UC_SPARC_REG_SP, 100)
uc.reg_write(UC_SPARC_REG_FP, 200)
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)
uc.mem_map(BASE, PAGE_SIZE)
uc.mem_write(BASE, CODE)
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)
uc.hook_add(UC_HOOK_CODE, hook_code)
uc.emu_start(BASE, len(CODE))
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)
self.assertEqual(0, uc.reg_read(UC_SPARC_REG_G0)) # G0 is always zero
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_G1))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_G2))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_G3))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_G4))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_G5))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_G6))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_G7))
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("")
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_O0))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_O1))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_O2))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_O3))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_O4))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_O5))
self.assertEqual(101, uc.reg_read(UC_SPARC_REG_O6))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_O7))
print_registers(uc)
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_L0))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_L1))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_L2))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_L3))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_L4))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_L5))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_L6))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_L7))
assert uc.reg_read(UC_SPARC_REG_PC) == 132 # make sure we executed all instructions
assert uc.reg_read(UC_SPARC_REG_SP) == 101
assert uc.reg_read(UC_SPARC_REG_FP) == 201
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_I0))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_I1))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_I2))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_I3))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_I4))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_I5))
self.assertEqual(201, uc.reg_read(UC_SPARC_REG_I6))
self.assertEqual(1, uc.reg_read(UC_SPARC_REG_I7))
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
# BUG: PC seems to get reset to 4 when done executing
# self.assertEqual(4 * 32, uc.reg_read(UC_SPARC_REG_PC)) # make sure we executed all instructions
self.assertEqual(101, uc.reg_read(UC_SPARC_REG_SP))
self.assertEqual(201, uc.reg_read(UC_SPARC_REG_FP))
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
if __name__ == '__main__':
regress.main()

View File

@ -1,134 +1,150 @@
from unicorn import *

import regress
from unicorn import *
from unicorn.arm_const import *
import binascii
MB = 1024 * 1024
PAGE = 4 * 1024
def PrintArmRegisters(uc_emu):
print 'R0 : '+hex(uc_emu.reg_read(UC_ARM_REG_R0))
print 'R1 : '+hex(uc_emu.reg_read(UC_ARM_REG_R1))
print 'R2 : '+hex(uc_emu.reg_read(UC_ARM_REG_R2))
print 'R3 : '+hex(uc_emu.reg_read(UC_ARM_REG_R3))
print 'R4 : '+hex(uc_emu.reg_read(UC_ARM_REG_R4))
print 'R5 : '+hex(uc_emu.reg_read(UC_ARM_REG_R5))
print 'R6 : '+hex(uc_emu.reg_read(UC_ARM_REG_R6))
print 'R7 : '+hex(uc_emu.reg_read(UC_ARM_REG_R7))
print 'R8 : '+hex(uc_emu.reg_read(UC_ARM_REG_R8))
print 'R9 : '+hex(uc_emu.reg_read(UC_ARM_REG_R9))
print 'R10 : '+hex(uc_emu.reg_read(UC_ARM_REG_R10))
print 'R11 : '+hex(uc_emu.reg_read(UC_ARM_REG_R11))
print 'R12 : '+hex(uc_emu.reg_read(UC_ARM_REG_R12))
print 'SP : '+hex(uc_emu.reg_read(UC_ARM_REG_SP))
print 'LR : '+hex(uc_emu.reg_read(UC_ARM_REG_LR))
print 'PC : '+hex(uc_emu.reg_read(UC_ARM_REG_PC))
flags = uc_emu.reg_read(UC_ARM_REG_CPSR)
print 'carry : '+str(flags >> 29 & 0x1)
print 'overflow : '+str(flags >> 28 & 0x1)
print 'negative : '+str(flags >> 31 & 0x1)
print 'zero : '+str(flags >> 30 & 0x1)
'''
issue #287
Initial Register States: R0=3, R1=24, R2=16, R3=0
----- code start -----
CMP R0,R1,LSR#3
SUBCS R0,R0,R1,LSR#3 # CPU flags got changed in these two instructions, and *REMEMBERED*, now NF == VF == 0
CMP R0,#1 # CPU flags changed again, now NF == 1, VF == 0, but they are not properly *REMEMBERED*
MOV R1,R1,LSR#4
SUBGES R2,R2,#4 # according to the result of CMP, we should skip this op
MOVGE R3,#100 # since changed flags are not *REMEMBERED* in CMP, now NF == VF == 0, which result in wrong branch
# at the end of this code block, should R3 == 0
----- code end ------
# issue #287
# Initial Register States: R0=3, R1=24, R2=16, R3=0
#
# ----- code start -----
# CMP R0,R1,LSR#3
# SUBCS R0,R0,R1,LSR#3 # CPU flags got changed in these two instructions, and *REMEMBERED*, now NF == VF == 0
# CMP R0,#1 # CPU flags changed again, now NF == 1, VF == 0, but they are not properly *REMEMBERED*
# MOV R1,R1,LSR#4
# SUBGES R2,R2,#4 # according to the result of CMP, we should skip this op
#
# MOVGE R3,#100 # since changed flags are not *REMEMBERED* in CMP, now NF == VF == 0, which result in wrong branch
# # at the end of this code block, should R3 == 0
# ----- code end ------
#
# TCG ops are correct, plain op translation is done correctly,
# but there're In-Memory bits invisible from ops that control the host code generation.
# all these codes are in one TCG translation-block, so wrong things could happen.
# detail explanation is given on the right side.
# remember, both set_label and brcond are point to refresh the dead_temps and mem_temps states in TCG
#
# ----- TCG ops ------
# ld_i32 tmp5,env,$0xfffffffffffffff4
# movi_i32 tmp6,$0x0
# brcond_i32 tmp5,tmp6,ne,$0x0
# mov_i32 tmp5,r1 -------------------------
# movi_i32 tmp6,$0x3 |
# shr_i32 tmp5,r1,tmp6 |
# mov_i32 tmp6,r0 |
# sub_i32 NF,r0,tmp5 |
# mov_i32 ZF,NF |
# setcond_i32 CF,r0,tmp5,geu | # This part is "CMP R0,R1,LSR#3"
# xor_i32 VF,NF,r0 |-----> # and "SUBCS R0,R0,R1,LSR#3"
# xor_i32 tmp7,r0,tmp5 | # the last op in this block, set_label get a chance to refresh the TCG globals memory states,
# and_i32 VF,VF,tmp7 | # so things get back to normal states
# mov_i32 tmp6,NF | # these codes are not affected by the bug. Let's called this Part-D
# movi_i32 tmp5,$0x0 |
# brcond_i32 CF,tmp5,eq,$0x1 |
# mov_i32 tmp5,r1 |
# movi_i32 tmp6,$0x3 |
# shr_i32 tmp5,r1,tmp6 |
# mov_i32 tmp6,r0 |
# sub_i32 tmp6,r0,tmp5 |
# mov_i32 r0,tmp6 |
# set_label $0x1 -------------------------
# movi_i32 tmp5,$0x1 ----------------- # Let's called this Part-C
# mov_i32 tmp6,r0 | # NF is used as output operand again!
# sub_i32 NF,r0,tmp5 ----------------|-----> # but it is stated as Not-In-Memory,
# mov_i32 ZF,NF | # no need to sync it after calculation.
# setcond_i32 CF,r0,tmp5,geu | # the generated host code does not write NF
# xor_i32 VF,NF,r0 | # back to its memory location, hence forgot. And the CPU flags after this calculation is not changed.
# xor_i32 tmp7,r0,tmp5 | # Caution: the following SUBGES's condition check is right, even though the generated host code does not *REMEMBER* NF, it will cache the calculated result and serve SUBGES correctly
# and_i32 VF,VF,tmp7 |
# mov_i32 tmp6,NF |
# mov_i32 tmp5,r1 | # this part is "CMP R0,#1"
# movi_i32 tmp6,$0x4 | # and "MOV R1,R1,LSR#4"
# shr_i32 tmp5,r1,tmp6 | # and "SUBGES R2,R2,#4"
# mov_i32 r1,tmp5 |-----> # This is the part where problem start to arise
# xor_i32 tmp5,VF,NF |
# movi_i32 tmp6,$0x0 |
# brcond_i32 tmp5,tmp6,lt,$0x2 --------|-----> # QEMU will refresh the InMemory bit for TCG globals here, but Unicorn won't
# movi_i32 tmp5,$0x4 |
# mov_i32 tmp6,r2 | # this is the 1st bug-related op get analyzed.
# sub_i32 NF,r2,tmp5 ----------------|-----> # here, NF is an output operand, it's flagged dead
# mov_i32 ZF,NF | # and the InMemory bit is clear, tell the previous(above) ops
# setcond_i32 CF,r2,tmp5,geu | # if it is used as output operand again, do not sync it
# xor_i32 VF,NF,r2 | # so the generated host-code for previous ops will not write it back to Memory
# xor_i32 tmp7,r2,tmp5 | # Caution: the CPU flags after this calculation is also right, because the set_label is a point of refresh, make them *REMEMBERED*
# and_i32 VF,VF,tmp7 | # Let's call this Part-B
# mov_i32 tmp6,NF |
# mov_i32 r2,ZF |
# set_label $0x2 -----------------
# xor_i32 tmp5,VF,NF -----------------
# movi_i32 tmp6,$0x0 |
# brcond_i32 tmp5,tmp6,lt,$0x3 | # Let's call this Part-A
# movi_i32 tmp5,$0x64 | # if Part-B is not skipped, this part won't go wrong, because we'll check the CPU flags as the result of Part-B, it's *REMEMBERED*
# movi_i32 r3,$0x64 |-----> # but if Part-B is skipped,
# set_label $0x3 | # what should we expected? we will check the condition based on the result of Part-D!!!
# call wfi,$0x0,$0,env | # because result of Part-C is lost. this is why things go wrong.
# set_label $0x0 |
# exit_tb $0x7f6401714013 -----------------
# ###########
# ----- TCG ends ------
# TCG ops are correct, plain op translation is done correctly,
# but there're In-Memory bits invisible from ops that control the host code generation.
# all these codes are in one TCG translation-block, so wrong things could happen.
# detail explanation is given on the right side.
# remember, both set_label and brcond are point to refresh the dead_temps and mem_temps states in TCG
----- TCG ops ------
ld_i32 tmp5,env,$0xfffffffffffffff4
movi_i32 tmp6,$0x0
brcond_i32 tmp5,tmp6,ne,$0x0
mov_i32 tmp5,r1 -------------------------
movi_i32 tmp6,$0x3 |
shr_i32 tmp5,r1,tmp6 |
mov_i32 tmp6,r0 |
sub_i32 NF,r0,tmp5 |
mov_i32 ZF,NF |
setcond_i32 CF,r0,tmp5,geu | # This part is "CMP R0,R1,LSR#3"
xor_i32 VF,NF,r0 |-----> # and "SUBCS R0,R0,R1,LSR#3"
xor_i32 tmp7,r0,tmp5 | # the last op in this block, set_label get a chance to refresh the TCG globals memory states,
and_i32 VF,VF,tmp7 | # so things get back to normal states
mov_i32 tmp6,NF | # these codes are not affected by the bug. Let's called this Part-D
movi_i32 tmp5,$0x0 |
brcond_i32 CF,tmp5,eq,$0x1 |
mov_i32 tmp5,r1 |
movi_i32 tmp6,$0x3 |
shr_i32 tmp5,r1,tmp6 |
mov_i32 tmp6,r0 |
sub_i32 tmp6,r0,tmp5 |
mov_i32 r0,tmp6 |
set_label $0x1 -------------------------
movi_i32 tmp5,$0x1 ----------------- # Let's called this Part-C
mov_i32 tmp6,r0 | # NF is used as output operand again!
sub_i32 NF,r0,tmp5 ----------------|-----> # but it is stated as Not-In-Memory,
mov_i32 ZF,NF | # no need to sync it after calculation.
setcond_i32 CF,r0,tmp5,geu | # the generated host code does not write NF
xor_i32 VF,NF,r0 | # back to its memory location, hence forgot. And the CPU flags after this calculation is not changed.
xor_i32 tmp7,r0,tmp5 | # Caution: the following SUBGES's condition check is right, even though the generated host code does not *REMEMBER* NF, it will cache the calculated result and serve SUBGES correctly
and_i32 VF,VF,tmp7 |
mov_i32 tmp6,NF |
mov_i32 tmp5,r1 | # this part is "CMP R0,#1"
movi_i32 tmp6,$0x4 | # and "MOV R1,R1,LSR#4"
shr_i32 tmp5,r1,tmp6 | # and "SUBGES R2,R2,#4"
mov_i32 r1,tmp5 |-----> # This is the part where problem start to arise
xor_i32 tmp5,VF,NF |
movi_i32 tmp6,$0x0 |
brcond_i32 tmp5,tmp6,lt,$0x2 --------|-----> # QEMU will refresh the InMemory bit for TCG globals here, but Unicorn won't
movi_i32 tmp5,$0x4 |
mov_i32 tmp6,r2 | # this is the 1st bug-related op get analyzed.
sub_i32 NF,r2,tmp5 ----------------|-----> # here, NF is an output operand, it's flagged dead
mov_i32 ZF,NF | # and the InMemory bit is clear, tell the previous(above) ops
setcond_i32 CF,r2,tmp5,geu | # if it is used as output operand again, do not sync it
xor_i32 VF,NF,r2 | # so the generated host-code for previous ops will not write it back to Memory
xor_i32 tmp7,r2,tmp5 | # Caution: the CPU flags after this calculation is also right, because the set_label is a point of refresh, make them *REMEMBERED*
and_i32 VF,VF,tmp7 | # Let's call this Part-B
mov_i32 tmp6,NF |
mov_i32 r2,ZF |
set_label $0x2 -----------------
xor_i32 tmp5,VF,NF -----------------
movi_i32 tmp6,$0x0 |
brcond_i32 tmp5,tmp6,lt,$0x3 | # Let's call this Part-A
movi_i32 tmp5,$0x64 | # if Part-B is not skipped, this part won't go wrong, because we'll check the CPU flags as the result of Part-B, it's *REMEMBERED*
movi_i32 r3,$0x64 |-----> # but if Part-B is skipped,
set_label $0x3 | # what should we expected? we will check the condition based on the result of Part-D!!!
call wfi,$0x0,$0,env | # because result of Part-C is lost. this is why things go wrong.
set_label $0x0 |
exit_tb $0x7f6401714013 -----------------
###########
----- TCG ends ------
'''
TestCode = b'\xa1\x01\x50\xe1\xa1\x01\x40\x20\x01\x00\x50\xe3\x21\x12\xa0\xe1\x04\x20\x52\xa2\x64\x30\xa0\xa3'
CODE = (
b'\xa1\x01\x50\xe1' # cmp r0, r1, lsr #3
b'\xa1\x01\x40\x20' # subhs r0, r0, r1, lsr #3
b'\x01\x00\x50\xe3' # cmp r0, #1
b'\x21\x12\xa0\xe1' # lsr r1, r1, #4
b'\x04\x20\x52\xa2' # subsge r2, r2, #4
b'\x64\x30\xa0\xa3' # movge r3, #0x64
)
def UseUcToEmulate():
try:
uc_emu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
#if LoadCode(uc_emu, 2*MB, 0x9004):
uc_emu.mem_map(0, 2*MB)
uc_emu.reg_write(UC_ARM_REG_SP, 0x40000)
uc_emu.reg_write(UC_ARM_REG_R0, 3)
uc_emu.reg_write(UC_ARM_REG_R1, 24)
uc_emu.reg_write(UC_ARM_REG_R2, 16)
uc_emu.mem_write(0, TestCode)
uc_emu.emu_start(0, 24)
PrintArmRegisters(uc_emu)
except UcError as e:
print("ERROR: %s" % e)
PrintArmRegisters(uc_emu)
BASE = 0x00000000
UseUcToEmulate()
def show_regs(uc):
regress.logger.debug('R0 : %08x', uc.reg_read(UC_ARM_REG_R0))
regress.logger.debug('R1 : %08x', uc.reg_read(UC_ARM_REG_R1))
regress.logger.debug('R2 : %08x', uc.reg_read(UC_ARM_REG_R2))
regress.logger.debug('R3 : %08x', uc.reg_read(UC_ARM_REG_R3))
regress.logger.debug('R4 : %08x', uc.reg_read(UC_ARM_REG_R4))
regress.logger.debug('R5 : %08x', uc.reg_read(UC_ARM_REG_R5))
regress.logger.debug('R6 : %08x', uc.reg_read(UC_ARM_REG_R6))
regress.logger.debug('R7 : %08x', uc.reg_read(UC_ARM_REG_R7))
regress.logger.debug('R8 : %08x', uc.reg_read(UC_ARM_REG_R8))
regress.logger.debug('R9 : %08x', uc.reg_read(UC_ARM_REG_R9))
regress.logger.debug('R10 : %08x', uc.reg_read(UC_ARM_REG_R10))
regress.logger.debug('R11 : %08x', uc.reg_read(UC_ARM_REG_R11))
regress.logger.debug('R12 : %08x', uc.reg_read(UC_ARM_REG_R12))
regress.logger.debug('SP : %08x', uc.reg_read(UC_ARM_REG_SP))
regress.logger.debug('LR : %08x', uc.reg_read(UC_ARM_REG_LR))
regress.logger.debug('PC : %08x', uc.reg_read(UC_ARM_REG_PC))
flags = uc.reg_read(UC_ARM_REG_CPSR)
regress.logger.debug('carry : %d', (flags >> 29) & 0b1)
regress.logger.debug('overflow : %d', (flags >> 28) & 0b1)
regress.logger.debug('negative : %d', (flags >> 31) & 0b1)
regress.logger.debug('zero : %d', (flags >> 30) & 0b1)
class TestReadMem(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
uc.mem_map(BASE, 0x1000)
uc.reg_write(UC_ARM_REG_SP, 0x40000)
uc.reg_write(UC_ARM_REG_R0, 3)
uc.reg_write(UC_ARM_REG_R1, 24)
uc.reg_write(UC_ARM_REG_R2, 16)
uc.reg_write(UC_ARM_REG_R3, 0)
uc.mem_write(BASE, CODE)
uc.emu_start(BASE, len(CODE))
show_regs(uc)
self.assertEqual(0, uc.reg_read(UC_ARM_REG_R3))
if __name__ == '__main__':
regress.main()

View File

@ -1,22 +1,32 @@
#!/usr/bin/python
# By Mariano Graziano
import struct
import regress
from unicorn import *
from unicorn.x86_const import *
import regress, struct
class Emulator:
def __init__(self, code, stack):
self.mask = 0xFFFFFFFFFFFFF000
def __page_aligned(address):
return address & ~(0x1000 - 1)
self.unicorn_code = code
self.unicorn_stack = stack
self.mu = Uc(UC_ARCH_X86, UC_MODE_64)
size = 1 * 4096
self.mu.mem_map(code & self.mask, size)
size = 1 * 4096
self.mu.mem_map(stack & self.mask, size)
regress.logger.debug("mapping code : %#x", __page_aligned(code))
regress.logger.debug("mapping stack : %#x", __page_aligned(stack))
self.mu.mem_map(__page_aligned(code), 0x1000)
self.mu.mem_map(__page_aligned(stack), 0x1000)
self.mu.reg_write(UC_X86_REG_RSP, stack)
self.mu.reg_write(UC_X86_REG_RIP, code)
self.set_hooks()
def set_hooks(self):
@ -26,53 +36,55 @@ class Emulator:
def hook_mem_fetch_unmapped(self, uc, access, address, size, value, user_data):
next_ip = self.unicorn_code + size
self.mu.reg_write(UC_X86_REG_RIP, next_ip)
self.mu.mem_write(next_ip, "\x90")
self.mu.reg_write(UC_X86_REG_RIP, address)
self.write_reg(UC_X86_REG_RIP, next_ip)
self.write_data(next_ip, b"\x90")
# self.write_reg(UC_X86_REG_RIP, address) # ???
return True
def hook_mem_invalid(self, uc, access, address, size, value, user_data):
regress.logger.debug("invalid mem access: access type = %d, to = %#x, size = %u, value = %#x", access, address, size, value)
return True
def hook_mem_access(self, uc, access, address, size, value, user_data):
return True
def emu(self, size):
def emu(self, steps):
ip = self.mu.reg_read(UC_X86_REG_RIP)
try:
self.mu.emu_start(ip, ip + size, timeout=10000, count=1)
except UcError as e:
print("Error %s" % e)
max_intel_insn_size = 15
regress.logger.debug("starting at : %#x", ip)
self.mu.emu_start(ip, ip + max_intel_insn_size, count=steps)
def write_data(self, address, content):
self.mu.mem_write(address, content)
def write_reg(self, reg, value):
self.mu.reg_write(reg, value)
class Init(regress.RegressTest):
def init_unicorn(self, ip, sp, counter):
#print "[+] Emulating IP: %x SP: %x - Counter: %x" % (ip, sp, counter)
E = Emulator(ip, sp)
E.write_data(ip, "\x90")
E.write_data(sp, self.generate_value(counter))
E.mu.reg_write(UC_X86_REG_RSP, sp)
E.mu.reg_write(UC_X86_REG_RIP, ip)
E.emu(1)
def generate_value(self, counter):
start = 0xffff880026f02000
offset = counter * 8
address = start + offset
return struct.pack("<Q", address)
def init_unicorn(self, ip, sp, magic):
emu = Emulator(ip, sp)
emu.write_data(ip, b"\xf4" * 8)
emu.write_data(sp, struct.pack("<Q", magic))
emu.emu(1)
def runTest(self):
global mu
ips = list(range(0xffffffff816a9000, 0xffffffff816af000, 0x1))
sps = list(range(0xffff88001b800000, 0xffff88001b801000, 0x1))
j = 0
for i in ips:
j += 1
index = ips.index(i)
self.init_unicorn(i, sps[index], j)
ip_base = 0x000fffff816a0000 # was: 0xffffffff816a0000
sp_base = 0x000f88001b800000 # was: 0xffff88001b800000
mg_base = 0x000f880026f02000 # was: 0xffff880026f02000
ips = range(0x9000, 0xf000, 8)
sps = range(0x0000, 0x6000, 8)
for i, (ip, sp) in enumerate(zip(ips, sps)):
self.init_unicorn(ip_base + ip, sp_base + sp, mg_base + i * 8)
if __name__ == '__main__':
regress.main()

View File

@ -1,113 +1,105 @@
#!/usr/bin/env python
# Moshe Kravchik
from __future__ import print_function
from unicorn import *
from unicorn.arm_const import *
import binascii
import regress
from unicorn import *
from unicorn.arm_const import *
# code to be emulated
#enable VFP
'''
00000016 f44f0370 mov.w r3, #0xf00000
0000001a ee013f50 mcr p15, #0x0, r3, c1, c0, #0x2
0000bfb6 f3bf8f6f isb sy
0000bfba f04f4380 mov.w r3, #0x40000000
0000bfbe eee83a10 vmsr fpexc, r3
'''
ENABLE_VFP_CODE = "\x4f\xf4\x70\x03\x01\xee\x50\x3f\xbf\xf3\x6f\x8f\x4f\xf0\x80\x43\xe8\xee\x10\x3a"
VLD_CODE = "\x21\xf9\x0f\x6a"
#0000002a f9216a0f vld1.8 {d6, d7}, [r1]
VST_CODE = "\x00\xf9\x0f\x6a"
#0000002e f9006a0f vst1.8 {d6, d7}, [r0]
ENABLE_VFP_CODE = (
b"\x4f\xf4\x70\x03" # 00000016 mov.w r3, #0xf00000
b"\x01\xee\x50\x3f" # 0000001a mcr p15, #0x0, r3, c1, c0, #0x2
b"\xbf\xf3\x6f\x8f" # 0000bfb6 isb sy
b"\x4f\xf0\x80\x43" # 0000bfba mov.w r3, #0x40000000
b"\xe8\xee\x10\x3a" # 0000bfbe vmsr fpexc, r3
)
VLD_CODE = b"\x21\xf9\x0f\x6a" # 0000002a vld1.8 {d6, d7}, [r1]
VST_CODE = b"\x00\xf9\x0f\x6a" # 0000002e vst1.8 {d6, d7}, [r0]
# memory address where emulation starts
ADDRESS = 0x10000
SCRATCH_ADDRESS = 0x1000
ADDRESS = 0x10000
SCRATCH_ADDRESS = 0x1000
class SIMDNotReadArm(regress.RegressTest):
def runTest(self):
code = ENABLE_VFP_CODE+VLD_CODE+VST_CODE
print("Emulate THUMB code")
try:
# Initialize emulator in thumb mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
regress.logger.debug("Emulate THUMB code")
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# Initialize emulator in thumb mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, code)
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# map 10K scratch memory for this emulation
mu.mem_map(SCRATCH_ADDRESS, 10 * 1024)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, code)
# write dummy data to be emulated to memory
mu.mem_write(SCRATCH_ADDRESS, "\x01"*64)
# map 10K scratch memory for this emulation
mu.mem_map(SCRATCH_ADDRESS, 10 * 1024)
# initialize machine registers
for i in range(UC_ARM_REG_R0, UC_ARM_REG_R12):
val = mu.reg_write(i, i - UC_ARM_REG_R0)
# write dummy data to be emulated to memory
mu.mem_write(SCRATCH_ADDRESS, b"\x01" * 64)
mu.reg_write(UC_ARM_REG_R1, SCRATCH_ADDRESS)
mu.reg_write(UC_ARM_REG_R0, SCRATCH_ADDRESS + 0x100)
# initialize machine registers
for i in range(UC_ARM_REG_R0, UC_ARM_REG_R12):
mu.reg_write(i, i - UC_ARM_REG_R0)
mu.reg_write(UC_ARM_REG_SP, 0x1234)
mu.reg_write(UC_ARM_REG_D6, UC_ARM_REG_D6)
mu.reg_write(UC_ARM_REG_D7, UC_ARM_REG_D7)
mu.reg_write(UC_ARM_REG_R1, SCRATCH_ADDRESS)
mu.reg_write(UC_ARM_REG_R0, SCRATCH_ADDRESS + 0x100)
print(">>> Before emulation ")
print("\tD6 = 0x%x" % mu.reg_read(UC_ARM_REG_D6))
print("\tD7 = 0x%x" % mu.reg_read(UC_ARM_REG_D7))
for i in range(UC_ARM_REG_R0, UC_ARM_REG_R12):
val = mu.reg_read(i)
print("\t %s = 0x%x" % ("R" + str(i-UC_ARM_REG_R0),val))
mu.reg_write(UC_ARM_REG_SP, 0x1234)
mu.reg_write(UC_ARM_REG_D6, UC_ARM_REG_D6)
mu.reg_write(UC_ARM_REG_D7, UC_ARM_REG_D7)
self.assertEqual(UC_ARM_REG_D6, mu.reg_read(UC_ARM_REG_D6))
self.assertEqual(UC_ARM_REG_D7, mu.reg_read(UC_ARM_REG_D7))
regress.logger.debug(">>> Before emulation")
regress.logger.debug("\tD6 = %#x", mu.reg_read(UC_ARM_REG_D6))
regress.logger.debug("\tD7 = %#x", mu.reg_read(UC_ARM_REG_D7))
try:
content = mu.mem_read(SCRATCH_ADDRESS, 100)
print("Memory at addr 0x%X %s" % (SCRATCH_ADDRESS, binascii.hexlify(content)))
content = mu.mem_read(SCRATCH_ADDRESS+0x100, 100)
print("Memory at addr 0x%X %s" % (SCRATCH_ADDRESS+0x100, binascii.hexlify(content)))
except Exception, errtxt:
print (errtxt)
for i in range(UC_ARM_REG_R0, UC_ARM_REG_R12):
regress.logger.debug("\tR%d = %#x", (i - UC_ARM_REG_R0), mu.reg_read(i))
addr = SCRATCH_ADDRESS
data = mu.mem_read(addr, 100)
regress.logger.debug("Memory at addr %#x: %s", addr, binascii.hexlify(data))
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + len(code))
addr = SCRATCH_ADDRESS + 0x100
data = mu.mem_read(addr, 100)
regress.logger.debug("Memory at addr %#x: %s", addr, binascii.hexlify(data))
# now print out some registers
print(">>> Emulation done. Below is the CPU context")
self.assertEqual(UC_ARM_REG_D6, mu.reg_read(UC_ARM_REG_D6))
self.assertEqual(UC_ARM_REG_D7, mu.reg_read(UC_ARM_REG_D7))
sp = mu.reg_read(UC_ARM_REG_SP)
print(">>> SP = 0x%x" %sp)
val = mu.reg_read(UC_ARM_REG_PC)
print(">>> PC = 0x%x" %val)
for i in range(UC_ARM_REG_R0, UC_ARM_REG_R12):
val = mu.reg_read(i)
print(">>> %s = 0x%x" % ("R" + str(i-UC_ARM_REG_R0),val))
# emulate machine code in infinite time
mu.emu_start(ADDRESS | 0b1, ADDRESS + len(code))
print("\tD6 = 0x%x" % mu.reg_read(UC_ARM_REG_D6))
print("\tD7 = 0x%x" % mu.reg_read(UC_ARM_REG_D7))
# now print out some registers
regress.logger.debug(">>> After emulation")
regress.logger.debug(">>> SP = %#x", mu.reg_read(UC_ARM_REG_SP))
regress.logger.debug(">>> PC = %#x", mu.reg_read(UC_ARM_REG_PC))
try:
content = mu.mem_read(SCRATCH_ADDRESS, 100)
print("Memory at addr 0x%X %s" % (SCRATCH_ADDRESS, binascii.hexlify(content)))
content = mu.mem_read(SCRATCH_ADDRESS+0x100, 100)
print("Memory at addr 0x%X %s" % (SCRATCH_ADDRESS+0x100, binascii.hexlify(content)))
except Exception, errtxt:
print (errtxt)
for i in range(UC_ARM_REG_R0, UC_ARM_REG_R12):
regress.logger.debug("\tR%d = %#x", (i-UC_ARM_REG_R0), mu.reg_read(i))
self.assertEqual(mu.reg_read(UC_ARM_REG_D6), 0x0101010101010101)
self.assertEqual(mu.reg_read(UC_ARM_REG_D7), 0x0101010101010101)
regress.logger.debug("\tD6 = %#x", mu.reg_read(UC_ARM_REG_D6))
regress.logger.debug("\tD7 = %#x", mu.reg_read(UC_ARM_REG_D7))
addr = SCRATCH_ADDRESS
data = mu.mem_read(addr, 100)
regress.logger.debug("Memory at addr %#x: %s", addr, binascii.hexlify(data))
addr = SCRATCH_ADDRESS + 0x100
data = mu.mem_read(addr, 100)
regress.logger.debug("Memory at addr %#x: %s", addr, binascii.hexlify(data))
self.assertEqual(mu.reg_read(UC_ARM_REG_D6), 0x0101010101010101)
self.assertEqual(mu.reg_read(UC_ARM_REG_D7), 0x0101010101010101)
except UcError as e:
print("ERROR: %s" % e)
if __name__ == '__main__':
regress.main()

View File

@ -1,12 +1,12 @@
#!/usr/bin/env python
from __future__ import print_function
from unicorn import *
from unicorn.x86_const import *
import regress
X86_CODE64 = "\x90" # NOP
from unicorn import *
from unicorn.x86_const import *
X86_CODE64 = b"\x90" # NOP
class WriteBeforeMap(regress.RegressTest):
@ -18,7 +18,10 @@ class WriteBeforeMap(regress.RegressTest):
ADDRESS = 0x1000000
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, X86_CODE64)
with self.assertRaises(UcError) as raisedEx:
mu.mem_write(ADDRESS, X86_CODE64)
self.assertEqual(UC_ERR_WRITE_UNMAPPED, raisedEx.exception.errno)
if __name__ == '__main__':

View File

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

View File

@ -1,21 +1,26 @@
#!/usr/bin/python
import regress
import unicorn as U
from unicorn import *
from unicorn.x86_const import *
class WrongConditionalPath(regress.RegressTest):
def test_eflags(self):
# 0: 4d 31 f6 xor r14, r14
# 3: 45 85 f6 test r14d, r14d
# 6: 75 fe jne 0x6
# 8: f4 hlt
CODE = 'M1\xf6E\x85\xf6u\xfe\xf4'
code = (
b'\x4d\x31\xf6' # xor r14, r14
b'\x45\x85\xf6' # test r14d, r14d
b'\x75\xfe' # jne 0x6
b'\xf4' # hlt
)
uc = U.Uc(U.UC_ARCH_X86, U.UC_MODE_64)
uc.reg_write(U.x86_const.UC_X86_REG_RIP, 0x6000b0)
uc.reg_write(U.x86_const.UC_X86_REG_EFLAGS, 0x246)
uc = Uc(UC_ARCH_X86, UC_MODE_64)
uc.reg_write(UC_X86_REG_RIP, 0x6000b0)
uc.reg_write(UC_X86_REG_EFLAGS, 0x246)
uc.mem_map(0x600000, 0x1000)
uc.mem_write(0x6000b0, CODE)
uc.mem_write(0x6000b0, code)
uc.emu_start(0x6000b0 + 6, 0, count=1)
@ -33,7 +38,8 @@ class WrongConditionalPath(regress.RegressTest):
# RIP=00000000006000b6 RFL=00000246 [---Z-P-] CPL=3 II=0 A20=1 SMM=0 HLT=0
# 0x00000000006000b8: hlt
# RIP=00000000006000b8 RFL=00000246 [---Z-P-] CPL=3 II=0 A20=1 SMM=0 HLT=0
self.assertEqual(0x6000b0 + 8, uc.reg_read(U.x86_const.UC_X86_REG_RIP))
self.assertEqual(0x6000b0 + 8, uc.reg_read(UC_X86_REG_RIP))
if __name__ == '__main__':
regress.main()

View File

@ -1,15 +1,19 @@
#!/usr/bin/python
import regress
import unicorn as U
from unicorn import *
from unicorn.x86_const import *
class WrongEFLAGS(regress.RegressTest):
def test_eflags(self):
# xor r14,r14
CODE = 'M1\xf6'
CODE = b'M1\xf6'
uc = U.Uc(U.UC_ARCH_X86, U.UC_MODE_64)
uc.reg_write(U.x86_const.UC_X86_REG_RIP, 0x6000b0)
uc.reg_write(U.x86_const.UC_X86_REG_EFLAGS, 0x200)
uc = Uc(UC_ARCH_X86, UC_MODE_64)
uc.reg_write(UC_X86_REG_RIP, 0x6000b0)
uc.reg_write(UC_X86_REG_EFLAGS, 0x200)
uc.mem_map(0x600000, 0x1000)
uc.mem_write(0x6000b0, CODE)
@ -31,8 +35,9 @@ class WrongEFLAGS(regress.RegressTest):
# (gdb) p $eflags
# $4 = [ PF ZF IF ]
self.assertEqual(0x6000b3, uc.reg_read(U.x86_const.UC_X86_REG_RIP))
self.assertEqual(0x246, uc.reg_read(U.x86_const.UC_X86_REG_EFLAGS))
self.assertEqual(0x6000b3, uc.reg_read(UC_X86_REG_RIP))
self.assertEqual(0x246, uc.reg_read(UC_X86_REG_EFLAGS))
if __name__ == '__main__':
regress.main()

View File

@ -1,10 +1,10 @@
#!/usr/bin/env python
from unicorn import *
from unicorn.x86_const import *
from struct import pack
import regress
from unicorn import *
from unicorn.x86_const import *
CODE_ADDR = 0x40000
CODE_SIZE = 0x1000
@ -32,7 +32,7 @@ def set_msr(uc, msr, value, scratch=SCRATCH_ADDR):
orip = uc.reg_read(UC_X86_REG_RIP)
# x86: wrmsr
buf = '\x0f\x30'
buf = b'\x0f\x30'
uc.mem_write(scratch, buf)
uc.reg_write(UC_X86_REG_RAX, value & 0xFFFFFFFF)
uc.reg_write(UC_X86_REG_RDX, (value >> 32) & 0xFFFFFFFF)
@ -58,7 +58,7 @@ def get_msr(uc, msr, scratch=SCRATCH_ADDR):
orip = uc.reg_read(UC_X86_REG_RIP)
# x86: rdmsr
buf = '\x0f\x32'
buf = b'\x0f\x32'
uc.mem_write(scratch, buf)
uc.reg_write(UC_X86_REG_RCX, msr & 0xFFFFFFFF)
uc.emu_start(scratch, scratch+len(buf), count=1)
@ -122,9 +122,9 @@ class TestGetSetMSR(regress.RegressTest):
uc.mem_map(CODE_ADDR, CODE_SIZE)
uc.mem_map(SCRATCH_ADDR, SCRATCH_SIZE)
code = '6548330C2518000000'.decode('hex') # x86-64: xor rcx, qword ptr gs:[0x18]
code = b'\x65\x48\x33\x0C\x25\x18\x00\x00\x00' # xor rcx, qword ptr gs:[0x18]
uc.mem_write(CODE_ADDR, code)
uc.mem_write(SEGMENT_ADDR+0x18, 'AAAAAAAA')
uc.mem_write(SEGMENT_ADDR+0x18, b'AAAAAAAA')
set_gs(uc, SEGMENT_ADDR)
self.assertEqual(SEGMENT_ADDR, get_gs(uc))
@ -140,9 +140,9 @@ class TestGetSetMSR(regress.RegressTest):
uc.mem_map(CODE_ADDR, CODE_SIZE)
uc.mem_map(SCRATCH_ADDR, SCRATCH_SIZE)
code = '6448330C2518000000'.decode('hex') # x86-64: xor rcx, qword ptr fs:[0x18]
code = b'\x64\x48\x33\x0C\x25\x18\x00\x00\x00' # xor rcx, qword ptr fs:[0x18]
uc.mem_write(CODE_ADDR, code)
uc.mem_write(SEGMENT_ADDR+0x18, 'AAAAAAAA')
uc.mem_write(SEGMENT_ADDR+0x18, b'AAAAAAAA')
set_fs(uc, SEGMENT_ADDR)
self.assertEqual(SEGMENT_ADDR, get_fs(uc))
@ -151,5 +151,6 @@ class TestGetSetMSR(regress.RegressTest):
self.assertEqual(uc.reg_read(UC_X86_REG_RCX), 0x4141414141414141)
if __name__ == '__main__':
regress.main()

View File

@ -1,16 +1,21 @@
#!/usr/bin/python
import regress
import unicorn as U
from unicorn import *
from unicorn.x86_const import *
class WrongEFLAGS2(regress.RegressTest):
def test_eflags(self):
# imul eax, ebx
CODE = '\x0f\xaf\xc3'
CODE = b'\x0f\xaf\xc3'
uc = U.Uc(U.UC_ARCH_X86, U.UC_MODE_32)
uc.reg_write(U.x86_const.UC_X86_REG_EAX, 16)
uc.reg_write(U.x86_const.UC_X86_REG_EBX, 1)
uc.reg_write(U.x86_const.UC_X86_REG_EFLAGS, 0x292)
uc = Uc(UC_ARCH_X86, UC_MODE_32)
uc.reg_write(UC_X86_REG_EAX, 16)
uc.reg_write(UC_X86_REG_EBX, 1)
uc.reg_write(UC_X86_REG_EFLAGS, 0x292)
uc.mem_map(0x600000, 0x1000)
uc.mem_write(0x6000b0, CODE)
@ -32,7 +37,7 @@ class WrongEFLAGS2(regress.RegressTest):
# (gdb) p/x $eflags
# $4 = 0x202
self.assertEqual(0x202, uc.reg_read(U.x86_const.UC_X86_REG_EFLAGS))
self.assertEqual(0x202, uc.reg_read(UC_X86_REG_EFLAGS))
if __name__ == '__main__':
regress.main()

View File

@ -1,31 +1,34 @@
#!/usr/bin/env python
from unicorn import *
from unicorn.x86_const import *
from struct import pack
import regress
CODE_ADDR = 0x1000000
from unicorn import *
from unicorn.x86_const import *
CODE = (
'\xb8\x00\x00\x00\x02' # mov eax, 0x2000000
'\xdb\x28' # fldt [eax]
'\xd9\xfa' # fsqrt
b'\xb8\x00\x00\x00\x02' # mov eax, 0x2000000
b'\xdb\x28' # fldt [eax]
b'\xd9\xfa' # fsqrt
)
BASE = 0x1000000
DATA_ADDR = 0x2000000
DATA = '\0\0\0\0\0\0\0\0\0\1'
DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'
class FldtFsqrt(regress.RegressTest):
def test_fldt_fsqrt(self):
uc = Uc(UC_ARCH_X86, UC_MODE_32)
uc.mem_map(CODE_ADDR, 0x1000)
uc.mem_write(CODE_ADDR, CODE)
uc.mem_map(BASE, 0x1000)
uc.mem_write(BASE, CODE)
uc.mem_map(DATA_ADDR, 0x1000)
uc.mem_write(DATA_ADDR, DATA)
uc.emu_start(CODE_ADDR, CODE_ADDR + len(CODE), 10000, 10)
uc.emu_start(BASE, BASE + len(CODE), 10000, 10)
if __name__ == '__main__':
regress.main()

View File

@ -1,25 +1,27 @@
#!/usr/bin/env python
import regress
from unicorn import *
from unicorn.x86_const import *
from struct import pack
import regress
F_GRANULARITY = 0x8
F_PROT_32 = 0x4
F_LONG = 0x2
F_AVAILABLE = 0x1
F_GRANULARITY = 0x8
F_PROT_32 = 0x4
F_LONG = 0x2
F_AVAILABLE = 0x1
A_PRESENT = 0x80
A_PRIV_3 = 0x60
A_PRIV_2 = 0x40
A_PRIV_1 = 0x20
A_PRIV_0 = 0x0
A_PRIV_0 = 0x00
A_CODE = 0x10
A_DATA = 0x10
A_TSS = 0x0
A_TSS = 0x0
A_GATE = 0x0
A_DATA_WRITABLE = 0x2
@ -34,27 +36,32 @@ S_PRIV_2 = 0x2
S_PRIV_1 = 0x1
S_PRIV_0 = 0x0
CODE = '65330d18000000'.decode('hex') # xor ecx, dword ptr gs:[0x18]
CODE = b'\x65\x33\x0d\x18\x00\x00\x00' # xor ecx, dword ptr gs:[0x18]
def create_selector(idx, flags):
to_ret = flags
to_ret |= idx << 3
return to_ret
def create_gdt_entry(base, limit, access, flags):
to_ret = limit & 0xffff;
to_ret |= (base & 0xffffff) << 16;
to_ret |= (access & 0xff) << 40;
to_ret |= ((limit >> 16) & 0xf) << 48;
to_ret |= (flags & 0xff) << 52;
to_ret |= ((base >> 24) & 0xff) << 56;
return pack('<Q',to_ret)
def create_gdt_entry(base, limit, access, flags):
return pack('<Q', (
limit & 0xffff
| (base & 0xffffff) << 16
| (access & 0xff) << 40
| ((limit >> 16) & 0xf) << 48
| (flags & 0xff) << 52
| ((base >> 24) & 0xff) << 56
))
def hook_mem_read(uc, type, addr,*args):
print(hex(addr))
regress.logger.debug("%#x", addr)
return False
CODE_ADDR = 0x40000
CODE_SIZE = 0x1000
@ -76,7 +83,7 @@ class GdtRead(regress.RegressTest):
uc.mem_map(CODE_ADDR, CODE_SIZE)
uc.mem_write(CODE_ADDR, CODE)
uc.mem_write(SEGMENT_ADDR+0x18, 'AAAA')
uc.mem_write(SEGMENT_ADDR + 0x18, b'AAAA')
gdt_entry = create_gdt_entry(SEGMENT_ADDR, SEGMENT_SIZE, A_PRESENT | A_DATA | A_DATA_WRITABLE | A_PRIV_3 | A_DIR_CON_BIT, F_PROT_32)
uc.mem_write(GDT_ADDR + 8, gdt_entry)
@ -90,5 +97,6 @@ class GdtRead(regress.RegressTest):
self.assertEqual(uc.reg_read(UC_X86_REG_ECX), 0x41414141)
if __name__ == '__main__':
regress.main()

File diff suppressed because one or more lines are too long

View File

@ -1,18 +1,19 @@
#!/usr/bin/env python
from unicorn import *
from unicorn.x86_const import *
from struct import pack
import os
import regress
from unicorn import *
from unicorn.x86_const import *
# The file we're loading is a full assembled ELF.
# Source for it, along with assembly instructions, are in x86_self_modifying.s
filename = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'x86_self_modifying.elf')
CODE_ADDR = 0x08048000
STACK_ADDR = 0x2000000
CODE = open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'x86_self_modifying.elf')).read()
CODE_SIZE = len(CODE) + (0x1000 - len(CODE)%0x1000)
CODE = open(filename, 'rb').read()
CODE_SIZE = len(CODE) + (0x1000 - len(CODE) % 0x1000)
STACK_SIZE = 0x8000
ENTRY_POINT = 0x8048074
@ -20,6 +21,7 @@ ENTRY_POINT = 0x8048074
def hook_intr(uc, intno, data):
uc.emu_stop()
class SelfModifying(regress.RegressTest):
def test_self_modifying(self):
uc = Uc(UC_ARCH_X86, UC_MODE_32)
@ -36,5 +38,6 @@ class SelfModifying(regress.RegressTest):
retcode = uc.reg_read(UC_X86_REG_EBX)
self.assertEqual(retcode, 65)
if __name__ == '__main__':
regress.main()

View File

@ -1,21 +1,38 @@
import regress
from unicorn import *
from unicorn.x86_const import *
count = 0
def cb(uc, addr, sz, data):
global count
count += 1
print(f"addr: {hex(addr)} count: {count}")
if count == 5:
uc.emu_stop()
else:
uc.reg_write(UC_X86_REG_RIP, 0x2000)
NOPSLED = b"\x90" * 5
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0x1000, 0x4000)
mu.mem_write(0x1000, b"\x90" * 5)
mu.mem_write(0x2000, b"\x90" * 5)
mu.hook_add(UC_HOOK_CODE, cb)
mu.emu_start(0x1000, 0x2000+1, 0, 0)
class TestSetIP(regress.RegressTest):
def runTest(self):
# execution history
history = []
def __code_hook(uc, addr, size, ud):
# track execution history
history.append(addr)
if len(history) == 5:
uc.emu_stop()
else:
uc.reg_write(UC_X86_REG_RIP, 0x1800)
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0x1000, 0x1000)
mu.mem_write(0x1000, NOPSLED)
mu.mem_write(0x1800, NOPSLED)
mu.hook_add(UC_HOOK_CODE, __code_hook)
mu.emu_start(0x1000, 0x1800 + 1)
self.assertListEqual([0x1000] + [0x1800] * 4, history)
if __name__ == '__main__':
regress.main()