精华内容
下载资源
问答
  • Unicorn 框架使用疑问

    2021-06-11 17:34:53
    Unicorn 框架主要用于对主流CPU指令,如Arm、x86、misp,进行模拟运行。 其中一个 Unicorn 实现名为 AndroidNativeEmu,可以模拟调用 Android jni 接口。在使用 AndroidNativeEmu 框架的时候发现一些问题,比如首先...

    Unicorn 框架主要用于对主流CPU指令,如Arm、x86、misp,进行模拟运行。 其中一个 Unicorn 实现名为 AndroidNativeEmu,可以模拟调用 Android jni 接口。

    在使用 AndroidNativeEmu 框架的时候发现一些问题,比如首先需要加载被模拟的 so 库文件,代码如下:

    lib_module = emulator.load_library("example_binaries/libnative-lib_jni.so")

    在 load_library 函数最终会调用 pyelftools 库里的 load_module 函数来重定位,代码如下:

    def load_module(self, filename):

    logger.debug("Loading module '%s'." % filename)

    ......

    rel_section = None

    # 找类型为 SHT_RELA 的 section

    for section in elf.iter_sections():

    if not isinstance(section, RelocationSection):

    continue

    rel_section = section

    break

    ......

    但 Android 在加载 so 的时候根本不会根据 section 来操作内存,而是直接通过 segment ,遇到以下这样,section header 被删去重定位信息的so,就懵逼了,代码就会抛出异常:

    Section Headers:

    [Nr] Name Type Addr Off Size ES Flg Lk Inf Al

    [ 0] emcpy DYNAMIC 00008dd4 008dd4 000110 08 WA 1 0 4

    [ 1] xa_atexit STRTAB 000008a4 0008a4 00075e 00 A 0 0 1

    Key to Flags:

    W (write), A (alloc), X (execute), M (merge), S (strings), I (info),

    L (link order), O (extra OS processing required), G (group), T (TLS),

    C (compressed), x (unknown), o (OS specific), E (exclude),

    y (purecode), p (processor specific)

    按照参考文章的解决办法是加一段代码:

    ELF 文件有两种视图,链接视图和执行视图。elftools 是基于链接视图解析ELF格式的,然而现在有一些ELF文件的section信息是被抹掉的,elftools就无法正常工作,我也没时间重写一个elf loader,就只能凑合用一下elftools。

    我在源码中也看到了这段代码,不过仍然报错,好像没看到解决此问题的地方。

    展开全文
  • Unicorn Admin前端框架

    2014-06-17 11:01:37
    Unicorn Admin是一款优秀的前端开发框架
  • unicorn教程一

    千次阅读 2020-01-30 12:06:45
    Unicorn 是一个轻量级, 多平台, 多架构的 CPU 模拟器框架. 我们可以更好地关注 CPU 操作, 忽略机器设备的差异. 想象一下, 我们可以将其应用于这些情景: 比如我们单纯只是需要模拟代码的执行而非需要一个真的 CPU 去...

    http://www.unicorn-engine.org/docs/tutorial.html
    先来了解下什么是unicorn引擎。。
    Unicorn 是一个轻量级, 多平台, 多架构的 CPU 模拟器框架. 我们可以更好地关注 CPU 操作, 忽略机器设备的差异. 想象一下, 我们可以将其应用于这些情景: 比如我们单纯只是需要模拟代码的执行而非需要一个真的 CPU 去完成那些操作, 又或者想要更安全地分析恶意代码, 检测病毒特征, 或者想要在逆向过程中验证某些代码的含义. 使用 CPU 模拟器可以很好地帮助我们提供便捷.
    它的亮点 (这也归功于 Unicorn 是基于 qemu 而开发的) 包括:
    支持多种架构: Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (include X86_64).
    对 Windows 和 nix 系统 (已确认包含 Mac OSX, Linux, BSD & Solaris) 的原生支持
    具有平台独立且简洁易于使用的 API
    使用 JIT 编译技术, 性能表现优异

    那么它应用的场景有哪些呢?
    • 你可以调用恶意软件中一些有趣的函数, 而不用创建一个有害的进程.
    • 用于 CTF 竞赛
    • 用于模糊测试
    • 用于 gdb 插件, 基于代码模拟执行的插件
    • 模拟执行一些混淆代码
    这款神器是在2015年BlackHat大会上发布的,作者的ppt可以在这儿下载到
    http://www.unicorn-engine.org/BHUSA2015-unicorn.pdf
    在具体操作演示之前,我们简要看看作者所做的一些介绍
    在这里插入图片描述
    上图是作者的议题流程,我们只介绍红圈部分,具体使用unicorn提供的API进行编程是本系列实验的中心任务,在这一部分暂时先不提及。
    Unicorn的设计目的就是称为一款轻量级的CPU模拟器(或称仿真器)
    首先要明确CPU模拟器的应用,包括:
    不需要真实的CPU就能模拟代码;可以安全地分析恶意代码,侦测病毒签名;在逆向工程中明确代码的含义
    CPU模拟器的定义是仅用软件来模拟物理CPU,只关注CPU操作,而忽略机器设备。
    在CPU模拟器内部,给定二进制形式的输入代码,CPU模拟器需要:
    1.将二进制代码解码为单独的指令
    2.精确地模拟每个指令所做的工作,涉及:参考所需的指令集手册,处理所需的内存访问及IO等
    3.在每一步执行后更新CPU上下文,包括寄存器、内存等。
    以模拟x86 32位的指令为例,所以的工作如下所示
    在这里插入图片描述
    可以看到要做一个CPU模拟器,工作量很大,而且需要对CPU架构、指令集有精通理解,还需要知道指令集的一些副作用(文档里不会提及,但是经验丰富的人都清楚),而且重点是需要支持所有已知的各种类型的代码,这是非常困难的
    一个好的CPU模拟器需要具备以下特点:多种架构支持、多平台支持、保持更新,尽量保持独立减少对其他工具的依赖,性能高
    在这里插入图片描述
    unicorn可以满足上述的要求,相比于已有的工具,比较如下
    在这里插入图片描述
    unicorn是基于QEMU的,QEMU的架构如下所示
    在这里插入图片描述
    为什么是QEMU呢?因为它支持所有架构而且保持更新,在CPU模拟中已经支持JIT
    那么unicorn在QEMU基础上做了哪些工作呢?

    1. 删去不必要的功能,只保留CPU模拟功能
    2. 支持子系统,包括Qobject,Qom
    3. 重写一些组件但保持CP模拟代码完整(将来很容易与Qemu同步)
    4. 隔离常量和结构体,通过设计确保线程安全
    5. 重构以允许同时使用Unicorn的多个实例
    6. 修改了构建系统以按需支持多种架构
    7. 从头构建动态的细粒度指令层
    8. 支持各层级的指令,包括:特定指令的单步(TCG层),访问内存的指令(TLB层),在模拟过程中动态读写寄存器或内存,通过用户提供的回调函数处理异常、终端、系统调用(架构层)
    9. 发现并修复所有的内存泄露问题
    10. 重构各种子系统以跟踪和清理悬空指针。
      基于以上的工作,unicorn相对于QEMU的优势在于:
      在这里插入图片描述
      unicorn的核心提供了C实现的API
      在这里插入图片描述
      如果用python编程,其库unicorn已经处理好细节了,我们使用pip install unicorn后就可以直接使用了

    使用pip install unicorn即可安装使用
    在这里插入图片描述
    安装完成后先来写一个demo,来模拟x86架构下的32位机器
    我们是在python2的环境下编写,但是要超前使用python3的print函数,所以第一句代码是
    在这里插入图片描述
    接下来
    在这里插入图片描述
    在使用Unicorn之前导入unicorn模块,由于我们这个dmeo使用了一些x86寄存器常量,所以还需要unicorn.x86_const
    在这里插入图片描述
    这是我们要模拟的代码,这里使用16进制表示,表示两个x86指令“INC ecx”和”DEC dex“
    在这里插入图片描述
    指定虚拟地址,我们将在这儿模拟上述代码
    在这里插入图片描述
    使用Uc类初始化Unicorn, 该类接受2个参数:硬件架构和硬件模式。 在示例中,我们希望模拟X86体系结构的32位代码。
    在这里插入图片描述
    使用mem_map方法在前面声明的地址处映射2MB内存。此过程中的所有CPU操作都只能访问此内存。 此内存使用默认权限READ,WRITE和EXECUTE进行映射。
    在这里插入图片描述
    将要模拟的代码写入我们刚刚映射到的内存中。 mem_write方法有两个参数:要写入的地址和要写入内存的代码。
    在这里插入图片描述
    使用reg_write方法设置ECX,EDX寄存器的值
    在这里插入图片描述
    使用emu_start方法开始模拟。该API采用4个参数:需要模拟的代码的地址、模拟停止的地址(正好在X86_CODE32的最后一个字节之后)、要模拟的时间和要模拟的指令数量。如果我们忽略最后两个参数,比如这个例子,unicorn将在无限时间和无限数量的指令中模拟代码。
    在这里插入图片描述
    通过reg_read函数读取,打印出寄存器ECX,EDX的值
    完整代码在test.py,运行后如图所示

    在这里插入图片描述

    模仿其他架构的也很简单,我们看看模拟MIPS的
    MIPS架构(英语:MIPS architecture,为Microprocessor without interlocked piped stages architecture的缩写,亦为Millions of Instructions Per Second的双关语),是一种采取精简指令集(RISC)的处理器架构,1981年出现,由MIPS科技公司开发并授权,广泛被使用在许多电子产品、网络设备、个人娱乐装置与商业装置上。目前很多路由器都是采用MIPS架构。来分析代码。
    在这里插入图片描述
    超前使用python3的print函数
    在这里插入图片描述
    导入unicorn模块,以及将要模拟的是unicorn.mips_const
    在这里插入图片描述
    要模拟的代码
    EB表示big endian即大端,EL表示little endain即小端
    所以其实这两句代码表示的同一条指令。
    另外我们需要知道,MIPS有32个通用寄存器($0-$31), 1 为 1为 1at,为汇编保留,由于I型指令的立即数字段只有16位,在加载大常数时,编译器或汇编程序需要把大常数拆开,然后重新组合到寄存器里。比如加载一个32位立即数需要 lui(装入高位立即数)和addi两条指令。像MIPS程序拆散和重装大常数由汇编程序来完成,汇编程序必需一个临时寄存器来重组大常数,这也是为汇编保留$at的原因之一。就是我们demo里的指令使用到的寄存器
    ori指令用于进行“或“操作,原型ori r s , rs, rs,rd,im;功能为rd=rd|im
    在我们demo中就是 a t = at= at=at|0x3456
    在这里插入图片描述
    指定内存地址,我们从这儿开始模拟
    在这里插入图片描述在这里插入图片描述

    分别用于测试大端和小端,都是差不多的,我们来分析大端的
    在这里插入图片描述
    使用Uc类创建一个对象,创建时指定架构为MIPS,为32位和大端格式
    在这里插入图片描述
    为这次模拟映射2MB内存
    在这里插入图片描述
    将要被模拟的代码写入内存
    在这里插入图片描述
    初始化寄存器
    在这里插入图片描述
    没有指定要模拟的时间和指令数量,所以会在无限时间内模拟
    在这里插入图片描述
    读出寄存器的值并打印出来
    完整代码在test1.py
    运行后结果如图
    在这里插入图片描述
    其他demo可以参考学习,链接为:https://github.com/unicorn-engine/unicorn/tree/master/bindings/python

    展开全文
  • Unicorn 是一款非常优秀的跨平台模拟执行框架,该框架可以跨平台执行Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (include X86_64)等指令集的原生程序。好了说得那么官方,我们举个例子好了,研究OLLVM的时候...

    我们来先说说Unicorn有啥子卵用。

    Unicorn 是一款非常优秀的跨平台模拟执行框架,该框架可以跨平台执行Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (include X86_64)等指令集的原生程序。

    好了说得那么官方,我们举个例子好了,研究OLLVM的时候是不是很头疼函数的地址,使用Unicorn就可以打印函数注册地址,已经参数名称,用某音的so来演示一下Unicorn的威力

    [Asm] 纯文本查看 复制代码RegisterNatives dvmClass=com/ss/android/common/applog/UserInfo, name=getUserInfo, signature=(ILjava/lang/String;[Ljava/lang/String;)Ljava/lang/String;, fnPtr=unicorn@0x4002c6c5[libcms.so]0x2c6c5

    RegisterNatives dvmClass=com/ss/android/common/applog/UserInfo, name=getUserInfo, signature=(ILjava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;, fnPtr=unicorn@0x4002c6dd[libcms.so]0x2c6dd

    RegisterNatives dvmClass=com/ss/android/common/applog/UserInfo, name=getUserInfoSkipGet, signature=(ILjava/lang/String;[Ljava/lang/String;)Ljava/lang/String;, fnPtr=unicorn@0x4002c7b1[libcms.so]0x2c7b1

    RegisterNatives dvmClass=com/ss/android/common/applog/UserInfo, name=getUserInfo, signature=(I[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;, fnPtr=unicorn@0x4002c7d1[libcms.so]0x2c7d1

    RegisterNatives dvmClass=com/ss/android/common/applog/UserInfo, name=getPackage, signature=(Ljava/lang/String;)V, fnPtr=unicorn@0x4002e0dd[libcms.so]0x2e0dd

    55fd2b2273b5a8b4531f72773c469d6e.gif

    image.png (46.69 KB, 下载次数: 6)

    1

    2019-9-19 15:15 上传

    很快就可以找到UserInfo的函数地址了,不管是Hook还是直接动态调试都是事半功倍。

    (当初我找函数地址,找到想哭)

    55fd2b2273b5a8b4531f72773c469d6e.gif

    image.png (257.52 KB, 下载次数: 1)

    表情

    2019-9-19 15:17 上传

    好了,开始Unicorn的入门

    Unicorn 快速入门

    多架构

    Unicorn 是一款基于qemu模拟器的模拟执行框架,支持Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (include X86_64)等指令集。

    多语言

    Unicorn 为多种语言提供编程接口比如C/C++、Python、Java 等语言。Unicorn的DLL 可以被更多的语言调用,比如易语言、Delphi,前途无量。

    多线程安全

    Unicorn 设计之初就考虑到线程安全问题,能够同时并发模拟执行代码,极大的提高了实用性。

    虚拟内存

    Unicorn 采用虚拟内存机制,使得虚拟CPU的内存与真实CPU的内存隔离。Unicorn 使用如下API来操作内存:

    uc_mem_map

    uc_mem_read

    uc_mem_write

    使用uc_mem_map映射内存的时候,address 与 size 都需要与0x1000对齐,也就是0x1000的整数倍,否则会报UC_ERR_ARG 异常。如何动态分配管理内存并实现libc中的malloc功能将在后面的课程中讲解。

    Hook 机制

    Unicorn的Hook机制为编程控制虚拟CPU提供了便利。

    Unicorn 支持多种不同类型的Hook。

    大致可以分为(hook_add第一参数,Unicorn常量):

    指令执行类

    UC_HOOK_INTR

    UC_HOOK_INSN

    UC_HOOK_CODE

    UC_HOOK_BLOCK

    内存访问类

    UC_HOOK_MEM_READ

    UC_HOOK_MEM_WRITE

    UC_HOOK_MEM_FETCH

    UC_HOOK_MEM_READ_AFTER

    UC_HOOK_MEM_PROT

    UC_HOOK_MEM_FETCH_INVALID

    UC_HOOK_MEM_INVALID

    UC_HOOK_MEM_VALID

    异常处理类

    UC_HOOK_MEM_READ_UNMAPPED

    UC_HOOK_MEM_WRITE_UNMAPPED

    UC_HOOK_MEM_FETCH_UNMAPPED

    调用hook_add函数可添加一个Hook。Unicorn的Hook是链式的,而不是传统Hook的覆盖式,也就是说,可以同时添加多个同类型的Hook,Unicorn会依次调用每一个handler。hook callback 是有作用范围的(见hook_add begin参数)。

    我们来写一个举一个简单的栗子:

    先装一下Unicorn的导入包

    [Asm] 纯文本查看 复制代码pip install unicorn

    然后新建一个py文件

    [Python] 纯文本查看 复制代码from unicorn import *

    from unicorn.arm_const import *

    ARM_CODE = b"\x37\x00\xa0\xe3\x03\x10\x42\xe0"

    # mov r0, #0x37;

    # sub r1, r2, r3

    # Test ARM

    # callback for tracing instructions

    def hook_code(uc, address, size, user_data):

    print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))

    def test_arm():

    print("Emulate ARM code")

    try:

    # Initialize emulator in ARM mode

    mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB) #创建UC对象

    # map 2MB memory for this emulation 创建2MB的内存空间

    ADDRESS = 0x10000

    mu.mem_map(ADDRESS, 2 * 0x10000)

    mu.mem_write(ADDRESS, ARM_CODE) #将前面定义的ARM_CODE传入内存空间内,只支持byte

    #未开机前寄存器赋值

    mu.reg_write(UC_ARM_REG_R0, 0x1234)

    mu.reg_write(UC_ARM_REG_R2, 0x6789)

    mu.reg_write(UC_ARM_REG_R3, 0x3333)

    #添加指令集Hook

    # mu.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=ADDRESS)

    # emulate machine code in infinite time,开机

    mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE))

    print("已开机")

    #获取计算器结果

    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)

    except UcError as e:

    print("ERROR: %s" % e)

    test_arm()

    我把核心的位置都写了备注,这样很明显了吧

    我们看看运行结果

    55fd2b2273b5a8b4531f72773c469d6e.gif

    image.png (3.9 KB, 下载次数: 4)

    2

    2019-9-19 15:24 上传

    R0寄存器的就变成了0x37,R1=0x3456,

    上面我们明明没有对R1寄存器进行任何操作,为什么R1会有值呢?

    55fd2b2273b5a8b4531f72773c469d6e.gif

    image.png (101.26 KB, 下载次数: 2)

    3

    2019-9-19 15:25 上传

    于是我们引入第二个汇编神器Capstone

    其实ARM_CODE = b"\x37\x00\xa0\xe3\x03\x10\x42\xe0"就是对寄存器的操作

    我们用Capstone来翻译看看是什么指令

    先插个件

    [Asm] 纯文本查看 复制代码pip install capstone

    建个py文件

    [Python] 纯文本查看 复制代码from capstone import *

    from capstone.arm import *

    CODE = b"\x37\x00\xa0\xe3\x03\x10\x42\xe0"

    md = Cs(CS_ARCH_ARM, CS_MODE_ARM)

    for i in md.disasm(CODE, 0x1000):

    print("%x:\t%s\t%s" % (i.address, i.mnemonic, i.op_str))

    查看运行结果

    55fd2b2273b5a8b4531f72773c469d6e.gif

    image.png (10.11 KB, 下载次数: 1)

    4

    2019-9-19 15:30 上传

    这个总是看得懂了吧,就是简单arm的指令R1=R2-R3

    55fd2b2273b5a8b4531f72773c469d6e.gif

    image.png (161.74 KB, 下载次数: 4)

    5

    2019-9-19 15:31 上传

    接下来你们肯定关心怎么打印地址?怎么让Unicorn想普通模拟器可以单步调试对不对?

    55fd2b2273b5a8b4531f72773c469d6e.gif

    image.png (24.52 KB, 下载次数: 5)

    6

    2019-9-19 15:33 上传

    无名大佬写了一个调试,我们来看看这个调试器的源码

    (本菜是无名大佬的脑残粉)

    [Python] 纯文本查看 复制代码from unicorn import *

    from unicorn import arm_const

    from unicorn.arm_const import *

    import sys

    import hexdump

    import capstone as cp

    BPT_EXECUTE = 1

    BPT_MEMREAD = 2

    UDBG_MODE_ALL = 1

    UDBG_MODE_FAST = 2

    REG_ARM = {arm_const.UC_ARM_REG_R0: "R0",

    arm_const.UC_ARM_REG_R1: "R1",

    arm_const.UC_ARM_REG_R2: "R2",

    arm_const.UC_ARM_REG_R3: "R3",

    arm_const.UC_ARM_REG_R4: "R4",

    arm_const.UC_ARM_REG_R5: "R5",

    arm_const.UC_ARM_REG_R6: "R6",

    arm_const.UC_ARM_REG_R7: "R7",

    arm_const.UC_ARM_REG_R8: "R8",

    arm_const.UC_ARM_REG_R9: "R9",

    arm_const.UC_ARM_REG_R10: "R10",

    arm_const.UC_ARM_REG_R11: "R11",

    arm_const.UC_ARM_REG_R12: "R12",

    arm_const.UC_ARM_REG_R13: "R13",

    arm_const.UC_ARM_REG_R14: "R14",

    arm_const.UC_ARM_REG_R15: "R15",

    arm_const.UC_ARM_REG_PC: "PC",

    arm_const.UC_ARM_REG_SP: "SP",

    arm_const.UC_ARM_REG_LR: "LR"

    }

    REG_TABLE = {UC_ARCH_ARM: REG_ARM}

    def str2int(s):

    if s.startswith('0x') or s.startswith("0X"):

    return int(s[2:], 16)

    return int(s)

    def advance_dump(data, base):

    PY3K = sys.version_info >= (3, 0)

    generator = hexdump.genchunks(data, 16)

    retstr = ''

    for addr, d in enumerate(generator):

    # 00000000:

    line = '%08X: ' % (base + addr * 16)

    # 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

    dumpstr = hexdump.dump(d)

    line += dumpstr[:8 * 3]

    if len(d) > 8: # insert separator if needed

    line += ' ' + dumpstr[8 * 3:]

    # ................

    # calculate indentation, which may be different for the last line

    pad = 2

    if len(d) < 16:

    pad += 3 * (16 - len(d))

    if len(d) <= 8:

    pad += 1

    line += ' ' * pad

    for byte in d:

    # printable ASCII range 0x20 to 0x7E

    if not PY3K:

    byte = ord(byte)

    if 0x20 <= byte <= 0x7E:

    line += chr(byte)

    else:

    line += '.'

    retstr += line + '\n'

    return retstr

    def _dbg_trace(mu, address, size, self):

    self._tracks.append(address)

    if not self._is_step and self._tmp_bpt == 0:

    if address not in self._list_bpt:

    return

    if self._tmp_bpt != address and self._tmp_bpt != 0:

    return

    return _dbg_trace_internal(mu, address, size, self)

    def _dbg_memory(mu, access, address, length, value, self):

    pc = mu.reg_read(arm_const.UC_ARM_REG_PC)

    print("memory error: pc: %x access: %x address: %x length: %x value: %x" %

    (pc, access, address, length, value))

    _dbg_trace_internal(mu, pc, 4, self)

    mu.emu_stop()

    return True

    def _dbg_trace_internal(mu, address, size, self):

    self._is_step = False

    print("======================= Registers =======================")

    self.dump_reg()

    print("======================= Disassembly =====================")

    self.dump_asm(address, size * self.dis_count)

    while True:

    raw_command = input(">")

    if raw_command == '':

    raw_command = self._last_command

    self._last_command = raw_command

    command = []

    for c in raw_command.split(" "):

    if c != "":

    command.append(c)

    try:

    if command[0] == 'set':

    if command[1] == 'reg': # set reg regname value

    self.write_reg(command[2], str2int(command[3]))

    elif command[1] == 'bpt':

    self.add_bpt(str2int(command[2]))

    else:

    print("[Debugger Error]command error see help.")

    elif command[0] == 's' or command[0] == 'step':

    # self._tmp_bpt = address + size

    self._tmp_bpt = 0

    self._is_step = True

    break

    elif command[0] == 'n' or command[0] == 'next':

    self._tmp_bpt = address + size

    self._is_step = False

    break

    elif command[0] == 'r' or command[0] == 'run':

    self._tmp_bpt = 0

    self._is_step = False

    break

    elif command[0] == 'dump':

    if len(command) >= 3:

    nsize = str2int(command[2])

    else:

    nsize = 4 * 16

    self.dump_mem(str2int(command[1]), nsize)

    elif command[0] == 'list':

    if command[1] == 'bpt':

    self.list_bpt()

    elif command[0] == 'del':

    if command[1] == 'bpt':

    self.del_bpt(str2int(command[2]))

    elif command[0] == 'stop':

    exit(0)

    elif command[0] == 't':

    self._castone = self._capstone_thumb

    print("======================= Disassembly =====================")

    self.dump_asm(address, size * self.dis_count)

    elif command[0] == 'a':

    self._castone = self._capstone_arm

    print("======================= Disassembly =====================")

    self.dump_asm(address, size * self.dis_count)

    elif command[0] == 'f':

    print(" == recent ==")

    for i in self._tracks[-10:-1]:

    print(self.sym_handler(i))

    else:

    print("Command Not Found!")

    except:

    print("[Debugger Error]command error see help.")

    class UnicornDebugger:

    def __init__(self, mu, mode=UDBG_MODE_ALL):

    self._tracks = []

    self._mu = mu

    self._arch = mu._arch

    self._mode = mu._mode

    self._list_bpt = []

    self._tmp_bpt = 0

    self._error = ''

    self._last_command = ''

    self.dis_count = 5

    self._is_step = False

    self.sym_handler = self._default_sym_handler

    self._capstone_arm = None

    self._capstone_thumb = None

    if self._arch != UC_ARCH_ARM:

    mu.emu_stop()

    raise RuntimeError("arch:%d is not supported! " % self._arch)

    if self._arch == UC_ARCH_ARM:

    capstone_arch = cp.CS_ARCH_ARM

    elif self._arch == UC_ARCH_ARM64:

    capstone_arch = cp.CS_ARCH_ARM64

    elif self._arch == UC_ARCH_X86:

    capstone_arch = cp.CS_ARCH_X86

    else:

    mu.emu_stop()

    raise RuntimeError("arch:%d is not supported! " % self._arch)

    if self._mode == UC_MODE_THUMB:

    capstone_mode = cp.CS_MODE_THUMB

    elif self._mode == UC_MODE_ARM:

    capstone_mode = cp.CS_MODE_ARM

    elif self._mode == UC_MODE_32:

    capstone_mode = cp.CS_MODE_32

    elif self._mode == UC_MODE_64:

    capstone_mode = cp.CS_MODE_64

    else:

    mu.emu_stop()

    raise RuntimeError("mode:%d is not supported! " % self._mode)

    self._capstone_thumb = cp.Cs(cp.CS_ARCH_ARM, cp.CS_MODE_THUMB)

    self._capstone_arm = cp.Cs(cp.CS_ARCH_ARM, cp.CS_MODE_ARM)

    self._capstone = self._capstone_thumb

    if mode == UDBG_MODE_ALL:

    mu.hook_add(UC_HOOK_CODE, _dbg_trace, self)

    mu.hook_add(UC_HOOK_MEM_UNMAPPED, _dbg_memory, self)

    mu.hook_add(UC_HOOK_MEM_FETCH_PROT, _dbg_memory, self)

    self._regs = REG_TABLE[self._arch]

    def dump_mem(self, addr, size):

    data = self._mu.mem_read(addr, size)

    print(advance_dump(data, addr))

    def dump_asm(self, addr, size):

    md = self._capstone

    code = self._mu.mem_read(addr, size)

    count = 0

    for ins in md.disasm(code, addr):

    if count >= self.dis_count:

    break

    print("%s:\t%s\t%s" % (self.sym_handler(ins.address), ins.mnemonic, ins.op_str))

    def dump_reg(self):

    result_format = ''

    count = 0

    for rid in self._regs:

    rname = self._regs[rid]

    value = self._mu.reg_read(rid)

    if count < 4:

    result_format = result_format + ' ' + rname + '=' + hex(value)

    count += 1

    else:

    count = 0

    result_format += '\n' + rname + '=' + hex(value)

    print(result_format)

    def write_reg(self, reg_name, value):

    for rid in self._regs:

    rname = self._regs[rid]

    if rname == reg_name:

    self._mu.reg_write(rid, value)

    return

    print("[Debugger Error] Reg not found:%s " % reg_name)

    def show_help(self):

    help_info = """

    # commands

    # set reg

    # set bpt

    # n[ext]

    # s[etp]

    # r[un]

    # dump

    # list bpt

    # del bpt

    # stop

    # a/t change arm/thumb

    # f show ins flow

    """

    print(help_info)

    def list_bpt(self):

    for idx in range(len(self._list_bpt)):

    print("[%d] %s" % (idx, self.sym_handler(self._list_bpt[idx])))

    def add_bpt(self, addr):

    self._list_bpt.append(addr)

    def del_bpt(self, addr):

    self._list_bpt.remove(addr)

    def get_tracks(self):

    for i in self._tracks[-100:-1]:

    # print (self.sym_handler(i))

    pass

    return self._tracks

    def _default_sym_handler(self, address):

    return hex(address)

    def set_symbol_name_handler(self, handler):

    self.sym_handler = handler

    def test_arm():

    print("Emulate Thumb code")

    THUMB = b"\x37\x00\xa0\xe3\x03\x10\x42\xe0"

    # sub sp, #0xc

    # sub sp, #0xc

    # sub sp, #0xc

    try:

    # Initialize emulator in ARM mrode

    mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)

    # map 2MB memory for this emulation

    ADDRESS = 0x10000

    mu.mem_map(ADDRESS, 2 * 0x10000)

    mu.mem_write(ADDRESS, THUMB)

    mu.reg_write(UC_ARM_REG_SP, 0x1234)

    mu.reg_write(UC_ARM_REG_R2, 0x6789)

    # debugger attach

    udbg = UnicornDebugger(mu)

    udbg.add_bpt(ADDRESS)

    # emulate machine code in infinite time

    mu.emu_start(ADDRESS, ADDRESS + len(THUMB))

    r0 = mu.reg_read(UC_ARM_REG_SP)

    r1 = mu.reg_read(UC_ARM_REG_R1)

    print(">>> SP = 0x%x" % r0)

    print(">>> R1 = 0x%x" % r1)

    except UcError as e:

    print("ERROR: %s" % e)

    test_arm()

    我们看看运行结果

    55fd2b2273b5a8b4531f72773c469d6e.gif

    image.png (19.17 KB, 下载次数: 4)

    7

    2019-9-19 15:36 上传

    寄存器的值,和反编译后的指令都显示出来了

    接下来就是输入指令了,step,run,next,这是不是跟F8,F9,F10,步入,步过,运行很像呢

    这个大家可以自己去尝试以下,我就直接run了

    55fd2b2273b5a8b4531f72773c469d6e.gif

    image.png (21.61 KB, 下载次数: 1)

    8

    2019-9-19 15:38 上传

    值都打印出来啦。

    这些都是Unicorn的基础,那些大佬已经基于Unicorn写出很多很强大的逆向工具,大家有兴趣可以自己找找

    55fd2b2273b5a8b4531f72773c469d6e.gif

    image.png (51.08 KB, 下载次数: 3)

    9

    2019-9-19 15:40 上传

    展开全文
  • 最近在研究一些用于进行逆向工程的框架:Chain of Fundamental Engines for Reverse Engineering: Capstone, Keystone, Unicorn, Qemu, Qiling。这些工具在某些场合中能够很好的帮助我们进行逆向工作。 汇编与反汇编...

    最近在研究一些用于进行逆向工程的框架:Chain of Fundamental Engines for Reverse Engineering: Capstone, Keystone, Unicorn, Qemu, Qiling。这些工具在某些场合中能够很好的帮助我们进行逆向工作。

    汇编与反汇编

    Capstone

    新加坡南洋理工大学团队在 Blackhat USA 2014 上发布的一个反汇编引擎

    Keystone

    新加坡南洋理工大学团队在 Blackhat USA 2016 上发布的一个汇编框架

    二进制模拟执行

    QEMU

    QEMU是一套由Fabrice Bellard所编写的模拟处理器的自由软件,一个通用的系统空间和用户空间仿真器和虚拟机

    Unicorn

    新加坡南洋理工大学团队在 Blackhat USA 2015 上发布的轻量级多平台,多体系结构的CPU仿真器框架

    • Unicorn 引擎 CPU仿真框架 官网
    • 项目主页:https://github.com/unicorn-engine/unicorn
    • 多平台:Windows、* nix
    • 多架构,例如 Arm、Mips 和 x86
    • 支持 C/Python 接口
    • 基于 QEMU

      QEMU 提供了一个完整的仿真环境,既可以模拟硬件外设、整个系统,也可以模拟单个二进制程序。而 Unicorn 专注于 CPU 指令的仿真。

    QiLing

    京东团队在 Defcon 2019 上发布的高级二进制仿真框架

    • Capstone 二进制仿真框架 官网
    • 项目主页:https://github.com/qilingframework/qiling
    • 多平台:Windows、* nix
    • 多架构,例如 Arm、Mips 和 x86
    • 基于 Unicorn

      Qiling 被设计为更高级别的框架,它利用 Unicorn 来模拟 CPU 指令,除此之外,还具有高级分析功能:执行动态检测,甚至可以在运行时热修补代码

    总结

    上述用于二进制逆向的开源工具,都提供了详细的使用方法,并且有团队一直在维护,对于研究二进制病毒、恶意样本分析大有裨益。例如,

    • 修改固件、二进制,增加或者修改其中的指令,可以使用 Capstone/Keystone 进行汇编指令与二进制的转换
    • 跨平台仿真一些架构的二进制可执行文件, 可以使用 QEMU
    • 二进制指令片段的模拟,可以使用 Unicorn、QiLing

    笔者使用过其中的几个,且有想法去集成其中的一些功能,编写一个可视化工具。在这里只是进行简单的介绍,如果感兴趣,还是要实际操作一下。这些工具的官网都给出了使用教程,用起来还是比较简单的。

    当然,如果是正常的渗透测试,漏洞挖掘,CTF,这些工具可能用到的场合还是比较受限,因为我们更常用的工具是 IDA、Ghidra、pwntools,他们具有更好的集成性和扩展性,这些工具大家可能更为熟悉,不再赘述。

    展开全文
  • 注意: Unicorn是最初由Nguyen Anh Quynh,Dang Hoang Vu等人开发的轻量级多体系结构CPU仿真器框架。 并根据GPLv2许可发布。 有关贡献者和许可条款的更多信息,可以在此存储库的unicorn子模块内的AUTHORS.TXT , ...
  • 使用unicorn-engine开发模拟器 什么是unicorn引擎 Unicorn是基于qemu开发的一个CPU模拟器,支持常见的各种指令集,能在各种系统上运行。 GITHUB项目地址: : 官网地址: : 一个中文API文档: : 它只是一个CPU...
  • 关于 unicorn engine 的相关知识以及开发,可访问笔者之前所写的博客 使用 Unicorn Engine 模拟执行二进制代码片段 Tutorial for UnicornUnicorn Engine 的开发和使用 0x10 uEmu 简介 uEmu 是一个小巧智能的 IDA...
  • 使用{% load unicorn %}加载Unicorn templatetag并使用{% unicorn 'component-name' %}将组件添加到模板中 :party_popper: :open_book: 更多细节 :clapping_hands: 贡献者 感谢这些很棒的人(): ...
  • 独角兽RAD框架
  • ServerEngine是一个框架,用于实现强大的多进程服务器,例如Unicorn。 主要特点: Heartbeat via pipe & auto-restart / \ ---+ +------------+ / +----------+ \ +--------+ | | Supervisor |------| Server |-...
  • Unicorn PE是基于的工具项目/框架,旨在模拟Windows PE文件(尤其是打包文件)的代码执行。 特征 将PE映像从emu内存中转储到文件中,修复导入表,解密VMProtect字符串,解密VMProtect导入。 对异常的部分支持。 ...
  • Unicorn Admin 后台模板 基于bootstrap框架的响应式适合多种用途的管理模板
  • Unicorn是基于的轻量级多平台,多体系结构的CPU仿真器框架。 执照 GPL 兼容性 操作系统:Windows,Linux 编译器:Delphi,Free Pascal 产品特点 与C核心相同的API 有一些针对uc_mem_write()不区分大小写的变通...
  • UI组件 目录 要求 安装 npm install 用法 故事书 启动具有热模块替换功能的Storybook开发服务器。 npm run develop 将生产用的故事书构建到docs文件夹中。 npm run build 测验 运行所有测试并整理。...np
  • 它有一个浪漫而美妙的名字“ Microsoft ADO.NET实体框架功能CTP4 ”。 您可以说“ EF Feature CTP4”,但我喜欢“ EF Magic Unicorn Edition”,但仅此而已。 我们正在使Microsoft的技术变得更好,但仍然无法正确...
  • Unicorn与Android

    2021-11-02 15:22:18
    Unicorn 是一款非常优秀的跨平台模拟执行框架,该框架可以跨平台执行Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (include X86_64)等指令集的原生程序。 Unicorn 不仅仅是模拟器,更是一种“硬件级”调试器...
  • :high_voltage: 小小的Web框架替代Express tinyhttp是一种现代的类似的Web框架,使用TypeScript编写并编译为本机ESM,它使用最少的依赖项来避免遗留地狱。 以下是tinyhttp具有的最重要功能的简短列表: :high_...
  • :high_voltage: 作为 Express 替代品的微型 Web 框架 :sauropod: tinyhttp 现在有一个(正在进行中) tinyhttp是一个现代的类似的 Web 框架,用 TypeScript 编写并编译为原生 ESM,它使用最少的依赖项试图避免遗留...
  • python unicorn engine

    2021-08-13 10:06:36
    Unicorn 是一个轻量级, 多平台, 多架构的 CPU 模拟器框架. 我们可以更好地关注 CPU 操作, 忽略机器设备的差异. 想象一下, 我们可以将其应用于这些情景: 比如我们单纯只是需要模拟代码的执行而非需要一个真的 CPU 去...
  • 这篇文章将详细介绍NDSS2020的《UNICORN: Runtime Provenance-Based Detector for Advanced Persistent Threats》,一种基于溯源图的实时APT检测器。希望这篇文章对您有所帮助,这些大佬是真的值得我们去学习,献上...
  • 数据类型 结构 作用 uc_arch CPU架构选择,UC_ARCH_X86 uc_mode 模式选择。包括大小端序,16/32/64位,CPU类型等 uc_err 错误类型。返回为0正常 uc_mem_type UC_HOOK_MEM_*的所有内存访问类型...uc_mem...
  • 快如闪电的ASGI服务器。 ...)Uvicorn速度很快。...直到最近,Python仍缺乏用于asyncio框架的最低限度的低级服务器/应用程序接口。 ASGI规范填补了这一空白,这意味着我们现在可以开始构建一套通用的可用工具。
  • Gunicorn服务器与各种Web框架广泛兼容,仅表示Gunicorn Gunicorn'Green Unicorn'是用于UNIX的Python WSGI HTTP服务器。 这是从Ruby的Unicorn项目移植来的前叉工作模型。 Gunicorn服务器与各种Web框架广泛兼容,实施...
  • Unidbg的底层支持-Unicorn Unidbg的底层支持-Unicorn Unicorn简介 Unicorn使用步骤 引入Unicorn 使用Unicorn Unicorn原生Hook CodeHook BlockHook ReadHook WriteHook MemHook InterruptHook EventMemHook ...
  • Unicorn学习笔记之一

    2021-10-13 00:40:40
    Unicorn是一款跨平台的模拟器执行框架,可以辅助我们模拟执行x86、arm等等平台的代码。从而达到调试器的作用,它的实用场景例如ollvm还原、静态脱壳机等等。 1、搭建编译环境 1、首先VS安装该组件 2、搭配好...
  • 经常接私活的朋友应该深有感触,如何能快速...今天给伙伴们推荐一款开源的框架Vue.NetCore,这个框架我熟悉了3,4个月,觉得不错才给大家推荐.首先,前端是vue,后端是.Net Core.如果喜欢前端可以单独拿出来使用,自己用php,ja
  • Unicorn 是一个轻量级的多平台多架构的 CPU 仿真框架。作为一款著名的开源CPU 模拟框架,很多二进制逆向分析软件都用到了 Unicorn ,或者使用到了它的思想。比如 Radare2、Pwndbg、gdb-gef。Unicorn 在 QEMU 的基础...
  • GitLab系列3 Unicorn

    千次阅读 2019-06-04 14:53:52
    GitLab 为什么需要 Unicorn上一回我们主要讲解了 GitLab-workhorse 组件的智能代理功能,从这一回起将开始介绍最核心也最复杂的组件:Unicorn(GitLab Rails),上次也说了这个组件主要处理动态网页和 api 接口此篇...
  • Unicorn的学习记录

    2020-08-28 12:53:22
    Unicorn,是一个基于qemu的模拟引擎,当前应该有很多教程了,许多的框架都基于了Unicorn,但是学习之后发现,仅仅只是个模拟cpu的框架,在逆向分析中确实有许多的不便,于是在这里记录下学习过程中的问题与收获。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,313
精华内容 525
关键字:

unicorn框架