首页
社区
课程
招聘
[原创]LineageOS20+Pixel6 下的Fart8.0脱壳机迁移和编译流程
2023-9-5 23:13 11209

[原创]LineageOS20+Pixel6 下的Fart8.0脱壳机迁移和编译流程

2023-9-5 23:13
11209

LineageOS20+Pixel6 下的Fart8.0脱壳机迁移和编译流程

一.LineageOS20源码下载和编译

1.选择LineageOS20系统的原因

​ 之前将Fart8.0的代码编译到Android13下,运行发现在将Java的Method对象转换成C的ArtMethod对象时报错,没找到原因。再加上AOSP的系统太素了,就琢磨是否可以用LineageOS来编译,所以就有了这篇文章。

​ 先罗列一下我的环境吧,编译环境是Kali2022,用的r0ysue大佬的集成版,手机是Pixel6,选择的系统是LineageOS20版(基于AOSP13)的,原本想用基于AOSP10的Lineage17的,但是官网同步源码后发现缺少device blob,遂决定就用20版。

2. LineageOS20源码下载和编译

1.2.1.虚拟机设置

我的虚拟机设置了32G内存,8核CPU,500G的硬盘,实际下载编译完成占用了快300G空间。这里坑的地方在于同样的配置,我的AOSP能顺利编译完成,但在编译LineageOS时中途报错,检查原因发现是因为swap只有1G大小,在设置了swap为20G后,才编译成功。

1
2
3
4
5
swapoff -a
dd if=/dev/zero of=/var/swapfile bs=1M count=20480
mkswap /var/swapfile
swapon /var/swapfile
free -m  --查看当前分区

1.2.2 编译环境配置

  • 安装编译必须的组件
1
2
3
4
apt-get update
apt-get install bc bison build-essential ccache curl flex g++-multilib gcc-multilib git git-lfs gnupg gperf imagemagick
lib32ncurses5-dev lib32readline-dev lib32z1-dev libelf-dev liblz4-tool libncurses5 libncurses5-dev
libsdl1.2-dev libssl-dev libxml2 libxml2-utils lzop pngcrush rsync schedtool squashfs-tools xsltproc zip zlib1g-dev m4
  • 安装好git和 platform-tools 并配置环境变量

  • 创建源码所需目录(默认在kali root账户下)

    1
    2
    mkdir -p ~/bin
    mkdir -p ~/android/lineage
  • 安装repo命令行工具

    1
    2
    curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
    chmod a+x ~/bin/repo
  • 将bin目录添加进环境变量。

​ 使用下面的命令打开~/.bashrc文件,

1
vim ~/.bashrc

​ 在文件最后添加下面的代码:

1
2
3
4
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi
  • 配置git

    1
    2
    git config --global user.email "you@example.com"#替换成你的邮件 随便写
    git config --global user.name "Your Name"  #替换成你的用户名 随便写

    查看git lfs是否安装

    1
    2
    3
    curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
    apt-get install git-lfs
    git lfs install #查看是否安装成功。
  • 配置缓存,加快编译速度

    1
    2
    export USE_CCACHE=1
    export CCACHE_EXEC=/usr/bin/ccache

    可将其加入到~/.bashrc文件中,并在命令行执行下行

    1
    ccache -M 50G

1.2.3 下载LineageOS源码

  • 初始化LineageOS source repository

    1
    2
    cd ~/android/lineage
    repo init -u https://github.com/LineageOS/android.git -b lineage-20.0 --git-lfs

    这里最好不要换成国内源,因为国内源同步出来的代码,我在编译时碰到浏览器app编译失败的问题,重新从官方源同步才解决,查看清华的issue发现有同样的问题,坑死了。

  • 下载源码

    1
    repo sync -j8

    上面的-j8是启动8个线程下载,可以不要,默认是4个线程。取决于你的虚拟机cpu内核数。由于网络问题,如果同步完成后报错,可根据提示,将线程数减为1,重新执行该命令即可。

  • 下载设备内核代码

    确保你在源码根目录下 ( <font color='red'>cd ~/android/lineage</font> )

    1
    2
    source build/envsetup.sh
    breakfast oriole  #这里也可使用lunch 选择官方提供的机型  如果没有的你要的机型需要到git上搜索相应机型的kernel

下载源码整个过程根据网速会有1段时间,我自己搭建了科学上网的软路由,整个时间有3个小时左右。

