吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4640|回复: 17
收起左侧

[Android 原创] 基于IDA Python的OLLVM反混淆(四) 实战拼某某混淆

  [复制链接]
Shocker 发表于 2021-9-12 11:34

前言

最后一次炒冷饭,这次以拼某某为例分析arm指令下的ollvm去混淆
拼某某版本(3.66.0)

实验环境

1.Android真机(Android5.1)
2.ida7.5
3.win10

过程

与x86的反混淆类型,思路还是找出所有控制块,对真实块下断点,记录断点执行顺序,之后连接真实块.
以JNI_OnLoad为例.
cfg0.jpg

找出所有控制块

控制块的特征比较明显,就是对内存基本上没有操作.
1. 1631240175(1).jpg
2. 1.jpg
3. 2.jpg
4. 3.jpg
5. 4.jpg
6. 5.jpg

........

ida python脚本

这里对部分进行说明

def dbg_process_attach(self, pid, tid, ea, name, base, size):
        print("Process attach pid=%d tid=%d ea=0x%x name=%s base=%x size=%x" % (pid, tid, ea, name, base, size))
        self.pre_block=None
        self.related_dict=dict()
        self.block_addr_dict=dict()
        so_base=idaapi.get_imagebase()
        self.f_blocks = idaapi.FlowChart(idaapi.get_func(so_base+fun_offset), flags=idaapi.FC_PREDS)
        for block in self.f_blocks:
            start=block.start_ea
            end=idc.prev_head(block.end_ea)
            # 排除所有的控制块
            if  (end==start) or\
                (idc.print_insn_mnem(start)=='LDR' and idc.print_insn_mnem(idc.next_head(start)).startswith('B')) or \
                (idc.print_insn_mnem(start)=='LDR' and idc.print_insn_mnem(idc.next_head(start))=='CMP' and idc.print_insn_mnem(idc.next_head(idc.next_head(start)))=='MOV' and idc.print_insn_mnem(idc.next_head(idc.next_head(idc.next_head(start)))).startswith('B')) or\
                (idc.print_insn_mnem(start)=='CMP' and idc.print_insn_mnem(idc.next_head(start))=='MOV' and idc.print_insn_mnem(idc.next_head(idc.next_head(start))).startswith('B')) or \
                (idc.print_insn_mnem(start)=='MOV' and idc.print_insn_mnem(idc.next_head(start))=='CMP' and idc.print_insn_mnem(idc.next_head(idc.next_head(start))).startswith('B')) or \
                (idc.print_insn_mnem(start)=='LDR' and idc.print_insn_mnem(idc.next_head(start))=='CMP' and idc.print_insn_mnem(idc.next_head(idc.next_head(start))).startswith('B')) or \
                (idc.print_insn_mnem(start)=='CMP' and idc.print_insn_mnem(idc.next_head(start)).startswith('B')) or \
                (idc.print_insn_mnem(start)=='LDR' and idc.print_insn_mnem(idc.next_head(start))=='CMP' and idc.print_insn_mnem(idc.next_head(idc.next_head(start)))=='MOV'\
                and idc.print_insn_mnem(idc.next_head(idc.next_head(idc.next_head(start)))).startswith('LDR')  \
                and idc.print_insn_mnem(idc.next_head(idc.next_head(idc.next_head(idc.next_head(start))))).startswith('B')
                ) or\
                (idc.print_insn_mnem(start)=='LDR' and idc.print_insn_mnem(idc.next_head(start))=='CMP' and idc.print_insn_mnem(idc.next_head(idc.next_head(start)))=='LDR'\
                and idc.print_insn_mnem(idc.next_head(idc.next_head(idc.next_head(start)))).startswith('B') 
                ):
                continue
            add_bpt(end,0,BPT_SOFT)
            while start<block.end_ea:   #对POP下断点 相当于x86的retn
                if idc.print_insn_mnem(start).startswith('POP'):
                    add_bpt(start,0,BPT_SOFT)
                    break
                start=idc.next_head(start)

