高研班成果展示
frida
版的fart
开源发布,提供了两种不同的实现,无需刷机便可体验函数粒度的脱壳修复
FART
首次实现了ART
下的基于主动调用的函数粒度的脱壳修复,同时,主动调用链的深度可以灵活的根据壳恢复的时机进行定制,比如在看雪的安卓高研班上给的函数执行中自修复的样本,就需要对FART
的主动调用链继续深度定制,让恢复函数体的smali
指令真正执行结束后再进行函数体的dump
。
事实上,使用frida
去构造主动调用链还是存在一定的困难的,ART
中大量丰富的api
往往无法直接调用,并没有执行修改ART
源码来的简单快捷。
但是,由于当前很多的函数抽取壳在类加载后就已经恢复了其中的函数的CodeItem
内容;其次,对于已经调用过的函数来说,其CodeItem
也已经被壳完成了修复。因此,如果不考虑主动调用链的构造,是可以使用frida
来实现一个能够达到函数粒度的脱壳修复的自动化脱壳脚本的。
这里,就实现了两种不同实现原理的frida
版fart
:
- 一种是基于
hook
技术实现,较容易理解;
- 另一种是基于反射实现。
两种实现各有特色,感兴趣的可以到github
:https://github.com/hanbinglengyue/FART上下载源码自行阅读。
下面就这两种frida
版的fart
的使用做一个简单的介绍。同时,寒冰大佬只是对Android 8
版本进行了兼容,如果需要对其他android
版本进行适配,还需要注意被hook
函数的LoadMethod
在不同Android
版本的实现差异,以及不同Android
版本下DexFile
对象以及ArtMethod
对象的偏移问题。
接下来进入两种不同实现的frida版fart的使用流程阶段
一、基于hook
实现的frida
版fart
该版本的fart
主要通过对加载类和初始化函数流程中的LoadMethod
函数进行hook
,该函数在Android 8
源码中的声明为:
3305 void ClassLinker::LoadMethod(const DexFile& dex_file,
3306 const ClassDataItemIterator& it,
3307 Handle<mirror::Class> klass,
3308 ArtMethod* dst) {
3309 uint32_t dex_method_idx = it.GetMemberIndex();
3310 const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
3311 const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
3312
3313 ScopedAssertNoThreadSuspension ants("LoadMethod");
3314 dst->SetDexMethodIndex(dex_method_idx);
3315 dst->SetDeclaringClass(klass.Get());
3316 dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
3317
3318 dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods(), image_pointer_size_);
3319
3320 uint32_t access_flags = it.GetMethodAccessFlags();
3321
3322 if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
3323 // Set finalizable flag on declaring class.
3324 if (strcmp("V", dex_file.GetShorty(method_id.proto_idx_)) == 0) {
3325 // Void return type.
3326 if (klass->GetClassLoader() != nullptr) { // All non-boot finalizer methods are flagged.
3327 klass->SetFinalizable();
3328 } else {
3329 std::string temp;
3330 const char* klass_descriptor = klass->GetDescriptor(&temp);
3331 // The Enum class declares a "final" finalize() method to prevent subclasses from
3332 // introducing a finalizer. We don't want to set the finalizable flag for Enum or its
3333 // subclasses, so we exclude it here.
3334 // We also want to avoid setting the flag on Object, where we know that finalize() is
3335 // empty.
3336 if (strcmp(klass_descriptor, "Ljava/lang/Object;") != 0 &&
3337 strcmp(klass_descriptor, "Ljava/lang/Enum;") != 0) {
3338 klass->SetFinalizable();
3339 }
3340 }
3341 }
3342 } else if (method_name[0] == '<') {
3343 // Fix broken access flags for initializers. Bug 11157540.
3344 bool is_init = (strcmp("<init>", method_name) == 0);
3345 bool is_clinit = !is_init && (strcmp("<clinit>", method_name) == 0);
3346 if (UNLIKELY(!is_init && !is_clinit)) {
3347 LOG(WARNING) << "Unexpected '<' at start of method name " << method_name;
3348 } else {
3349 if (UNLIKELY((access_flags & kAccConstructor) == 0)) {
3350 LOG(WARNING) << method_name << " didn't have expected constructor access flag in class "
3351 << klass->PrettyDescriptor() << " in dex file " << dex_file.GetLocation();
3352 access_flags |= kAccConstructor;
3353 }
3354 }
3355 }
3356 dst->SetAccessFlags(access_flags);
3357 }
因此,在对该函数完成hook
后,便可以拿到第二个参数:DexFile
对象的地址以及最后一个参数即要准本初始化的ArtMethod
对象指针,需要注意的是在进入该函数时,其ArtMethod
对象还没有完成初始化。
同时需要注意的是谷歌在开发不同Android
版本的时候该函数有细微的差异,如在Android7
中的定义多了一个参数Thread* self
,如下是Android7
中的该函数的源码:
3115 void ClassLinker::LoadMethod(Thread* self,
3116 const DexFile& dex_file,
3117 const ClassDataItemIterator& it,
3118 Handle<mirror::Class> klass,
3119 ArtMethod* dst) {
3120 uint32_t dex_method_idx = it.GetMemberIndex();
3121 const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
3122 const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
...
...
这个是在hook
的时候需要注意的地方,给的frida
版的源码是针对Android 8
的,如果大家需要移植到7
,自然需要对DexFile
对象和ArtMethod
对象的参数位置做一下调整即可。
那么有了DexFile
对象以及ArtMethod
对象,我们就可以很轻松通过DexFile
对象中dex
文件在内存中加载的基地址,加上ArtMethod
对象中CodeItem
的偏移,就可以很轻松定位当前函数的函数体在内存中的真实地址,而不管该抽取壳是填充类型的还是修改偏移类型的。
此时,需要注意的是,LoadMethod
只是类函数加载初始化的一个中间流程,壳也有可能在该函数后面的其他流程完成对函数的解密或者修改偏移,因此,直接在该函数返回时就进行函数体的dump
并不一定准确,我们可以将被ART
加载的ArtMethod
对象指针进行缓存,等待壳完成控制权的交付,真正进入到app
自己的代码空间后,比如已经进入了app
的主界面,或者是点击一些按钮,完成一些交互操作,这个时候再进行缓存的所有的ArtMethod
中的CodeItem
的dump
,这便是基于被动调用进行函数粒度的脱壳修复。
因此,就算是函数执行中自解密的强度更大的抽取壳也是可以完成脱壳修复的。但是,基于被动调用的脱壳修复,由于代码覆盖率低,不可能触发app
中的所有函数的调用,因此,修复的范围有限。接下来我们需要获取到dex
中的所有类下的所有函数的CodeItem
,然后再进行遍历进行dump
即可。
此时,就可以像FART
源码中的一样,首先获取classloader
,然后再获取classloader
中的所有类列表,最后遍历对每一个类进行加载获取其对应的CodeItem
,就完成了对所有函数体的dump
。这里对函数体的dump
依然按照FART
中的五元组格式进行,保存到bin
文件当中。
因此,对于hook
实现的frida
版fart
,自然就需要使用spawn
方式启动app
进程,而不能使用attach
方式直接附加到进程。下面是该版本的使用流程:
- 推送
fart.so
以及fart64.so
到/data/app
目录下,并注意权限
- 安装
apk
,并给予sd
卡读写权限
- 手机端以
root
启动frida-server
,然后以spawn
方式启动app
,如应用包名为com.test.package
,则frida -U -f com.test.package -l frida_fart_hook.js --no-pause
- 等待
app
进入主界面后,调用fart()
即可,等待出现end dump CodeItem
即可,此时可以在sd
卡下看到dump
的dex
和函数体bin
文件
高级用法:可以只完成对某一个类下的所有函数的CodeItem
的dump
,只需要调用dumpclass(类名)
,传入需要处理的类名即可。
如果发现dump
下来的bin
文件中缺少了某些类,也可以手工调用该函数完成对缺少类函数的dump
。
二、基于反射实现的frida版fart
该版本的fart
主要通过java
的反射机制实现,具体流程如下:
- 通过
java
的反射对dex
中的类进行加载;
- 然后再反射获取该类下所有的函数的
Method
对象;
- 接下来直接通过
java
层的Method
对象转成Native
层对应的ArtMethod
对象;
- 然后再通过
ArtMethod
对象获取到DexFile
对象;
- 自然最后就可以定位到当前
java
函数在内存中的CodeItem
的偏移和具体大小;
- 最后再进行
dump
即可。
由于该实现不是基于hook
,不会对ART
的流程进行任何形式的干扰,因此,也就可以在spawn
方式以及attach
方式线下都能够成功工作。
下面说下具体操作流程,与上面hook
实现的版本流程大体相同。
- 推送
fart.so
以及fart64.so
到/data/app
目录下,并注意权限
- 安装
apk
,并给予sd
卡读写权限
- 手机端以
root
启动frida-server
,然后以spawn
方式启动app
或者待app
进入主界面后直接attach
附加到进程
这两种方式都需要保证app
的代码执行权限已经由壳交付到app
的代码中,如已经进入到app
的主界面
- 调用
fart()
,等待出现end dump CodeItem
即可,此时可以在sd
卡下看到dump
的dex
和函数体bin
文件
高级用法:可以只完成对某一个类下的所有函数的CodeItem
的dump
,只需要调用dumpclass(类名)
,传入需要处理的类名即可,dump
下来的该类的所有函数的函数体在包含该类名的bin
文件当中。
如果发现dump
下来的dex
或者bin
文件中缺少了某些类,也可以手工调用该函数完成对缺少dex
以及缺失类函数的dump
。
最后看下效果:
下面附上图:
最后附上下载地址:https://github.com/hanbinglengyue/FART
三、好了,就到这里了,感兴趣的可以去github体验frida版fart强大的函数粒度的脱壳能力。
优秀学员作品展示(四月):
ddsf - 《某抽取壳的原理简析》
JNI
动态注册函数定位
patch so
层过frida
反调试
- 在
art::DexFile::DexFile()
函数进行frida dump dex
frida hook LoadMethod Dump
被动调用还原方法体
frida
实现主动调用(反射版)
新萌 - 《frida辅助脱壳》
- 某商业壳
frida
主动调用触发壳修复
frida registerClass
实现Runnable
多线程接口
frida
重写defineClassNative
实现主动调用
- 虚函数的处理、函数过滤
- 阻断函数执行来
dump
方法体
优秀学员作品展示(三月):
认证:《看雪安卓安全人才标准认证》
在去年的帖子中《看雪拟推出《看雪逆向工程能力认证》体系证书,为用人单位和高级人才创造价值,欢迎大家多提建议!》,收到了近百楼层的反馈建议,谢谢大家百忙之中帮助出谋划策,衷心感谢。
证书存在的意义本质上为技术水平达到一定程度的一种的肯定,不管是看雪、用人单位还是应试者本身,都是冲着技术而来。先有更强的、贴近实战的、持续领先的技术,后面才会衍生一系列的支撑服务。
这正与我们高研班的理念不谋而合。高研班强手如云,把证书颁发给优秀学员,是对真正高超技术的表彰和认可。
在考核形式上:
- 首先优先从优秀学员中产生;
- 其次考虑到纯线上容易有舞弊的情况,增加线下见面的面试,确保实力真正达到要求水平。
在价格上,因集成到了高研班中,现阶段会保持免费,针对高研班学员不再额外收费,暂不对非学员开放。
我们会持续调整《看雪安卓安全人才标准认证》的各项细则,以符合大家的期待和利益,实现多方共赢和实际技术能力的提升。
线下班:《安卓高级研修班》
受疫情影响,原有的线下班暂停。现在国家大力出台诸多促经济发展措施,我们的新线下班也在紧锣密鼓的筹备中!
新的线下班开班将会设在《看雪2020
安全开发者峰会》现场,以《FridaFart
高级逆向&算法还原》闭门会议环节的形式开启。
同时,为了降低大家拿到证书的门槛,新的线下班将会大幅降低价格,同样的内容、更低的价格,适合真正高手之间的交流沟通。
另外,高研班网课时间较长,得在长达一年的时间里付出大量的时间学习和考试;而参加线下班即可进入快速通道,最快三个月即可拿到证书。
开班闭门会议的议题、简介等将会很快释出,敬请期待;具体价格、内容和招生公告等请关注看雪论坛看雪高研ID 。
《安卓高级研修班(网课)》9月班开始招生!
课程内容
服务对象:
有一定基础的初、中级安卓逆向研究员,迫切希望提高自身能力、学习能力强,升职加薪意愿强烈、学习意愿强烈。
服务内容:
- 上述列出的两大计划、各八大专题及其包含的二十四个细目;
- 专属班主任,敦促学习、鼓励士气;良好的抱团学习的氛围;
- 可以参加《安卓高级研修班》线下班,鼓励线下交流,与大佬谈笑风生;
注意2W
班和3W
班是完全独立噢,没有交集;
开班时间:2020年9月开班(202009期)
PS:以上为总体服务计划,具体课程时间(段)安排以最终合同约定的课程表为准。
培训价格:
高研网课 |
就业班 |
强化班 |
月薪三万计划 |
16999元 |
8599元 |
月薪两万计划 |
11199元 |
5599元 |
就业班注意事项:
- 就业班附带包就业服务(须达到合同规定的毕业标准),签合同保证就业及薪资,达不到退全款;
- 就业班有入学考核,缴费成功后进入考核流程,考核不通过退全款;
- 考核流程会包括简历筛选、班主任和老师(电话)面试等环节;
强化班注意事项:
- 强化班仅去除包就业服务,并且无入学考核,其余与就业班完全相同;
- 就业班与强化班一起授课,合计35人一个班,教学上不做任何区分。
金融风险注意事项:
- 《安卓高级研修班》全系列无任何金融计划,纯预付;无任何金融套路。
- 网络课程为虚拟商品,购买之前可以观看下述试看内容,购买成功之后不接受退款。
报名地址:
试看地址:
联系我们:
课程顾问微信:r0ysue(备注“安卓高研网课”)
渴望知识和力量的你还在等什么,赶紧报名加入我们吧!
免责条款
- 以上所有宣传稿件内容均不作为服务承诺,最终以实际签订培训合同为准。
- 课程大纲与细目会根据教学反馈不断优化、调整与更新,实际授课可能与宣传主题略有不同;
常见Q&A及预习指南
Q:有优惠么?!有优惠么?!有优惠么?!重要的事情说三遍!!
A:没有任何优惠噢。只送开学大礼包,把我们网课中需要准备的设备和环境直接送给大家。
3W班高研网课开学大礼包:
- 一部pixel手机(sailfish)(安卓8脱壳镜像)
- 安卓源码开发编译调试环境SSD移动硬盘500G
2W计划的话大礼包中的手机或移动硬盘二选一。
Q:网课内容与线下班内容一样么?
A:月薪三万计划的内容与线下班的内容是一样的,我们在线下班沉淀大家的切实的需求和疑问,重新编排和制作内容作为网课与大家分享。月薪两万计划的内容由三万计划的讲师全新制作,充分体现工作场景一线的需求,更加贴近实战、实用,有用、好用。
Q:非常关心ollvm和vmp,可以详细介绍下还原的方法和细节么?
A:目前针对ollvm和vmp,任何所谓的自动化,都是带很多前提和条件限制的;目前最快的还原ollvm或vmp的方法,还是手动分析,一般快则两三日、慢则一两周,基本上可以还原出来。ollvm或vmp虽然非常复杂,但是并不代表没有取巧和判断的方法;依托于我们丰富的经验,我们会在课上将我们调试和分析的普适方法和一般性及特殊性技巧教给大家,同时带领大家开发属于自己的ollvm和vmp虚拟机,让学员既能够自己给自己的程序加密,又能够分析别人的经过ollvm或vmp保护的算法,这才是我们看雪高级研修班所传达的授人以渔的精神。
Q:想报名网课需要什么样的基础?像我这样的初学者可以报名么?
A:
- 月薪两万计划推荐至少有实际安卓安全岗位工作经验一年以上为宜。初学者可以先看我们安卓版主非虫大佬的《Android软件安全权威指南》等安卓安全书籍进行入门,在看雪论坛看帖发帖提升自身水平,本套课程建议有工作经验的老手前来充电学习。
- 月薪三万计划视大家实际需求而定,一般看得懂目录及想要学习的人自己就懂,大家不用盲目跟风。如果看不懂目录及不理解目录的具体含义及意义,建议先从两万计划学起,多积累技术和经验。
Q:学习三万计划之前,需要先掌握两万计划的基础吗?
A:不需要,互相独立的。月薪两万计划的定位更加偏向工作岗位一线逆向需求,月薪三万计划则更加偏向于高级调试技巧,二者互为补充,相辅相成。有非常多地大佬两个计划一起报名了,我们也会确保直播时间不会冲突。
Q:想报三万的班,真的很想学高级技巧;但两万的班中也有很多是我想了解和学习的,大佬给些建议呢?
A:其实推荐两个班一起报,有好几位大佬就是两个班全报的。因为首先价格真心不贵,其实我们会将直播的时间错开,方便大家同时进修三万和两万计划,学习自己想要学习的、心仪的知识。
Q:直播答疑如果错过了,是否会有直播内容的回放?
A:每一场直播都有回放,在看雪课程中可以观看。
Q:就业班如何报名呢?流程是怎样的呢?
A:就业班是需要考核的。考核流程是先缴费报名,然后开始。会经过简历、(远程)一面和二面。通过之后补差价,不通过退全款。
Q:我已经报名了,趁开班前还想再预习一下,可否给个预习指南,让我好好利用开班前这段时间再恶补一下。
- 在月薪三万计划中,我们学习的主要目标是,掌握调试、分析和还原ollvm、vmp的方法,定制
art
虚拟机进行自动化脱壳的方法,主要涉及的技术栈是C\C++
还原、arm(64)
,C++
开发。因此首先推荐邓凡平先生的《深入理解Android:Java虚拟机ART》,里面的第五章详细讲解了ART虚拟机的实现语言C++11
,是阅读ART源代码必备的知识;其余部分也详细讲解了Class文件、dex文件和ELF文件的格式和内容,以及art虚拟机的编译、runtime、解释执行、内存、线程等art
的技术细节;推荐的第二本书是《C++反汇编与逆向分析技术揭秘》,按照书中的方法自己编写实验代码对C++
使用ndk
编译后arm
汇编进行对照,掌握c++
数据类型、控制流、函数和类在编译后arm汇编的表现形式;希望大家预先掌握这些知识,即使现在不开始看,开课后也会要求大家必须掌握。
- 在月薪两万计划中,我们更加注重的是实际工作中遇到的各种场景、实际工作能力的提升,及解决实际问题的能力。因此各种逆向环境的搭建、逆向的综合能力和利用代码的编写是最关键的,这里主要涉及的技术栈也是比较杂的:比如网络、Ubuntu/安卓系统知识、应用安全开发、Frida/JS/Python等等、Java技巧,比较考验学员的计算机综合技术基础水平。因此我们从工作实践中的需求出发,推荐大家首先强化安卓Java代码的开发、及各种网络和接口的知识,这两大技能被大量应用到应用安全、漏洞检测、渗透测试、黑灰攻防等方向,我们并不推荐具体的书目,只要涉及Java、安卓和网络的图书,都可以。有句话叫做开发的高度,决定了你逆向的高度,希望大家利用好开班前的时间,强化一下Java和网络开发的能力。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-6-11 15:01
被看雪高研编辑
,原因: