360加固保分析
2020-06-15 23:21:07 Author: bbs.pediy.com(查看原文) 阅读量:780 收藏

背景:

调试手机是Android 6.032位的手机。样本是自己写的一个经过360加固的小程序。加固时间为今年的5月份左右。

步骤:

总体来说就是分为两大步,首先是分析libjiagu.so,从中dump出第二个so,也就是解释器so,第二步就是修复分析解释器so,找到指令映射的对应关系,得出指令映射表。

第一步:

首先看一下.init_array做了什么事


可以看到这里只有一个函数,经过我的分析这里并没有做什么重要的事。

然后继续看JNI_OnLoad区域。

发现是这样子的,然后我们的静态分析就变得困难了,只能开始我们的动态调试之旅了。

通过动态调试我从JNI_OnLoad一路跟到这个重要的函数,_Z10__fun_a_18Pcj

可以看到这个函数被混淆的非常严重。但是经过我的分析有用的分支基本只有case31case35两个分支。这里可以说一下case31是一个反调试的分支,case35是进入第二个so的入口,别的分支有的也做了一些事,但是对于我们来说用处不大。

反调试:

我们可以在这里下断,然后跟随R0寄存器。如图

这个版本的一共有三个反调试的点,一个是符号,一个是端口,一个是时间。

此处为第一个反调试了。

我们可以在内存窗口修改指令,改成无用指令。

第一个反调试之后,两次f9就是第二个反调试的点了,也就是时间反调试。

从这个跳转进入,即为时间调试。

在这里我们只需把R0寄存器置0就可以。

还有一个是端口检测,我们只需更改ida的默认调试端口就可以了。

到此,反调试告一段落。

接下来我们继续分析,sub_5CE8为第二个so加载的关键地方。

如图,这个是ida f5的结果。

但是我们会发现一个有趣的地方。

有没有觉得这个地方与Android源码中加载so的函数有点相似。

在这个函数断下就可以dump第二个so

但是可惜的是它并没有走这个分支,而是这个分支

sub_540C这个函数一共要解密四个部分,分别为程序头表、JMPREL、RELA、DYNAMIC

一个循环即为一部分。我们把这四部分dump出来。

R7寄存器地址即为整个第二个so的开始地址,我们可以把整个malloc的区域全dump下来。

需要注意的是

一定要在这个循环执行完之后dump,即解密完。

在这里说一下如何修复,因为这个so没有elf_header,所以需要我们自己修复,并且把其他三部分放到原来的地方。在这里特别说一下,R7寄存器为so的开始地址,R1寄存器为此部分在so的偏移,R0为要解密的数据大小。如此,我们可以修复解释器so

总结一下,我们把dump出来的四部分按照偏移直接覆盖到dump出来的so中就可以,因为我们dump出来的so的那四部分并未解密。但是需要注意先修复elf_header

第二步:

按惯例来分析init_array区域,经过分析init_array区域并没有做什么重要的事情。

然后分析JNI_OnLoad,这个函数做了很多事情,最重要的就是注册stub方法和dex的加载。

Dex的加载在这里完成

通过动态调试我们进入这个函数sub_1A104。这个函数很长,完成dex的一系列操作。

对了忘记说了,我们可以通过case35分支进入第二个so

因为我们的目标不是dump dex 这里dex的加载就不多说了,直接分析被native化的函数如何还原。

分析我们dumpdex会发现这样的现象,


这里有个interface11 那么这个动态注册的函数就是我们的切入点。

但是我们发现这个函数是这个样子的,

这个jumpout我确实解决的不是很好,就是静态分析和动态调试硬着头皮看的,我也试过网上分享的一些方法,但是效果都不怎么好。如果跳转的地方是连在一起的还好,可以进行patchp成一个函数,那样参数,变量还可以看,如果中间夹杂着别的东西,不能p成一个函数,那就是一团糟,索性我就这样看了。希望大佬能够在这里给点意见。

在这里说一下360 进行native化的函数都是绑定了同一个函数,类似于分发的作用。然后,经过分析找到这个函数,sub_BF75C。其实这个函数就是调用了sub_1C480

到这里我们进入正题,这个最重要的函数sub_1C480的分析。

我们悲剧的发现,这里跟前面一样,都被处理了。

幸好这个函数不是很长,我就一步步跟出来了。

然后进行jni接口的赋值,然后根据注册vmp方法时的描述信息执行哪条分支,

一种是直接将指令复制到原地方,然后用jni函数调用,调用完成后再将其清空。另一种方式是自己实现的解释器,边解密边解释执行,且解密后的指令也是替换过的

描述信息是这样的,

4F 3C 00 00 01 00 00 00  5C 60 1C 00 03 00 00 00

00 00 00 00 00 00 00 00  00 00 00 00 6D 07 00 00

00 00 00 00 00 00 00 00  00 00 00 00 65 78 00 00

4F 3C 00 00   methon_id

01 00 00 00   0为实例方法,1为静态方法

5C 60 1C 00   code_item在dex中的偏移

03 00 00 00   第几个方法

00 00 00 00   如果为0表示直接解密原来code_item中的指令执行,不为0则执行的时候,   把该处的指令复制到原来的code_item,执行完后又清除。  

其他字段意义就不是很大了。

接下来执行sub_1C51E,解析参数,分析类名和包名

再就是执行sub_1C5D0,根据是否为静态方法来分别走两个分支。

但是,最后都会执行到这个地方

这里是申请寄存器空间,将参数解析出来最后调用sub_2ABC8。

经过分析sub_37652函数为重点。

此处的描述信息为

54 B2 E5 A1 04 00 00 00  00 5D B1 AE C1 3B

54 B2 E5 A1 指向指令

04 00 00 00 这个字段还不知道代表什么

00 5D B1 AE 执行dex

C1 3B  method_id

C1 3B 这个是我的apk的oncreate方法的method_id

现在内存窗口是这样的

下一条指令

58-54=4

4即为上一条指令的长度。

后面就是根据op来对应指令执行了。因为是自己写的apkoncreate方法的smali指令都知道,所以分析指令映射表就比较容易点,到这里,我们就可以对应出指令映射表来了。

到此为止,我对这个数字壳的加固就分析完了。有感兴趣的大佬可以分析一下指令映射表。

最后,再奉上附件。

[培训]科锐逆向工程师培训(6月24日远程教学开班, 第38期)!

最后于 4天前 被[軍]编辑 ,原因:


文章来源: https://bbs.pediy.com/thread-260049.htm
如有侵权请联系:admin#unsafe.sh