首页
社区
课程
招聘
[原创]Android加壳与脱壳(11)——不落地加载壳的对抗研究
2023-5-21 16:37 11853

[原创]Android加壳与脱壳(11)——不落地加载壳的对抗研究

2023-5-21 16:37
11853

Android加壳与脱壳(11)——不落地加载的对抗研究

目录

1
声明:本文所使用的工具和样本为研究学习使用,任何人不得使用其进行非法用途,其行为与本人无关

1.前言

最近抽空把之前写的一些文章梳理出来,力争把相关系列更新完成

 

前面我们十分清晰的讲解了一代壳的加壳原理,还使用开源代码制作了一代壳加壳器,并进行了对抗研究,后面我们针对一代壳的加壳原理,还进行有针对性的脱壳研究,研究了脱壳点和脱壳原理,并分享了六类一代壳脱壳的相关方法,并进行了具体的实现,以及上一篇文章提供给大家了脱壳工具集。本文将在基础上进一步研究不落地加载的基本原理,以及不落地加载和动态加载的区别,不落地加载开源代码解析,不落地加载加壳器对抗实验。

2.不落地加载原理

2.1 动态加载回顾

我们说动态加载被称为第一代加壳技术,其原理十分简单,主要是使用了动态加载的技术,并选择了合适的加壳时机,具体原理大家参考前文

 

这里简单总结一下流程:

1
APP启动----->加载壳的代理类Application------>在壳代理类中的attchBaseContext和onCreate函数中对源程序dex进行加载和解密----->启动原程序dex的执行流程

这个中间需要注意的两点就是类加载器DexClassLoader的替换Application的修正,当然成熟的方案也许需要考虑多dex的加载问题,这里我们就不具体的展开了。

 

类加载器修正原因:

1
我们使用自定义的DexClassLoader加载,使得其不具备Android加载的生命周期,导致后面会出现崩溃,所以我们需要解决,相关的方案前面我也讲解了,一般可以替换为系统类加载器mClassLoader

Applicaition修正:

1
我们使用代理类的Application,但是可能我们的源Apk里面也包含自身的代理类Application,因此在我们针对这种情况,完成壳的加载后,还需要对Application进行修正

至于在壳代理类中需不需要完成原始dex的解密,这取决于原始的dex有无进行加密,但无论怎么处理,DexClassLoader加载了源dex后,都会将其释放在/data/data/...文件夹或相关的文件夹下,这使得这种加壳技术的防护性较低,恶意攻击者可以直接对本地的源文件进行解密,拿到原始dex。

2.2不落地加载

参考文章:

 

安卓加固方案从落地加载到类指令抽取编写报告

 

[Android加固实现,不落地加载(support 5.0-11)]

 

第二代不落地加载器具体实现

 

由于动态加载存在释放dex到本地的关键致命问题,为了解决这种问题,不落地加载的加壳技术就出现了。不落地加载技术可以实现直接将dex文件加载到内存中,而不需要先释放到本地的文件夹,这样就很好的对本地的释放的缺陷进行了防护。那怎么实现直接加载到dex文件到内存中呢?我们都知道Android中一般用DexClassLoader实现对dex文件的加载,而我们要想实现直接加载到内存中,无疑就需要重写DexClassLoader,重写DexClassLoader必然会涉及到defineClassfindClassloadClass,因为一个类在加载流程中必然会先后调用这三个函数,因此我们需要重写这三个函数。其实DexClassLoader在加载dex进入内存中也是通过字节加载的,因此我们只需要在Dalivk和Art选择在so文件中重写合适的加载函数,然后通过cookie来进行操作,即可

 

Dalvik:

1
hook重写的函数:libdvm.so中的openDexFile

Art:

1
2
Android8.0以下版本采用call libart的OpenMemory函数实现内存加载dex
Android8.0及以上采用系统提供的InMemoryDexClassLoader实现内存加载dex

而现在基本都是ART,难点在于8.0及以后有系统提供的内存加载dex接口,所以难点主要集中在8.0以前。8.0以前实现原理是加载虚dex然后替换成真实的cookie返回。这里如何替换是个难点,好在网上大神已经开源了方案,只是一番尝试下来只能在5.0和5.1上使用,并且也不支持多dex。网上查找相关资料,没有找到有用的结果,可能是搜索姿势不对。

