使用 Unicorn 还原变异 CRC32 算法

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

ARM64Emulator

ARM64Emulator 是基于 Unicorn 实现一个轻量级的 ARM64 模拟器,具备代码加载、内存映射、指令执行、反汇编、寄存器监控、Hook、Patch、字符串处理等功能

项目地址:https://github.com/CYRUS-STUDIO/ARM64Emulator

这里主要使用 ARM64Emulator 模拟执行 so 中的汇编指令实现算法还原。

目标应用信息

word/media/image1.png

app 中实现一个 CRC32 算法变形,具体实现在 so 中 modifiedCRC32 函数,现在要通过 unicorn 和 IDA Pro 逆向还原 so 中的算法。

word/media/image2.png

项目地址:https://github.com/CYRUS-STUDIO/AndroidExample

目标 so 文件地址:https://github.com/CYRUS-STUDIO/ARM64Emulator/tree/main/examples

使用 ARM64Emulator 加载 so 并执行 modifiedCRC32 函数的汇编指令实现算法还原。

from unicorn.arm64_const import *
import struct
import re

from ARM64Emulator import ARM64Emulator


def modifiedCRC32(data):
    emulator = ARM64Emulator("libcrc32.so")

    mu = emulator.mu

    # 字符串地址
    str_addr = emulator.STACK_BASE + emulator.STACK_SIZE
    emulator.mu.mem_map(str_addr, 0x1000)  # 4KB
    
    ...

    # 初始化传参
    emulator.set_x0(0) # JNIEnv*
    emulator.set_x1(0) # jobject
    emulator.set_x2(str_addr) # input

    # 运行
    emulator.run(0x1C040, 0x1C2D8)

    return hex(mu.reg_read(UC_ARM64_REG_X4))

if __name__ == "__main__":
    result = modifiedCRC32("546NBypEyvgBt")
    print(f"modifiedCRC32 result: '{result}'")

但汇编指令中有调用到一些 JNI 接口函数和系统函数,需要分析汇编代码并替换成对应的 Python 实现。

关键汇编代码分析

_ReadStatusReg

汇编代码如下:

.text:000000000001C05C 59 D0 3B D5                   MRS             X25, #3, c13, c0, #2
.text:000000000001C060 3A 01 00 D0                   ADRP            X26, #modified_crc32_table_ptr@PAGE
.text:000000000001C064 F4 03 02 AA                   MOV             X20, X2
.text:000000000001C068 28 17 40 F9                   LDR             X8, [X25,#0x28]
.text:000000000001C06C F3 03 00 AA                   MOV             X19, X0
.text:000000000001C070 A8 83 1F F8                   STUR            X8, [X29,#var_8]

MRS X25, #3, c13, c0, #2

  • MRS(Move from System Register)用于 读取系统寄存器。

  • #3, c13, c0, #2 对应 TPIDR_EL1(线程特定寄存器,常用于存储 TLS 线程本地存储指针)。

  • 这行指令 将 TPIDR_EL1 读入 X25,可能是为了访问某个线程局部存储的数据。

ADRP X26, #modified_crc32_table_ptr@PAGE

  • ADRP(Address of Page)用于 获取 modified_crc32_table_ptr 所在的内存页地址,存入 X26。

  • 这个指令不会提供完整地址,需要 结合 ADD 或 LDR 获取最终地址。

MOV X20, X2

  • 保存 X2 到 X20

LDR X8, [X25,#0x28]

  • 从 X25(即 TPIDR_EL1)的偏移 0x28 处读取一个 64-bit 值,存入 X8。

  • X25 指向 TLS(线程局部存储),所以 0x28 偏移量可能是线程相关的变量。

MOV X19, X0

  • 备份 X0 到 X19,可能是 函数的第一个参数,用于后续计算。

STUR X8, [X29,#var_8]

  • 把 X8 存入 X29(即 FP,帧指针)的 var_8 位置,通常是局部变量或栈空间的一部分。

  • STUR(Store Register Unscaled)是 STR 的变种,支持负偏移。

这段汇编代码中,主要通过 MRS 指令读取系统寄存器中内存访问异常相关状态信息信息,只需要把相关的两条指令 nop 掉就好了。

# v49 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
emulator.patch_nop([0X1C05C, 0X1C068])

GetStringUTFChars

汇编代码如下:

.text:000000000001C160 68 02 40 F9                   LDR             X8, [X19]
.text:000000000001C164 E0 03 13 AA                   MOV             X0, X19
.text:000000000001C168 E1 03 14 AA                   MOV             X1, X20
.text:000000000001C16C E2 03 1F AA                   MOV             X2, XZR
.text:000000000001C170 08 A5 42 F9                   LDR             X8, [X8,#0x548]
.text:000000000001C174 00 01 3F D6                   BLR             X8
.text:000000000001C174
.text:000000000001C178 F5 03 00 AA                   MOV             X21, X0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值