2020年安卓源码编译指南及FART脱壳机谷歌全设备镜像发布

阅读量1997184

|评论6

|

发布时间 : 2020-03-05 10:30:16

 

简介&&引言

作为寒冰大佬的好基友,经常有人来问我要FART脱壳机的镜像,今天,它来了!

我制作好了以上版本的全部FART脱壳机镜像,百度云盘地址和密码在我的githubhttps://github.com/r0ysue/AndroidSecurityStudy,大家可以帮我测测,更加新的设备我也会更新上去,如果刷机和脱壳有问题,欢迎联系我一起探讨和研究。

如果还有人不知道FART是啥,在这里稍微科普下,FARTART环境下基于主动调用的自动化脱壳方案,FART的创新主要在两个方面:

  • 之前所有的内存脱壳机都是基于Dalvik虚拟机做的,比如F8LEFT大佬的FUPK3,只能在安卓4.4之下使用,FART开创了ART虚拟机内存脱壳的“新纪元”,上至最新的安卓10甚至还在preview的安卓11都可以。
  • ART虚拟机中彻底解决函数抽取型壳的问题;构造主动调用链,主动调用类中的每一个方法,并实现对应CodeItemdump,最终实现完整dex的修复和重构。

详细的介绍和源码下载地址当然是在大佬的githubhttps://github.com/hanbinglengyue/FART

FART的脱壳是通过修改ART解释器的源码来实现的,所以我们要重新编译ART,这就涉及到AOSP的源码编译。很多人问我是如何编译AOSP源码的,其实我就是按照官网指南一路操作到底就实现了,但是大家还是不求甚解,甚至一直出错,所以在这里也把最新的AOSP源码编译方法介绍给大家,大家可以动手试一试,非常简单,不会出错

最后还兼顾一下大家现在的电脑硬盘都非常小,这样一个现状。本文介绍的流程全部是在SSD移动硬盘上完成的,型号是海康威视的T200N,普通的SATA3,拷贝速度一般在三四百,当然这个速度已经足够了。如果是NVMeSSD移动硬盘,那肯定就更快了。下图就是我的编译环境,挂着SSD移动硬盘编译的。

 

2020年的AOSP源码编译指南

话不多说,开始干活。

选择编译目标:安卓10

  • 2020年了,写个安卓4.4编译估计要被打;
  • 其实方法都是一样的,毕竟我在这套组合上完成了所有版本的编译;

选择虚拟机编译

  • 现在的虚拟机性能跟真机不相上下,intel是有专门给虚拟机优化的指令的;
  • 编译的时候,还能吃着火锅唱着歌,平时该干嘛干嘛,就是性能有些损失
  • 最重要的还是因为虚拟机自带“时光机”功能,可以“时光倒流”,比如秀一下寒冰大佬的日常FART开发过程:

  • 做危险操作的时候,先拍个快照,如果遭遇了重大挫折,赶紧“回到过去”,岂不美哉。
  • 其次虚拟机具有良好的跨平台特性,完美支持WindowsmacOSLinux三大主流桌面平台。可以随时将完整的学习和工作环境整体打包,在各种环境中进行部署和迁移。

  • 虚拟机具有良好的隔离特性,做实验不会“污染”真机,是测试全新功能的天然“沙盘”,推荐读者使用VMware出品的系列虚拟机。

选择Kali Linux操作系统

  • 为啥选择Kali,因为漂亮!

  • 主要是因为默认就是root,这一点非常爽,没有令人讨厌的权限问题;
  • 有专门的VMware版本,解压就是个虚拟机,省去了安装的过程,下载地址也放在githubFART目录里了,是个种子文件,可以用迅雷下载,下载完带checksum的;
  • 自带各种抓包软件,自带openjdk,自带radara2
  • Ubuntu一样的apt包管理系统,Ubuntu有的它都有。

下载完之后用certutil -hashfile yourfilename.ext SHA256命令查看下包是否损坏:

然后解压到SSD移动硬盘即可。在VMware里直接选择“文件”→“打开”,选择文件夹里的vmx文件,即可直接打开(导入)该虚拟机。

因为该虚拟机默认的八十几G的磁盘空间肯定是不够的,我们给他扩展到450G

CPU给2核2线程没问题,内存要给的多,我一般给12G,也就是12*1024=12288。少于12G会报out of memory错误。

首次启动的时候会问是“移动”的还是“复制”的,貌似没啥区别,我一直按照默认选。默认账号是root,密码是toor,即可登录系统,Ctrl + Alt + t是新建终端的快捷键,这是用的最多的快捷键。

选择清华源初始包

  • 若干年前我也挂着科学上网工具从谷歌那里拖源码,整整三天三夜;
  • 现在还是觉得清华源真香,直接用迅雷下载这个地址https://mirrors.tuna.tsinghua.edu.cn/aosp-monthly/aosp-latest.tar就行了,下载好了检查下checksum
  • 进入系统后启动Gparted软件,在unallocated部分右击,选择新建,按照默认即可,即可新建这个370Gext4分区,点击选择Apply,应用到磁盘。然后将这个新建的磁盘给mount到某个文件夹:
