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:
parent
1742486319
commit
429dbf3012
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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__':
|
||||
|
@ -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
177
tests/regress/core_ctl.py
Normal 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()
|
@ -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__':
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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
66
tests/regress/high_mem.py
Normal 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()
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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__':
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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__':
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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__':
|
||||
|
@ -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()
|
||||
|
@ -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))
|
||||
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
|
||||
|
||||
|
@ -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__':
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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__':
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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
@ -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()
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user