首页
论坛
课程
招聘
[原创]使用ida trace来还原ollvm混淆的非标准算法
2021-1-5 23:48 7510

[原创]使用ida trace来还原ollvm混淆的非标准算法

2021-1-5 23:48
7510

这是3W班9月的题目。


题目使用ollvm混淆算法。

通过题目我掌握了IDA trace的使用方法,并灵活使用frida及调试等方式来获得中间状态来完成题目。

但是对常见算法不够熟悉,导致恢复了整个base64。这个工作量实际是可以省下的。


先拖进IDA看看,不是能简单逆向出来的。先上trace

 

拿到tracelog后,尝试从输出往前找。本次的输入输出如下:

按输出的字符搜索,经过几次尝试后,可定位到sub_7F0FA11764:loc_7F0FA1198C行就是生成输出的指令。和输出是完全一样的。

先看一下output[0]是怎么计算的。

分以下3步:

1、从一个0000007F0FA39010地址中的0x15偏移中取出一会字节。我直接静态看这个地址的值与取出的值是不对的,观察了init array,发现有大量的解密操作,估计在里面做了解密,我动态调了一下,得到0000007F0FA39010这个数组的值为:0123456789-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,此时值可以对应上了。

20x15的的计算是0x55>>2得到。

3、而0x55是从0000007F0F7CFDA0地址的0偏移中取出。0000007F0F7CFDA0暂时不知道是什么,暂称为middle数组。


为了便于计算,需要先得到这个middle数组的值,这个用trace不大好看,我在IDA中二进制逆向跟踪一下。其实就是sub_F04C的第一个参数a1

大概看一下整体的流程,在Java_com_kanxue_ollvm_1ndk_MainActivity_UUIDCheckSum这个函数中,input经过sub_1029c函数,生成v19。而v19就是一直透传到sub_F04C函数的a1

为了证明sub_F9B8v19的值与sub_F04C的值是一样的,我写frida脚本hook一下并打印内存,确实是一样的。

因此整个流程就比较清楚了,input处理成middle,再处理成output

第一次trace没有把这个参数记录下来,为了能更好地验证,再trace一次,并且写一个frida脚本,把这个a1地址的值取出来 。

脚本关键部分如下:

