unicorn_learning1

unicorn start!

效仿大佬的文章简单地给自己作个学习记录,就当作写了篇日记了

Unicorn 入门学习

unicorn 是用于执行多种cpu框架的虚拟架构系统

下面进行模仿arm架构,执行arm指令

首先在python中导入unicorn

from unicorn import *

如何根据自己要执行指令对应哪个cpu架构,来导入相应的处理器相关的常量

from unicorn.arm_const  import *
from unicorn.arm64_const import *
from unicorn.m68k_const import *
from unicorn.mips_const import *
from unicorn.sparc_const import *
from unicorn.x86_const import *

寄存器常量命名规则:
UC_ + 指令集 + REG + 大写寄存器名
UC_ARMREG + 大写寄存器名 (UC_ARM_REG_R0)
UC_X86REG + 大写寄存器名 (UC_X86_REG_EAX)

这里我们选择unicorn.arm_const

创建arm虚拟机(UC)

Uc 是unicorn的主类,Uc对象则代表了一个独立的虚拟机实例,它有独立的寄存器和内存等资源,不同Uc对象之间的数据是独立的。Uc的构造函数有两个参数 archmode,用来指定模拟执行的指令集和对应的位数或模式。
arch常量参数一般以 UCARCH 开头,MODE常量以UCMODE 开头。

# Test ARM
def test_arm():
    print("Emulate ARM code")
    try:
        # Initialize emulator in ARM mode
        mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)	# 创建代码
        # 其它代码添加到此处
        return mu
    except UcError as e:
        print("ERROR: %s" % e)

mu = test_arm() # mu就是arm虚拟机

映射内存

想用Unicorn模拟执行代码,是不能将代码字节流直接以参数形式传递给Unicorn,而是将要执行的代码写入到Unicorn 的虚拟内存中。Uc 虚拟机实例初始内存是没有任何映射的,在读写内存之前使用uc_mem_map函数映射一段内存

这里开始地址和地址大小都要和0x1000==对齐==

否则就是我这种错误:

image-20221229151625712

ADDRESS = 0x10000
mu.mem_map(ADDRESS, 0x1000)  # 这里大小自己估算

写入代码

将想要执行的代码写进我们创建的内存中

mem_write的第二个参数必须是byte字节数组,只支持python的byte数组,不能是String或者bytearray。

ARM_CODE   = b"\x37\x00\xa0\xe3\x03\x10\x42\xe0"
# mov r0, #0x37;
# sub r1, r2, r3
mu.mem_write(ADDRESS, ARM_CODE) 

给寄存器初始赋值

mu.reg_write(UC_ARM_REG_R0, 0x0)
mu.reg_write(UC_ARM_REG_R2, 0x4)
mu.reg_write(UC_ARM_REG_R3, 0x1)
# 这里r1的结果预估是0x3

添加指令级的Hook

hook类型:

  • 指令执行类:
    • 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

image-20221229153037712

def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0):
    pass
mu.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=0x1000)

以上是添加hook的操作

在begin…end范围内的每一条指令被执行前都会调用callback。

hook函数编写:

# callback for tracing instructions
def hook_code(uc, address, size, user_data):
    print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))

执行虚拟机

emu_start 可以通过timeout参数设置最长执行时长,防止线程死在虚拟机里面。emu_start 执行完成后,可以通过读取内存或寄存器的方式来获取执行结果。

def emu_start(self, begin, until, timeout=0, count=0):
    pass
mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE))

执行成功,hook函数一共被调用两次(指令有两条)

image-20221229154734059

获取寄存器结果

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)

和推理的结果相同!!!!

image-20221229154900787


个人测试全过程:

image-20221229155328503

image-20221229155356531

完整代码:

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)
 
        # map 2MB memory for this emulation
        ADDRESS = 0x10000
        mu.mem_map(ADDRESS, 2 * 0x10000)
        mu.mem_write(ADDRESS, ARM_CODE)
 
        mu.reg_write(UC_ARM_REG_R0, 0x1234)
        mu.reg_write(UC_ARM_REG_R2, 0x6789)
        mu.reg_write(UC_ARM_REG_R3, 0x3333)
 
        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))
        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)

文章引用Pandaos大佬的文章:[原创] Unicorn 在 Android 的应用-Android安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com

×

喜欢就点赞,疼爱就打赏