# cd Desktop
# mkdir COMPILE
# mount /dev/sda3/ /root/COMPILE
  • 记得到设置里面的Display设置里,把所有的息屏、休眠选项都关掉,否则接下来开始拷贝要几十分钟,老是息屏休眠的耽误事儿。Power Manager里把Display里的Display power management关掉,并且把Plugged in那里的10 min调成0 never
  • 桌面上就出现了COMPILE文件夹,双击打开,把刚刚下载的aosp-latest.tar拖进这个文件夹内部,VMware是支持直接拖拽的

到这里已经完成了一半儿不止了。

拷贝完成之后记得把VMware拖动复制的缓存删掉,否则无法进行任何软件包的安装,系统空间被占满了。

# rm -rf /root/.cache/vmware/drag_and_drop/*
  • 解压源码tar包,耗时大几分钟,根据你的SSD移动硬盘速度而定
# tar xvf aosp-latest.tar
  • 删掉原来的tar包节约空间
# rm aosp-latest.tar

准备编译环境

  • 准备环境
# apt update
# git config --global user.email "you@example.com"
# git config --global user.name "Your Name"
# apt install bison tree
# dpkg --add-architecture i386
# apt update
# apt install libc6:i386 libncurses5:i386 libstdc++6:i386
# apt install libxml2-utils
  • 系统内置的openjdk 11太新了,会报错,装个官网要求的openjdk-8
# apt install openjdk-8-jdk
  • 下载aosp源码版本管理工具,并设置可运行
# curl https://storage.googleapis.com/git-repo-downloads/repo > /usr/bin/repo
# chmod a+x /usr/bin/repo
  • 装个看CPU、内存、缓存的htop
# apt install htop
  • 装个看系统网络流量连接的jnettop
# wget http://ftp.us.debian.org/debian/pool/main/j/jnettop/jnettop_0.13.0-1+b3_amd64.deb
# dpkg -i jnettop_0.13.0-1+b3_amd64.deb
  • 装个窗口分屏软件tmux
# apt install tmux
  • 将源码同步到最新状态
# cd /root/Desktop/COMPILE/aosp/
# repo sync -j8

-j8 是开启八个线程同时下载

这一步会持续非常久,大概要下载十几个G,具体取决于您的网速;

可以用jnettop看看网速,如果陷入假死状态,就ctrl-c终止进程,重新repo sync

环境都准备好了,关机打个快照吧,接下来编译不同版本的AOSP,都从这里开始。

开始动手编译

  • 重新开机后还是先挂载磁盘:
# mount /dev/sda3 /root/Desktop/COMPILE/
  • 然后进入该磁盘,进行代码检出和同步操作:
# cd /root/Desktop/COMPILE/aosp/
# mkdir WORKING_DIRECTORY
# cd WORKING_DIRECTORY
# repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-10.0.0_r2
# repo sync --current-branch

init那一步有个y要键入下

查看安卓版本的网站是AOSP – Codenames, Tags, and Build Numbers,需要科学上网,并且页面语言调成英文噢

  • 删除掉源码节约空间
# rm -rf /root/Desktop/COMPILE/aosp/.repo
  • 开始编译:导入环境变量
# cd /root/Desktop/COMPILE/aosp/
# source build/envsetup.sh
  • 选择设备:
# lunch
Buildtype Use
user Limited access; suited for production
userdebug Like user but with root access and debug capability; preferred for debugging
eng Development configuration with additional debugging tools

最终刷机的手机是pixel,并且是用于调试的,要带root,所以选择16

  • 开始编译,有多少个核心就是j几。
# make -j8

编译开始后,CPU会迅速权限飙到百分百,系统开始进行各项准备。

当开始出现百分比读数的时候,基本上进入“体力活儿”阶段,不会再出错了,除非内存给的不够,会报out of memory错误,给虚拟机加内存就行了,12G基本可以满足需求。

还有一个容易报错的阶段是编译接近完成时的链接阶段,主要还是因为各种环境和依赖没有满足,当然按照本教程来是不会出现那些问题的,毕竟我们都是同一个环境,所以会是同一个结果。

编译成功

下图为编译完成的画面。

编译完成的系统镜像位于当前目录的out/target/product/sailfish/下,各类img就是。

 

FART自动脱壳机全设备镜像制作

所谓内存型脱壳机,就是直接修改解释器的具体实现源码,在解释器的内存中直接将捕获到的dex对象给写到存储器中,下述代码是FART组件一之dump dex的核心源码:

const DexFile *dex_file = artmethod->GetDexFile();
const char *methodname =
    PrettyMethod(artmethod).c_str();

//确定dex大小
const uint8_t *begin_ = dex_file->Begin();
size_t size_ = dex_file->Size();
memset(dexfilepath, 0, 2000);
int size_int_ = (int) size_;
//构造路径
memset(dexfilepath, 0, 2000);
sprintf(dexfilepath, "%s", "/sdcard/fart");
mkdir(dexfilepath, 0777);
//构造文件名
memset(dexfilepath, 0, 2000);
sprintf(dexfilepath, "/sdcard/fart/%s",
        szProcName);
