基于 Unicorn 实现一个轻量级的 ARM64 模拟器

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/

基于 Unicorn 实现一个轻量级的 ARM64 模拟器,具备代码加载、内存映射、指令执行、反汇编、寄存器监控、Hook、Patch、字符串处理等功能,适合用于逆向分析或调试 ARM64 代码。

初始化与内存管理

  • 代码加载:通过 _load_binary() 将 so 文件加载到内存中。

  • 内存映射:在 _setup_memory() 中分配 10MB 的代码区和 1MB 的栈区。

  • 寄存器初始化:在 _setup_registers() 中设置栈指针(SP)和程序计数器(PC)。

  • 寄存器设置:提供了 set_x0()、set_x1() 和 set_x2() 等方法,用于直接设置寄存器值。

import capstone
from unicorn import *
from unicorn.arm64_const import *


class ARM64Emulator:

    def __init__(self, so_file: str):
        self.so_file = so_file

        # 分配代码区(TEXT 段)
        self.CODE_BASE = 0x000000  # 假设代码段起始地址
        self.CODE_SIZE = 1024 * 1024 * 10  # 10MB

        # 分配栈区(STACK 段)
        self.STACK_BASE = self.CODE_BASE + self.CODE_SIZE
        self.STACK_SIZE = 1024 * 1024 * 1  # 1MB

        # 初始化 Unicorn
        self.mu = Uc(UC_ARCH_ARM64, UC_MODE_ARM)

        self._load_binary()
        self._setup_memory()
        self._setup_registers()
        self._setup_hooks()

    def _load_binary(self):
        with open(self.so_file, "rb") as f:
            self.CODE = f.read()

    def _setup_memory(self):
        self.mu.mem_map(self.CODE_BASE, self.CODE_SIZE)
        self.mu.mem_map(self.STACK_BASE, self.STACK_SIZE)
        # 写入指令
        self.mu.mem_write(self.CODE_BASE, self.CODE)

    def _setup_registers(self):
        self.mu.reg_write(UC_ARM64_REG_SP, self.STACK_BASE + self.STACK_SIZE - 4)  # 使 SP 从栈的顶部往下移动 4 字节,以 预留一点空间,避免越界错误。
        self.mu.reg_write(UC_ARM64_REG_PC, self.CODE_BASE)

    def set_x0(self, value):
        self.mu.reg_write(UC_ARM64_REG_X0, value)

    def set_x1(self, value):
        self.mu.reg_write(UC_ARM64_REG_X1, value)


    def set_x2(self, value):
        self.mu.reg_write(UC_ARM64_REG_X2, value)

打印寄存器

dump_registers() 打印所有 ARM64 寄存器的当前值。

def dump_registers(self):
    """ 打印 Unicorn ARM64 CPU 的所有寄存器 """
    print("\n====== Registers Dump ======")

    # 遍历 X0 - X30
    for i in range(31):  # X0 ~ X30
        reg_id = getattr(arm64_const, f'UC_ARM64_REG_X{i}')
        value = self.mu.reg_read(reg_id)
        print(f"X{i:02}: 0x{value:016x}")

    # 打印 SP(栈指针)和 PC(程序计数器)
    sp = self.mu.reg_read(UC_ARM64_REG_SP)
    pc = self.mu.reg_read(UC_ARM64_REG_PC)

    print(f"\nSP:  0x{sp:016x}")
    print(f"PC:  0x{pc:016x}")
    print("============================\n")

运行程序

run() 使用 emu_start() 运行从 start_address 到 end_address 的指令。

def run(self, start_address, end_address):
    print("\nBefore execution:")
    self.dump_registers()
    # 运行 Unicorn
    self.mu.emu_start(self.CODE_BASE + start_address, self.CODE_BASE + end_address)
    print("\nAfter execution:")
    self.dump_registers()

反汇编

disassembly() 使用 Capstone 对指定地址的内存数据进行反汇编。

class ARM64Emulator:

    def __init__(self, so_file: str):
        
        # 初始化 Capstone 反汇编器 (针对 ARM64 架构)
        self.cs = capstone.Cs(capstone.CS_ARCH_ARM64, capstone.CS_MODE_ARM)

    def disassembly(self, start_address, end_address):
        """
        反汇编指定地址的字节码
        :param start_address: 开始地址
        :param end_address: 结束地址
        """
        # 提取目标方法的字节码
        target_data = self.CODE[start_address:end_address]
        # 反汇编字节码
        print("Disassembly:")
        for instruction in self.cs.dis
SimIt-ARM-3.0 给予命令行ARM指令模拟器,短小精悍,是研究ARM处理器的好工具,该模拟器既可以运行用户级别的ELF程序,又可以模拟运行Linux操作系统;提供了简单易用的调试命令,可以逐条跟踪指令的执行。 SimIt-ARM-3.0-gk-20150902.tar.bz2 HowTo 0.what is SimIt-ARM-3.0 SimIt-ARM 3.0 is an instruction-set simulator that runs both system-level and user-level ARM programs, for more about it please read user's guide file. 1.how to build tar jxvf SimIt-ARM-3.0-gk-20150902.tar.bz2 cd SimIt-ARM-3.0-gk ./configure make make install After these steps, the ./build/bindirectory contains the following programs: ema An ARM interpreter. To test the installation was successful type ./build/bin/ema test/wc configure modifiy PATH environment variable: PATH=$PATH:$HOME/SimIt-ARM-3.0-gk/build/bin ; export PATH 2. how to use 2.1 run user-level ARM programs [root@ORA9 SimIt-ARM-3.0-gk]# cd gcc-asm [root@ORA9 gcc-asm]# more hello.c /* * hello.c * Tue Sep 8 10:13:40 CST 2015 */ int main() { printf("hello world\n"); __asm("mov r0,#2\n\t" "swi 0x1\n\t"); // syscall: exit(2); } [root@ORA9 gcc-asm]# arm-linux-gcc -v Reading specs from /usr/local/arm/3.4.1/bin/../lib/gcc/arm-linux/3.4.1/specs Configured with: /opt/crosstool/crosstool-0.28/build/arm-linux/gcc-3.4.1-glibc-2.3.2/gcc-3.4.1/configure --target=arm-linux --host=i686-host_pc-linux-gnu --prefix=/opt/crosstool/arm-linux/gcc-3.4.1-glibc-2.3.2 --with-float=soft --with-headers=/opt/crosstool/arm-linux/gcc-3.4.1-glibc-2.3.2/arm-linux/include --with-local-prefix=/opt/crosstool/arm-linux/gcc-3.4.1-glibc-2.3.2/arm-linux --disable-nls --enable-threads=posix --enable-symvers=gnu --enable-__cxa_atexit --enable-languages=c,c++ --enable-shared --enable-c99 --enable-long-long Thread model: posix gcc version 3.4.1 [root@ORA9 gcc-asm]# arm-linux-gcc hello.c -o hello -static [root@ORA9 gcc-asm]# ls -l hello* -rwxr-xr-x 1 root root 520775 Sep 8 10:18 hello -rw-r--r-- 1 root root 160 Sep 8 10:15 hello.c [root@ORA9 gcc-asm]# file hello hello: ELF 32-bit LSB executable, ARM, vers
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值