下载完kernel源码后会报如下的错误,这是因为还没有下载device blob的缘故,暂时不用管,下载完device blob后再重新执行上面的命令即可

image-20230905183014828

1.2.4 提取专有device blob

这里是个大坑。我按照官方推荐的方式直接从已经安装了LineageOS的piexl6手机上提取blob,结果有几千个文件没有找到,害的我折腾了2天。总算使用官方镜像提取成功。下面是过程。

  • 创建提取目录

    1
    2
    mkdir ~/android/system_dump/
    cd ~/android/system_dump/
  • 下载官方镜像 LineageOS Downloads

    image-20230905185252612

  • 从zip文件中解压出 payload.bin文件

    1
    unzip /path/to/lineage-*.zip payload.bin
  • 安装 python-protobuf

    1
    apt-get install python-protobuf
  • 下载官方提供的导出脚本,然后用python运行脚本,注意脚本目录路径

    1
    2
    git clone https://github.com/LineageOS/scripts
    python scripts/update-payload-extractor/extract.py payload.bin --output_dir ./

    成功运行后,应该能在system_dump目录下看到如下一些.img文件
    image-20230905190110559

然后使用mout命令挂载这些img文件

1
2
3
4
5
mkdir system/
sudo mount -o ro system.img system/
sudo mount -o ro vendor.img system/vendor/
sudo mount -o ro product.img system/product/
sudo mount -o ro system_ext.img system/system_ext/
  • 进入<font color='red'>~/android/lineage/device/google/oriole</font>文件夹 运行如下命令 导出blob文件

    1
    2
    cd ~/android/lineage/device/google/oriole
    ./extract-files.sh ~/android/system_dump/
  • 重新执行如下命令

    1
    2
    source build/envsetup.sh
    breakfast oriole

1.2.5 编译源码

1
2
croot
brunch oriole

编译时间在2小时左右,尤其最后阶段编译kernel会持续50多分钟,这里即使我的内存设置到了32G,也不够用,需要设置swap,而且每次修改源码再编译 都会要重新编译这个kernel,很耗费时间,暂时没找到不重复编译的办法,在XDA上看到可以下载prebuild的内核,避免重复编译,实在懒折腾了,所以没尝试。

编译成功后会在/root/android/lineage/out/target/product/oriole目录下生成boot.img 和 lineage-20.0****.zip文件。按照官方文档替换官方镜像刷机即可。
image-20230905192434053

1.2.6 刷机过程

按照官方文档操作即可。实在懒翻译了

Install LineageOS on oriole | LineageOS Wiki

1.2.7 源码导入AndroidStudio和CLion

为了方便修改源码,减少报错,可以将源码中的Java代码导入AndroidStudio,C语言代码导入CLionAS导入Android源码

  • Java代码导入AndroidStudio
  1. 先成功编译一次,再使用以下方法导入

  2. 在ubuntu系统下,进入源码根目录,运行如下命令, 会在源码目录下的out/host/linux-x86/framework目录下生成了idegen.jar文件

    1
    2
    3
    source build/envsetup.sh
     
    mmm development/tools/idegen/
  3. 在源码根目录下继续执行如下命令,会在根目录下生成android.iml和android.ipr两个文件,这两个文件是AndroidStudio的工程配置文件

1
development/tools/idegen/idegen.sh
  1. 安装并打开AndroidStudio,选择Open an existing Android Studio project,找到源码根目录,点击Android.ipr

  2. 具体参考:https://wuxiaolong.me/2018/08/15/AOSP3/

    我在AOSP中成功导入了AS,但在LineageOS源码中在执行到第3步时长时间卡住,等了30个小时不动,没辙只好放弃。改用VSCode编辑java代码。

  • C/C++代码导入CLion

    1. 生成用于将源码导入Clion的CMakeLists.txt
    1
    2
    3
    4
    5
    source build/envsetup.sh
    #打开开关,编译时生成CMakeLists.txt
    export SOONG_GEN_CMAKEFILES=1
    export SOONG_GEN_CMAKEFILES_DEBUG=1
    breakfast oriole

    CMakeLists.txt会生成在out/development/ide/clion/art/runtime/libart-arm64-android/CMakeLists.txt

    1. 用Clion打开CMakeLists.txt

    2. tools--->cmake-->Change Project Root

    ​ 选择aosp源码根路径,等解析完毕即可

二. Fart8.0源码迁移

