好友
阅读权限10
听众
最后登录1970-1-1
|
我已经蓝屏
发表于 2021-7-21 14:03
本帖最后由 我已经蓝屏 于 2021-7-21 14:07 编辑
前言
本文就是写写Unicorn咋用的
不涉及原理层面
地址
官方网站
https://www.unicorn-engine.org/
Github
https://github.com/unicorn-engine/unicorn
我的博客(欢迎来踩)
https://kdajv.com/2021/07/21/capstoneengine/
介绍
Unicorn是一个轻量级的多平台多架构CPU仿真器
高亮特点:
- 多架构支持: Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (包括X86_64).
- 干净/简单/轻量级/直观的API,同时不依赖任何架构。
- 以C/C++实现,可在众多语言里使用:Pharo, Crystal, Clojure, Visual Basic, Perl, Rust, Haskell, Ruby, Python, Java, Go, .NET, Delphi/Pascal & MSVC。
- 原生支持Windows和*nix系统(以下系统已确认支持:Mac OSX, Linux, *BSD & Solaris)。
- 通过使用即时编译器技术以实现高性能。
- 支持各种级别的细粒度检测。
- 线程安全的设计。
- 允许在开源软件许可 GPLv2 下分发。
使用
from unicorn import *
# 要执行的字节码
# 可以使用Keystone引擎生成
binary = b'1\xc0Ph//shh/bin\x89\xe3PS\x89\xe1\xb0\x0b'
# 规定内存地址
ADDRESS = 0x400000
print("开始模拟-X86")
# 初始化仿真器,模式为X86-32
mu = Uc(UC_ARCH_X86, UC_MODE_32)
# 给仿真器映射2MB内存
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# 将指令写到内存
mu.mem_write(ADDRESS, binary)
# 初始化仿真器的寄存器,并赋值
# ESP给了内存的最后一个位置
mu.reg_write(x86_const.UC_X86_REG_EAX, 0x1000)
mu.reg_write(x86_const.UC_X86_REG_ESP, ADDRESS + 2 * 1024 * 1024 - 1)
# 这里创建一个钩子,每执行一条指令会先执行一次这里,如果有不想执行的语句可以跳过
# 跳过方法:EIP+size
def hook(emu: Uc, addr, size, userdata):
# 反汇编当前语句的语义,详情请看Capstone篇
from capstone import Cs, CS_ARCH_X86, CS_MODE_32
CS = Cs(CS_ARCH_X86, CS_MODE_32)
instruction = list(CS.disasm(emu.mem_read(addr, size), 0))[0]
print(f"当前位置:{hex(addr)},指令长度:{size},指令:{instruction.mnemonic} {instruction.op_str}")
userdata.Count += 1
# 这里可以传给钩子一个变量(注意不能是初始类型,否则就只传值而不是引用了),执行结束的时候可以读取到钩子里处理的数据
class InstCount:
Count = 0
count = InstCount()
# 添加钩子,钩子类型为CODE,再传一个用户数据,别的暂时还不知道
mu.hook_add(UC_HOOK_CODE, hook, count)
# 开始仿真
mu.emu_start(ADDRESS, ADDRESS + len(binary))
# 仿真结束
print("仿真结束")
print(f"共执行{count.Count}条指令")
# 读寄存器
r_eax = mu.reg_read(x86_const.UC_X86_REG_EAX)
r_ebx = mu.reg_read(x86_const.UC_X86_REG_EBX)
r_ecx = mu.reg_read(x86_const.UC_X86_REG_ECX)
r_esp = mu.reg_read(x86_const.UC_X86_REG_ESP)
print(">>> EAX = 0x%x" % r_eax)
print(">>> EBX = 0x%x" % r_ebx)
print(">>> ECX = 0x%x" % r_ecx)
print(">>> ESP = 0x%x" % r_esp)
# 读栈内容
now = r_esp
while now != ADDRESS + 2 * 1024 * 1024 - 1:
buf = mu.mem_read(now, 4)
print(f"Stack > ESP - {hex(now)} - {buf}")
now += 4
Output
开始模拟-X86
当前位置:0x400000,指令长度:2,指令:xor eax, eax
当前位置:0x400002,指令长度:1,指令:push eax
当前位置:0x400003,指令长度:5,指令:push 0x68732f2f
当前位置:0x400008,指令长度:5,指令:push 0x6e69622f
当前位置:0x40000d,指令长度:2,指令:mov ebx, esp
当前位置:0x40000f,指令长度:1,指令:push eax
当前位置:0x400010,指令长度:1,指令:push ebx
当前位置:0x400011,指令长度:2,指令:mov ecx, esp
当前位置:0x400013,指令长度:2,指令:mov al, 0xb
仿真结束
共执行9条指令
>>> EAX = 0xb
>>> EBX = 0x5ffff3
>>> ECX = 0x5fffeb
>>> ESP = 0x5fffeb
Stack > ESP - 0x5fffeb - bytearray(b'\xf3\xff_\x00')
Stack > ESP - 0x5fffef - bytearray(b'\x00\x00\x00\x00')
Stack > ESP - 0x5ffff3 - bytearray(b'/bin')
Stack > ESP - 0x5ffff7 - bytearray(b'//sh')
Stack > ESP - 0x5ffffb - bytearray(b'\x00\x00\x00\x00')
|
|