首页
社区
课程
招聘
[原创] 如何让IDA真正为你所用,OLLVM为何能魅惑IDA让它无法P出完整函数
发表于: 2021-8-25 18:26 10665

[原创] 如何让IDA真正为你所用,OLLVM为何能魅惑IDA让它无法P出完整函数

2021-8-25 18:26
10665

论两个生死冤家的前世今生

从PE时代流传下来的神器IDA,新生代的混淆神器OLLVM,他们之间的碰撞让逆向人员如何是好


ollvm混淆IDA无法精准识别函数末尾

当各位把各种CarckME分析的透透的时候,信心满满的准备进军大厂APK的时候,打开IDA拖入SO,定位JniOnload函数,F5,嗯????F5,F5,F5,F5
图片描述
图片描述

 

除非您的功力可以达到只看那令人头大的汇编代码,就能脑补翻译成C伪代码的地步,否则这种情况对逆向人员的打击不可谓不大.

 

但是碰到那种被OLLVM强混淆并且本身函数就超长的那种(笔者见过最多的一个被混淆的函数指令有26000+行)我相信就算您是神人也无法脑补!!!

 

其实,这就是OLLVM这个小坏蛋欺骗IDA的一个办法.

 

图片描述

 

如果你对x86指令集或者arm指令集的函数构成有所了解的话,你一定知道在未经特殊处理的编译器生成的函数汇编中,函数开头会保存现场,保存返回点,分配函数栈空间,而函数结尾会恢复函数栈空间,恢复现场,回到返回点.

 

而当前IDA分析出来竟然在0x4F64E就是返回点.这当然不可能啦!


如何查找函数尾部,并且修复,给IDA指定函数尾部

所以我们需要定位真正的函数返回值然后告诉笨笨的IDA,首先我们放出一个正常的未经过混淆的函数在IDA中的样子
图片描述

 

经过观察发现真正的函数结尾是在恢复现场,那我们就有理由说那个被欺骗的Jni_Onload的函数结尾应该是 POP {R4-R7,PC}

IDApy的妙用

如果说我们要手动找一个离自己最近的POP {R4-R7,PC}指令的话,那么请先看一张图
图片描述

 

这里面全部都是IDA无法识别的指令,需要我们手动alt+g设置为1然后再强行解释为code才能正常识别,然后还要翻过大篇的指令寻找我们要的指令

 

对于懒懒的我来说,我们必须找到一种能让不知疲倦的电脑帮我们干活的方法.
于是笔者找到了IDAPython
以及在线版的KeyStore将汇编指令转换为Hex机器码的工具

 

图片描述

 

在网站中输入我们的汇编指令,得到当前指令THUMB的opcode为F0BD ,为啥是THUMB呢 ,有基础的小伙伴应该知道ARM32有两种运行模式(ARM/THUMB),因为我们发现JniOnload中存在2字节的opcode以及经验来说,它一定用的THUMB指令集.

在ARM32下如何确定一个函数是ARM指令还是THUMB指令呢,最简单的就是把opcode翻译成arm指令,看哪一个更像真正的函数结构. 这种东西一眼就能看出来,所以不在赘述.

 

上脚本!!!

 

图片描述

 

设置起点以及分析长度开跑.然后你就能在IDA的输出窗口看到一大串函数地址

 

图片描述

 

正常来说第一个就是 我们直接双击进入0x50310
图片描述

 

发现它一定是JniOnload的返回值,因为它的条件完全符合JniOnload保存现场,创建栈空间的大小.

 

(函数结尾)0x50312 - (函数开始)0x4f620 = 3314

 

这么多指令我们要手动查找的话,着实得费一番功夫,现在我们知道了函数结尾的地方.

 

那我们现在P一下,嗯哼? 还是不行,根据IDA输出窗口的地方我们找到了
图片描述
重点看04FB0E这个地方 CBZ竟然跳到了一条指令中间???
他真是太坏了,正常这种指令是永远也不会走到的分支,但是它的存在就是为了欺骗IDA,像这种存在,我这个样本中还有很多处,时间关系大家要慢慢挖掘.我这里只是给一个思路,学习还要靠大家自己.ollvm其实并不可怕,大家加油
图片描述

 

既然遇见了,我们就patch一下 给他nop暂时.

 

图片描述

 

然后P一下就好啦,虽然还是有OLLVM的流程平坦化,指令替换,以及控制流伪造,但是至少我们能F5了不是.

 

有空我们再把去混淆脚本升级一下,让IDA更智能,更能让我们随心所用!!!


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-8-27 12:05 被至尊小仙侠编辑 ,原因:
收藏
免费 6
支持
分享
最新回复 (11)
雪    币: 576
活跃值: (2035)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享 
2021-8-25 19:13
0
雪    币: 2466
活跃值: (4550)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
我寻思不都是先去混淆吗?
2021-8-25 20:18
1
雪    币: 3064
活跃值: (7808)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
from idc import *
from idautils import *
from idaapi import *
from keystone import *


ks = Ks(KS_ARCH_ARM, KS_MODE_THUMB)
print("11111111")

def ks_disasm(dis_str):
    global ks
    encoding, count = ks.asm(dis_str)
    return encoding


func_start =0x1BA54   #函数起点
func_end = func_start+0x400  #定位长度

for i in range(func_start, func_end):
    # PUSH{R0-R3} or PUSH{R0-R3,R7}
    #if get_bytes(i, 2, 0) == b'\xf0\xbd':
    if get_bytes(i, 2, 0) == bytes(ks_disasm("POP       {R4-R7,PC}")):  #Push 换成Pop LR换成PC
        patch_start = i
        print(hex(patch_start))



最后于 2021-8-25 22:00 被至尊小仙侠编辑 ,原因:
2021-8-25 21:58
0
雪    币: 3064
活跃值: (7808)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
默NJ 我寻思不都是先去混淆吗?
先教简单的 去混淆我得梳理一下 怎么讲
2021-8-25 22:01
0
雪    币: 2458
活跃值: (3323)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
6
有没样本,发出来看一下
2021-9-7 19:02
0
雪    币: 2458
活跃值: (3323)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
另外我对2.6W行没什么概念,能说下大概有多大不,在IDA的符号窗口length?80K?
2021-9-7 19:04
0
雪    币: 3064
活跃值: (7808)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
8
baikaishiu 另外我对2.6W行没什么概念,能说下大概有多大不,在IDA的符号窗口length?80K?


F5后这么多行

2021-9-7 19:14
0
雪    币: 3064
活跃值: (7808)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
9
baikaishiu 有没样本,发出来看一下

0x152B0  偏移起始点在这里     end 在0x1BA54    大佬请过目

上传的附件:
2021-9-7 19:16
0
雪    币: 2458
活跃值: (3323)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
10
至尊小仙侠 0x152B0  偏移起始点在这里     end 在0x1BA54    大佬请过目
好的,谢谢
2021-9-7 21:39
0
雪    币: 248
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
cy
2021-9-8 17:50
0
雪    币: 754
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
04FB0E这个地方不知道是什么找出来的,样本的地址又和案例的地址不一样
2022-10-15 19:28
0
游客
登录 | 注册 方可回帖
返回
//