2.1修改Fart脱壳机的Java层代码

Java代码可按上面导入的步骤,用AS编辑

  • 修改LineageOS源码的/root/android/lineage/frameworks/base/core/java/android/app/ActivityThread.java文件,将Fart8.0对应文件中添加的部分复制到该文件中,并导入对应的包,为了防止加固厂商的检测,修改了函数名和日志输出。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    //add
     public static Field getClassField(ClassLoader classloader, String class_name,
                                         String filedName) {
     
           try {
               Class obj_class = classloader.loadClass(class_name);//Class.forName(class_name);
               Field field = obj_class.getDeclaredField(filedName);
               field.setAccessible(true);
               return field;
           } catch (SecurityException e) {
               e.printStackTrace();
           } catch (NoSuchFieldException e) {
               e.printStackTrace();
           } catch (IllegalArgumentException e) {
               e.printStackTrace();
           } catch (ClassNotFoundException e) {
               e.printStackTrace();
           }
           return null;
     
       }
     
       public static Object getClassFieldObject(ClassLoader classloader, String class_name, Object obj,
                                                String filedName) {
     
           try {
               Class obj_class = classloader.loadClass(class_name);//Class.forName(class_name);
               Field field = obj_class.getDeclaredField(filedName);
               field.setAccessible(true);
               Object result = null;
               result = field.get(obj);
               return result;
           } catch (SecurityException e) {
               e.printStackTrace();
           } catch (NoSuchFieldException e) {
               e.printStackTrace();
           } catch (IllegalArgumentException e) {
               e.printStackTrace();
           } catch (ClassNotFoundException e) {
               e.printStackTrace();
           } catch (IllegalAccessException e) {
               e.printStackTrace();
           }
           return null;
     
       }
     
       public static Object invokeStaticMethod(String class_name,
                                               String method_name, Class[] pareTyple, Object[] pareVaules) {
     
           try {
               Class obj_class = Class.forName(class_name);
               Method method = obj_class.getMethod(method_name, pareTyple);
               return method.invoke(null, pareVaules);
           } catch (SecurityException e) {
               e.printStackTrace();
           } catch (IllegalArgumentException e) {
               e.printStackTrace();
           } catch (IllegalAccessException e) {
               e.printStackTrace();
           } catch (NoSuchMethodException e) {
               e.printStackTrace();
           } catch (InvocationTargetException e) {
               e.printStackTrace();
           } catch (ClassNotFoundException e) {
               e.printStackTrace();
           }
           return null;
     
       }
     
       public static Object getFieldOjbect(String class_name, Object obj,
                                           String filedName) {
           try {
               Class obj_class = Class.forName(class_name);
               Field field = obj_class.getDeclaredField(filedName);
               field.setAccessible(true);
               return field.get(obj);
           } catch (SecurityException e) {
               e.printStackTrace();
           } catch (NoSuchFieldException e) {
               e.printStackTrace();
           } catch (IllegalArgumentException e) {
               e.printStackTrace();
           } catch (IllegalAccessException e) {
               e.printStackTrace();
           } catch (ClassNotFoundException e) {
               e.printStackTrace();
           } catch (NullPointerException e) {
               e.printStackTrace();
           }
           return null;
     
       }
     
       public static ClassLoader getClassloader() {
           ClassLoader resultClassloader = null;
           Object currentActivityThread = invokeStaticMethod(
                   "android.app.ActivityThread", "currentActivityThread",
                   new Class[]{}, new Object[]{});
           Object mBoundApplication = getFieldOjbect(
                   "android.app.ActivityThread", currentActivityThread,
                   "mBoundApplication");
           Application mInitialApplication = (Application) getFieldOjbect("android.app.ActivityThread",
                   currentActivityThread, "mInitialApplication");
           Object loadedApkInfo = getFieldOjbect(
                   "android.app.ActivityThread$AppBindData",
                   mBoundApplication, "info");
           Application mApplication = (Application) getFieldOjbect("android.app.LoadedApk", loadedApkInfo, "mApplication");
           resultClassloader = mApplication.getClassLoader();
           return resultClassloader;
       }
       public static void loadClassAndCall(ClassLoader appClassloader, String eachclassname, Method saveMethodCode) {
           Class resultclass = null;
           Log.i("wayne", "go into loadClassAndCall->" + "classname:" + eachclassname);
           try {
               resultclass = appClassloader.loadClass(eachclassname);
           } catch (Exception e) {
               e.printStackTrace();
               return;
           } catch (Error e) {
               e.printStackTrace();
               return;
           }
           if (resultclass != null) {
               try {
                   Constructor<?> cons[] = resultclass.getDeclaredConstructors();
                   for (Constructor<?> constructor : cons) {
                       if (saveMethodCode != null) {
                           try {
                               saveMethodCode.invoke(null, constructor);
                           } catch (Exception e) {
                               e.printStackTrace();
                               continue;
                           } catch (Error e) {
                               e.printStackTrace();
                               continue;
                           }
                       } else {
                           Log.e("wayne", "saveMethodCode is null ");
                       }
     
                   }
               } catch (Exception e) {
                   e.printStackTrace();
               } catch (Error e) {
                   e.printStackTrace();
               }
               try {
                   Method[] methods = resultclass.getDeclaredMethods();
                   if (methods != null) {
                       for (Method m : methods) {
                           if (saveMethodCode != null) {
                               try {
                                   saveMethodCode.invoke(null, m);
                                } catch (Exception e) {
                                   e.printStackTrace();
                                   continue;
                               } catch (Error e) {
                                   e.printStackTrace();
                                   continue;
                               }
                           } else {
                               Log.e("wayne", "saveMethodCode is null ");
                           }
                       }
                   }
               } catch (Exception e) {
                   e.printStackTrace();
               } catch (Error e) {
                   e.printStackTrace();
               }
           }
       }
       public static void wayne() {
           ClassLoader appClassloader = getClassloader();
           ClassLoader tmpClassloader=appClassloader;
           ClassLoader parentClassloader=appClassloader.getParent();
           if(appClassloader.toString().indexOf("java.lang.BootClassLoader")==-1)
           {
               wayneDoWithClassloader(appClassloader);
           }
           while(parentClassloader!=null){
               if(parentClassloader.toString().indexOf("java.lang.BootClassLoader")==-1)
               {
                   wayneDoWithClassloader(parentClassloader);
               }
               tmpClassloader=parentClassloader;
               parentClassloader=parentClassloader.getParent();
           }
       }
       public static void wayneDoWithClassloader(ClassLoader appClassloader) {
           List<Object> dexFilesArray = new ArrayList<Object>();
           Field pathList_Field = (Field) getClassField(appClassloader, "dalvik.system.BaseDexClassLoader", "pathList");
           Object pathList_object = getFieldOjbect("dalvik.system.BaseDexClassLoader", appClassloader, "pathList");
           Object[] ElementsArray = (Object[]) getFieldOjbect("dalvik.system.DexPathList", pathList_object, "dexElements");
           Field dexFile_fileField = null;
           try {
               dexFile_fileField = (Field) getClassField(appClassloader, "dalvik.system.DexPathList$Element", "dexFile");
           } catch (Exception e) {
                   e.printStackTrace();
               } catch (Error e) {
                   e.printStackTrace();
               }
           Class DexFileClazz = null;
           try {
               DexFileClazz = appClassloader.loadClass("dalvik.system.DexFile");
           } catch (Exception e) {
                   e.printStackTrace();
               } catch (Error e) {
                   e.printStackTrace();
               }
           Method _getClassNameList = null;
           Method _saveMethodCode = null;
     
           for (Method field : DexFileClazz.getDeclaredMethods()) {
               if (field.getName().equals("getClassNameList")) {
                   _getClassNameList = field;
                   _getClassNameList.setAccessible(true);
               }
               if (field.getName().equals("saveMethodCode")) {
                   _saveMethodCode = field;
                   _saveMethodCode.setAccessible(true);
               }
           }
           Field mCookiefield = getClassField(appClassloader, "dalvik.system.DexFile", "mCookie");
           Log.e("wayne->methods", "dalvik.system.DexPathList.ElementsArray.length:" + ElementsArray.length);//5个
           for (int j = 0; j < ElementsArray.length; j++) {
               Object element = ElementsArray[j];
               Object dexfile = null;
               try {
                   dexfile = (Object) dexFile_fileField.get(element);
               } catch (Exception e) {
                   e.printStackTrace();
               } catch (Error e) {
                   e.printStackTrace();
               }
               if (dexfile == null) {
                   Log.e("ActivityThread", "dexfile is null");
                   continue;
               }
               if (dexfile != null) {
                   dexFilesArray.add(dexfile);
                   Object mcookie = getClassFieldObject(appClassloader, "dalvik.system.DexFile", dexfile, "mCookie");
                   if (mcookie == null) {
                       Object mInternalCookie = getClassFieldObject(appClassloader, "dalvik.system.DexFile", dexfile, "mInternalCookie");
                       if(mInternalCookie!=null)
                       {
                           mcookie=mInternalCookie;
                       }else{
                               Log.e("wayne->err", "get mInternalCookie is null");
                               continue;
                               }
                        
                   }
                   String[] classnames = null;
                   try {
                       classnames = (String[]) _getClassNameList.invoke(dexfile, mcookie);
                   } catch (Exception e) {
                       e.printStackTrace();
                       continue;
                   } catch (Error e) {
                       e.printStackTrace();
                       continue;
                   }
                   if (classnames != null) {
                       for (String eachclassname : classnames) {
                           loadClassAndCall(appClassloader, eachclassname, _saveMethodCode);
                       }
                   }
     
               }
           }
           return;
       }
       
       public static void wayneThread() {
           new Thread(new Runnable() {
     
               @Override
               public void run() {
                   // TODO Auto-generated method stub
                   try {
                       Log.e("wayne", "start sleep......");
                       Thread.sleep(1 * 60 * 1000);
                   } catch (InterruptedException e) {
                       // TODO Auto-generated catch block
                       e.printStackTrace();
                   }
                   Log.e("wayne", "sleep over and start myshell");
                   wayne();
                   Log.e("wayne", "myshell run over");
     
               }
           }).start();
       }
     //add

    在文件中的performLaunchActivity方法最后添加 wayneThread()方法的调用。

