草庐IT

【胖虎的逆向之路】03——Android一代壳脱壳办法罗列&实操

胖虎哥er 2024-04-11 原文

【胖虎的逆向之路】03——Android脱壳办法罗列&脱壳原理详解

【胖虎的逆向之路】01——动态加载和类加载机制详解
【胖虎的逆向之路】02——Android整体加壳原理详解&实现


文章目录


前言

在上文中,我们讲解了关于Android整体加壳的原理和实际操作,现在我们来针对目前主流的脱壳工具以及流程进行讲解,由于作者能力有限,会尽力的详细描述 整体壳脱壳 的流程及原理,如本文中有任何错误,烦请指正,感谢~


一、主流脱壳方法

1.工具脱壳法

工具脱壳是指的利用现有的工具进行脱壳,很多的大佬已经开发了很多实用的工具,我们可以直接搞来使用(嘻嘻嘻)~

1) Frida-DexDump

得益于Frida, 在电脑上面进行内存搜索、转储的时候都变得十分方便,不再去通过繁琐的Xposed代码来获取Dex中对应的类与方法,仅需要关注如何去搜索想要的函数即可,对于完整的 dex,采用暴力搜索 dex035 即可找到。而对于抹头的 dex,通过匹配一些特征来找~

  • 支持模糊搜索断头dex(深度搜索模式)。
  • 兼容所有安卓版本(支持frida)。
  • 一键安装,无需修改系统,易于部署和使用

项目地址: https://github.com/hluwa/FRIDA-DEXDump

使用方法也变得简单很多,在这里借助一个大佬的使用流程图,可以快速进行脱壳

我们简单演示一下,这里结合objection一起使用

然后再次打开脱下来的dex,即可~

ps:获取到dex后,推荐使用Jadx进行反编译,dex2jar有点过时了…

另外附上深度介绍: 深入 FRIDA-DEXDump 中的矛与盾

2) Fart

Fart 的制作过程略显繁琐,主要是FART的代码是通过修改少量Android源码文件而成的,经过修改的Android源码编译成系统镜像,刷入手机,这样的手机启动后,针对Apk可以进行脱壳~
基于此,我更愿意称之为是脱壳鸡,因为是把经过修改的Android源码编译成了系统镜像,刷入了手机~

官方介绍:
ART环境下基于主动调用的自动化脱壳方案,基于Android 6.0实现,理论上可以移植到任何系统上~

项目地址:https://github.com/hanbinglengyue/FART

具体的实现原理和步骤在看雪:

脱壳流程:

1、安装待脱壳apk,并到设置中授予sd卡读写权限(否则dump下的文件无法写入到sdcard)

2、点击app图标,开始进入fart脱壳过程

接下来可以对logcat中的tag为ActivityThread的log进行过滤,等待待脱壳app进程出现"fart run over",此时fart主动调用过程结束。脱壳下来的

dex文件和函数体bin文件均在/sdcard/fart/app包名的目录下~

下面截图为fart的运行流程和脱壳结果

官方Ps:添加frida版的fart的两种不同实现,各有特色。可以实现具体到对某一个类下的所有函数甚至是对某一个函数的CodeItem的dump。需要的可以去体验下其强大的脱壳能力。(注意,测试环境为pixel Android8.0,frida-server 12.8.0)

3) Youpk

Youpk基于ART的主动调用的脱壳机,主要针对dex整体加固和各式各样的dex抽取加固,但是目前 Youpk 只支持 pixel 1代。所以必须需要 pixel 1代手机,而且需要刷入对应的系统~

基本流程如下:

  1. 从内存中dump DEX
  2. 构造完整调用链, 主动调用所有方法并dump CodeItem
  3. 合并 DEX, CodeItem

项目地址:https://github.com/youlor/unpacker

在该地址中,有较多的流程及方法、注意问题等,有需要的可以去看一哈

4) 常用脱壳工具对比

2.Hook脱壳法

我们上面有写到,只要函数中包含DexFile对象,其实就可以通过Hook拿到该对象,然后取到begin和size,从而进行脱壳,目前使用较多的Hook框架是Xposed和frida两种,感觉Frida使用人数较多也方便,在这里用frida进行演示~

首先使用GDA识别加壳程序~

看起来很明显是进行了整体加壳,有没其他加壳暂时不知道,我们先进行脱壳处理

首先找到脱壳点~

通过IDA打开libart.so,搜索DexFile,我们可以找到海量的脱壳点

然后我们编写hook脚本

这里之所以获取begin加上一个指针,是因为我们前面讲了dexfile含有一个虚函数地址,所以加上一个指针偏移

然后在手机中启动frida_server

附加进程进行dump,这里我们存在sdcard下面,所以需要提前赋予读写文件权限


