360脱壳分析

发布时间:2015-04-29 14:27:12   来源:文档文库   
字号:

360 so脱壳分析

1 修复错误的elf文件

首先我们将原始的libqihoo.so拖到IDA分析,发现IDA报如下两个错误:

第一个错误说明是节区头部表格的表项大小错误,第二个错误是节区头部表格的大小或偏移值错误。了解ELF的同学都知道这几个信息都包含ELFheader那么我们使用WinHex查看下此ELFheader即可:

Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F

00000000 7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00 ELF

00000010 03 00 28 00 01 00 00 00 00 00 00 00 34 00 00 00 ( 4

00000020 8C 11 02 00 00 00 00 05 34 00 20 00 07 00 6C 00 ? 4 l

00000030 66 00 78 00 06 00 00 00 34 00 00 00 34 00 00 00 f x 4 4

00000040 34 00 00 00 E0 00 00 00 E0 00 00 00 04 00 00 00 4 ? ?

00000050 04 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00

因为节区头部表的偏移值为0x2118c,所以根据ELF文件的结构,该偏移值开始到文件结尾的数据为整个节区头部表。由于节区头部表项的大小固定为0x28,所以我们可以由:(0x214fb - 0x2118c + 1)/0x28 = 0x16 得出真正的节区头部表项数目为0x16

下面再来看e_shstrndx字段,我们从ELF文件中可以明显地看出,字符串表节区为最后一个节区,所以它的索引值应当为0x15至此,ELF修复完毕。

然后我们将修复完毕的ELF拖到 IDA中发现不会报错了~

2 开始脱壳

IDA不报错,并不意味我们就可以开始痛快地分析了!我们在IDA查看导出函数发现JNI_Onloadverify函数

但是双击这两个函数发现代码是被加密过的 o(╯□╰)o

由于JNI_OnloadAndroid APK在加载so的时候第一个执行的函数,而此函数又被加密了,那么解密函数就只能在so的入口地址init.array处了。

定位到init.array节,发现了关键信息:

在上图中可以很明显地看到init.array会执行__gnu_armfinit_26函数下面就开始分析这个函数吧。此函数也是加入了大量花指令,我已经将去除花指令后的代码放在了附件中,大家可以参照附件中的init.txt文档继续阅读

大致流程就是:

①进行系统配置,为操作修改so文件准备

根据so中特定位置的字符串,构造转换表;

③以此转换表为基础,解密so文件中的0x176d c0x176dc+0x8aec的代码

了解了解密逻辑,我们就可以自己编写解密程序了。鉴于so的解密与前一帖子中计算序列号的算法是一样的,所以我们只需要对前一帖子中的代码进行更改即可详细代码见附件的unshell1.cpp

满心欢喜地解密so,以为大功告成,结果~~~

将解密后的so拖到IDA,通过EXPORT找到JNI_Onload

TMD还是密文!!!看来我们只脱了一层壳,还有其他壳等着我们啊~

问题来了,我用的IDA6.1并不能通过am start的方式在init.array下断点,而且我静态 分析__gnu_armfinit_26函数后就不知道它下一步会执行到哪了~~因为在__gnu_armfinit_26执行完后的指令如下

.text:000019A4 ; ---------------------------------------------------------------------------

.text:000019A4 STMFD SP!, {R0}

.text:000019A8 ANDEQ R6, R0, R7,ROR PC

.text:000019AC ADD R0, R0, #4

.text:000019B0 SUB R0, R0, #4

.text:000019B4 BX R0

.text:000019B4 ; --------------------------------------------------------------------------

静态分析根本得不到这坑爹的r7,r6的值,所以r0未知,所以就不知道它会跳转到哪儿去了~

就这么放弃?No!,喝杯咖啡继续刚正面!

3 人工智能发威,再脱一层壳

为什么说是人工智能呢?因为我无法动态跟踪,所以此时的分析已经告别各种黑科技,由我们的大脑接管后续工作了考虑到我在前一个帖子当中已经dump出来了完全脱壳后的so,那么我们有必要将只脱了一层壳的so其进行比较(当然,只需要比较0x176dc之后的0x8aec字节的16进制数据即可)找啊找,找啊找,还终于被我找出了第二层壳(个中辛酸,一言难尽)为了方便,我们将脱了一层壳的so称为unshell1.so,完全脱壳后的so称为NoShell.so

通过大量的对比,发现unshell1.so0x176dc0x210c8之间的16进制数据与NoShell.so有一个相同的区别前者较后者而言,每一个0x0A之前都有一个0x0D字节。

逻辑理清了之后,马上编写代码去掉这些多余的0x0D代码见附件unshell2.cpp

再将脱壳后的so拖到IDA中分析,发现绝大部分代码都已经解密了,只是JNI_Onload还是密文

其实到这里,关键代码基本都解密了(只剩下JNI_Onload没解密),脱壳工作也算完成了大半。本来想依葫芦画瓢搞定JNI_Onload的,不过对比了半天愣没看出个头绪,也就放弃了。

能在init.array下断点的同学可以自己跟一下,思路已经有了,这个应该不难,搞定之后,望告知~

4后记

此脱壳笔记主要用于学习so/相关的知识并不是以获取脱壳后so为目的(dump肯定省时又省力)另外,个人认为无论在java层做多大的加固工作都较容易被dump出来特别是有Xposed这种逆天神器存在,简直可以一秒钟变上帝(前段时间写了xposed插件,它的hook函数真是NB)所以以后的代码保护工作重点应该就是so的加壳处理以及VMP(我在这个so里看到了有操作/proc/pid/map的代码~不知道是不是360在测试Android上的VMP)

还有一点诡异的情况我使用unshell1.cpp中的文件操作代码(fopen,fread,fwrite之类)so0x176dc之后的0x8aec字节进行更改没问题。但同样的文件操作代码使用在unshell2.cpp用于删除0xd发现文件原封不动。这是为什么呢?

最后的最后,不知道哪位大侠的正版IDA能借我远程用一用~~屌丝学生,买不起啊~~

本文来源:https://www.2haoxitong.net/k/doc/12d085a93186bceb19e8bb91.html

《360脱壳分析.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式