1693921584305

  • 修改源码 /root/android/lineage/libcore/dalvik/src/main/java/dalvik/system/DexFile.java文件,将Fart8.0中添加的方法定义复制过来,并修改方法命名,

    1
    2
    3
    //add
    private static native void saveMethodCode(Object m);
    //add

2.2修改Fart8.0 SO层代码

SO层的c\c++代码可按上面的步骤导入CLion编辑。

  • 在DexFile.java文件对应的so实现文件,即/root/android/lineage/art/runtime/native/dalvik_system_DexFile.cc文件中添加之前saveMethodCode方法的so层实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//addfunction
    static void DexFile_saveMethodCode(JNIEnv* env, jclass,jobject method) {
        if(method!=nullptr)
        {
            LOG(ERROR) << "wayne +++++++++++";
            ArtMethod* proxy_method = jobject2ArtMethod(env, method);
            LOG(ERROR) << "wayne -----------";
            myWayneCall(proxy_method);
            LOG(ERROR) << "wayne -+-+-+-+-+-+-+";
        }
         
        return;
    }
//addfunction
  • 修改该文件最开始的art命名空间

    1
    2
    3
    4
    5
    6
    //add
    #include "scoped_fast_native_object_access.h"
    namespace art {
        extern "C" void myWayneCall(ArtMethod* artmethod);
        extern "C" ArtMethod* jobject2ArtMethod(JNIEnv* env, jobject javaMethod);
    //addend
  • 在该文件最末尾添加saveMethodCode函数的函数名命名定义,<font color='red'>注意在上一行末尾添加逗号</font>
    image-20230905220022645

  • 编辑 /root/android/lineage/art/runtime/native/java_lang_reflect_Method.cc文件,添加上面用到的jobject2ArtMethod函数

//add
    extern "C" ArtMethod* jobject2ArtMethod(JNIEnv* env, jobject javaMethod) {
        ScopedFastNativeObjectAccess soa(env);
        ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
        return method;
    }
//add
  • 编辑/root/android/lineage/art/runtime/art_method.cc文件,将Fart8.0源码同名文件中添加的代码复制到该代码中,并修改函数名和日志输出内容。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    //add
        uint8_t* codeitem_end(const uint8_t **pData)
        {
            uint32_t num_of_list = DecodeUnsignedLeb128(pData);
            for (;num_of_list>0;num_of_list--) {
                int32_t num_of_handlers=DecodeSignedLeb128(pData);
                int num=num_of_handlers;
                if (num_of_handlers<=0) {
                    num=-num_of_handlers;
                }
                for (; num > 0; num--) {
                    DecodeUnsignedLeb128(pData);
                    DecodeUnsignedLeb128(pData);
                }
                if (num_of_handlers<=0) {
                    DecodeUnsignedLeb128(pData);
                }
            }
            return (uint8_t*)(*pData);
        }
     
        extern "C" char *base64_encode(char *str,long str_len,long* outlen){
            long len;
            char *res;
            int i,j;
            const char *base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
            if(str_len % 3 == 0)
                len=str_len/3*4;
            else
                len=(str_len/3+1)*4;
     
            res=(char*)malloc(sizeof(char)*(len+1));
            res[len]='\0';
            *outlen=len;
            for(i=0,j=0;i<len-2;j+=3,i+=4)
            {
                res[i]=base64_table[str[j]>>2];
                res[i+1]=base64_table[(str[j]&0x3)<<4 | (str[j+1]>>4)];
                res[i+2]=base64_table[(str[j+1]&0xf)<<2 | (str[j+2]>>6)];
                res[i+3]=base64_table[str[j+2]&0x3f];
            }
     
            switch(str_len % 3)
            {
                case 1:
                    res[i-2]='=';
                    res[i-1]='=';
                    break;
                case 2:
                    res[i-1]='=';
                    break;
            }
     
            return res;
        }
        extern "C" void saveDexFileByExeMethod(ArtMethod* artmethod)  REQUIRES_SHARED(Locks::mutator_lock_) {
            char *dexfilepath=(char*)malloc(sizeof(char)*1000);
            if(dexfilepath==nullptr)
            {
                LOG(ERROR)<< "wayne::saveDexFileByExeMethod,methodName:"<<artmethod->PrettyMethod().c_str()<<"malloc 1000 byte failed";
                return;
            }
            int result=0;
            int fcmdline =-1;
            char szCmdline[64]= {0};
            char szProcName[256] = {0};
            int procid = getpid();
            sprintf(szCmdline,"/proc/%d/cmdline", procid);
            fcmdline = open(szCmdline, O_RDONLY|O_CREAT,0644);
            if(fcmdline >0)
            {
                result=read(fcmdline, szProcName,256);
                if(result<0)
                {
                    LOG(ERROR) << "wayne::saveDexFileByExeMethod,open cmdline file error";
                }
                close(fcmdline);
     
            }
     
            if(szProcName[0])
            {
     
                const DexFile* dex_file = artmethod->GetDexFile();
                const uint8_t* begin_=dex_file->Begin();  // Start of data.
                size_t size_=dex_file->Size();  // Length of data.
     
                memset(dexfilepath,0,1000);
                int size_int_=(int)size_;
     
     
                memset(dexfilepath,0,1000);
                sprintf(dexfilepath,"/data/data/%s/wayne",szProcName);
                mkdir(dexfilepath,0777);
     
                memset(dexfilepath,0,1000);
                sprintf(dexfilepath,"/data/data/%s/wayne/%d_dexfile_execute.dex",szProcName,size_int_);
                if(access(dexfilepath,F_OK)!=-1){
                    LOG(ERROR) << dexfilepath << "File have exist";
                }else{
                    int fp=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666);
                    if(fp>0)
                    {
                        result=write(fp,(void*)begin_,size_);
                        if(result<0)
                        {
                            LOG(ERROR) << "wayne::saveDexFileByExeMethod,open dexfilepath error";
                        }
                        fsync(fp);
                        close(fp);
                        memset(dexfilepath,0,1000);
                        sprintf(dexfilepath,"/data/data/%s/wayne/%d_classlist_execute.txt",szProcName,size_int_);
                        int classlistfile=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666);
                        if(classlistfile>0)
                        {
                            for (size_t ii= 0; ii< dex_file->NumClassDefs(); ++ii)
                            {
                                const dex::ClassDef& class_def = dex_file->GetClassDef(ii);
                                const char* descriptor = dex_file->GetClassDescriptor(class_def);
                                result=write(classlistfile,(void*)descriptor,strlen(descriptor));
                                if(result<0)
                                {
                                    LOG(ERROR) << "wayne::saveDexFileByExeMethod,write classlistfile file error";
     
                                }
                                const char* temp="\n";
                                result=write(classlistfile,(void*)temp,1);
                                if(result<0)
                                {
                                    LOG(ERROR) << "wayne::saveDexFileByExeMethod,write classlistfile file error";
     
                                }
                            }
                            fsync(classlistfile);
                            close(classlistfile);
     
                        }
                    }
     
     
                }
     
     
            }
     
            if(dexfilepath!=nullptr)
            {
                free(dexfilepath);
                dexfilepath=nullptr;
            }
     
        }
     
        extern "C" void saveArtMethod(ArtMethod* artMethod)  REQUIRES_SHARED(Locks::mutator_lock_) {
            char *dexfilepath=(char*)malloc(sizeof(char)*1000);
            if(dexfilepath==nullptr)
            {
                LOG(ERROR) << "wayne::saveArtMethod,methodname:"<<artMethod->PrettyMethod().c_str()<<"malloc 1000 byte failed";
                return;
            }
            int result=0;
            int fcmdline =-1;
            char szCmdline[64]= {0};
            char szProcName[256] = {0};
            int procid = getpid();
            sprintf(szCmdline,"/proc/%d/cmdline", procid);
            fcmdline = open(szCmdline, O_RDONLY|O_CREAT,0644);
            if(fcmdline >0)
            {
                result=read(fcmdline, szProcName,256);
                if(result<0)
                {
                    LOG(ERROR) << "wayne::saveArtMethod,open cmdline file file error";
                }
                close(fcmdline);
            }
     
            if(szProcName[0])
            {
                const DexFile* dex_file = artMethod->GetDexFile();
                const uint8_t* begin_=dex_file->Begin();  // Start of data.
                size_t size_=dex_file->Size();  // Length of data.
     
                memset(dexfilepath,0,1000);
                int size_int_=(int)size_;
     
     
                memset(dexfilepath,0,1000);
                sprintf(dexfilepath,"/data/data/%s/wayne/",szProcName);
                mkdir(dexfilepath,0777);
     
                memset(dexfilepath,0,1000);
                sprintf(dexfilepath,"/data/data/%s/wayne/%d_dexfile.dex",szProcName,size_int_);
                if(access(dexfilepath,F_OK) != -1){
                    LOG(ERROR) << "invoke DexFile have exist ";
                }else{
                    int fp=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666);
                    if(fp>0)
                    {
                        result=write(fp,(void*)begin_,size_);
                        if(result<0)
                        {
                            LOG(ERROR) << "wayne::saveArtMethod,open dexfilepath file error";
     
                        }
                        fsync(fp);
                        close(fp);
                        memset(dexfilepath,0,1000);
                        sprintf(dexfilepath,"/data/data/%s/wayne/%d_classlist.txt",szProcName,size_int_);
                        int classlistfile=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666);
                        if(classlistfile>0)
                        {
                            for (size_t ii= 0; ii< dex_file->NumClassDefs(); ++ii)
                            {
                                const dex::ClassDef& class_def = dex_file->GetClassDef(ii);
                                const char* descriptor = dex_file->GetClassDescriptor(class_def);
                                result=write(classlistfile,(void*)descriptor,strlen(descriptor));
                                if(result<0)
                                {
                                    LOG(ERROR) << "wayne::saveArtMethod,write classlistfile file error";
     
                                }
                                const char* temp="\n";
                                result=write(classlistfile,(void*)temp,1);
                                if(result<0)
                                {
                                    LOG(ERROR) << "wayne::saveArtMethod,write classlistfile file error";
     
                                }
                            }
                            fsync(classlistfile);
                            close(classlistfile);
     
                        }
                    }
     
     
                }
                const dex::CodeItem* code_item = artMethod->GetCodeItem();
                if (LIKELY(code_item != nullptr))
                {
     
     
                    uint8_t *item=(uint8_t *) code_item;
                    uint32_t code_item_len = dex_file->GetCodeItemSize(*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,1000);
                    int size_int = (int)dex_file->Size();
                    uint32_t method_idx = artMethod->GetDexMethodIndex();
                    sprintf(dexfilepath,"/data/data/%s/wayne/%d_ins_%d.bin",szProcName,size_int,(int)gettidv1());
                    int fp2=open(dexfilepath,O_CREAT|O_APPEND|O_RDWR,0666);
                    if(fp2>0){
                        lseek(fp2,0,SEEK_END);
                        memset(dexfilepath,0,1000);
                        int offset=(int)(item - begin_);
                        sprintf(dexfilepath,"{name:'%s',method_idx:'%d',offset:'%d',code_item_len:'%d',ins:'",artMethod->PrettyMethod().c_str(),method_idx,offset,code_item_len);
                        int contentlength=0;
                        while(dexfilepath[contentlength]!=0) contentlength++;
                        result=write(fp2,(void*)dexfilepath,contentlength);
                        if(result<0)
                        {
                            LOG(ERROR) << "wayne::saveArtMethod,write ins file error";
     
                        }
                        long outlen=0;
                        char* base64result=base64_encode((char*)item,(long)code_item_len,&outlen);
                        result=write(fp2,base64result,outlen);
                        if(result<0)
                        {
                            LOG(ERROR) << "wayne::saveArtMethod,write ins file error";
     
                        }
                        result=write(fp2,"'};",3);
                        if(result<0)
                        {
                            LOG(ERROR) << "wayne::saveArtMethod,write ins file error";
     
                        }
                        fsync(fp2);
                        close(fp2);
                        if(base64result!=nullptr){
                            free(base64result);
                            base64result=nullptr;
                        }
                    }
     
                }
     
     
            }
     
            if(dexfilepath!=nullptr)
            {
                free(dexfilepath);
                dexfilepath=nullptr;
            }
     
        }
        extern "C" void myWayneCall(ArtMethod* artmethod)  REQUIRES_SHARED(Locks::mutator_lock_) {
            JValue *result=nullptr;
            Thread *self=nullptr;
            uint32_t temp=6;
            uint32_t* args=&temp;
            uint32_t args_size=6;
            artmethod->Invoke(self, args, args_size, result, "aaa");
        }
    //addend

    为了防止加固厂商的检测,修改了dex文件保存的目录,由原来的sdcard目录全部改为 "/data/data/%s/wayne/%d_classlist.txt",szProcName,size_int_);"

