前言

unicorn 是一个模拟执行软件,用于模拟执行各种平台的二进制文件,前几天在  twitter 上看到一篇文章,这里做个记录。

正文

记录系统调用

首先是一个简单的示例

e8ffffffffc05d6a055b29dd83c54e89e96a02030c245b31d266ba12008b39c1e710c1ef1081e9feffffff8b4500c1e010c1e81089c309fb21f8f7d021d86689450083c5024a85d20f85cfffffffec37755d7a0528ed24ed24ed0b887feb509838f95c962b9670fec6ffc6ff9f321f581e00d380

这是一段 x86_32 的  shellcode,可以用 radare2 反汇编它

rasm2 -a x86 -b 32 -d e8ffffffffc05d6a055b29dd83c54e89e96a02030c245b31d266ba12008b39c1e710c1ef1081e9feffffff8b4500c1e010c1e81089c309fb21f8f7d021d86689450083c5024a85d20f85cfffffffec37755d7a0528ed24ed24ed0b887feb509838f95c962b9670fec6ffc6ff9f321f581e00d380

这里的目标是记录他的系统调用,在 32 中使用 int 80 来执行系统调用,所以我们在 执行 int 80  前 记录它的 寄存器信息,就可以记录系统调用了。


from unicorn import *
from unicorn.x86_const import * shellcode = "e8ffffffffc05d6a055b29dd83c54e89e96a02030c245b31d266ba12008b39c1e710c1ef1081e9feffffff8b4500c1e010c1e81089c309fb21f8f7d021d86689450083c5024a85d20f85cfffffffec37755d7a0528ed24ed24ed0b887feb509838f95c962b9670fec6ffc6ff9f321f581e00d380".decode("hex") BASE = 0x400000
STACK_ADDR = 0x0
STACK_SIZE = 1024*1024 mu = Uc (UC_ARCH_X86, UC_MODE_32) mu.mem_map(BASE, 1024*1024)
mu.mem_map(STACK_ADDR, STACK_SIZE) mu.mem_write(BASE, shellcode)
mu.reg_write(UC_X86_REG_ESP, STACK_ADDR + STACK_SIZE/2) def syscall_num_to_name(num):
syscalls = {1: "sys_exit", 15: "sys_chmod"}
return syscalls[num] def hook_code(mu, address, size, user_data):
#print('>>> Tracing instruction at 0x%x, instruction size = 0x%x' %(address, size)) machine_code = mu.mem_read(address, size)
if machine_code == "\xcd\x80": r_eax = mu.reg_read(UC_X86_REG_EAX)
r_ebx = mu.reg_read(UC_X86_REG_EBX)
r_ecx = mu.reg_read(UC_X86_REG_ECX)
r_edx = mu.reg_read(UC_X86_REG_EDX)
syscall_name = syscall_num_to_name(r_eax) print "--------------"
print "We intercepted system call: "+syscall_name if syscall_name == "sys_chmod":
s = mu.mem_read(r_ebx, 20).split("\x00")[0]
print "arg0 = 0x%x -> %s" % (r_ebx, s)
print "arg1 = " + oct(r_ecx)
elif syscall_name == "sys_exit":
print "arg0 = " + hex(r_ebx)
exit() mu.reg_write(UC_X86_REG_EIP, address + size) mu.hook_add(UC_HOOK_CODE, hook_code) mu.emu_start(BASE, BASE-1)

关键就是使用 mu.hook_add, 使得在 unicorn 执行一条指令之前会先执行 hook_code 并且传入了与程序运行状态相关的参数,便于我们对程序状态进行操纵。在这里就是获取了 寄存器的值,然后根据系统调用号解析参数。

ARM代码模拟执行

测试程序位于

http://t.cn/RQ6viS6

其实就是执行一个递归函数,最后打印返回值

我们的目标是加速程序的执行,可以加速的原理在于,这里是递归调用,对于的参数,返回值确定,所以我们就可以对已经执行过的参数,直接设置返回值,进而加速程序的运行。

from unicorn import *
from unicorn.arm_const import *
import struct def read(name):
with open(name) as f:
return f.read() def u32(data):
return struct.unpack("I", data)[0] def p32(num):
return struct.pack("I", num) mu = Uc(UC_ARCH_ARM, UC_MODE_LITTLE_ENDIAN) BASE = 0x10000
STACK_ADDR =
STACK_SIZE = 1024*10240x300000 mu.mem_map(BASE, 1024*1024)
mu.mem_map(STACK_ADDR, STACK_SIZE) mu.mem_write(BASE, read("./task4"))
mu.reg_write(UC_ARM_REG_SP, STACK_ADDR + STACK_SIZE/2) instructions_skip_list = [] CCC_ENTRY = 0x000104D0
CCC_END = 0x00010580 stack = [] # Stack for storing the arguments
d = {} # Dictionary that holds return values for given function arguments def hook_code(mu, address, size, user_data):
#print('>>> Tracing instruction at 0x%x, instruction size = 0x%x' %(address, size))
if address == CCC_ENTRY: # Are we at the beginning of ccc function?
arg0 = mu.reg_read(UC_ARM_REG_R0) # Read the first argument. it is passed by R0 if arg0 in d: # Check whether return value for this function is already saved.
ret = d[arg0]
mu.reg_write(UC_ARM_REG_R0, ret) # Set return value in R0
mu.reg_write(UC_ARM_REG_PC, 0x105BC) # Set PC to point at "BX LR" instruction. We want to return from fibonacci function else:
stack.append(arg0) # If return value is not saved for this argument, add it to stack. elif address == CCC_END:
arg0 = stack.pop() # We know arguments when exiting the function ret = mu.reg_read(UC_ARM_REG_R0) # Read the return value (R0)
d[arg0] = ret # Remember the return value for this argument mu.hook_add(UC_HOOK_CODE, hook_code)
mu.emu_start(0x00010584, 0x000105A8)
return_value = mu.reg_read(UC_ARM_REG_R1) # We end the emulation at printf("%d\n", ccc(x)).
print "The return value is %d" % return_value

