使用IDA trace来还原ollvm混淆的非标准算法
2021-01-09 18:58:00 Author: mp.weixin.qq.com(查看原文) 阅读量:149 收藏

本文为看雪论坛优秀文章

看雪论坛作者ID:pass_

这是3W班9月的题目。
题目使用ollvm混淆算法。
通过题目我掌握了IDA trace的使用方法,并灵活使用frida及调试等方式来获得中间状态来完成题目。
但是对常见算法不够熟悉,导致恢复了整个base64。这个工作量实际是可以省下的。
先拖进IDA看看,不是能简单逆向出来的。先上trace。
 
拿到trace的log后,尝试从输出往前找。本次的输入输出如下:
按输出的字符搜索,经过几次尝试后,可定位到sub_7F0FA11764:loc_7F0FA1198C行就是生成输出的指令。和输出是完全一样的。
先看一下output[0]是怎么计算的。
分以下3步:
1、从一个0000007F0FA39010地址中的0x15偏移中取出一会字节。我直接静态看这个地址的值与取出的值是不对的,观察了init array,发现有大量的解密操作,估计在里面做了解密,我动态调了一下,得到0000007F0FA39010这个数组的值为:”0123456789-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ”,此时值可以对应上了。
2、0x15的的计算是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_F9B8的v19的值与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,按余数为0,1,2,3来处理。其中为0部分上面已经大概恢复了。这4个规律大同小异,按trace来恢复就行了,不一一细讲,其中对middle下标的处理有点小trick,我被卡了一下。
看sub_F04C的伪码其实可看出来,每次index是加3的。
最终恢复成python代码如下:
tab10="0123456789-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";output=""i=-1while 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]    continueprint(output)
剩下就是逆向input到middle的部分。 
类似的,在新的trace文件中,取input的字符来搜索(前面要添加0,不然结果太多)。找到处理input的地方。处理如下,取出input并异或1。
我是结合trace和ida一起分析的。在sub_FCB4函数中。
其中这里的混淆强度加的不大,是可以直接看的。
一般流程是直接异或,并写回input中(middle没新申请内存,使用input的空间)
并且也很容易看出,下标为8,0xd,0x12,0x18和0xE位的处理比较特殊。先看下标为8,0xd,0x12,0x18的情况,这里只加了控制流程平坦化,v8这个状态可以跟踪到最终的处理(其他的分支也是类似的)。
根据v8的状态值,可一直跟到此处,这些下标的值直接改为”-”。
类似地,下标为0xe的位,可看到最终被赋值为“4”。
而最终2位处理如下,其中v14和v16是之前非特殊处理位的累异或和累加实现。
而v14和v16的初值分别为0xff和0。
Xmmword_37060同样被加密了,我动态取出它的值:"0123456789abcdef"。
理论上,这个mikddle数组应该就完成了。但是实际上,第0x17位的值是不对的(最后2位也是,但是因为有累积的因素,因此先忽略)。而看代码,0x17这个下标并没有特殊处理。
此时再trace看一下,发现这个输入数组和input并不是完全一致的。17位的值被18位的值覆盖了……
如果细心点是可以看到如下一句代码……此时就真的完全搞定了。

贴出完整代码:
tab_1="0123456789abcdef"input="DKR0hQV5ZzqM3v8kMdRYZ9qbhCFqSruTvdoQ"#input: WnD6JZC9NilAwTPEUXbXhZSykE4mCqP0sRRM output:   jAX5bOHpexuHo6P0rwOOf5fn_jzDkP9E_iePp49Kih5MiNiS  middle=""tmp1=0xfftmp2=0for 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=-1while 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]    continueprint(output)

- End -

看雪ID:pass_

https://bbs.pediy.com/user-home-897363.htm

  *本文由看雪论坛 pass_ 原创,转载请注明来自看雪社区。

 安卓应用层抓包通杀脚本发布!

《高研班》2021年3月班正在火热招生中!👇


* 戳图片了解详情

# 往期推荐

公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458379394&idx=1&sn=9f027c7afc61fa9a01fb10e8c7202a81&chksm=b180d40886f75d1ecdb9ba8e25488f70a36dd162ec5eed70fe4c1579b205bd94084f426458b3#rd
如有侵权请联系:admin#unsafe.sh