前言

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. Linux CentOS7系统配置nginx服务器

    作为一个以服务器为主要市场的操作系统,主要就是对客户端的请求进行响应,进行处理的.在经历过系统镜像安装和本地配置好ssh功能后,接下来进行服务器的安装,这里我以nginx为主,介绍一下如何安装ngin ...

  2. 【DB2】关闭表的日志功能

    2018.11.19 客户遇到一个问题,在import数据的时候,产生了大量的日志,客户的数据库是HADR模式,通过评估,这几张表是可以允许在备库上不查询的,表中的数据时临时的. 方案一:修改脚本,将 ...

  3. Vundle,Vim 的 Bundle(转)

    长久以来,我管理 Vim 配置的方式都非常原始—— zip 打包,然后发到邮箱上.偶尔会发生忘记备份,或者配置混淆的状况,不过由于懒筋发作,竟然这个方案就这么用了两年. 终有一天,我觉得这个方法太笨了 ...

  4. 搭建互联网架构学习--003--maven以及nexus私服搭建

    跳过,等待完善中,,, 后台服务工具maven:使用Nexus配置Maven私有仓库 一.安装配置Nexus 1. 下载nexus https://www.sonatype.com/download- ...

  5. 浅谈Android Studio中项目结构中project模式的各个文件和文件夹

    致敬郭霖,这些知识是从第一行代码第二版中直接码下来的,谢谢他,注意每个条目前是否有. 1..gradle和.idea 这两个目录下放置的都是Android Studio自动生成的一些文件,我们无需关心 ...

  6. 如何虚拟机里安装Win8操作系统

    不多说,直接上干货! Windows Server 2003.2008.2012系统的安装 推荐网址:打开MSDN网站(http://msdn.itellyou.cn ) 关于给电脑换系统,很多人会花 ...

  7. Glide的用法

    最基本用法 glide采用的都是流接口方式 简单的从网络加载图片 Glide.with(context).load(internetUrl).into(targetImageView); 从文件加载 ...

  8. 图解-安卓中调用OpenGL

    游戏开发中经常使用到OpenGL,当然很多人都喜欢直接用现有的游戏引擎,但相信了解的更多对你没有坏处 安卓开发中,采用的OpenGL ex2的规范,前几天看了下这个规范,整体上难度比1.0规范难度加大 ...

  9. Nginx 为 Golang 配置 web 服务

    server { charset utf-; client_max_body_size 128M; #listen ; ## 监听 ipv4 上的 端口 #listen [::]: default_s ...

  10. rails image_tag生成图片标签

    image_tag(source, options={}) Link Returns an HTML image tag for thesource. The source can be a full ...