从图中可以看得出来,到这里就已经脱壳成功~

然后使用jadx打开对应的dex,进行查看

此时说明我们整体脱壳成功,不过应用看起来还有抽取壳,抽取壳后续会单开一篇文章进行记录~

3.插桩脱壳法

插桩脱壳法,就是在Android源码里面定位到相应的脱壳点,然后插入相应的代码,重新编译源码生成系统镜像,最后就可以使用定制的系统进行脱壳~

其原理感觉跟youpk比较像,如何编译源码不再进行赘述,有需要的小伙伴可以看下这篇文章~
源码编译(1)——Android6.0源码编译详解

那么还是借助大佬已经完成的图片进行讲解,同理、还是定位脱壳点,我们还是随便定位一个脱壳点LoadMethod 然后进行插桩

//add
char dexfilepath[100]=0;
memset(dexfilepath,0,100);
sprintf(dexfilepath,"%d_%zu_LoadMethod.dex",getpid(),dex_file.Size());
int dexfd = open(dexfilepathm,O_CREAT|O_RDWR,666);
if(dexfd>0){
    int result = write(dexfd,dex_file.Begin(),dex_file.Size());
    if(result>0){
        close(dexfd);
        LOG(WARNING)<<"LoadMethod"<<dexfilepath;
    }
 
}
//add

同理我们在execute同样插桩此段代码,最后进行编译,编译成功


然后给程序授权sdcard权限,再次启动应用,就可以看见脱取的dex文件就保存在sdcard目录下

然后在使用jadx,打开dex,就会得到跟上面一样的结果~


Ps:由于该方法需要进行Android源码修改编译,本文作者没有进行实现,若有任何问题欢迎随时沟通(有问题了我再去编译)

4.插桩脱壳法

反射脱壳我自己的理解是利用反射得到一系列的classloader,最后得到DexFile结构,然后获取变量mCookie&mFileName这两个属性后,得到dexFile内存指针,然后该指针转换为dexfile,再通过findClassDef来匹配寻找的dex,最后dump写入文件~
借助前人的总结,流程如下:


那么还是做一下演示~
mCookie是在native层的dexfile的指针,然后我们利用反射原理来获取到mCookie,就可以进行脱壳了,在这里还是使用frida进行代码演示~

编写hook代码ing


打印出相关值


就可以看到相同大小的dex

然后使用jadx打开,发现同样的界面又出现了!

5.动态调试脱壳法

动态调试法,其核心原理还是要得到DexFile的起始地址和大小,不过所有的方式不同, 如果说上面是针对代码做修改得到一些值,那么接下来就是利用IDA工具获取对应的起始地址和大小,然后再通过脚本进行dump~

请欣赏!
首先选一个脱壳点,我们还是选择DexFile::DexFile

然后手机启动android_servcer,记得要以Root启动

然后使用IDA进行附加进程

然后ida开始介入

然后我们打开libart.so,并定位到DexFile::DexFile


然后在该函数下断点,然后F9过来看一哈


在这里就可以很明显看到X1就是DexFile的起始地址,X4是偏移值

然后利用Frida进行dump~


直接运行run即可

然后使用gda查看本地的dump.dex文件


可以发现这里竟然是代理类,对比大小不是我们想要的dex,再来一遍F9,可以看到地址再次改变,再次结合长度来计算,试了几次还是没有出来,后来就没有在进行了,不过感觉是可以得出来的,作为演示没有废太多的功夫~

6.特殊API调试法

特殊API调试意思是指的通过Android系统提供的API方法,来获取Dex,在Android 7.0 及以下系统提供了getDex及getBytes这两个API,所以如果我们想要获取对象,可以直接调用这两个API~


但是在实际测试中,发现在Android 高版本中Dex的getBytes方法依然存在,但是核心的Class类中的getDex方法已经消失不见了~

编写hook代码:

操作流程:


然后我们查看程序的类对象,随便dump一个类对象



得到dex之后,我们再次使用jadx工具打开~

发现就可以成功的dump~

二、实验总结

本文总结了当下dex整体加壳的常用的一些脱壳方案,并进行复现,但是在这里仅作为实验加深自己的理解为主(目前也不会这么简单的就可以拿到源Dex)但是有兴趣的朋友可以像我一样去把整个流程走一遍,加深自己的理解~

三、参考文献

https://bbs.kanxue.com/thread-273293.htm#msg_header_h2_6

文中所述图片部分取自该文章,栓Q~

有关【胖虎的逆向之路】03——Android一代壳脱壳办法罗列&实操的更多相关文章

  1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  3. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  4. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  5. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  6. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  7. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  8. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  9. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  10. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

随机推荐