3.项目代码分析

前面讲述了那么多的原理,这里我们拿具体的项目来进行全面的分析,帮助大家进行理解

 

项目地址:https://github.com/Frezrik/Jiagu

 

分析项目前,我们先看看工具的效果

3.1实验效果

1
实验环境:jdk18

大佬开发的工具已经十分的完善,支持linux端和windows端,这里我们简单的使用下linux端的效果

 

未加壳的样本:

 

image-20221018161913453

 

加壳后的样本:

 

image-20221018162050946

 

可以发现除了代理类,我们基本看不到源样本的任何代码,这是不是比原来的第一代壳加壳器的防护要更高呢

3.2源码分析

项目的模块大概分为:

1
2
3
app: 需要加固的源程序代码
jiagu: 用于生成壳dex
pack: java执行程序,用于打包加固app

按照加壳程序的运行流程,我们首先分析pack这个目录

 

image-20221018162546493

 

从结构我们可以看出这部分功能主要是制作一个加壳器,但加壳实现具体流程肯定不在这里面,我们从Main类开始分析

3.2.1Main.java

main()

 

image-20221018162935785

 

parse()函数主要作用是对我们输入参数进行过滤

 

(1)解压APK

 

image-20221018163257606

 

主要功能:

1
解压APK、删除META-INF、修改Application的名字为代理类

(2)解压壳Dex

 

image-20221018163542392

 

主要功能:

1
将壳的代理样本从jar转换为dex,说明很多真实壳的代理样本通过jar方式进行保存在项目中

(3)将壳和原dex进行加密然后组合成一个dex

 

image-20221018163954460

 

这里是很多制作加壳器的基本的过程,就是拼接壳和dex为一个dex,这里最关键对dex进行了加密,所以防护上上升了一级

 

(4)copy so

 

image-20221018170350734

 

保存数据到libjiagu.so中

 

(5)重打包APK

 

image-20221018170459670

 

将APK重新的打包

 

(6)重签名APK

 

image-20221018170629040

 

对APK进行签名

 

这里我们可以发现该函数主要是我们加壳器的主要功能,接下来我们具体分析加壳的原理

3.2.2 StubApp.java

前面我们将壳dex和原始dex拼接成一个dex,而且对原始dex进行了加密,修改了Application:name的值,根据程序的执行流程必然会先加载壳的dex,我们继续分析

 

image-20221018172421487

 

与我们前面说的一致,壳的Application中含有attachBaseContext和onCreate函数,这也是我们使用加壳的具体实现所在

 

(1)attachBaseContext

 

copyJiagu:

 

image-20221018172729123

 

完成对libjiagu.so的拷贝

 

attach:

 

image-20221018172814034

 

这里我们可以发现attach在so层,说明这里就是我们前面分析的重写OpenMemory函数的地方

 

image-20221018173055510

 

可以发现attach函数进行了动态注册,注册到native_attach函数

 

native_attach:

 

image-20221018173231059

 

首先从安装后的apk中获得dex,然后在内存加载dex,我们主要关注内存加载dex

 

loadDex:

 

image-20221018173449775

 

对dex解密并保存到字节数据,然后获取application的名称

 

image-20221018173616091

 

实现内存加载dex,这里对sdk的版本进行了判定,如果是Android8.0以下,就对openmemory函数进行hook重写,反之如果Android8.0以上则反射调用InMemoryDexClassLoader, 然后通过InMemoryDexClassLoader来加载dex,并返回mCookie,就可以通过mCookie来操作dex

 

image-20221018191947243

 

将dex中的对象保存字节数组,这是为了处理多dex的情况

 

image-20221018191730654

 

然后对application进行hook

 

这里就是代理类实现的大致功能,8.0上是直接反射调用InMemoryDexClassLoader,这个函数可以直接加载dex到内存,我们主要关注8.0下的openmemory函数的重写

 

openmemory_load_dex:

 

image-20221018193422095

 

同样是加载然后返回dexfile

 

image-20221018193704296

 

这两个函数是对dex进行加载

 

load:

 

image-20221018193828120

 

image-20221018194854155

 

这里最后还是通过dlsym进行函数调用,然后对原始的OpenMemory进行hook,返回是一个DexFile,这里然后进行了重写,将dex传进去

 

针对7.0即以下上面加上了dex check的代码

 

7.0

 

image-20221018195505872

 

我们再次查看8.0这里是如何处理,因为8.0可以直接加载dex到内存

 

image-20221018200023682

 

所以这里给location赋值了一样的

 

到这里我们c层的代码也分析完了,整体框架的项目也就分析到这里

3.3 执行流程

最后梳理执行流程:

 

工具处理:

  • 获取app的application名
  • 修改app的AndroidManifest.xml的Application为dex壳的Application
  • 壳dex和源dex拼接成一个dex,格式如下:
    • 壳dex + (1字节application名长度 + app的application名 + 4字节源dex大小 + 源dex) + 4字节源dex2大小 + [源dex2] + 4字节源dex3大小 + [源dex3] + ... + 4字节壳dex大小
    • 小括号的数据前512字节进行AES加密
    • 中括号的数据的dex头(也就是前112位进行异或)
  • 打包签名app

壳dex处理:

  • 解密出app的application名和dex
  • 加载app的dex
    • Android8.0以下版本采用call libart的OpenMemory函数实现内存加载dex
    • Android8.0及以上采用系统提供的InMemoryDexClassLoader实现内存加载dex
  • 壳application替换为app的application

4.不落地加载壳的对抗

我们为了进一步验证不落地加载的安全性,使用恶意应用检测来验证最好,大家可以设想,如果我们的加壳技术进行升级后,防护性更强是不是说明源码不易被检测和识别,那么使用加壳的恶意应用来检测就十分能说明这个问题,例如加壳防护级别越高的恶意应用越难以检测出恶意性,那么我们检测平台的分数应该也会越低,按照这个设想我们开展实验:

4.1 未加壳

我们还是拿之前的恶意样本,我们先不对其加壳,查看恶意性:

 

image-20221008210342685

 

可以发现VirusTotal上面有27家厂商识别出了恶意应用,说明这个恶意性还是很容易检测到的

4.2 动态加载壳

我们使用之前的一代壳加载器进行加壳,查看其恶意性:

 

image-20221008210405210

 

这里发现分数略微降低,但是还是很高,这是因为之前一代加壳器,我们未对dex进行加密,而且dex保存本地,所以十分容易检测出来

4.3 不落地加载壳

我们使用本文的不落地加载壳进行加载,查看其恶意性:

 

image-20221018201207513

 

这里可以发现67家厂商中只有9家厂商可以识别出来,识别率大大降低,这更加反映了不落地加载防护技术的升级

5.实验总结

本文讲述了不落地加载的基本原理,也总结了和前面的落地加载的区别,本文通过分析一个开源项目详细的分析了不落地加载器实现的基本原理,最后通过实验进一步证明了不落地加载的防护性进一步升级。本文的相关资料存放知识星球:安全后厨。

 

github地址:github

6.参考文献

1
2
3
https://bbs.pediy.com/thread-261939.htm#msg_header_h1_2
https://www.361shipin.com/blog/1545774720673120256
https://github.com/Frezrik/Jiagu

[培训]《安卓高级研修班(网课)》月薪三万计划

收藏
点赞9
打赏
分享
最新回复 (9)
雪    币: 42
活跃值: (3341)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
New对象处 2023-5-23 09:42
2
0
66666
雪    币: 9
活跃值: (210697)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
shinratensei 1 2023-5-23 10:26
3
0
tql
雪    币: 37
活跃值: (238)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
万里星河 2023-8-22 22:14
4
0
学习了
雪    币: 17901
活跃值: (25552)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-8-23 09:17
5
1
感谢分享
雪    币: 1138
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
微微T52G25 2023-8-23 12:20
6
0
太厉害了大佬
雪    币: 7634
活跃值: (20995)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
随风而行aa 10 2023-8-27 18:40
7
0
微微T52G25 太厉害了大佬
感谢支持
雪    币: 803
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
xjh88232259 2023-8-28 08:27
8
0
学习学习,谢谢楼主分享。
雪    币: 870
活跃值: (1045)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mb_fssslkzs 2023-8-28 10:11
9
0
学习了感谢分享,ing
雪    币: 7634
活跃值: (20995)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
随风而行aa 10 2023-8-29 21:55
10
0
mb_fssslkzs 学习了感谢分享,ing
感谢支持
游客
登录 | 注册 方可回帖
返回