这段代码是ida附加进程执行的代码,排除所有控制块代码,对真实块下断点

def dbg_process_exit(self, pid, tid, ea, code):#调试退出时执行
        print("Process exited pid=%d tid=%d ea=0x%x code=%d" % (pid, tid, ea, code))
        for ea in self.related_dict:
            if len(self.related_dict[ea])==1:
                if idc.print_insn_mnem(ea).startswith('B'):
                    disasm='B'+' '+hex(self.related_dict[ea].pop())
                    patcher.patch_code(ea,disasm,patcher.syntax,True,False)
                else:
                    disasm='B'+' '+hex(self.related_dict[ea].pop())
                    patcher.patch_code(idc.next_head(ea),disasm,patcher.syntax,True,False)
            else:
                print(ea,self.related_dict[ea])#该真实块有两个后继真实块,要手动patch

这段代码是退出调试执行,连接所有真实块,对于有两个后继真实块的块需要自行手动修改.

动态调试

1.将ida文件夹dbgsrv的android_server传入手机端,改变文件权限

adb push android_server /data/local/tmp/android_server
adb shell
su
chmod 777 /data/local/tmp/android_server
/data/local/tmp/android_server

2.adb端口转发

adb forward tcp:23946 tcp:23946

3.打开ddms

4.ida载入python脚本,附加进程,,ddms运行
ida.jpg
ida2.jpg

jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8700

5.运行直到retn块后,结束调试
1631414896(1).jpg

去混淆结果

1631358122(1).jpg
F5后结果
res.jpg

写在最后

基于ida的ollvm有一定的局限性,比如要处理反调试,还需要可调试的真机.
较好的方案可以使用unidbg(动态调试)代替
github地址:
https://github.com/PShocker/de-ollvm-arm

免费评分

参与人数 6威望 +1 吾爱币 +25 热心值 +6 收起 理由
#sky# + 1 + 1 热心回复!
jafck + 1 + 1 用心讨论,共获提升!
笙若 + 1 + 1 谢谢@Thanks!
qtfreet00 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
xiudi + 1 + 1 我很赞同!
chenjingyes + 1 + 1 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

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

huhuf6 发表于 2021-9-12 13:28
Shocker 发表于 2021-9-12 13:22
对,这个方法有一定的局限性.但相比其他大神的反混淆脚本,这个应该是最通俗易懂的.

目前我是用angr实现了armv7的fla还原,但是bcf还没有怎么研究,楼主对bcf了解吗,我想把这两个弄在一个脚本里还原
 楼主| Shocker 发表于 2021-9-12 13:22
huhuf6 发表于 2021-9-12 13:13
楼主看了一下你都样本,是纯arm32不带thumb指令的,如果带thumb指令的话应该还有蛮多坑的,如果是在动态调 ...

对,这个方法有一定的局限性.但相比其他大神的反混淆脚本,这个应该是最通俗易懂的.
meichangsu 发表于 2021-9-12 12:23
诅咒者之魂 发表于 2021-9-12 12:45
感谢楼主分享
huhuf6 发表于 2021-9-12 13:13
楼主看了一下你都样本,是纯arm32不带thumb指令的,如果带thumb指令的话应该还有蛮多坑的,如果是在动态调试的时候执行patch的话,是不是就原本没有执行的块就被nop掉了?
chenjingyes 发表于 2021-9-12 18:57
谢谢楼主分享
yyb414 发表于 2021-9-12 19:00

谢谢楼主分享
Forgo7ten2020 发表于 2021-9-13 10:15
请问楼楼idpython有没有什么好的教程?官方的api文档比较难查阅啊
 楼主| Shocker 发表于 2021-9-13 10:41
Forgo7ten2020 发表于 2021-9-13 10:15
请问楼楼idpython有没有什么好的教程?官方的api文档比较难查阅啊

你可以看看这篇文章
基于python3.x IDAPython第二讲 段 函数 汇编指令等操作
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-28 05:43

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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