122 lines
3.3 KiB
Python
122 lines
3.3 KiB
Python
# Unicorn Emulator Engine
|
|
# By Lazymio(@wtdcode), 2021
|
|
|
|
from unicorn import *
|
|
from unicorn.unicorn import UC_HOOK_EDGE_GEN_CB
|
|
from unicorn.x86_const import *
|
|
from datetime import datetime
|
|
|
|
def test_uc_ctl_read():
|
|
uc = Uc(UC_ARCH_X86, UC_MODE_32)
|
|
|
|
print("Reading some properties by uc_ctl.")
|
|
|
|
arch = uc.ctl_get_arch()
|
|
|
|
mode = uc.ctl_get_mode()
|
|
|
|
page_size = uc.ctl_get_page_size()
|
|
|
|
timeout = uc.ctl_get_timeout()
|
|
|
|
print(f">>> arch={arch} mode={mode} page size={page_size} timeout={timeout}")
|
|
|
|
def time_emulation(uc, start, end):
|
|
n = datetime.now()
|
|
|
|
uc.emu_start(start, end)
|
|
|
|
return (datetime.now() - n).total_seconds() * 1e6
|
|
|
|
def test_uc_ctl_tb_cache():
|
|
# Initialize emulator in X86-32bit mode
|
|
uc = Uc(UC_ARCH_X86, UC_MODE_32)
|
|
addr = 0x10000
|
|
|
|
# Fill the code buffer with NOP.
|
|
code = b"\x90" * 8 * 512
|
|
|
|
print("Controling the TB cache in a finer granularity by uc_ctl.")
|
|
|
|
uc.mem_map(addr, 0x10000)
|
|
|
|
# Write our code to the memory.
|
|
uc.mem_write(addr, code)
|
|
|
|
# Do emulation without any cache.
|
|
standard = time_emulation(uc, addr, addr + len(code))
|
|
|
|
# Now we request cache for all TBs.
|
|
for i in range(8):
|
|
tb = uc.ctl_request_cache(addr + i * 512)
|
|
print(f">>> TB is cached at {hex(tb.pc)} which has {tb.icount} instructions with {tb.size} bytes")
|
|
|
|
# Do emulation with all TB cached.
|
|
cached = time_emulation(uc, addr, addr + len(code))
|
|
|
|
# Now we clear cache for all TBs.
|
|
for i in range(8):
|
|
uc.ctl_remove_cache(addr + i * 512)
|
|
|
|
evicted = time_emulation(uc, addr, addr + len(code))
|
|
|
|
print(f">>> Run time: First time {standard}, Cached: {cached}, Cached evicted: {evicted}")
|
|
|
|
def trace_new_edge(uc, cur, prev, data):
|
|
print(f">>> Getting a new edge from {hex(prev.pc + prev.size - 1)} to {hex(cur.pc)}")
|
|
|
|
def trace_tcg_sub(uc, address, arg1, arg2, data):
|
|
print(f">>> Get a tcg sub opcode at {hex(address)} with args: {arg1} and {arg2}")
|
|
|
|
def test_uc_ctl_exits():
|
|
uc = Uc(UC_ARCH_X86, UC_MODE_32)
|
|
addr = 0x1000
|
|
# cmp eax, 0;
|
|
# jg lb;
|
|
# inc eax;
|
|
# nop;
|
|
# lb:
|
|
# inc ebx;
|
|
# nop;
|
|
code = b"\x83\xf8\x00\x7f\x02\x40\x90\x43\x90"
|
|
exits = [addr + 6, addr + 8]
|
|
|
|
print("Using multiple exits by uc_ctl")
|
|
|
|
uc.mem_map(addr, 0x1000)
|
|
|
|
# Write our code to the memory.
|
|
uc.mem_write(addr, code)
|
|
|
|
# We trace if any new edge is generated.
|
|
uc.hook_add(UC_HOOK_EDGE_GENERATED, trace_new_edge)
|
|
|
|
# Trace cmp instruction.
|
|
uc.hook_add(UC_HOOK_TCG_OPCODE, trace_tcg_sub, UC_TCG_OP_SUB, UC_TCG_OP_FLAG_CMP)
|
|
|
|
uc.ctl_exits_enabled(True)
|
|
|
|
uc.ctl_set_exits(exits)
|
|
|
|
# This should stop at ADDRESS + 6 and increase eax, even thouhg we don't provide an exit.
|
|
uc.emu_start(addr, 0)
|
|
|
|
eax = uc.reg_read(UC_X86_REG_EAX)
|
|
ebx = uc.reg_read(UC_X86_REG_EBX)
|
|
|
|
print(f">>> eax = {hex(eax)} and ebx = {hex(ebx)} after the first emulation")
|
|
|
|
# This should stop at ADDRESS + 8, even thouhg we don't provide an exit.
|
|
uc.emu_start(addr, 0)
|
|
|
|
eax = uc.reg_read(UC_X86_REG_EAX)
|
|
ebx = uc.reg_read(UC_X86_REG_EBX)
|
|
|
|
print(f">>> eax = {hex(eax)} and ebx = {hex(ebx)} after the first emulation")
|
|
|
|
if __name__ == "__main__":
|
|
test_uc_ctl_read()
|
|
print("="*32)
|
|
test_uc_ctl_tb_cache()
|
|
print("="*32)
|
|
test_uc_ctl_exits() |