【Android 逆向】类加载器 ClassLoader ( 使用 DexClassLoader 动态加载字节码文件 | 拷贝 DEX 文件到内置存储 | 加载并执行 DEX 字节码文件 )
文章目錄
- 一、拷貝 Assets 目錄下的 classes.dex 字節碼文件到內置存儲區
- 二、加載 DEX 文件并執行其中的方法
- 三、MainActivity 及執行結果
- 四、博客資源
一、拷貝 Assets 目錄下的 classes.dex 字節碼文件到內置存儲區
在 【Android 逆向】類加載器 ClassLoader ( 使用 DexClassLoader 動態加載字節碼文件 | 準備 DEX 字節碼文件 ) 博客中 , 準備了 classes.dex 字節碼文件 , 將字節碼文件拷貝到了 將 app\src\main\assets\classes.dex 目錄中 ;
解析字節碼文件時 , 首先將該 DEX 字節碼文件 從
app\src\main\assets\classes.dex路徑拷貝到
/data/user/0/com.example.classloader_demo/files/classes.dex內置存儲空間中 ;
下面的代碼 , 是拷貝字節碼文件的代碼 ;
代碼示例 :
/*** 將 app\src\main\assets\classes.dex 文件 ,* 拷貝到 /data/user/0/com.example.classloader_demo/files/classes.dex 位置*/private String copyFile() {// DEX 文件File dexFile = new File(getFilesDir(), "classes.dex");// DEX 文件路徑String dexPath = dexFile.getAbsolutePath();Log.i(TAG, "開始拷貝文件 dexPath : " + dexPath);// 如果之前已經加載過 , 則退出if (dexFile.exists()) {Log.i(TAG, "文件已經拷貝 , 退出");return dexPath;}try {InputStream inputStream = getAssets().open("classes.dex");FileOutputStream fileOutputStream = new FileOutputStream(dexPath);byte[] buffer = new byte[1024 * 4];int readLen = 0;while ( (readLen = inputStream.read(buffer)) != -1 ) {fileOutputStream.write(buffer, 0, readLen);}inputStream.close();fileOutputStream.close();} catch (IOException e) {e.printStackTrace();} finally {Log.i("HSL", "文件拷貝完畢");}return dexPath;}二、加載 DEX 文件并執行其中的方法
使用 DexClassLoader 加載字節碼文件時 , 要準備幾個參數
- DEX 字節碼文件路徑 : 必須制定準確的 DEX 字節碼文件目錄 ;
- 優化目錄 : 設置一個空的文件目錄即可 ;
- 依賴庫目錄 : 可以為空 , 也可以設置一個文件目錄 ;
- 父節點類加載器 : 直接獲取當前類的父類類加載器節點 ;
從字節碼文件中 , 加載的類時 Class 對象 , 通過反射調用其方法即可 ;
代碼示例 :
/*** 測試調用 Dex 字節碼文件中的方法* @param context* @param dexFilePath*/private void testDex(Context context, String dexFilePath) {// 優化目錄File optFile = new File(getFilesDir(), "opt_dex");// 依賴庫目錄 , 用于存放 so 文件File libFile = new File(getFilesDir(), "lib_path");// 初始化 DexClassLoaderDexClassLoader dexClassLoader = new DexClassLoader(dexFilePath, // Dex 字節碼文件路徑optFile.getAbsolutePath(), // 優化目錄libFile.getAbsolutePath(), // 依賴庫目錄context.getClassLoader() // 父節點類加載器);// 加載 com.example.dex_demo.DexTest 類// 該類中有可執行方法 test()Class<?> clazz = null;try {clazz = dexClassLoader.loadClass("com.example.dex_demo.DexTest");} catch (ClassNotFoundException e) {e.printStackTrace();}// 獲取 com.example.dex_demo.DexTest 類 中的 test() 方法if (clazz != null) {try {// 獲取 test 方法Method method = clazz.getDeclaredMethod("test");// 獲取 Object 對象Object object = clazz.newInstance();// 調用 test() 方法method.invoke(object);} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}三、MainActivity 及執行結果
完整代碼示例 :
package com.example.classloader_demo;import androidx.appcompat.app.AppCompatActivity;import android.content.Context; import android.os.Bundle; import android.util.Log;import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;import dalvik.system.DexClassLoader;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";/*** Dex 文件路徑*/private String mDexPath;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 打印類加載器及父節點classloaderLog();// 拷貝 dex 文件mDexPath = copyFile();// 測試 DEX 文件中的方法testDex(this, mDexPath);}/*** 打印當前的類加載器及父節點*/private void classloaderLog(){// 獲取當前 Activity 的 類加載器 ClassLoaderClassLoader classLoader = MainActivity.class.getClassLoader();// 打印當前 Activity 的 ClassLoader 類加載器Log.i(TAG, "MainActivity ClassLoader : " + classLoader);// 獲取 類加載器 父類ClassLoader parentClassLoader = classLoader.getParent();// 打印當前 Activity 的 ClassLoader 類加載器 的父類Log.i(TAG, "MainActivity Parent ClassLoader : " + parentClassLoader);}/*** 將 app\src\main\assets\classes.dex 文件 ,* 拷貝到 /data/user/0/com.example.classloader_demo/files/classes.dex 位置*/private String copyFile() {// DEX 文件File dexFile = new File(getFilesDir(), "classes.dex");// DEX 文件路徑String dexPath = dexFile.getAbsolutePath();Log.i(TAG, "開始拷貝文件 dexPath : " + dexPath);// 如果之前已經加載過 , 則退出if (dexFile.exists()) {Log.i(TAG, "文件已經拷貝 , 退出");return dexPath;}try {InputStream inputStream = getAssets().open("classes.dex");FileOutputStream fileOutputStream = new FileOutputStream(dexPath);byte[] buffer = new byte[1024 * 4];int readLen = 0;while ( (readLen = inputStream.read(buffer)) != -1 ) {fileOutputStream.write(buffer, 0, readLen);}inputStream.close();fileOutputStream.close();} catch (IOException e) {e.printStackTrace();} finally {Log.i("HSL", "文件拷貝完畢");}return dexPath;}/*** 測試調用 Dex 字節碼文件中的方法* @param context* @param dexFilePath*/private void testDex(Context context, String dexFilePath) {// 優化目錄File optFile = new File(getFilesDir(), "opt_dex");// 依賴庫目錄 , 用于存放 so 文件File libFile = new File(getFilesDir(), "lib_path");// 初始化 DexClassLoaderDexClassLoader dexClassLoader = new DexClassLoader(dexFilePath, // Dex 字節碼文件路徑optFile.getAbsolutePath(), // 優化目錄libFile.getAbsolutePath(), // 依賴庫目錄context.getClassLoader() // 父節點類加載器);// 加載 com.example.dex_demo.DexTest 類// 該類中有可執行方法 test()Class<?> clazz = null;try {clazz = dexClassLoader.loadClass("com.example.dex_demo.DexTest");} catch (ClassNotFoundException e) {e.printStackTrace();}// 獲取 com.example.dex_demo.DexTest 類 中的 test() 方法if (clazz != null) {try {// 獲取 test 方法Method method = clazz.getDeclaredMethod("test");// 獲取 Object 對象Object object = clazz.newInstance();// 調用 test() 方法method.invoke(object);} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}} }打印的日志 :
2021-12-10 13:25:22.915 31065-31065/com.example.classloader_demo I/MainActivity: MainActivity ClassLoader : dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.classloader_demo-kqe1gP2jfD1FRwkny0hX1w==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.classloader_demo-kqe1gP2jfD1FRwkny0hX1w==/lib/arm64, /system/lib64]]] 2021-12-10 13:25:22.915 31065-31065/com.example.classloader_demo I/MainActivity: MainActivity Parent ClassLoader : java.lang.BootClassLoader@6457c5 2021-12-10 13:25:22.916 31065-31065/com.example.classloader_demo I/MainActivity: 開始拷貝文件 dexPath : /data/user/0/com.example.classloader_demo/files/classes.dex 2021-12-10 13:25:22.980 31065-31065/com.example.classloader_demo I/HSL: 文件拷貝完畢 2021-12-10 13:25:23.951 31065-31065/com.example.classloader_demo I/lassloader_dem: The ClassLoaderContext is a special shared library. 2021-12-10 13:25:23.955 31065-31065/com.example.classloader_demo I/DexTest: DexTest : Hello World!!!拷貝到 /data/user/0/com.example.classloader_demo/files/classes.dex 位置的文件 , 以及在 /data/user/0/com.example.classloader_demo/files/opt/ 目錄生成的字節碼優化相關目錄 ;
四、博客資源
GitHub 源碼地址 : https://github.com/han1202012/ClassLoader_Demo
CSDN 下載地址 : https://download.csdn.net/download/han1202012/60180205
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的【Android 逆向】类加载器 ClassLoader ( 使用 DexClassLoader 动态加载字节码文件 | 拷贝 DEX 文件到内置存储 | 加载并执行 DEX 字节码文件 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 逆向】类加载器 Cla
- 下一篇: 【Android 逆向】加壳的 Andr