菜鸡诈尸水贴之fart适配Android9

查看 109|回复 9
作者:Shutd0wn   
Android9拖壳机说明
适配了google pixel2的android 9版本,先看一下拖出来的样子


Screenshot from 2021-05-14 12-12-26.png (233.25 KB, 下载次数: 0)
下载附件
2021-5-18 10:46 上传



Screenshot from 2021-05-14 12-07-01.png (160.71 KB, 下载次数: 0)
下载附件
2021-5-18 10:46 上传

看一下修复后的结果


Screenshot from 2021-05-14 12-02-16.png (229.04 KB, 下载次数: 0)
下载附件
2021-5-18 10:46 上传

系统编译
下载源码
# ubuntu20.04编译android9
# 新系统下载aosp9
echo '更新系统,注意输入密码提示框'
sudo apt-get update && sudo apt-get upgrade -y
echo '安装python2'
sudo apt-get install python
echo '安装编译依赖'
sudo apt-get install bison g++-multilib git gperf libxml2-utils make zlib1g-dev:i386 zip liblz4-tool libncurses5 libssl-dev bc flex curl -y
echo '配置git'
git config -global user.email "[email protected]"
git config -global user.name "test"
echo '安装jdk8'
sudo apt-get install openjdk-8-jdk
echo '安装repo'
mkdir ~/bin
echo "PATH=~/bin:\$PATH" >> ~/.bashrc
source ~/.bashrc
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
echo '修改repo下载地址'
echo "export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'" >> ~/.bashrc
source ~/.bashrc
echo '创建aosp文件夹,下载镜像'
mkdir ~/AND_SOURCE
cd ~/AND_SOURCE
# PQ3A.190801.002
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-9.0.0_r46
repo sync -j4
# 强制更新
# repo sync --force-sync
下载驱动
# 下载https://developers.google.com/android/drivers驱动
# 找到与aosp版本对应的驱动版本
# 一般包含google与qcom两个文件,拷贝到aosp代码根目录下
# 解压出来sh文件后,执行解压驱动
$ ./extract-google_devices-*.sh
$ ./extract-qcom-*.sh
刷官方底包
# 版本信息
walleye-pq3a.190801.002
编译
cd ~/Downloads/AND_SOURCE
source build/envsetup.sh
lunch aosp_walleye-userdebug
export SOONG_GEN_CMAKEFILES=1
export SOONG_GEN_CMAKEFILES_DEBUG=1
make -j10
adb reboot bootloader
sleep 10
fastboot flashall
java导入android studio
在源码目录下继续执行如下命令:
./development/tools/idegen/idegen.sh
会在根目录下生成android.iml 和 android.ipr 这两个文件,打开 android.iml 文件,搜下excludeFolder,在后面加入如下代码:
打开 Android Studio,选择 Open an existing Android Studio project,找到源码目录,点击 Android.ipr,Open,等很久,导入完毕。
native导入clion
路径:out/development/ide/clion/建立一个CMakeLists.txt文件
cmake_minimum_required(VERSION 3.6)
project(AOSP-Native)
#// 添加子模块,导入了部分工程。工程很多,我是用到了再导入
add_subdirectory(frameworks/native)
add_subdirectory(art/dalvikvm/dalvikvm-arm64-android)
add_subdirectory(art/libdexfile/libdexfile-arm64-android)
add_subdirectory(art/runtime/libart-arm64-android)
add_subdirectory(bionic/libc/libc_bionic-arm64-android)
add_subdirectory(bionic/libc/libc_bionic_ndk-arm64-android)
add_subdirectory(bionic/libc/system_properties/libsystemproperties-arm64-android)
add_subdirectory(external/compiler-rt/lib/sanitizer_common/libsan-arm64-android)
add_subdirectory(frameworks/av/media/libaaudio/src/libaaudio-arm64-android)
add_subdirectory(frameworks/av/soundtrigger/libsoundtrigger-arm64-android)
add_subdirectory(frameworks/base/core/jni/libandroid_runtime-arm64-android)
add_subdirectory(frameworks/native/cmds/installd/installd-arm64-android)
add_subdirectory(frameworks/native/cmds/servicemanager/servicemanager-arm64-android)
add_subdirectory(frameworks/native/libs/binder/libbinder-arm64-android)
add_subdirectory(libcore/libjavacore-arm64-android)
add_subdirectory(libcore/libopenjdk-arm64-android)
add_subdirectory(libnativehelper/libnativehelper-arm64-android)
add_subdirectory(libnativehelper/libnativehelper_compat_libc++-arm64-android)
#add_subdirectory(kernel/msm-4.4/unifdef-x86_64-linux_glibc)
#// 内核的CMakeLists是自己写的,只导入了头文件,跳转还有问题
#add_subdirectory(kernel/msm-4.4/kernel_custom)
add_subdirectory(system/core/base/libbase-arm64-android)
add_subdirectory(system/core/init/libinit-arm64-android)
add_subdirectory(system/core/libziparchive/libziparchive-arm64-android)
add_subdirectory(system/core/liblog/liblog-arm64-android)
add_subdirectory(system/core/libcutils/libcutils-arm64-android)
add_subdirectory(system/core/libutils/libutils-arm64-android)
add_subdirectory(system/core/libprocessgroup/libprocessgroup-arm64-android)
add_subdirectory(system/core/logcat/logcatd-arm64-android)
add_subdirectory(system/core/logcat/liblogcat-arm64-android)
add_subdirectory(system/core/logd/logd-arm64-android)
add_subdirectory(system/core/logd/liblogd-arm64-android)
add_subdirectory(system/core/lmkd/liblmkd_utils-arm64-android)
add_subdirectory(system/core/lmkd/lmkd-arm64-android)
打开CLion,选择「New CMake Project from Sources」,指定包含 CMakeLists.txt 的目录out/development/ide/clion,选择「Open Existing Project」
导入之后目录结构是扁平的,需要修改工程根目录
  • Tools -> CMake -> Change Project Root,指定为你的源码的路径

    实际导入的过程中,CMakeLists.txt中可能报错,修改一下就好了。
    修改源码编译
    主要的流程如下


    Screenshot from 2021-05-14 13-53-38.png (48.39 KB, 下载次数: 0)
    下载附件
    2021-5-18 10:46 上传

    [ol]
  • OpenCommon下面开始保存Dex文件与classnamelist
  • ActivityThread的startOrNot发起fakeInvoke的调用
  • fakeInvoke获取classnamelist,然后过滤一下不需要主动加载的类,然后加载类,获取所有的方法,开始主动调用。
    [/ol]
    其实是把FART的思想移植到android 9中,参考了AUPK的部分代码。具体见代码。
    先dump dex文件与classname文件:dumpDexFileAndClassNames
    std::unique_ptr ArtDexFileLoader::OpenCommon(const uint8_t* base,
                                                          size_t size,
                                                          const uint8_t* data_base,
                                                          size_t data_size,
                                                          const std::string& location,
                                                          uint32_t location_checksum,
                                                          const OatDexFile* oat_dex_file,
                                                          bool verify,
                                                          bool verify_checksum,
                                                          std::string* error_msg,
                                                          std::unique_ptr container,
                                                          VerifyResult* verify_result) {
      std::unique_ptr dex_file = DexFileLoader::OpenCommon(base,
                                                                    size,
                                                                    data_base,
                                                                    data_size,
                                                                    location,
                                                                    location_checksum,
                                                                    oat_dex_file,
                                                                    verify,
                                                                    verify_checksum,
                                                                    error_msg,
                                                                    std::move(container),
                                                                    verify_result);
      // Check if this dex file is located in the framework directory.
      // If it is, set a flag on the dex file. This is used by hidden API
      // policy decision logic.
      // Location can contain multidex suffix, so fetch its canonical version. Note
      // that this will call `realpath`.
      Laster::dumpDexFileAndClassNames(dex_file);
      std::string path = DexFileLoader::GetDexCanonicalLocation(location.c_str());
      if (dex_file != nullptr && LocationIsOnSystemFramework(path.c_str())) {
        dex_file->SetIsPlatformDexFile();
      }
      return dex_file;
    }
        void Laster::dumpDexFileAndClassNames(std::unique_ptr &dex_file) {
            std::string configPkgName = Laster::readConfigFile();
            std::string procName = Laster::getProcessName();
            if (!configPkgName.empty()) {
                LOG(WARNING)
    再启动加载类遍历方法调用:startOrNot
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            ......
            String packageName = r.packageInfo.getPackageName();
            String activityName = r.activityInfo.name;
            Log.i("Laster", "ActivityThread:performLaunchActivity, packageName: " + packageName + ", activityName: " + activityName);
            Laster.startOrNot(packageName, r.activity.getClassLoader());
            return activity;
        }
    public static synchronized void startOrNot(String packageName, final ClassLoader classLoader) {
            String readFileDirStr = "/data/data/" + packageName + "/dexfile/";
            Log.d("Laster", "startOrNot read file dir: " + readFileDirStr);
            if (isDirExist(readFileDirStr)) {
                cleanDirFiles(readFileDirStr);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Log.d("Laster", "startOrNot  sleep 5s");
                            Thread.sleep(5 * 1000);
                            Log.d("Laster", "startOrNot  try to start...");
                            initFilterList();
                            File[] classNameFileList = getClassnameFileList(readFileDirStr);
                            for (File file : classNameFileList) {
                                Set classnameSet = readFileList(file.getAbsolutePath());
                                classnameSet = filterClassNameList(classnameSet);
                                Log.d("Laster", "startOrNot  try to get classnameSet");
                                if (classnameSet != null) {
                                    Log.d("Laster", "startOrNot  try to get start to dump method insn");
                                    startToDumpMethodInsn(classnameSet, classLoader, packageName);
                                }
                                Thread.sleep(1500);
                            }
                        } catch (Exception e) {
                            Log.d("Laster", "startOrNot: error, " + e.getMessage());
                        }
                    }
                }).start();
            }
        }
    ......
            private static synchronized void startToDumpMethodInsn(Set classnameSet, ClassLoader loader, String packageName) {
            try {
                for (String classname : classnameSet) {
                    Class target = null;
                    try {
                        saveClassnameList(classname, packageName);
                        target = loader.loadClass(classname);
                    } catch (Exception e) {
                    }
                    if (target != null) {
                        List methodList = getAllClassMethods(target);
                        for (Object method : methodList) {
                            try {
                                if (method instanceof Method) {
                                    Log.d("Laster", "Start to dump dex file class method name: " + ((Method) method).getName());
                                } else {
                                    Log.d("Laster", "Start to dump dex file class cons name: " + ((Constructor) method).getName());
                                }
                                # 这里调用native层的方法开始模拟调用
                                fakeInvoke(method);
                            } catch (Exception e) {
                                Log.d("Laster", "Start to dump dex file class method error!");
                            }
                        }
                    }
                }
            } catch (Exception e) {
                Log.d("Laster", "startToDumpMethodInst: error, " + e.getMessage());
            }
        }
    native层抄了FART与AUPK的部分代码,只是对Android 9做了适配。
    刷机测试
    安装目标应用,
    在/data/local/tmp/下配置两个文件
    # 配置过滤class,有些class不需要加载
    filter.config
    # 配置需要拖壳的包名
    laster.config


    image-20210514141759232.png (64.09 KB, 下载次数: 0)
    下载附件
    2021-5-18 10:46 上传



    image-20210514141829011.png (15.2 KB, 下载次数: 0)
    下载附件
    2021-5-18 10:46 上传

    点击app,启动,等待拖壳完成,看日志如果方法加载完成。就算结束了。
    复制出dex文件
    adb shell
    su
    cd /data/data/packagename/
    cp -r dexfile/ ~/sdcard/
    exit
    exit
    adb pull /sdcard/dexfile ./
    拷贝dex文件与method文件到到一个文件夹,使用python脚本修复:


    image-20210514142552884.png (21.17 KB, 下载次数: 0)
    下载附件
    2021-5-18 10:46 上传

    python3 fart_fix_dex_00.py -d dex_*.dex -b dex_*_method.txt
    编译Release版本
    Android标准签名key文件位于源码/build/target/product/security目录下,四组默认签名供Android.mk在编译APK使用。主要有4个key:
  • testkey:普通签名APK,默认情况下使用。
  • platform:该APK完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的APK所在进程的UID为system。
  • shared:该APK需要和home/contacts进程共享数据。
  • media:该APK是media/download系统中的一环。

    应用程序的Android.mk中有一个LOCAL_CERTIFICATE字段,由它指定哪个key签名,未指定的默认用testkey.
    build/target/product/security目录下查看:


    image-20201125172656538.png (58.12 KB, 下载次数: 0)
    下载附件
    2021-5-18 10:46 上传

    *.pk8代表私钥,*.x509.pem公钥,它们都是成对出现;
    testkey是作为android编译的时候默认的签名key,如果系统中的apk的Android.mk中没有设置LOCAL_CERTIFICATE的值,就默认使用testkey。
    在aosp代码根目录下创建脚本,生成key
    # create_cert.sh
    subject='/C=CN/ST=Shanghai/L=Shanghai/O=ingeek/OU=mo/CN=www.ingeek.com/[email protected]'
    for x in releasekey platform shared media;
    do
      ./development/tools/make_key ./build/target/product/security/$x "$subject";
    done
    另存/build/target/product/security下所有证书信息,保存原始key
    $ cd ./build/target/product/security/
    $ mkdir bak
    $ mv *.pk8 bak/
    $ mv *.pem bak/
    $ cd bak/
    $ cp verity ../
    运行脚本创建key,提示输入密码时,直接回车,使用默认密码。
    修改默认签名key
    [ol]

  • 修改Android配置./build/core/config.mk中定义变量:
    # The default key if not set as LOCAL_CERTIFICATE
    ifdef PRODUCT_DEFAULT_DEV_CERTIFICATE
    DEFAULT_SYSTEM_DEV_CERTIFICATE := $(PRODUCT_DEFAULT_DEV_CERTIFICATE)
    else
    + DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/releasekey
    - DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/testkey
    endif

  • 修改./build/core/Makefile中定义变量:
    ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/target/product/security/releasekey)
    BUILD_KEYS := release-keys

  • 修改./system/sepolicy/private/keys.conf和./system/sepolicy/prebuilts/api/{apilevel}/private/keys.conf
    # Example of ALL TARGET_BUILD_VARIANTS
    [@RELEASE]
    ENG       : $DEFAULT_SYSTEM_DEV_CERTIFICATE/releasekey.x509.pem
    USER      : $DEFAULT_SYSTEM_DEV_CERTIFICATE/releasekey.x509.pem
    USERDEBUG : $DEFAULT_SYSTEM_DEV_CERTIFICATE/releasekey.x509.pem

  • 添加user版本编译选项(如果lunch中没有)
    cd ./device
    grep -ril 'aosp_walleye-userdebug' # 按照你的手机来
    ./google/muskie/vendorsetup.sh
    gedit ./google/muskie/vendorsetup.sh
    # 添加一行
    # add_lunch_combo aosp_walleye-user
    [/ol]
    编译系统
    cd ~/Downloads/AND_SOURCE
    source build/envsetup.sh
    lunch aosp_walleye-user
    make clean
    export SOONG_GEN_CMAKEFILES=1
    export SOONG_GEN_CMAKEFILES_DEBUG=1
    make -j10
    adb reboot bootloader
    sleep 10
    fastboot flashall
    # 如果开不了机,进入recovery双清一下
    使用
    [ol]

  • root你的手机,安装应用

  • 配置packagename到/data/local/tmp/laster.config
    echo 'packagename' > /data/local/tmp/laster.config

  • 点击apk启动,等一会,如果你只是想dump出dex文件,那么现在你就可以去
    /data/data/packagename/dexfile/
    下面拿到dex文件

  • 如果你还想尝试修复抽取的代码,那么你现在可以先删掉
    /data/local/tmp/laster.config
    这个文件,然后不停的点开你的apk,然后通过日志,或者
    /data/data/packagename/dexfile/loaded.txt
    查看主动调用到哪个class失败了,然后在
    /data/local/tmp/filter.config
    中配置过滤来尝试尽可能的多加载类,如果一切顺利apk没有闪退会在
    /data/data/packagename/dexfile/
    产生对应的method.txt文件,拖出来尝试使用python脚本修复。
    [/ol]
    windows下python脚本修复
    安装kaitaistruct
    pip install --upgrade git+https://github.com/kaitai-io/kaitai_struct_python_runtime.git
    使用
    python3 fart_fix_dex_00.py -d dexfile -b binfile
    测试镜像
    链接:https://pan.baidu.com/s/1sMLDq6Mr5K8GmLe8IunNVQ
    提取码:PV74

    文件, 下载次数

  • guangzisam   

    用FART脱壳。没官网地址,没说明官方适配Android版本
    bant   

    标题有鬼吹灯的赶脚
    贾东平   

    这个真不错啊。
    茶茶大人L   

    不明觉厉,前排
    xixicoco   

    牛逼的,支持你
    fzj   

    楼主厉害,感谢分享
    紫色叶景   

    感谢楼主分享 这个思路还是很有参考性的 学习一下
    legs   

    感谢楼主分享,想法很好,学习一下
    shiqiangge   

    感谢分享心得,学习了
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部