吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7602|回复: 7
收起左侧

[Android 原创] 基于Miasm符号执行移除OLLVM虚假控制流

  [复制链接]
coldnight 发表于 2019-7-23 21:22
本帖最后由 coldnight 于 2019-7-23 21:29 编辑

背景

分析被OLLVM混淆后的样本,该样本开启了虚假控制流保护。编译器会在正常的控制流中会通过不透明谓词添加额外控制流块阻止静态分析。人工去除该保护较简单,本文期望自动化去除虚假控制流,减少人力。例如:
sub_27810
1561982954751.png
代码块1中的y_149_ptr值为变量y_149的地址,还有其他以x_num或y_num为名称的变量:
1561983871211.png
在程序运行时,这些变量(x_num)初始化为0。因此代码块1中[eax]的值为0,jl跳转永远成立,代码块2和3不会被执行。此外代码块2中的jz跳转也永远成立。
代码块3中的指令add esp, 2E68B6h阻碍了静态分析,使IDA F5功能失效:
1562748741700.png

分析

手动修复:
  • 虚假控制流:代码块1中jl改为jmp,同时以NOP填充代码块2和3。
自动修复:
对于仅使用虚假控制流混淆的样本,需要识别jl测试条件是否为不透明谓词,如果是则修改jl为jmp即可。对于jz也如此。在去除jx等测试条件后,遍历所有基本块,未被遍历的块即为虚假控制流生成的块,可以去除。

实现
Miasm 2.0是一款逆向工程框架,提供了基于IR的符号执行引擎。在Miasm中,jl的测试条件的IR可以表示为:(@32[@32[x_ptr]] <s 0xA)?(addr_succ, addr_fail)即在地址x_ptr读取32位整数值a,以a作为地址,读取32位整数b,如果b < 0xA,则跳转到addr_succ,否则跳转到addr_fail。构造以下表达式匹配测试条件
[Python] 纯文本查看 复制代码
ptr_jk = ExprId("x_ptr", 32)
memop = ExprMem(ExprMem(ptr_jk, 32), 32)
j_succ_jk = ExprId("addr_succ", 32)
j_fail_jk = ExprId("addr_fail", 32)
to_match = ExprCond(ExprOp("<s", memop, ExprInt(0xA, 32)), j_succ_jk, j_fail_jk)

如果地址的名称以x.或y.开头,则认为是不透明谓词的变量:
[Python] 纯文本查看 复制代码
def is_dummy_var(s):  # type: (str) -> bool
    return s.startswith("x.") or s.startswith("y.")

使用符号执行引擎执行基本块,匹配基本块的分支条件,如果属于不透明谓词,则修改跳转指为为JMP即可:
[Python] 纯文本查看 复制代码
loc = todo.pop()  # 获得未遍历的基本块nxt_addr = sb.run_block_at(ircfg, loc)
r = match_expr(nxt_addr, to_match, [mem_addr_jk, jl_dst_jk, njl_dst_jk])
if r and any(filter(is_dummy_var, loc_db.get_location_names(ircfg.get_loc_key(r[mem_addr_jk])))) \
and isinstance(r[jl_dst_jk], ExprInt):
    # 不透明谓词 生成补丁
    ablk = asmcfg.loc_key_to_block(loc_db.get_offset_location(offset))  # type: AsmBlock
    j_asm = ablk.lines[-1]  # type: instruction 汇编语句块最后一行即为跳转指令
    j_offset = j_asm.offset
    j_size = len(j_asm.b)
    j_dst = int(r[jl_dst_jk])  # addr_succ
    # 生成JMP addr_succ的op_code
    new_j_asm = gen_j_ins("JMP", j_dst, j_offset, j_size, strict=True)
    patches.append((j_offset, new_j_asm))
    todo.add(ExprInt(j_dst, 32))  # 遍历下一基本块
else:
    for dst in possible_values(nxt_addr):
        value = dst.value
        if value.is_mem():
            logging.warning('Bad destination: %s', value)
            continue
        todo.add(value)  # 添加所有应遍历的分支基本块
遍历完成后未被未遍历的块属于虚假控制流,可以清空:
[Python] 纯文本查看 复制代码
for ablk in asmcfg.blocks:
    blk_off = loc_db.get_location_offset(ablk.loc_key)
    if ExprInt(blk_off, 32) not in visited_asm_blk:
        b_start, b_end = ablk.get_range()
        patches.append((b_start, bytes(NOP_B * (b_end - b_start))))  # 以nop清空

效果
去除不透明谓词前(手动删除阻止F5的语句):
1562748940811.png

去除后:
1562749056561.png

免费评分

参与人数 5威望 +1 吾爱币 +11 热心值 +4 收起 理由
LQMIKU + 1 + 1 太强了!
一夜梦惊人 + 1 我很赞同!
Hmily + 1 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
qq3bot + 1 + 1 谢谢@Thanks!
nj001 + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

hlrlqy 发表于 2019-7-24 11:09
以前也看过用这个东西搞OLLVM的,不过还是楼主的帖子看起来浅显易懂
数据摧毁 发表于 2019-7-24 14:40
smartdone 发表于 2019-7-24 15:28
yaoyao7 发表于 2019-10-21 13:05
感谢师傅,刚好在看ollvm,学习流
dolphinzhu 发表于 2020-9-22 09:42
符号执行的资料太少了,非常感谢! 正在学习!
o10pwno 发表于 2020-12-14 15:14
https://blog.quarkslab.com/deobfuscation-recovering-an-ollvm-protected-program.html 这里还有一篇古老的去混淆
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-6 07:36

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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