关键点,用一个数组存储了 参数:返回值 对, 从而规避一些冗余的运算。

参考

http://eternal.red/2018/unicorn-engine-tutorial/

unicorn模拟执行学习的更多相关文章

  1. 芝麻HTTP:JavaScript加密逻辑分析与Python模拟执行实现数据爬取

    本节来说明一下 JavaScript 加密逻辑分析并利用 Python 模拟执行 JavaScript 实现数据爬取的过程.在这里以中国空气质量在线监测分析平台为例来进行分析,主要分析其加密逻辑及破解 ...

  2. Spring练习,使用Properties类型注入方式,注入MySQL数据库连接的基本信息,然后使用JDBC方式连接数据库,模拟执行业务代码后释放资源,最后在控制台输出打印结果。

    相关 知识 >>> 相关 练习 >>> 实现要求: 使用Properties类型注入方式,注入MySQL数据库连接的基本信息,然后使用JDBC方式连接数据库,模拟执 ...

  3. PHP命令执行学习总结

    前言 最近学习了PHP命令执行,内容比较多,把自己学到的总结下来,加深理解,水平有限,欢迎大佬斧正. 什么是PHP命令注入攻击? Command Injection,即命令注入攻击,是指由于Web应用 ...

  4. DVWA-命令执行学习笔记

    DVWA-命令执行 原理: web服务器没有对用户提交的数据进行严格的过滤,造成调用操作系统的命令或者在操作系统恶意拼接拼接命令,以达到攻击者的目的. 1.将DVWA的级别设置为low 1.2查看源代 ...

  5. ImageMagick命令执行学习笔记(常见于图片预览处)

    实验版本: ImageMagick版本:6.9.2 push graphic-context viewbox 0 0 640 480 fill 'url(https://"|whoami&q ...

  6. <模拟电子学习1>Multisim 12.0 结构和仿真51最小的单芯片系统

    周围环境: 系统环境: win7 64位置 软件平台:Multisim 12.0 目的: 刚毕业,可是模电知识也忘得差点儿相同了,加之自己想搞搞硬件设计.假设仅仅是看模电书.不实践,还是终觉浅.当做兴 ...

  7. 洛谷 P1033 自由落体 Label:模拟&&非学习区警告

    题目描述 在高为 H 的天花板上有 n 个小球,体积不计,位置分别为 0,1,2,….n-1.在地面上有一个小车(长为 L,高为 K,距原点距离为 S1).已知小球下落距离计算公式为 d=1/2*g* ...

  8. 模拟电路学习之NMOS开关电路1

  9. 基于qemu和unicorn的Fuzz技术分析

    前言 本文主要介绍如果使用 qemu 和 unicorn 来搜集程序执行的覆盖率信息以及如何把搜集到的覆盖率信息反馈到 fuzzer 中辅助 fuzz 的进行. AFL Fork Server 为了后 ...

随机推荐

  1. easyUI的分页,只显示第X 共Y页。改为显示 第X 页 共Y页

    如下图,easyUI的分页,只显示第X 共Y页. 需求需要显示 第X 页 共Y页. 解决办法:在easyui-lang-zh_CN.js更改以下代码,即可.也就是在 “共{pages}页”前面加个 “ ...

  2. 如何在Mac OS中安装 wget

    首先从Apple Store下载Xcode,然后安装Xcode,接着安装Homebrew包管理,类似于Ubuntu下的apt-get: 终端下输入ruby -e "$(curl -fsSL ...

  3. 在Vue的webpack中结合runder函数

    在Vue的webpack中结合runder函数 1.引入: <h1>下面是vue的内容:</h1> <div id="app"> <log ...

  4. Springboot+ajax传输json数组以及单条数据的方法

    Springboot+ajax传输json数组以及单条数据的方法 下面是用ajax传输到后台单条以及多条数据的解析的Demo: 结构图如下: 下面是相关的代码: pom.xml: <?xml v ...

  5. php 实现繁体转简体代码效率对比

    第一份代码: <?php Header("Content-Type:text/html;charset=utf-8"); function microtime_float() ...

  6. Postman—测试脚本

    前言 对于Postman中的每个请求,我们都可以使用JavaScript语言来开发测试脚本.这也就好比单元测试.我们先看看Postman的相关界面: 编写测试脚本 Postman测试脚本本质上是在发送 ...

  7. Android之Zxing二维码扫描图片拉伸

    还是这个接手项目,二维码扫描集成的是zxing,扫描界面的图像有明显的拉伸变形. 这种问题,根据以往的经验,一般是x,y轴错位引起的,处理好x,y轴的问题,一般可以解决问题. 由于这个问题,之前有很多 ...

  8. IntelliJ IDEA的黑白色背景切换(Ultimate和Community版本皆通用)

    不多说,直接上干货! IntelliJ IDEA的黑白色背景切换 File    ->   Setting    ->  Editor     ->   Colors & F ...

  9. C/C++ -- Gui编程 -- Qt库的使用 -- 使用.ui文件

    1.创建Qt空工程 2.添加Qt设计师界面,无按钮对话框helloqt.ui 3.编辑界面,添加部件,修改对话框对象名为HelloQt <?xml version="1.0" ...

  10. 安装sublime text2 for ubuntu

        Add our Sublime Text 2 Ubuntu PPA using the following commands: sudo add-apt-repository ppa:webu ...