var base_xxx = Module.findBaseAddress("libnative-lib.so");
var sub_0xF04C = base_xxx.add(0xF04C);
Interceptor.attach(sub_0xF04C, {
            onEnter: function (args) {
                this.arg0 = args[0];
                this.arg1 = args[1];
                this.arg2 = args[2];
                console.log("addr:", sub_0xF04C, " onEnter \r\n", hexdump(this.arg0), "\r\n",this.arg1,"\r\n",  this.arg2);
            }, 
            onLeave: function (retval) {
        });

这次有input, middle,以及output的值了。

仍然从后往前恢复,先把middle转换成output部分恢复了。

发现这部分有4个规律,分别按模4,按余数为0123来处理。其中为0部分上面已经大概恢复了。这4个规律大同小异,按trace来恢复就行了,不一一细讲,其中对middle下标的处理有点小trick,我被卡了一下。

sub_F04C的伪码其实可看出来,每次index是加3的。


最终恢复成python代码如下:

tab10="0123456789-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
output=""
i=-1
while i < 47:
  #print(output)
  i=i+1
  #print("index:",i)
  if i % 4==0:
    plus =int( (i / 4)*3)   
    tmp=ord(middle[plus])>>2
    output=output+tab10[tmp]
    continue
  if i %4 ==1:
    plus =int( (i / 4)*3)   
    tmp=ord(middle[plus])
    #print(tmp)
    tmp=0x10*(tmp&0x3)
    #print(tmp)
    tmp = tmp | ord(middle[1+plus])>>4
    output=output+tab10[tmp]
    continue
  if i % 4==2:    
    plus =(int(i / 4))
    plus=plus*3
    #print("plus:",plus)
    tmp=ord(middle[1+plus])
   # print(tmp)
    tmp=4*(tmp & 0xf)
   # print(tmp)
    tmp=tmp | (ord(middle[2+plus])>>6)
    output=output+tab10[tmp]
    continue
  if i % 4==3:
    plus =int( (i / 4)*3) 
    #print(plus)
    tmp=ord(middle[plus])&0x3f
    #print(tmp)
    output=output+tab10[tmp]
    continue
print(output)

剩下就是逆向inputmiddle的部分。

 

类似的,在新的trace文件中,取input的字符来搜索(前面要添加0,不然结果太多)。找到处理input的地方。处理如下,取出input并异或1


我是结合traceida一起分析的。在sub_FCB4函数中。

其中这里的混淆强度加的不大,是可以直接看的。

一般流程是直接异或,并写回input中(middle没新申请内存,使用input的空间)

并且也很容易看出,下标为8,0xd,0x12,0x180xE位的处理比较特殊。先看下标为8,0xd,0x12,0x18的情况,这里只加了控制流程平坦化,v8这个状态可以跟踪到最终的处理(其他的分支也是类似的)。

根据v8的状态值,可一直跟到此处,这些下标的值直接改为-

类似地,下标为0xe的位,可看到最终被赋值为“4”。

 

而最终2位处理如下,其中v14v16是之前非特殊处理位的累异或和累加实现

v14v16的初值分别为0xff0

Xmmword_37060同样被加密了,我动态取出它的值:"0123456789abcdef"

理论上,这个mikddle数组应该就完成了。但是实际上,第0x17位的值是不对的(最后2位也是,但是因为有累积的因素,因此先忽略)。而看代码,0x17这个下标并没有特殊处理。

此时再trace看一下,发现这个输入数组和input并不是完全一致的。17位的值被18位的值覆盖了……

如果细心点是可以看到如下一句代码……。此时就真的完全搞定了。


贴出完整代码:

tab_1="0123456789abcdef"
input="DKR0hQV5ZzqM3v8kMdRYZ9qbhCFqSruTvdoQ"
#input: WnD6JZC9NilAwTPEUXbXhZSykE4mCqP0sRRM output:   jAX5bOHpexuHo6P0rwOOf5fn_jzDkP9E_iePp49Kih5MiNiS
 
middle=""
tmp1=0xff
tmp2=0
for i in range(len(input)-2):
  if i == 8 or i == 0xd or i == 0x12 or i ==0x18:
    middle=middle+"-"
    continue
  if i==0xe:
    middle=middle+"4"
    continue
  if i == 0x17:
    middle=middle+chr(ord(input[i+1]) ^ 1)
    tmp1=tmp1 ^ ord(input[i+1])
    tmp2=tmp2 + ord(input[i+1])
    continue
  middle=middle+chr(ord(input[i]) ^ 1)
  tmp1=tmp1 ^ ord(input[i])
  tmp2=tmp2 + ord(input[i])
tmp2=tmp2 - (tmp2 & 0xFFFFFFF0)
tmp1=(tmp1&0xf)
#print(tmp1,tmp2)
middle=middle+tab_1[tmp2]+tab_1[tmp1]
print("middle array:")
print(middle)
tab10="0123456789-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
output=""
i=-1
while i < 47:
  #print(output)
  i=i+1
  #print("index:",i)
  if i % 4==0:
    plus =int( (i / 4)*3)   
    tmp=ord(middle[plus])>>2
    output=output+tab10[tmp]
    continue
  if i %4 ==1:
    plus =int( (i / 4)*3)   
    tmp=ord(middle[plus])
    #print(tmp)
    tmp=0x10*(tmp&0x3)
    #print(tmp)
    tmp = tmp | ord(middle[1+plus])>>4
    output=output+tab10[tmp]
    continue
  if i % 4==2:    
    plus =(int(i / 4))
    plus=plus*3
    #print("plus:",plus)
    tmp=ord(middle[1+plus])
   # print(tmp)
    tmp=4*(tmp & 0xf)
   # print(tmp)
    tmp=tmp | (ord(middle[2+plus])>>6)
    output=output+tab10[tmp]
    continue
  if i % 4==3:
    plus =int( (i / 4)*3) 
    #print(plus)
    tmp=ord(middle[plus])&0x3f
    #print(tmp)
    output=output+tab10[tmp]
    continue
print(output)







[2022夏季班]《安卓高级研修班(网课)》月薪两万班招生中~

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (2)
雪    币: 2344
活跃值: 活跃值 (581)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mfkiwl 活跃值 2021-1-7 20:20
2
0
mark. 跟大神学习
雪    币: 10010
活跃值: 活跃值 (4629)
能力值: ( LV11,RANK:198 )
在线值:
发帖
回帖
粉丝
neilwu 活跃值 1 2021-11-5 17:06
3
0

去混淆之后,算法还是挺明显的

游客
登录 | 注册 方可回帖
返回