mkdir(dexfilepath, 0777);
//创建文件
memset(dexfilepath, 0, 2000);
sprintf(dexfilepath,
        "/sdcard/fart/%s/%d_dexfile.dex",
        szProcName, size_int_);
int dexfilefp = open(dexfilepath, O_RDONLY, 0666);
if (dexfilefp > 0) {
        close(dexfilefp);
        dexfilefp = 0;
//写入dex内容
} else {
        dexfilefp =
            open(dexfilepath, O_CREAT | O_RDWR,
                  0666);
        if (dexfilefp > 0) {
                write(dexfilefp, (void *) begin_,
                      size_);
                fsync(dexfilefp);
                close(dexfilefp);
        }
}

下方代码为FART第二组件构建主动调用链之后dump方法体并写入bin文件的核心代码:

const DexFile::CodeItem * code_item =
      artmethod->GetCodeItem();
  if (LIKELY(code_item != nullptr)) {
          int code_item_len = 0;
          uint8_t *item = (uint8_t *) code_item;
          //获取方法体大小
          if (code_item->tries_size_ > 0) {
                  const uint8_t *handler_data =
                      (const uint8_t *) (DexFile::
                                          GetTryItems
                                          (*code_item,
                                          code_item->
                                          tries_size_));
                  uint8_t *tail =
                      codeitem_end(&handler_data);
                  code_item_len =
                      (int) (tail - item);
          } else {
                  code_item_len =
                      16 +
                      code_item->
                      insns_size_in_code_units_ * 2;
          }
          //根据方法索引写入文件
          memset(dexfilepath, 0, 2000);
          int size_int = (int) dex_file->Size();  // Length of data
          uint32_t method_idx =
              artmethod->get_method_idx();
          sprintf(dexfilepath,
                  "/sdcard/fart/%s/%d_%ld.bin",
                  szProcName, size_int, gettidv1());
          int fp2 =
              open(dexfilepath,
                    O_CREAT | O_APPEND | O_RDWR,
                    0666);
          if (fp2 > 0) {
                  lseek(fp2, 0, SEEK_END);
                  memset(dexfilepath, 0, 2000);
                  int offset = (int) (item - begin_);
                  sprintf(dexfilepath,
                          "{name:%s,method_idx:%d,offset:%d,code_item_len:%d,ins:",
                          methodname, method_idx,
                          offset, code_item_len);
                  int contentlength = 0;
                  while (dexfilepath[contentlength]
                          != 0)
                          contentlength++;
                  write(fp2, (void *) dexfilepath,
                        contentlength);
                  long outlen = 0;
                  //对方法体进行编码,防止打开是乱码,使用fart.py进行还原时,会解码
                  char *base64result =
                      base64_encode((char *) item,
                                    (long)
                                    code_item_len,
                                    &outlen);
                  write(fp2, base64result, outlen);
                  write(fp2, "};", 2);
                  fsync(fp2);
                  close(fp2);
                  if (base64result != nullptr) {
                          free(base64result);
                          base64result = nullptr;
                  }
          }

  }

加入FART代码

这一步就非常简单了,相应的将artframeworkslibcore目录对应路径下的文件替换掉aosp源码里的文件即可,然后重新make -j8一遍,即可得到带脱壳功能的aosp镜像,也就是FART脱壳机。

寒冰大佬开源的是6.0的源码,大家手动编译aosp6.0FART脱壳机是没有问题的。

制作镜像刷机

官网(需科学上网)下载原设备的线刷包,注意下载对应设备并且与aosp版本相对应的版本,比如我们要下载nexus5xaosp6.0版本,就是下图所示:

手机如何线刷这个不写了吧?百度一下全都是。具体来说就是手机进bootloader,电脑上直接运行flash-all.sh就完事儿,当然路径里得有fastboot命令。

线刷包解压出来,里面会还有个系统zip包,这个系统zip再解压出来,才是各种系统的img

这时候把我们编译出来的各种img,替换掉原zip包的img,就可以刷进系统了。

 

总结

总结一下,难点在于编译aosp系统,只要会编译系统,改源码放进去其实很简单,当然最难的还是如何改源码,这个功力就更深了,再次膜寒冰大佬。

大家如果在编译、刷机和FART脱壳方面有疑问,欢迎联系我共同探讨。后续我也会进一步分享一些使用FART脱壳机进行脱壳的实际操作,敬请期待。

本文由roysue原创发布

转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/199898

安全客 - 有思想的安全新媒体

分享到:微信
+127赞
收藏
roysue
分享到:微信

发表评论

内容需知
  • 投稿须知
  • 转载须知
  • 官网QQ群8:819797106
  • 官网QQ群3:830462644(已满)
  • 官网QQ群2:814450983(已满)
  • 官网QQ群1:702511263(已满)
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 360网络攻防实验室 安全客 All Rights Reserved 京ICP备08010314号-66