找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 421|回复: 0

【Python】测试Claripy操作符与LLVM IR一致性

[复制链接]
发表于 2025-9-10 20:46:27 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
本帖最后由 lichao 于 2025-9-10 21:30 编辑

背景

  笔者前段时间在分析iOS系统模块时发现关键算法代码加了一些MCB表达式做BR混淆(以下展示的是模块混淆的一处作为示例),分析过程中尝试用Angr还原,
在此过程中笔者尝试将该混淆方式还原为OLLVM逻辑并加入到笔者自己研发的SLLVM混淆器。此文正是此过程的一部分有感而发。

__text:000000018CD955E4                 SUB             X26, X8, #3
__text:000000018CD955E8                 MOV             W0, #0x18
__text:000000018CD955EC                 BLR             X26
__text:000000018CD955F0                 MOV             X8, #0x385FA333FCDBE678
__text:000000018CD95600                 ADD             X19, X0, X8
__text:000000018CD95604                 MOV             X8, #0x904EC4DDC4524EA8
__text:000000018CD95614                 ADD             X9, X0, X8
__text:000000018CD95618                 CMP             X9, X8
__text:000000018CD9561C                 CSET            W8, NE
__text:000000018CD95620                 CSET            W9, EQ
__text:000000018CD95624                 MOV             W2, #0xA4B50D3
__text:000000018CD9562C                 SUB             W10, W2, #6
__text:000000018CD95630                 MUL             W10, W9, W10
__text:000000018CD95634                 SUB             W8, W10, W8,LSL#1
__text:000000018CD95638                 ADD             W21, W8, #6
__text:000000018CD9563C                 ORR             W8, W9, #6
__text:000000018CD95640                 ADRL            X23, jpt_18CD95678
__text:000000018CD95648                 LDRSW           X8, [X23,W8,UXTW#2]
__text:000000018CD9564C                 ADRP            X9, #0x18CD95000
__text:000000018CD95650                 ADD             X9, X9, #0x618 ; jumptable 000000018CD95678 case 0
__text:000000018CD95654                 ADD             X8, X8, X9
__text:000000018CD95658                 ADRP            X9, #off_1C3880B50@PAGE
__text:000000018CD9565C                 LDR             X9, [X9,#off_1C3880B50@PAGEOFF] ; unk_1CDDBDEFB
__text:000000018CD95660                 SUB             X22, X9, #3
__text:000000018CD95664                 MOV             W27, #0xFFFF5035
__text:000000018CD95668                 MOV             X20, #0x385FA333FCDBE678
__text:000000018CD95678                 BR              X8      ; ['0x18cd9567c', '0x18cd95754']
__text:000000018CD9567C                 MOV             X24, X0 ; jumptable 000000018CD95678 case 0
__text:000000018CD95680                 MOV             X8, #0x4B91BD37674B1CED
__text:000000018CD95690                 STP             XZR, X8, [X0] ; jumptable 000000018CD95678 case 1
__text:000000018CD95694                 STR             WZR, [X0,#0x10]
__text:000000018CD95698                 MOV             W0, #0x1000
__text:000000018CD9569C                 BLR             X26

  关于OLLVM的基础知识https://www.0xaa55.com/thread-27509-1-1.html

表达式混淆的研究

第一阶段 OLLVM/SUB

  最早出现表达式混淆的是OLLVM项目,它提供了3大混淆方式控制流伪造(BCF),控制流平坦化(FLA),指令替换(SUB)至今仍在延续和发展。
其中指令替换其实就是最早的表达式混淆,他是在IR层做指令替换,如:
a = b + c替换为a = b - (-c)

%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = sub i32 0, %1
%3 = sub nsw i32 %0, %2

a = b + c替换为r = rand (); a = b + r; a = a + c; a = a - r

%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = add i32 %0, 1107414009
%3 = add i32 %2, %1
%4 = sub nsw i32 %3, 1107414009

a = b & c替换为a = (b ^ ~c) & b

%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = xor i32 %1, -1
%3 = xor i32 %0, %2
%4 = and i32 %3, %0

a = b | c替换为a = (b & c) | (b ^ c)

%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = and i32 %0, %1
%3 = xor i32 %0, %1
%4 = or i32 %2, %3

a= b ^ c替换为a = (~a & b) | (a & ~b)

%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = xor i32 %0, -1
%3 = and i32 %1, %2
%4 = xor i32 %1, -1
%5 = and i32 %0, %4
%6 = or i32 %3, %5

第二阶段 Z3/MBA

  上述OLLVM/SUB具有一定的灵活性,但是灵活性较低,而且基本上无法干扰IDA等成熟分析工具,此时Z3求解器和符号执行开始流行,加上MBA相关的数学定理以论文形式出现,因此OLLVM/SUB升级为Z3/MBA。
  什么是Z3呢?Z3是Microsoft出品的求解器,用途极广,可以处理科学问题,可以求解方程,可以分析物理受力平衡,可以求解工科线性规划问题,也可以用于计算机中的符号执行,甚至你可以用它求解数独。
  什么是MBA呢?MBA(Mixed Boolean-Arithmetic expressions),即混合布尔操作和数学运算的表达式,以64位整数x/y举例:x ^ y == (x + y) - 2*(x & y),此类恒等式理论上是无限的,且有办法用Z3无限生成此类数学公式。实际使用时也有2种用法:运算替换和常量替换,人们将表达式提前通过Z3随机生成恒等式并存储,然后应用到增强版OLLVM中。Z3/MBA大大增强了混淆的自由度,如果再经过多层嵌套,其IDA伪代码会显得非常复杂,笔者2024年刚接触OLLVM开发时,也研究过一部分,例如生成如下公式:

x y ~x ~y 1            
    x + ~x == -1    y + ~y == -1
x&y x&~y ~x&y ~x&~y    
    ~x&~y == ~(x|y)
    (~x|~y) + (x&y) == -1
    (~x&y) + (x|~y) == -1
x|y x|~y ~x|y ~x|~y    
    ~x|~y == ~(x&y)  
    (~x&~y) + (x|y) == -1  
    (~x|y) + (x&~y) == -1
x^y x^~y ~x^y          
    x^y == ~x^~y    x^~y == ~x^y 
    (x^~y) + (x^y) == -1  

可以用代码:

from z3 import *
from random import randint

N = 8
c = [Int("a{}".format(i)) for i in range(N)]
s = Solver()
for i in range(4): # 取4时求解速度最快
    x = randint(1, 0xffffffff)
    y = randint(1, 0xffffffff)
    s.add(c[0]*x + c[1]*y + c[2] + c[3]*(x&y) + c[4]*(x&~y) + c[5]*(x|y) + c[6]*(x|~y) + c[7]*(x^y) == 0)
sum = Sum([Abs(ci) for ci in c])
s.add(And(sum > 0, sum <= 2*N, c[2] != 0))

expr = ["x", "y", "1", "(x&y)", "(x&~y)", "(x|y)", "(x|~y)", "(x^y)"]
for i in range(1000):
    r = s.check()
    if r != sat:
        break
    m = s.model()
    fs = " + ".join(["{}*{}".format(m[c[j]], expr[j]) for j in range(N) if m[c[j]].as_long() != 0])
    print("{}: ".format(i+1) + fs + " == 0")
    s.add(Not(And([c[j] == m[c[j]] for j in range(N)])))
1: 1*x + -1*1 + -1*(x|y) + -1*(x|~y) == 0
2: 2*x + -1*y + -4*1 + 1*(x&y) + 1*(x&~y) + -2*(x|y) + -4*(x|~y) + -1*(x^y) == 0
3: 3*x + -1*y + -4*1 + -2*(x|y) + -4*(x|~y) + -1*(x^y) == 0
4: -3*x + -2*y + 1*1 + 5*(x|y) + 1*(x|~y) + -2*(x^y) == 0
5: -1*x + -2*y + 1*1 + -2*(x&y) + -2*(x&~y) + 5*(x|y) + 1*(x|~y) + -2*(x^y) == 0
6: -2*x + -2*y + 1*1 + -1*(x&y) + -1*(x&~y) + 5*(x|y) + 1*(x|~y) + -2*(x^y) == 0
7: 2*x + -2*y + -2*1 + -2*(x&y) + -2*(x&~y) + 2*(x|y) + -2*(x|~y) + -2*(x^y) == 0
8: 1*x + -2*y + -3*1 + -1*(x&y) + 2*(x|y) + -3*(x|~y) + -3*(x^y) == 0
9: 1*x + -2*y + -2*1 + -2*(x&y) + -1*(x&~y) + 3*(x|y) + -2*(x|~y) + -3*(x^y) == 0
10: -2*y + -1*1 + -2*(x&y) + -1*(x&~y) + 4*(x|y) + -1*(x|~y) + -3*(x^y) == 0
...

  那么如何对抗呢,其实大部分情况一大坨运算算出来的是个0或1的布尔值,可以直接忽略。另外2020年底出现一款IDA插件https://gitlab.com/eshard/d810,它在IDA微代码层处理,可以完美还原MBA表达式。市面上大部分MBA混淆都是此类,有的是把MBA和包括IGV(间接引用)的其他手段混合使用以增强效果,例如https://github.com/za233/Polaris-Obfuscator,以下是混淆效果
05eee71b416ba3b92b5e426b1b145511abcbffa4.png

第三阶段 增强表达式

  MCB(Mixed Boolean-Comparison expressions)即混合比较和数学运算的表达式,属于增强表示式的一种,此类表达式的操作包含比较操作和数学运算等。笔者遇到的这个iOS系统模块便是MCB表达式,MCB表达式还原显然比MBA难多了,此模块包含如下特点:

  • MCB表达式保护BR混淆(IndirectBranch,前面引用帖子里的间接分支),此混淆会将B指令直接跳转改造成BR跳转表间接跳转,保护跳转表的索引和基址。
  • MCB表达式保护BLR混淆(IndirectGlobalVariable),此混淆会把BL指令调用函数地址处理成跳转表间接调用,同样保护跳转表的索引和基址。
  • 每个函数中的每个BasicBlock的跳转表的索引和基址计算过程是相关的,如将上一个BasicBlock的一个中间值用作当前BasicBlock计算,这给还原带来较大难度

“拿来主义”,将混淆思路应用到混淆器

  笔者还是觉得有必要扩展一下逆向的定义:逆向不仅包含把汇编或字节码还原为高级源码的过程,也应该包含将可见逻辑还原成高级逻辑的过程,本例就是一个。
  笔者最终还原了该混淆,且规划将Apple的混淆逻辑,应用到自己的SLLVM混淆器中,笔者在构造难度高于MCB的增强表达式,目前使用Claripy代替Z3。   

  • 第一步就是确定Claripy操作符和LLVM IR操作符的对应关系和验证是否完美对应,给出如下的对应关系
Claripy 含义 对应 LLVM IR
一元
Not(expr) 逻辑非(布尔) xor i1 %x, trueicmp eq %x, 0
~expr(invert) 按位取反 xor iN %x, -1
-expr(neg) 取负(算术取反) sub iN 0, %x
Reverse(expr) 位反转 llvm.bitreverse
二元
expr1 + expr2(add) 加法 add
expr1 - expr2(sub) 减法 sub
expr1 * expr2(mul) 乘法 mul
expr1 / expr2(floordiv) 有符号除法 udiv
expr1 % expr2(mod) 有符号取模 urem
expr1 & expr2(and) 按位与 and
expr1 \| expr2(or) 按位或 or
expr1 ^ expr2(xor) 按位异或 xor
LShR(expr, k) 逻辑右移 lshr
expr >> k(lshift) 算术右移 ashr
expr << k(rshift) 左移 shl
RotateLeft(expr,k) 左旋 llvm.fshl
RotateRight(expr,k) 右旋 llvm.fshr
Concat(expr1, expr2) 拼接
==, !=, <, <=, >, >= 比较 icmp
三元
If(cond, t_expr, f_expr) 条件选择 select i1 %cond, %t, %f
ITE(cond, a, b) If 相同 select
Extract(hi, lo, expr) 截取bitfield shl+sub+lshr+and/sub+shl+lshr

验证代码:

import claripy
from claripy import BVS, BVV, Solver
import ctypes 
from llvmlite import ir, binding
import random
from unicorn import *
from unicorn.arm64_const import *

triple = "arm64-apple-ios12.0"

# prepare llvm
binding.initialize()
binding.initialize_all_targets()
binding.initialize_all_asmprinters()
target = binding.Target.from_triple(triple)
tm = target.create_target_machine()

# prepare unicorn
code_base, code_size = 0x1000, 0x400
emu = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
emu.mem_map(code_base, code_size)

# prepare claripy
x0 = BVS("x0", 64)
x1 = BVS("x1", 64)
x2 = BVS("x2", 64)
s = Solver()

def test_1op(name):
    name_dic = {
        "invert":   {"claripy": "__invert__",   "llvm": "?",    "op": '~'       },
        "neg":      {"claripy": "__neg__",      "llvm": "?",    "op": '-'       },
        "reverse":  {"claripy": "Reverse",      "llvm": "?",    "op": '(rev)'   },
    }
    op = name_dic[name]["op"]
    llvm_op = name_dic[name]["llvm"]
    # get machine code from llvm
    tm = target.create_target_machine()
    module = ir.Module()
    module.triple = triple
    fty = ir.FunctionType(ir.IntType(64), [ir.IntType(64)])
    func = ir.Function(module, fty, name=name)
    block = func.append_basic_block(name="entry")
    builder = ir.IRBuilder(block)
    if name == "invert": # ~x == x ^ -1
        ret = builder.xor(func.args[0], ir.Constant(ir.IntType(64), -1))
    elif name == "neg": # -x = 0 - x
        ret = builder.sub(ir.Constant(ir.IntType(64), 0), func.args[0])
    elif name == "reverse":
        bswap_ty = ir.FunctionType(ir.IntType(64), [ir.IntType(64)])
        bswap = ir.Function(module, bswap_ty, name="llvm.bswap.i64")
        ret = builder.call(bswap, [func.args[0]])
    else:
        ret = getattr(builder, llvm_op)(*func.args)
    builder.ret(ret)
    mod = binding.parse_assembly(str(module))
    mod.verify()
    #print(tm.emit_assembly(mod))
    engine = binding.create_mcjit_compiler(mod, tm)
    func_ptr = engine.get_function_address(name)
    bs = ctypes.string_at(func_ptr, 32)
    func_bs = bs[:bs.find(b"\xc0\x03\x5f\xd6") + 4]
    # init claripy
    claripy_op = name_dic[name]["claripy"]
    if hasattr(x0, claripy_op):
        expr = getattr(x0, claripy_op)()
    else:
        expr = getattr(claripy, claripy_op)(x0)
    # get result
    a1 = random.randint(0, 0x7fffffffffffffff)
    a2 = random.randint(0x8000000000000000, 0xffffffffffffffff)
    for a in [a1, a2]:
        emu.mem_write(code_base, func_bs)
        emu.reg_write(UC_ARM64_REG_X0, a)
        emu.reg_write(UC_ARM64_REG_PC, code_base)
        emu.emu_start(code_base, code_base + len(func_bs) - 4)
        r = emu.reg_read(UC_ARM64_REG_X0)
        print(f"llvm: {op}{a} = {r}")
        r = s.eval(expr, 1, extra_constraints=[x0 == a])[0]
        print(f"claripy: {op}{a} = {r}")

def test_2op(name):
    name_dic = {
        "add":      {"claripy": "__add__",      "llvm": "add",  "op": '+'       },
        "sub":      {"claripy": "__sub__",      "llvm": "sub",  "op": '-'       },
        "mul":      {"claripy": "__mul__",      "llvm": "mul",  "op": '*'       },
        "div":      {"claripy": "__floordiv__", "llvm": "udiv", "op": '/'       },
        "mod":      {"claripy": "__mod__",      "llvm": "urem", "op": '%'       },
        "and":      {"claripy": "__and__",      "llvm": "and_", "op": '&'       },
        "or":       {"claripy": "__or__",       "llvm": "or_",  "op": '|'       },
        "xor":      {"claripy": "__xor__",      "llvm": "xor",  "op": '^'       },
        "lsr":      {"claripy": "LShR",         "llvm": "lshr", "op": '>>'      }, # 逻辑右移
        "asr":      {"claripy": "__rshift__",   "llvm": "ashr", "op": '>>s'     }, # 算数右移
        "lsl":      {"claripy": "__lshift__",   "llvm": "shl",  "op": '<<'      }, # 逻辑左移
        "ror":      {"claripy": "RotateRight",  "llvm": "?",    "op": '>>>'     },
        "rol":      {"claripy": "RotateLeft",   "llvm": "?",    "op": '<<<'     },
    }
    op = name_dic[name]["op"]
    llvm_op = name_dic[name]["llvm"]
    # get machine code from llvm
    tm = target.create_target_machine()
    module = ir.Module()
    module.triple = triple
    fty = ir.FunctionType(ir.IntType(64), [ir.IntType(64), ir.IntType(64)])
    func = ir.Function(module, fty, name=name)
    block = func.append_basic_block(name="entry")
    builder = ir.IRBuilder(block)
    if name == "ror":
        bswap_ty = ir.FunctionType(ir.IntType(64), [ir.IntType(64), ir.IntType(64), ir.IntType(64)])
        bswap = ir.Function(module, bswap_ty, name="llvm.fshr.i64")
        ret = builder.call(bswap, [func.args[0], func.args[0], func.args[1]])
    elif name == "rol":
        bswap_ty = ir.FunctionType(ir.IntType(64), [ir.IntType(64), ir.IntType(64), ir.IntType(64)])
        bswap = ir.Function(module, bswap_ty, name="llvm.fshl.i64")
        ret = builder.call(bswap, [func.args[0], func.args[0], func.args[1]])
    else:
        ret = getattr(builder, llvm_op)(*func.args)
    builder.ret(ret)
    mod = binding.parse_assembly(str(module))
    mod.verify() 
    #print(tm.emit_assembly(mod))
    engine = binding.create_mcjit_compiler(mod, tm)
    func_ptr = engine.get_function_address(name)
    bs = ctypes.string_at(func_ptr, 32)
    func_bs = bs[:bs.find(b"\xc0\x03\x5f\xd6") + 4]
    # init claripy
    claripy_op = name_dic[name]["claripy"]
    if hasattr(x0, claripy_op):
        expr = getattr(x0, claripy_op)(x1)
    else:
        expr = getattr(claripy, claripy_op)(x0, x1)
    # get result
    a1 = random.randint(0, 0x7fffffffffffffff)
    a2 = random.randint(0x8000000000000000, 0xffffffffffffffff)
    b1 = random.randint(0, 0x7fffffff)
    b2 = random.randint(0x80000000, 0xffffffff)
    if name in ["lsr", "asr", "lsl", "ror", "rol"]:
        b1 = random.randint(1, 63)
        b2 = random.randint(1, 63)
    for a, b in [(a1, b1), (a1, b2), (a2, b1), (a2, b2)]:
        emu.mem_write(code_base, func_bs)
        emu.reg_write(UC_ARM64_REG_X0, a)
        emu.reg_write(UC_ARM64_REG_X1, b)
        emu.reg_write(UC_ARM64_REG_PC, code_base)
        emu.emu_start(code_base, code_base + len(func_bs) - 4)
        r = emu.reg_read(UC_ARM64_REG_X0)
        print(f"llvm: {a} {op} {b} = {r}")
        r = s.eval(expr, 1, extra_constraints=[x0 == a, x1 == b])[0]
        print(f"claripy: {a} {op} {b} = {r}")

def test_3op(name):
    name_dic = {
        "extract":  {"claripy": "?",    "llvm": "?",    "op": 'extract' },
    }
    op = name_dic[name]["op"]
    llvm_op = name_dic[name]["llvm"]
    # get machine code from llvm
    tm = target.create_target_machine()
    module = ir.Module()
    module.triple = triple
    fty = ir.FunctionType(ir.IntType(64), [ir.IntType(64), ir.IntType(64), ir.IntType(64)])
    func = ir.Function(module, fty, name=name)
    block = func.append_basic_block(name="entry")
    builder = ir.IRBuilder(block)
    if name == "extract":
        x, lsb, width = func.args
        # func1
        one = ir.Constant(ir.IntType(64), 1)
        mask = builder.sub(builder.shl(one, width), one)
        shifted = builder.lshr(x, lsb)
        ret = builder.and_(shifted, mask)
        # func2
        #c_64 = ir.Constant(ir.IntType(64), 64)
        #rshift_nbit = builder.sub(c_64, width)
        #lshifted = builder.shl(x, builder.sub(rshift_nbit, lsb)) # x << (64 - width - lsb)
        #ret = builder.lshr(lshifted, rshift_nbit) # x >> (64 - width)
    else:
        raise Exception("unimplemented")
    builder.ret(ret)
    mod = binding.parse_assembly(str(module))
    mod.verify()
    #print(tm.emit_assembly(mod))
    engine = binding.create_mcjit_compiler(mod, tm)
    func_ptr = engine.get_function_address(name)
    bs = ctypes.string_at(func_ptr, 32)
    func_bs = bs[:bs.find(b"\xc0\x03\x5f\xd6") + 4]
    # init claripy
    a1 = random.randint(0x8fffffffffffffff, 0xffffffffffffffff)
    b1 = random.randint(0, 64 - 1) # lsb
    c1 = random.randint(1, 64 - b1) # width
    if name == "extract":
        expr1 = claripy.Extract(b1 + c1 - 1, b1, x0)
        expr = claripy.ZeroExt(64 - c1, expr1)
    else:
        raise Exception("unimplemented")
    # get result
    for a, b, c in [(a1, b1, c1)]:
        emu.mem_write(code_base, func_bs)
        emu.reg_write(UC_ARM64_REG_X0, a)
        emu.reg_write(UC_ARM64_REG_X1, b)
        emu.reg_write(UC_ARM64_REG_X2, c)
        emu.reg_write(UC_ARM64_REG_PC, code_base)
        emu.emu_start(code_base, code_base + len(func_bs) - 4)
        r = emu.reg_read(UC_ARM64_REG_X0)
        print(f"llvm: {op}({a}, {b}, {c}) = {r}")
        r = s.eval(expr, 1, extra_constraints=[x0 == a])[0]
        print(f"claripy: {op}({a}, {b}, {c}) = {r}")

def test_cmp(name):
    name_dic = {
        "eq":   {"claripy": "__eq__",   "llvm": "==",   "op": '=='  },
        "ne":   {"claripy": "__ne__",   "llvm": "!=",   "op": '!='  },
        "slt":  {"claripy": "SLT",      "llvm": "<",    "op": '<s'  },
        "ult":  {"claripy": "ULT",      "llvm": "<",    "op": '<'   },
        "sle":  {"claripy": "SLE",      "llvm": "<=",   "op": '<=s' },
        "ule":  {"claripy": "ULE",      "llvm": "<=",   "op": '<='  },
        "sgt":  {"claripy": "SGT",      "llvm": ">",    "op": '>s'  },
        "ugt":  {"claripy": "UGT",      "llvm": ">",    "op": '>'   },
        "sge":  {"claripy": "SGE",      "llvm": ">=",   "op": '>=s' },
        "ule":  {"claripy": "ULE",      "llvm": ">=",   "op": '>='  },
    }
    op = name_dic[name]["op"]
    llvm_op = name_dic[name]["llvm"]
    # get machine code from llvm
    tm = target.create_target_machine()
    module = ir.Module()
    module.triple = triple
    fty = ir.FunctionType(ir.IntType(64), [ir.IntType(64), ir.IntType(64)])
    func = ir.Function(module, fty, name=name)
    block = func.append_basic_block(name="entry")
    builder = ir.IRBuilder(block)
    if name.startswith("S"):
        cmp = builder.icmp_signed(llvm_op, func.args[0], func.args[1])
        ret = builder.zext(cmp, ir.IntType(64))
    else:
        cmp = builder.icmp_unsigned(llvm_op, func.args[0], func.args[1])
        ret = builder.zext(cmp, ir.IntType(64))
    builder.ret(ret)
    mod = binding.parse_assembly(str(module))
    mod.verify()
    #print(tm.emit_assembly(mod))
    engine = binding.create_mcjit_compiler(mod, tm)
    func_ptr = engine.get_function_address(name)
    bs = ctypes.string_at(func_ptr, 32)
    func_bs = bs[:bs.find(b"\xc0\x03\x5f\xd6") + 4]
    # init claripy
    claripy_op = name_dic[name]["claripy"]
    cond = getattr(x0, claripy_op)(x1)
    expr = claripy.If(cond, BVV(1, 64), BVV(0, 64))
    # get result
    a1 = random.randint(0, 0x7fffffffffffffff)
    a2 = random.randint(0x8000000000000000, 0xffffffffffffffff)
    b1 = random.randint(0, 0x7fffffffffffffff)
    b2 = random.randint(0x8000000000000000, 0xffffffffffffffff)
    if name in ["eq", "ne"]:
        b1 = a1
    for a, b in [(a1, b1), (a1, b2), (a2, b1), (a2, b2)]:
        emu.mem_write(code_base, func_bs)
        emu.reg_write(UC_ARM64_REG_X0, a)
        emu.reg_write(UC_ARM64_REG_X1, b)
        emu.reg_write(UC_ARM64_REG_PC, code_base)
        emu.emu_start(code_base, code_base + len(func_bs) - 4)
        r = emu.reg_read(UC_ARM64_REG_X0)
        print(f"llvm: {a} {op} {b} = {r}")
        r = s.eval(expr, 1, extra_constraints=[x0 == a, x1 == b])[0]
        print(f"claripy: {a} {op} {b} = {r}")

#test_1op("invert")
#test_1op("neg")
#test_1op("reverse")

#test_2op("add")
#test_2op("sub")
#test_2op("mul")
#test_2op("div")
#test_2op("mod")
#test_2op("and")
#test_2op("or")
#test_2op("lsr")
#test_2op("asr")
#test_2op("lsl")
#test_2op("rol")

#test_3op("extract")
#test_cmp("eq")
#test_cmp("ne")
#test_cmp("slt")
#test_cmp("ult")
#test_cmp("sle")
#test_cmp("ule")
#test_cmp("sgt")
#test_cmp("ugt")
#test_cmp("sge")
#test_cmp("ule")
  • 第二步,使用Claripy生成定理,并应用到SLLVM
回复

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2025-12-2 18:51 , Processed in 0.039789 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表