同时修改了invoke脱壳点的脱壳函数saveArtMethod和Execute脱壳点的脱壳函数saveDexFileByExeMethod中提示错误的部分,如下所列

  1. 打开文件添加O_CREATE方式
    image-20230905224354735

  2. 修改文件是否存在的判断方式
    image-20230905224447643

  3. 修改类型定义变化的出错
    image-20230905224609024

image-20230905224648865

  1. 修改saveArtMethod函数中计算codeItem长度的方式
    image-20230905224844797

  2. 在该文件最开始添加gettidv1()的宏定义

image-20230905224942005

  1. 导入需要的.h文件

  2. 在Invoke函数中添加对saveArtMethod函数的调用
    image-20230905225136707

  • 在 /root/android/lineage/art/runtime/interpreter/interpreter.cc文件中的Execute函数脱壳点添加脱壳函数的调用。
    image-20230905225255689

在该文件最前面的art命名空间添加脱壳函数的引入:

image-20230905225454188

2.3 编译后刷机

刷机完毕,将待脱壳的apk安装后运行,等待一会,进入/data/data/包名/XXX目录下可看到脱壳下来的dex文件和方法的bin文件,copy到/sdcard目录
再使用adb pull命令拖到虚拟机中修复即可。 测试发现Execute脱壳点没有生效,需要进一步查找原因。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
点赞8
打赏
分享
最新回复 (8)
雪    币: 598
活跃值: (1247)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ty1937 2023-9-8 09:41
2
1
排查出原因了吗? 为啥没有走Execute
雪    币: 4848
活跃值: (2948)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
vigiles 2023-9-8 09:55
3
0
300G!几何倍数增长啊。
雪    币: 3344
活跃值: (1361)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Elice 2023-9-13 08:52
4
1
求分享r0ysue大佬的集成版Kali2022
雪    币: 19299
活跃值: (28938)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-9-13 09:19
5
1
感谢分享
雪    币: 362
活跃值: (1075)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
woaiziyou 2023-9-14 09:01
6
0
Elice 求分享r0ysue大佬的集成版Kali2022
同求
雪    币: 606
活跃值: (603)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wpfpzw 2023-9-16 20:23
7
0
为什么最后编译成功了进去一直有factory data reset 可以请教一下这是什么原因引起的,,我是lineageos17.1 手机oneplus5
雪    币: 606
活跃值: (603)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wpfpzw 2023-9-16 20:26
8
0
execute问题是不是因为目录只能逐级建立
雪    币: 606
活跃值: (603)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wpfpzw 2023-9-17 15:33
9
0
wpfpzw 为什么最后编译成功了进去一直有factory data reset 可以请教一下这是什么原因引起的,,我是lineageos17.1 手机oneplus5
已解决
游客
登录 | 注册 方可回帖
返回