Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

移植 FART 到 Android 10,ART 环境下基于主动调用的自动化脱壳方案(Porting FART to Android 10: An Automated Unpacking Solution in the ART Environment Based on Active Invocation)

License

Notifications You must be signed in to change notification settings

CYRUS-STUDIO/FART

Repository files navigation

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/

FART 源码

FART 是 ART 环境下基于主动调用的自动化脱壳方案。

关于 FART 详细介绍参考:

开源地址:https://github.com/hanbinglengyue/FART

目前 FART 是基于 Android 6.0 实现,源码文件结构如下:

word/media/image1.png

把 FART 源码移植到 LineageOS 17.1(Android 10)。

关于 LineageOS 源码的下载与编译参考:LineageOS源码下载和编译(Xiaomi Mi 6X,wayne)

移植 FART 到 Android 10

对比 android 6.0 中的源码和 FART 的源码找到修改的地方并移植到 Android 10 源码中

word/media/image2.png

interpreter.cc

路径:art/runtime/interpreter/interpreter.cc

Android 6.0 源码:https://cs.android.com/android/platform/superproject/+/android-6.0.0_r1:art/runtime/interpreter/interpreter.cc

namespace art 中增加 dumpDexFileByExecute 函数声明

//add
extern "C" void dumpDexFileByExecute(ArtMethod* artmethod);

在 Execute 函数头部增加 dumpDexFileByExecute 调用

static inline JValue Execute(
 Thread* self,
 const CodeItemDataAccessor& accessor,
 ShadowFrame& shadow_frame,
 JValue result_register,
 bool stay_in_interpreter = false,
 bool from_deoptimize = false) REQUIRES_SHARED(Locks::mutator_lock_) {
 //add
 LOG(INFO) << "[Execute]" << shadow_frame.GetMethod()->PrettyMethod(); 
 if(strstr(PrettyMethod(shadow_frame.GetMethod()).c_str(),"<clinit>")!=nullptr) {
 dumpDexFileByExecute(shadow_frame.GetMethod());
 } 
 
 ... 
} 

dalvik_system_DexFile.cc

路径:art/runtime/native/dalvik_system_DexFile.cc

Android 6.0 源码:https://cs.android.com/android/platform/superproject/+/android-6.0.0_r1:art/runtime/native/dalvik_system_DexFile.cc

导入头文件:

//add
#include "scoped_fast_native_object_access-inl.h"

namespace art 中增加 myfartInvoke 函数声明

//add
extern "C" void myfartInvoke(ArtMethod* artmethod);
//add
extern "C" ArtMethod* jobject2ArtMethod(JNIEnv* env, jobject javaMethod);

添加 DexFile_dumpMethodCode 函数实现(注意:要在 gMethods 之前)

//add
static void DexFile_dumpMethodCode(JNIEnv* env, jclass,jobject method) {
 if(method!=nullptr) {
 ArtMethod* proxy_method = jobject2ArtMethod(env, method);
 myfartInvoke(proxy_method);
 }
 return;
}

在 gMethods 中增加 dumpMethodCode 的函数签名

static JNINativeMethod gMethods[] = {
 NATIVE_METHOD(DexFile, dumpMethodCode, "(Ljava/lang/Object;)V"),
};

java_lang_reflect_Method.cc

在 namespace art 中增加 jobject2ArtMethod 方法实现

//add
extern "C" ArtMethod* jobject2ArtMethod(JNIEnv* env, jobject javaMethod) {
 ScopedFastNativeObjectAccess soa(env);
 ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
 return method;
}

art_method.cc

路径:art/runtime/art_method.cc

Android 6.0 源码:https://cs.android.com/android/platform/superproject/+/android-6.0.0_r1:art/runtime/art_method.cc

添加头文件

//add
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "runtime.h"
#include <android/log.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <time.h>
#include <unistd.h>

增加宏定义

//add
#define gettidv1() syscall(__NR_gettid)
#define LOG_TAG "ActivityThread"
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

namespace art 中增加以下函数

//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);
}
//add
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;
}
//add
extern "C" void dumpDexFileByExecute(ArtMethod* artmethod) REQUIRES_SHARED(Locks::mutator_lock_) {
 char szCmdline[64] = {0};
 char szProcName[256] = {0};
 int procid = getpid();
 snprintf(szCmdline, sizeof(szCmdline), "/proc/%d/cmdline", procid);
 int fcmdline = open(szCmdline, O_RDONLY);
 if (fcmdline > 0) {
 ssize_t result = read(fcmdline, szProcName, sizeof(szProcName) - 1);
 if (result < 0) {
 LOG(ERROR) << "dumpDexFileByExecute: Failed to read cmdline";
 }
 close(fcmdline);
 }
 if (szProcName[0] == '0円') return;
 const DexFile* dex_file = artmethod->GetDexFile();
 const uint8_t* begin_ = dex_file->Begin();
 size_t size_ = dex_file->Size();
 int size_int = static_cast<int>(size_);
 std::string base_dir = "/sdcard/fart/";
 std::string app_dir = base_dir + szProcName;
 std::string dex_path = app_dir + "/" + std::to_string(size_int) + "_dexfile_execute.dex";
 std::string classlist_path = app_dir + "/" + std::to_string(size_int) + "_classlist_execute.txt";
 mkdir(base_dir.c_str(), 0777);
 mkdir(app_dir.c_str(), 0777);
 int dexfilefp = open(dex_path.c_str(), O_RDONLY);
 if (dexfilefp > 0) {
 close(dexfilefp);
 } else {
 int fp = open(dex_path.c_str(), O_CREAT | O_APPEND | O_RDWR, 0666);
 if (fp > 0) {
 ssize_t w1 = write(fp, begin_, size_);
 if (w1 < 0) {
 LOG(ERROR) << "dumpDexFileByExecute: Failed to write dex file";
 }
 fsync(fp);
 close(fp);
 int classlistfile = open(classlist_path.c_str(), 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);
 ssize_t w2 = write(classlistfile, descriptor, strlen(descriptor));
 if (w2 < 0) {
 LOG(ERROR) << "dumpDexFileByExecute: Failed to write class descriptor";
 }
 ssize_t w3 = write(classlistfile, "\n", 1);
 if (w3 < 0) {
 LOG(ERROR) << "dumpDexFileByExecute: Failed to write newline";
 }
 }
 fsync(classlistfile);
 close(classlistfile);
 }
 }
 }
}
//add
extern "C" void dumpArtMethod(ArtMethod* artmethod) REQUIRES_SHARED(Locks::mutator_lock_) {
 char szProcName[256] = {0};
 int procid = getpid();
 // 获取进程名
 char szCmdline[64] = {0};
 snprintf(szCmdline, sizeof(szCmdline), "/proc/%d/cmdline", procid);
 int fcmdline = open(szCmdline, O_RDONLY);
 if (fcmdline > 0) {
 ssize_t result = read(fcmdline, szProcName, sizeof(szProcName) - 1);
 if (result < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: read cmdline failed.";
 }
 close(fcmdline);
 }
 if (szProcName[0] == '0円') return;
 const DexFile* dex_file = artmethod->GetDexFile();
 const uint8_t* begin_ = dex_file->Begin();
 size_t size_ = dex_file->Size();
 int size_int = static_cast<int>(size_);
 // 路径拼接
 std::string baseDir = "/sdcard/fart/";
 std::string processDir = baseDir + szProcName;
 mkdir(baseDir.c_str(), 0777);
 mkdir(processDir.c_str(), 0777);
 // 保存 dex 文件
 std::string dexPath = processDir + "/" + std::to_string(size_int) + "_dexfile.dex";
 int dexfilefp = open(dexPath.c_str(), O_RDONLY);
 if (dexfilefp > 0) {
 close(dexfilefp);
 } else {
 int fp = open(dexPath.c_str(), O_CREAT | O_APPEND | O_RDWR, 0666);
 if (fp > 0) {
 ssize_t w = write(fp, begin_, size_);
 if (w < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: write dexfile failed -> " << dexPath;
 }
 fsync(fp);
 close(fp);
 // 保存 class 列表
 std::string classListPath = processDir + "/" + std::to_string(size_int) + "_classlist.txt";
 int classlistfile = open(classListPath.c_str(), O_CREAT | O_APPEND | O_RDWR, 0666);
 if (classlistfile > 0) {
 for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
 const dex::ClassDef& class_def = dex_file->GetClassDef(i);
 const char* descriptor = dex_file->GetClassDescriptor(class_def);
 ssize_t w1 = write(classlistfile, descriptor, strlen(descriptor));
 if (w1 < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: write class descriptor failed";
 }
 ssize_t w2 = write(classlistfile, "\n", 1);
 if (w2 < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: write newline failed";
 }
 }
 fsync(classlistfile);
 close(classlistfile);
 }
 }
 }
 // 保存指令码
 const dex::CodeItem* code_item = artmethod->GetCodeItem();
 if (LIKELY(code_item != nullptr)) {
 uint8_t* item = (uint8_t*)code_item;
 int code_item_len = 0;
 CodeItemDataAccessor accessor(*dex_file, code_item);
 if (accessor.TriesSize() > 0) {
 const uint8_t* handler_data = accessor.GetCatchHandlerData();
 uint8_t* tail = codeitem_end(&handler_data);
 code_item_len = static_cast<int>(tail - item);
 } else {
 code_item_len = 16 + accessor.InsnsSizeInCodeUnits() * 2;
 }
 uint32_t method_idx = artmethod->GetDexMethodIndex();
 int offset = static_cast<int>(item - begin_);
 pid_t tid = gettidv1();
 std::string insPath = processDir + "/" + std::to_string(size_int) + "_ins_" + std::to_string(tid) + ".bin";
 int fp2 = open(insPath.c_str(), O_CREAT | O_APPEND | O_RDWR, 0666);
 if (fp2 > 0) {
 lseek(fp2, 0, SEEK_END);
 std::string header = "{name:" + artmethod->PrettyMethod() +
 ",method_idx:" + std::to_string(method_idx) +
 ",offset:" + std::to_string(offset) +
 ",code_item_len:" + std::to_string(code_item_len) +
 ",ins:";
 ssize_t w3 = write(fp2, header.c_str(), header.length());
 if (w3 < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: write header failed";
 }
 long outlen = 0;
 char* base64result = base64_encode((char*)item, (long)code_item_len, &outlen);
 if (base64result != nullptr) {
 ssize_t w4 = write(fp2, base64result, outlen);
 if (w4 < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: write base64 ins failed";
 }
 free(base64result);
 }
 ssize_t w5 = write(fp2, "};", 2);
 if (w5 < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: write tail failed";
 }
 fsync(fp2);
 close(fp2);
 }
 }
}
//add
extern "C" void myfartInvoke(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, "fart");
}

ArtMethod::Invoke 中添加判断如果是 fart 的主动调用就 dump

void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
 const char* shorty) {
 //add
 if (self == nullptr) {
 dumpArtMethod(this);
 return;
 }
 
 ...
} 

ActivityThread.java

路径:frameworks/base/core/java/android/app/ActivityThread.java

Android 6.0 源码:https://cs.android.com/android/platform/superproject/+/android-6.0.0_r1:frameworks/base/core/java/android/app/ActivityThread.java

import 相关 java 类引用

//add
import android.app.Application;
import android.util.ArrayMap;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
//add
public static HashMap<String, String> dumpClassm_hashmap = new HashMap<>();

添加以下 java 方法到 ActivityThread 类

//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;
}
//add
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;
}
//add
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;
}
//add
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;
}
//add
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;
}
//add
public static void loadClassAndInvoke(ClassLoader appClassloader, String eachclassname, Method dumpMethodCode_method) {
 Class resultclass = null;
 Log.i("ActivityThread", "go into loadClassAndInvoke->" + "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 (dumpMethodCode_method != null) {
 try {
 dumpMethodCode_method.invoke(null, constructor);
 } catch (Exception e) {
 e.printStackTrace();
 continue;
 } catch (Error e) {
 e.printStackTrace();
 continue;
 }
 } else {
 Log.e("ActivityThread", "dumpMethodCode_method 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 (dumpMethodCode_method != null) {
 try {
 dumpMethodCode_method.invoke(null, m);
 } catch (Exception e) {
 e.printStackTrace();
 continue;
 } catch (Error e) {
 e.printStackTrace();
 continue;
 }
 } else {
 Log.e("ActivityThread", "dumpMethodCode_method is null ");
 }
 }
 }
 } catch (Exception e) {
 e.printStackTrace();
 } catch (Error e) {
 e.printStackTrace();
 }
 }
}
//add
public static void fart() {
 ClassLoader appClassloader = getClassloader();
 ClassLoader tmpClassloader=appClassloader;
 ClassLoader parentClassloader=appClassloader.getParent();
 if(appClassloader.toString().indexOf("java.lang.BootClassLoader")==-1)
 {
 fartwithClassloader(appClassloader);
 }
 while(parentClassloader!=null){
 if(parentClassloader.toString().indexOf("java.lang.BootClassLoader")==-1)
 {
 fartwithClassloader(parentClassloader);
 }
 tmpClassloader=parentClassloader;
 parentClassloader=parentClassloader.getParent();
 }
}
//add
public static void fartwithClassloader(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_method = null;
 Method defineClass_method = null;
 Method dumpDexFile_method = null;
 Method dumpMethodCode_method = null;
 for (Method field : DexFileClazz.getDeclaredMethods()) {
 if (field.getName().equals("getClassNameList")) {
 getClassNameList_method = field;
 getClassNameList_method.setAccessible(true);
 }
 if (field.getName().equals("defineClassNative")) {
 defineClass_method = field;
 defineClass_method.setAccessible(true);
 }
 if (field.getName().equals("dumpDexFile")) {
 dumpDexFile_method = field;
 dumpDexFile_method.setAccessible(true);
 }
 if (field.getName().equals("dumpMethodCode")) {
 dumpMethodCode_method = field;
 dumpMethodCode_method.setAccessible(true);
 }
 }
 Field mCookiefield = getClassField(appClassloader, "dalvik.system.DexFile", "mCookie");
 Log.v("ActivityThread->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.v("ActivityThread->err", "get mInternalCookie is null");
 continue;
 }
 }
 String[] classnames = null;
 try {
 classnames = (String[]) getClassNameList_method.invoke(dexfile, mcookie);
 } catch (Exception e) {
 e.printStackTrace();
 continue;
 } catch (Error e) {
 e.printStackTrace();
 continue;
 }
 if (classnames != null) {
 for (String eachclassname : classnames) {
 loadClassAndInvoke(appClassloader, eachclassname, dumpMethodCode_method);
 }
 }
 }
 }
 return;
}
//add
public static void fartthread() {
 new Thread(new Runnable() {
 @Override
 public void run() {
 // TODO Auto-generated method stub
 try {
 Log.e("ActivityThread", "start sleep......");
 Thread.sleep(1 * 60 * 1000);
 } catch (InterruptedException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 Log.e("ActivityThread", "sleep over and start fart");
 fart();
 Log.e("ActivityThread", "fart run over");
 }
 }).start();
}

在 performLaunchActivity 方法中添加日志和 fartthread 方法调用

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
 //add
 Log.e("ActivityThread","go into performLaunchActivity");
 //add
 fartthread();
 
 return activity;
}

handleBindApplication 中添加日志

private void handleBindApplication(AppBindData data) {
 //add
 Log.e("ActivityThread","go into handleBindApplication");
}

DexFile.java

路径:libcore/dalvik/src/main/java/dalvik/system/DexFile.java

Android 6.0 源码:https://cs.android.com/android/platform/superproject/+/android-6.0.0_r1:libcore/dalvik/src/main/java/dalvik/system/DexFile.java

在 DexFile 类中增加 native 方法 dumpMethodCode

//add
private static native void dumpMethodCode(Object m);

编译系统

重新编译 android 系统

# 初始化编译环境
source build/envsetup.sh
# 设置编译目标
breakfast wayne
# 回到 Android 源码树的根目录
croot
# 开始编译
brunch wayne

参考:LineageOS源码下载和编译(Xiaomi Mi 6X,wayne)

生成 OTA 包

./sign_ota_wayne.sh

参考:使用 release key 对 LineageOS 进行编译和签名

解决编译报错

报错日志如下:

cyrus@cyrus:/mnt/case_sensitive/lineage-17.1$ brunch wayne
Trying dependencies-only mode on a non-existing device tree?
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=10
LINEAGE_VERSION=17.1-20250521-UNOFFICIAL-wayne
TARGET_PRODUCT=lineage_wayne
TARGET_BUILD_VARIANT=userdebug
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm64
TARGET_ARCH_VARIANT=armv8-a
TARGET_CPU_VARIANT=cortex-a73
TARGET_2ND_ARCH=arm
TARGET_2ND_ARCH_VARIANT=armv8-a
TARGET_2ND_CPU_VARIANT=kryo
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-5.15.153.1-microsoft-standard-WSL2-x86_64-Ubuntu-22.04.3-LTS
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=QQ3A.200805.001
OUT_DIR=out
PRODUCT_SOONG_NAMESPACES=vendor/xiaomi/sdm660-common device/xiaomi/sdm660-common device/xiaomi/wayne vendor/xiaomi/wayne-common hardware/qcom-caf/msm8998
============================================
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=10
LINEAGE_VERSION=17.1-20250521-UNOFFICIAL-wayne
TARGET_PRODUCT=lineage_wayne
TARGET_BUILD_VARIANT=userdebug
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm64
TARGET_ARCH_VARIANT=armv8-a
TARGET_CPU_VARIANT=cortex-a73
TARGET_2ND_ARCH=arm
TARGET_2ND_ARCH_VARIANT=armv8-a
TARGET_2ND_CPU_VARIANT=kryo
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-5.15.153.1-microsoft-standard-WSL2-x86_64-Ubuntu-22.04.3-LTS
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=QQ3A.200805.001
OUT_DIR=out
PRODUCT_SOONG_NAMESPACES=vendor/xiaomi/sdm660-common device/xiaomi/sdm660-common device/xiaomi/wayne vendor/xiaomi/wayne-common hardware/qcom-caf/msm8998
============================================
device/xiaomi/sdm660-common/common_prop.mk was modified, regenerating...
device/xiaomi/sdm660-common/common_prop.mk was modified, regenerating...
[100% 1065/1065] writing build rules ...
build/make/core/base_rules.mk:510: warning: overriding commands for target `out/target/product/wayne/vendor/lib/libstdc++.so'
build/make/core/base_rules.mk:510: warning: ignoring old commands for target `out/target/product/wayne/vendor/lib/libstdc++.so'
build/make/core/base_rules.mk:510: warning: overriding commands for target `out/target/product/wayne/vendor/lib64/libstdc++.so'
build/make/core/base_rules.mk:510: warning: ignoring old commands for target `out/target/product/wayne/vendor/lib64/libstdc++.so'
out/target/product/wayne/obj/CONFIG/kati_packaging/dist.mk was modified, regenerating...
[ 19% 1093/5705] //art/runtime:libart clang++ art_method.cc
FAILED: out/soong/.intermediates/art/runtime/libart/android_arm64_armv8-a_cortex-a73_core_shared_com.android.runtime.release/obj/art/runtime/art_method.o
PWD=/proc/self/cwd /usr/bin/ccache prebuilts/clang/host/linux-x86/clang-r353983c1/bin/clang++ -c -Iart/runtime -Ibionic/libc/private -Iexternal/vixl/src -Iart/sigchainlib -Iexternal/zlib -Iart/runtime -D__ANDROID_APEX__=com.android.runtime.release -Werror=implicit-function-declaration -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -no-canonical-prefixes -DNDEBUG -UDEBUG -fno-exceptions -Wno-multichar -O2 -g -fno-strict-aliasing -fdebug-prefix-map=/proc/self/cwd= -D__compiler_offsetof=__builtin_offsetof -faddrsig -Wimplicit-fallthrough -Werror=int-conversion -Wno-reserved-id-macro -Wno-format-pedantic -Wno-unused-command-line-argument -fcolor-diagnostics -Wno-zero-as-null-pointer-constant -Wno-sign-compare -Wno-defaulted-function-deleted -Wno-inconsistent-missing-override -ffunction-sections -fdata-sections -fno-short-enums -funwind-tables -fstack-protector-strong -Wa,--noexecstack -D_FORTIFY_SOURCE=2 -Wstrict-aliasing=2 -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Werror=date-time -Werror=format-security -nostdlibinc -march=armv8-a -mcpu=cortex-a53 -Iart/cmdline -Iart/tools/cpp-define-generator -Iexternal/icu/icu4c/source/common -Iexternal/icu/android_icu4c/include -Ilibnativehelper/header_only_include -Ilibnativehelper/platform_include -Iexternal/zlib -Iart/libelffile -Iart/libartpalette/include -Isystem/core/libnativebridge/include -Isystem/core/libnativeloader/include -Isystem/core/libbacktrace/include -Isystem/core/demangle/include -Isystem/core/liblog/include -D__LIBLOG_API__=10000 -Isystem/core/base/include -Iart/libartbase -Iexternal/lz4/lib -Iexternal/lzma/C -Iart/libdexfile -Iart/libprofile -D__LIBDL_ANDROID_API__=10000 -Ibionic/libc/async_safe/include -Iexternal/libcxx/include -Iexternal/libcxxabi/include -Ibionic/libc/include -Ibionic/libc/system_properties/include -Isystem/core/property_service/libpropertyinfoparser/include -Iout/soong/.intermediates/art/runtime/art_operator_srcs/gen/gensrcs -Iout/soong/.intermediates/art/tools/cpp-define-generator/cpp-define-generator-asm-support/android_arm64_armv8-a_cortex-a73_core/gen -Isystem/core/include -Isystem/media/audio/include -Ihardware/libhardware/include -Ihardware/libhardware_legacy/include -Ihardware/ril/include -Iframeworks/native/include -Iframeworks/native/opengl/include -Iframeworks/av/include -isystem bionic/libc/include -isystem bionic/libc/kernel/uapi -isystem bionic/libc/kernel/uapi/asm-arm64 -isystem bionic/libc/kernel/android/scsi -isystem bionic/libc/kernel/android/uapi -Ilibnativehelper/include_jni -fno-rtti -ggdb3 -Wall -Werror -Wextra -Wstrict-aliasing -fstrict-aliasing -Wunreachable-code -Wredundant-decls -Wshadow -Wunused -fvisibility=protected -Wthread-safety -Wthread-safety-negative -Wimplicit-fallthrough -Wfloat-equal -Wint-to-void-pointer-cast -Wused-but-marked-unused -Wdeprecated -Wunreachable-code-break -Wunreachable-code-return -Wno-invalid-offsetof -Winconsistent-missing-override -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -O3 -DART_DEFAULT_GC_TYPE_IS_CMS -DIMT_SIZE=43 -DART_USE_READ_BARRIER=1 -DART_READ_BARRIER_TYPE_IS_BAKER=1 -DART_USE_GENERATIONAL_CC=1 -DART_DEFAULT_COMPACT_DEX_LEVEL=fast -DART_STACK_OVERFLOW_GAP_arm=8192 -DART_STACK_OVERFLOW_GAP_arm64=8192 -DART_STACK_OVERFLOW_GAP_mips=16384 -DART_STACK_OVERFLOW_GAP_mips64=16384 -DART_STACK_OVERFLOW_GAP_x86=8192 -DART_STACK_OVERFLOW_GAP_x86_64=8192 -DUSE_D8_DESUGAR=1 -DBUILDING_LIBART=1 -Wmissing-noreturn -DART_TARGET -DART_ENABLE_CODEGEN_arm -DART_ENABLE_CODEGEN_arm64 -Wframe-larger-than=1736 -DART_FRAME_SIZE_LIMIT=1736 -DART_BASE_ADDRESS=0x70000000 -DART_TARGET_ANDROID -DART_BASE_ADDRESS_MIN_DELTA=-0x1000000 -DART_BASE_ADDRESS_MAX_DELTA=0x1000000 -DANDROID_LINK_SHARED_ICU4C -target aarch64-linux-android -Bprebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/aarch64-linux-android/bin -DANDROID_STRICT -fPIC -D_USING_LIBCXX -flto=thin -fsplit-lto-unit -std=gnu++17 -Wsign-promo -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -Wno-thread-safety-negative -Wno-gnu-include-next -fvisibility-inlines-hidden -fno-rtti -Werror=int-to-pointer-cast -Werror=pointer-to-int-cast -Werror=address-of-temporary -Werror=return-type -Wno-tautological-constant-compare -Wno-tautological-type-limit-compare -Wno-tautological-unsigned-enum-zero-compare -Wno-tautological-unsigned-zero-compare -Wno-c++98-compat-extra-semi -Wno-return-std-move-in-c++11 -MD -MF out/soong/.intermediates/art/runtime/libart/android_arm64_armv8-a_cortex-a73_core_shared_com.android.runtime.release/obj/art/runtime/art_method.o.d -o out/soong/.intermediates/art/runtime/libart/android_arm64_armv8-a_cortex-a73_core_shared_com.android.runtime.release/obj/art/runtime/art_method.o art/runtime/art_method.cc
art/runtime/art_method.cc:964:26: error: use of undeclared identifier 'PrettyMethod'
 << PrettyMethod(artmethod).
 ^
art/runtime/art_method.cc:973:50: error: 'open' has superfluous mode bits; missing O_CREAT? [-Werror,-Wuser-defined-warnings]
 fcmdline = open(szCmdline, O_RDONLY, 0644);
 ^
bionic/libc/include/bits/fortify/fcntl.h:69:9: note: from 'diagnose_if' attribute on 'open':
 __clang_warning_if(!__open_modes_useful(flags) && modes,
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bionic/libc/include/sys/cdefs.h:134:54: note: expanded from macro '__clang_warning_if'
#define __clang_warning_if(cond, msg) __attribute__((diagnose_if(cond, msg, "warning")))
 ^ ~~~~
art/runtime/art_method.cc:1001:61: error: 'open' has superfluous mode bits; missing O_CREAT? [-Werror,-Wuser-defined-warnings]
 int dexfilefp = open(dexfilepath, O_RDONLY, 0666);
 ^
bionic/libc/include/bits/fortify/fcntl.h:69:9: note: from 'diagnose_if' attribute on 'open':
 __clang_warning_if(!__open_modes_useful(flags) && modes,
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bionic/libc/include/sys/cdefs.h:134:54: note: expanded from macro '__clang_warning_if'
#define __clang_warning_if(cond, msg) __attribute__((diagnose_if(cond, msg, "warning")))
 ^ ~~~~
art/runtime/art_method.cc:1029:26: error: use of undeclared identifier 'PrettyMethod'
 << PrettyMethod(artmethod).
 ^
art/runtime/art_method.cc:1038:50: error: 'open' has superfluous mode bits; missing O_CREAT? [-Werror,-Wuser-defined-warnings]
 fcmdline = open(szCmdline, O_RDONLY, 0644);
 ^
bionic/libc/include/bits/fortify/fcntl.h:69:9: note: from 'diagnose_if' attribute on 'open':
 __clang_warning_if(!__open_modes_useful(flags) && modes,
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bionic/libc/include/sys/cdefs.h:134:54: note: expanded from macro '__clang_warning_if'
#define __clang_warning_if(cond, msg) __attribute__((diagnose_if(cond, msg, "warning")))
 ^ ~~~~
art/runtime/art_method.cc:1048:21: error: use of undeclared identifier 'PrettyMethod'
 PrettyMethod(artmethod).c_str();
 ^
art/runtime/art_method.cc:1068:61: error: 'open' has superfluous mode bits; missing O_CREAT? [-Werror,-Wuser-defined-warnings]
 int dexfilefp = open(dexfilepath, O_RDONLY, 0666);
 ^
bionic/libc/include/bits/fortify/fcntl.h:69:9: note: from 'diagnose_if' attribute on 'open':
 __clang_warning_if(!__open_modes_useful(flags) && modes,
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bionic/libc/include/sys/cdefs.h:134:54: note: expanded from macro '__clang_warning_if'
#define __clang_warning_if(cond, msg) __attribute__((diagnose_if(cond, msg, "warning")))
 ^ ~~~~
art/runtime/art_method.cc:1081:19: error: no type named 'CodeItem' in 'art::DexFile'; did you mean 'dex::CodeItem'?
 const DexFile::CodeItem * code_item = artmethod->GetCodeItem();
 ^~~~~~~~~~~~~~~~~
 dex::CodeItem
art/libdexfile/dex/class_accessor.h:29:8: note: 'dex::CodeItem' declared here
struct CodeItem;
 ^
art/runtime/art_method.cc:1085:32: error: no member named 'tries_size_' in 'art::dex::CodeItem'
 if (code_item->tries_size_ > 0) {
 ~~~~~~~~~ ^
art/runtime/art_method.cc:1086:114: error: no member named 'tries_size_' in 'art::dex::CodeItem'
 const uint8_t *handler_data = (const uint8_t *) (DexFile::GetTryItems(*code_item, code_item->tries_size_));
 ~~~~~~~~~ ^
art/runtime/art_method.cc:1090:53: error: no member named 'insns_size_in_code_units_' in 'art::dex::CodeItem'
 code_item_len = 16 + code_item->insns_size_in_code_units_ * 2;
 ~~~~~~~~~ ^
art/runtime/art_method.cc:1142:23: error: redefinition of 'FromReflectedMethod'
ArtMethod *ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable &soa, jobject jlr_method) {
 ^
art/runtime/art_method.cc:128:23: note: previous definition is here
ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
 ^
art/runtime/art_method.cc:1143:67: error: expected expression
 auto *abstract_method = soa.Decode < mirror::AbstractMethod * >(jlr_method);
 ^
art/runtime/art_method.cc:1143:50: error: no member named 'AbstractMethod' in namespace 'art::mirror'
 auto *abstract_method = soa.Decode < mirror::AbstractMethod * >(jlr_method);
 ~~~~~~~~^
art/runtime/art_method.cc:1143:68: error: expected unqualified-id
 auto *abstract_method = soa.Decode < mirror::AbstractMethod * >(jlr_method);
 ^
15 errors generated.
[ 19% 1097/5705] Building Kernel Config
make: Entering directory '/mnt/case_sensitive/lineage-17.1/kernel/xiaomi/sdm660'
make[1]: Entering directory '/mnt/case_sensitive/lineage-17.1/out/target/product/wayne/obj/KERNEL_OBJ'
 GEN ./Makefile
 HOSTCC scripts/basic/fixdep
 HOSTCC scripts/basic/bin2c
 HOSTCC scripts/kconfig/conf.o
clang-9: warning: argument unused during compilation: '-fuse-ld=lld' [-Wunused-command-line-argument]
 HOSTCC scripts/kconfig/zconf.tab.o
clang-9: warning: argument unused during compilation: '-fuse-ld=lld' [-Wunused-command-line-argument]
 HOSTLD scripts/kconfig/conf
#
# configuration written to .config
#
make[1]: Leaving directory '/mnt/case_sensitive/lineage-17.1/out/target/product/wayne/obj/KERNEL_OBJ'
make: Leaving directory '/mnt/case_sensitive/lineage-17.1/kernel/xiaomi/sdm660'
make: Entering directory '/mnt/case_sensitive/lineage-17.1/kernel/xiaomi/sdm660'
make[1]: Entering directory '/mnt/case_sensitive/lineage-17.1/out/target/product/wayne/obj/KERNEL_OBJ'
 GEN ./Makefile
scripts/kconfig/conf --savedefconfig=defconfig Kconfig
make[1]: Leaving directory '/mnt/case_sensitive/lineage-17.1/out/target/product/wayne/obj/KERNEL_OBJ'
make: Leaving directory '/mnt/case_sensitive/lineage-17.1/kernel/xiaomi/sdm660'
[ 19% 1106/5669] //libcore/mmodules/core_platform_api:core-platform-api-stubs Metalava [common]
/mnt/case_sensitive/lineage-17.1/external/bouncycastle/repackaged/bcprov/src/main/java/com/android/org/bouncycastle/asn1/x500/style/BCStyle.java:17: warning: Public class com.android.org.bouncycastle.asn1.x500.style.BCStyle stripped of unavailable superclass com.android.org.bouncycastle.asn1.x500.style.AbstractX500NameStyle [HiddenSuperclass]
23:34:38 ninja failed with: exit status 1
#### failed to build some targets (10:08 (mm:ss)) ####

1. 未声明的标识符:PrettyMethod

把 FART 中 PrettyMethod 的调用

LOG(INFO) << "ArtMethod::dumpDexFileByExecute,methodname:" << PrettyMethod(artmethod).c_str() << "malloc 2000 byte failed";
LOG(INFO) << "ArtMethod::dumpArtMethodinvoked,methodname:" << PrettyMethod(artmethod).c_str() << "malloc 2000 byte failed";
const char *methodname = PrettyMethod(artmethod).c_str();
PrettyMethod(shadow_frame.GetMethod()).c_str()

修改如下

LOG(INFO) << "ArtMethod::dumpDexFileByExecute,methodname:" << artmethod->PrettyMethod().c_str() << "malloc 2000 byte failed";
LOG(INFO) << "ArtMethod::dumpArtMethodinvoked,methodname:" << artmethod->PrettyMethod().c_str() << "malloc 2000 byte failed";
const char *methodname = artmethod->PrettyMethod().c_str();
shadow_frame.GetMethod()->PrettyMethod().c_str()

2. open 函数带有多余 mode 参数

error: 'open' has superfluous mode bits; missing O_CREAT? [-Werror,-Wuser-defined-warnings]

这个意思是你使用了 open 函数时传了第三个参数(mode),但没有设置 O_CREAT 标志,而 mode 参数只有在创建新文件时才有意义。

在较老版本(如 Android 6.0)的编译器中,这类用法:

int fd = open("xxx", O_RDONLY, 0644); // 没有 O_CREAT,却传了 mode

虽然语义上多余,但不会报错或中断构建。

而在 Android 10(Q)以后,AOSP 使用了更严格的 Clang,并开启了如下 warning:

-Wuser-defined-warnings

然后又通过 -Werror 将这些警告强制为错误,所以编译器现在直接拒绝这类写法。

如果你只是读文件(O_RDONLY),就不要写第三个参数:

int fd = open("file.txt", O_RDONLY);

修改前:

fcmdline = open(szCmdline, O_RDONLY, 0644);
int dexfilefp = open(dexfilepath, O_RDONLY, 0666);

修改后:

fcmdline = open(szCmdline, O_RDONLY);
int dexfilefp = open(dexfilepath, O_RDONLY);

3. DexFile::CodeItem 类型名错误

这是因为新版代码中 CodeItem 定义在 dex 命名空间中,而不是 art::DexFile。

修改前:

const DexFile::CodeItem* code_item = artmethod->GetCodeItem();

修改后:

const dex::CodeItem* code_item = artmethod->GetCodeItem();

4. CodeItem 无 tries_size_ 和 insns_size_in_code_units_ 成员

art/runtime/art_method.cc:1076:32: error: no member named 'tries_size_' in 'art::dex::CodeItem'
 if (code_item->tries_size_ > 0) {
 ~~~~~~~~~ ^
art/runtime/art_method.cc:1077:114: error: no member named 'tries_size_' in 'art::dex::CodeItem'
 const uint8_t *handler_data = (const uint8_t *) (DexFile::GetTryItems(*code_item, code_item->tries_size_));
 ~~~~~~~~~ ^
art/runtime/art_method.cc:1081:53: error: no member named 'insns_size_in_code_units_' in 'art::dex::CodeItem'
 code_item_len = 16 + code_item->insns_size_in_code_units_ * 2;
 ~~~~~~~~~ ^

从 Android 9(Pie)开始,ART 对 Dex 解析部分的内部结构进行了重构,CodeItem 成员变成私有的或受限访问,不能再直接通过 code_item->tries_size_ 或 code_item->insns_size_in_code_units_ 来访问了。

应该使用官方提供的辅助类 CodeItemDataAccessor 访问:

const DexFile *dex_file = artmethod->GetDexFile();
// 获取 CodeItem
const dex::CodeItem* code_item = ...;
// 创建 DataAccessor
CodeItemDataAccessor accessor(*dex_file, code_item);
// 正确访问 tries_size 和 insns_size_in_code_units
uint32_t tries_size = accessor.TriesSize();
uint32_t insns_size = accessor.InsnsSizeInCodeUnits();

5. DexFile::GetTryItems

报错日志如下:

art/runtime/art_method.cc:1071:91: error: no viable conversion from 'const dex::CodeItem' to 'const art::DexInstructionIterator'
 const uint8_t *handler_data = (const uint8_t *) (DexFile::GetTryItems(*code_item, accessor.TriesSize()));

在 Android 9 之后,应该用 CodeItemDataAccessor::GetTries() 来访问 tries 数组,用 accessor.GetCatchHandlerData() 来访问 handler 。

 const uint8_t *handler_data = (const uint8_t *) (DexFile::GetTryItems(*code_item, accessor.TriesSize()));

改为

const uint8_t* handler_data = accessor.GetCatchHandlerData();

6. mirror::AbstractMethod 不存在

art/runtime/art_method.cc:1128:67: error: expected expression
 auto *abstract_method = soa.Decode < mirror::AbstractMethod * >(jlr_method);
 ^
art/runtime/art_method.cc:1128:50: error: no member named 'AbstractMethod' in namespace 'art::mirror'
 auto *abstract_method = soa.Decode < mirror::AbstractMethod * >(jlr_method);
 ~~~~~~~~^
art/runtime/art_method.cc:1128:68: error: expected unqualified-id
 auto *abstract_method = soa.Decode < mirror::AbstractMethod * >(jlr_method);

说明:

  • Android 6.0 中有 mirror::AbstractMethod;

  • Android 10 中已经移除或合并进 Executable / Method 等类型。

修复方式:使用 mirror::Executable(它是 ART 中 java.lang.reflect.Method 和 Constructor 的基类)代替。

ArtMethod *ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable &soa, jobject jlr_method) {
 ObjPtr<mirror::Executable> executable = soa.Decode<mirror::Executable>(jlr_method);
 DCHECK(executable != nullptr);
 return executable->GetArtMethod();
}

7. 'jni_internal.h' file not found

报错日志如下:

art/runtime/native/dalvik_system_DexFile.cc:57:10: fatal error: 'jni_internal.h' file not found
#include "jni_internal.h"
 ^~~~~~~~~~~~~~~~

#include "jni_internal.h"

替换为

#include "jni/jni_internal.h"

8. ignoring return value of function declared with 'warn_unused_result'

art/runtime/art_method.cc:965:13: error: ignoring return value of function declared with 'warn_unused_result' attribute [-Werror,-Wunused-result]
 read(fcmdline, szProcName, 256);
 ^~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
art/runtime/art_method.cc:998:21: error: ignoring return value of function declared with 'warn_unused_result' attribute [-Werror,-Wunused-result]
 write(dexfilefp, (void *) begin_,
 ^~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
art/runtime/art_method.cc:1025:13: error: ignoring return value of function declared with 'warn_unused_result' attribute [-Werror,-Wunused-result]
 read(fcmdline, szProcName, 256);
 ^~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
art/runtime/art_method.cc:1060:21: error: ignoring return value of function declared with 'warn_unused_result' attribute [-Werror,-Wunused-result]
 write(dexfilefp, (void *) begin_, size_);
 ^~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
art/runtime/art_method.cc:1094:21: error: ignoring return value of function declared with 'warn_unused_result' attribute [-Werror,-Wunused-result]
 write(fp2, (void *) dexfilepath, contentlength);
 ^~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
art/runtime/art_method.cc:1097:21: error: ignoring return value of function declared with 'warn_unused_result' attribute [-Werror,-Wunused-result]
 write(fp2, base64result, outlen);
 ^~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
art/runtime/art_method.cc:1098:21: error: ignoring return value of function declared with 'warn_unused_result' attribute [-Werror,-Wunused-result]
 write(fp2, "};", 2);
 ^~~~~ ~~~~~~~~~~~~
7 errors generated.

这些函数都被标记了 attribute((warn_unused_result)),表示返回值必须使用。Clang 编译器将它们视为错误(因为加了

-Werror),所以编译失败了。

处理返回值, 比如:

// 原来的写法(错误)
read(fcmdline, szProcName, 256);
// 处理返回值
ssize_t bytes_read = read(fcmdline, szProcName, 256);
if (bytes_read < 0) {
 LOG(INFO) << "read failed";
}
ssize_t written = write(dexfilefp, begin_, size_);
LOG(INFO) << "write to file: " << dexfilepath << ", written = " << written << ", expected = " << size_;
ssize_t written = write(dexfilefp, (void *) begin_, size_);
LOG(INFO) << "write to file: " << dexfilepath << ", written = " << written << ", expected = " << size_;
 
ssize_t written = write(fp2, (void *) dexfilepath, contentlength);
LOG(INFO) << "write to file: " << dexfilepath << ", written = " << written << ", expected = " << contentlength;
ssize_t written_fp2 = write(fp2, base64result, outlen);
LOG(INFO) << "written_fp2: "<< ", written = " << written_fp2 << ", expected = " << outlen;
ssize_t written_fp2_end = write(fp2, "};", 2);
LOG(INFO) << "written_fp2_end: " << ", written = " << written_fp2_end << ", expected = " << 2;

9. 找不到 ScopedFastNativeObjectAccess

ld.lld: error: undefined symbol: art::ScopedFastNativeObjectAccess::ScopedFastNativeObjectAccess(_JNIEnv*)
>>> referenced by dalvik_system_DexFile.cc:72 (art/runtime/native/dalvik_system_DexFile.cc:72)
>>> lto.tmp:(art::DexFile_dumpMethodCode(_JNIEnv*, _jclass*, _jobject*))

链接器找不到 ScopedFastNativeObjectAccess 构造函数的实现。

#include "scoped_fast_native_object_access.h"

替换为

#include "scoped_fast_native_object_access-inl.h"

10. no member named 'GetDexMethodIndexUnchecked'

art/runtime/art_method.cc:359:52: error: no member named 'GetDexMethodIndexUnchecked' in 'art::ArtMethod'
 uint32_t method_idx=artmethod->GetDexMethodIndexUnchecked();
 ~~~~~~~~~ ^

uint32_t method_idx = artmethod->GetDexMethodIndexUnchecked();

改为

uint32_t method_idx = artmethod->GetDexMethodIndex();

编译完成

word/media/image3.png

执行 ls -hl 可以看到目录下已经生成了 signed-ota_update.zip

word/media/image4.png

刷机

由于我这里是在 WSL 中编译,先把 ota 文件 copy 到 windwos 目录下

 cp ./signed-ota_update.zip /mnt/e/lineageos/xiaomi6x_wayne_lineageos-17.1_signed-ota_update_fart.zip

设备进入 recovery 模式(或者同时按住【音量+】和【开机键】)

adb reboot recovery

【Apply update】【Apply from adb】开启 adb sideload

word/media/image5.png

开始刷机

adb sideload E:\lineageos\xiaomi6x_wayne_lineageos-17.1_signed-ota_update_fart.zip

成功刷入后重启手机。

参考:LineageOS刷机教程

自动化脱壳

如果 app 没有存储权限,先授予存储卡读写权限

word/media/image6.png

打印 app 日志

adb logcat --pid=$(adb shell pidof com.cyrus.example)

打开 app,等待60秒后开始完整的主动调用,可以看到每个调用到的 dex 函数

word/media/image7.png

通过下面的命令过滤出 fart 日志

  • linux / mac:
adb logcat | grep fart
  • windodws:
adb logcat | Select-String fart

出现 fart over就是脱壳完成了

抽取壳的应用脱壳完成后,在 /sdcard/fart/packageName 目录下可以找到如下文件:

wayne:/sdcard/fart/com.cyrus.example $ ls
10637856_classlist.txt 1321896_dexfile_execute.dex 1472352_9399.bin 198768_11648.bin
10637856_classlist_execute.txt 1321896_ins_7860.bin 1472352_9496.bin 198768_16643.bin
10637856_dexfile.dex 1321896_ins_7971.bin 1472352_9651.bin 198768_16667.bin
10637856_dexfile_execute.dex 1351008_10667.bin 1472352_9754.bin 198768_16826.bin
10637856_ins_5496.bin 1351008_10739.bin 1472352_dexfile.dex 198768_17570.bin
10637856_ins_5523.bin 1351008_10869.bin 1472352_dexfile_execute.dex 198768_17704.bin
10637856_ins_5762.bin 1351008_11525.bin 1472352_ins_7860.bin 198768_20150.bin
10637856_ins_5945.bin 1351008_11648.bin 1472352_ins_7971.bin 198768_9399.bin
10637856_ins_6217.bin 1351008_16643.bin 1481472_10667.bin 198768_9496.bin
11125808_classlist.txt 1351008_16667.bin 1481472_10739.bin 198768_9651.bin
11125808_classlist_execute.txt 1351008_16826.bin 1481472_10869.bin 198768_9754.bin
11125808_dexfile.dex 1351008_17570.bin 1481472_11525.bin 198768_dexfile.dex
11125808_dexfile_execute.dex 1351008_17704.bin 1481472_11648.bin 198768_dexfile_execute.dex

其中

  • *_dexfile_execute.dex 是从 Execute 方法中 dump 下来的 dex 文件;

  • *_dexfile.dex 是从 ArtMethod::Invoke 方法中 dump 下来的 dex 文件;

  • *_classlist.txt 或 *_classlist_execute.txt 是 dex 的类列表;

  • *.bin 是从 ArtMethod::Invoke 方法中 dump 下来的方法的 CodeItem;

把整个目录拉取到本地

adb pull /sdcard/fart/com.cyrus.example

sprintf 缓冲区溢出

在测试某个电商 app 脱壳时偶现报错如下:

2025年05月23日 21:15:46.790 13890-16106 libc pid-13890 A FORTIFY: vsprintf: prevented 1026-byte write into 1000-byte buffer
2025年05月23日 21:15:46.872 13890-16084 libc pid-13890 A FORTIFY: vsprintf: prevented 1026-byte write into 1000-byte buffer
2025年05月23日 21:15:52.339 13890-16278 libc pid-13890 A FORTIFY: vsprintf: prevented 1026-byte write into 1000-byte buffer
2025年05月23日 21:15:52.340 13890-16278 libc pid-13890 A Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 16278 (Thread-14), pid 13890 (shizhuang.duapp)
2025年05月23日 21:15:52.542 16906-16906 DEBUG pid-16906 A *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
2025年05月23日 21:15:52.542 16906-16906 DEBUG pid-16906 A LineageOS Version: '17.1-20250523-UNOFFICIAL-wayne'
2025年05月23日 21:15:52.542 16906-16906 DEBUG pid-16906 A Build fingerprint: 'xiaomi/wayne/wayne:8.1.0/OPM1.171019.011/V9.5.11.0.ODCCNFA:user/release-keys'
2025年05月23日 21:15:52.542 16906-16906 DEBUG pid-16906 A Revision: '0'
2025年05月23日 21:15:52.542 16906-16906 DEBUG pid-16906 A ABI: 'arm64'
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A Timestamp: 2025年05月23日 21:15:52+0800
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A pid: 13890, tid: 16278, name: Thread-14 >>> com.shizhuang.duapp <<<
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A uid: 10139
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A Abort message: 'FORTIFY: vsprintf: prevented 1026-byte write into 1000-byte buffer'
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A x0 0000000000000000 x1 0000000000003f96 x2 0000000000000006 x3 00000071e127a3c0
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A x4 fefefefefeff7164 x5 fefefefefeff7164 x6 fefefefefeff7164 x7 7f7f7f7f7f7f7f7f
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A x8 00000000000000f0 x9 00000075b873c4a0 x10 0000000000000000 x11 0000000000000001
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A x12 0000000000000018 x13 0000001b26f96dc9 x14 0014343f445098a4 x15 00000000002d0120
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A x16 00000075b88098c0 x17 00000075b87e7310 x18 00000071ddc8e000 x19 00000000000000ac
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A x20 0000000000003642 x21 00000000000000b2 x22 0000000000003f96 x23 00000000ffffffff
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A x24 000000000000007c x25 000000000000c685 x26 00000000000003e8 x27 00000071e127c020
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A x28 0000007537de0000 x29 00000071e127a470
2025年05月23日 21:15:52.543 16906-16906 DEBUG pid-16906 A sp 00000071e127a3a0 lr 00000075b879a170 pc 00000075b879a1a0
2025年05月23日 21:15:52.698 16906-16906 DEBUG pid-16906 A 
 backtrace:
2025年05月23日 21:15:52.698 16906-16906 DEBUG pid-16906 A #00 pc 00000000000821a0 /apex/com.android.runtime/lib64/bionic/libc.so (abort+176) (BuildId: a5aa1dd8572ed64645c321b17b43e24d)
2025年05月23日 21:15:52.698 16906-16906 DEBUG pid-16906 A #01 pc 00000000000a92bc /apex/com.android.runtime/lib64/bionic/libc.so (__fortify_fatal(char const*, ...)+116) (BuildId: a5aa1dd8572ed64645c321b17b43e24d)
2025年05月23日 21:15:52.698 16906-16906 DEBUG pid-16906 A #02 pc 00000000000a9f70 /apex/com.android.runtime/lib64/bionic/libc.so (__vsprintf_chk+144) (BuildId: a5aa1dd8572ed64645c321b17b43e24d)
2025年05月23日 21:15:52.698 16906-16906 DEBUG pid-16906 A #03 pc 00000000001448d4 /apex/com.android.runtime/lib64/libart.so (_ZL7sprintfPcU17pass_object_size1PKcz+124) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.698 16906-16906 DEBUG pid-16906 A #04 pc 0000000000144d74 /apex/com.android.runtime/lib64/libart.so (dumpArtMethod+1140) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.698 16906-16906 DEBUG pid-16906 A #05 pc 000000000004944c /system/framework/arm64/boot-core-libart.oat (art_jni_trampoline+172) (BuildId: ec978110cc23b14d9f94b2304a344f21a20e848d)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #06 pc 00000000001375b8 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_static_stub+568) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #07 pc 0000000000145374 /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+292) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #08 pc 00000000004b2fe8 /apex/com.android.runtime/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #09 pc 00000000004b4a30 /apex/com.android.runtime/lib64/libart.so (art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned long)+1472) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #10 pc 00000000004406c0 /apex/com.android.runtime/lib64/libart.so (art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*)+48) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #11 pc 00000000000bfc34 /system/framework/arm64/boot.oat (art_jni_trampoline+180) (BuildId: 9180a0d3ab0acb7f4675c6605dd909d40007fd68)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #12 pc 00000000021b619c /memfd:/jit-cache (deleted) (android.app.ActivityThread.loadClassAndInvoke+1148)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #13 pc 00000000021b6ddc /memfd:/jit-cache (deleted) (android.app.ActivityThread.fartwithClassloader+2508)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #14 pc 00000000001375b8 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_static_stub+568) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #15 pc 0000000000145374 /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+292) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #16 pc 00000000002e4388 /apex/com.android.runtime/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+384) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #17 pc 00000000002df414 /apex/com.android.runtime/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+900) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #18 pc 00000000005a5660 /apex/com.android.runtime/lib64/libart.so (MterpInvokeStatic+368) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.699 16906-16906 DEBUG pid-16906 A #19 pc 0000000000131994 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_static+20) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #20 pc 0000000000181b24 /system/framework/framework.jar (android.app.ActivityThread.fart+44)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #21 pc 00000000005a5960 /apex/com.android.runtime/lib64/libart.so (MterpInvokeStatic+1136) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #22 pc 0000000000131994 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_static+20) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #23 pc 000000000017998e /system/framework/framework.jar (android.app.ActivityThread2ドル.run+46)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #24 pc 00000000002b4c2c /apex/com.android.runtime/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEbb.llvm.5230655971336280632+340) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #25 pc 0000000000593fa0 /apex/com.android.runtime/lib64/libart.so (artQuickToInterpreterBridge+1024) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #26 pc 0000000000140468 /apex/com.android.runtime/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #27 pc 00000000001a3088 /system/framework/arm64/boot.oat (java.lang.Thread.run+72) (BuildId: 9180a0d3ab0acb7f4675c6605dd909d40007fd68)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #28 pc 0000000000137334 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_stub+548) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #29 pc 0000000000145348 /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+248) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #30 pc 00000000004b2fe8 /apex/com.android.runtime/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #31 pc 00000000004b4098 /apex/com.android.runtime/lib64/libart.so (art::InvokeVirtualOrInterfaceWithJValues(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, jvalue const*)+416) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #32 pc 00000000004f45e0 /apex/com.android.runtime/lib64/libart.so (art::Thread::CreateCallback(void*)+1176) (BuildId: a54f40638f14fad0786ba67b78899d39)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #33 pc 00000000000e35fc /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+36) (BuildId: a5aa1dd8572ed64645c321b17b43e24d)
2025年05月23日 21:15:52.700 16906-16906 DEBUG pid-16906 A #34 pc 0000000000083d98 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: a5aa1dd8572ed64645c321b17b43e24d)

触发崩溃的原因是:

FORTIFY: vsprintf: prevented 1026-byte write into 1000-byte buffer

触发了 Android 的 FORTIFY 安全机制,这个机制会检测标准库函数(如 sprintf / vsprintf)是否发生了缓冲区溢出。

在尝试写入超过目标缓冲区大小的内容(尝试写入 1026 字节,但缓冲区仅有 1000 字节),结果触发了 libc 中的 FORTIFY 检测机制,引发了 SIGABRT(abort)信号终止进程。

崩溃发生在 libart.so 中的 dumpArtMethod() 函数内部。

解决方案:使用 std::string 替代手动 malloc + sprintf 就好了。

调整 dumpArtMethod 代码如下:

//add
extern "C" void dumpArtMethod(ArtMethod* artmethod) REQUIRES_SHARED(Locks::mutator_lock_) {
 char szProcName[256] = {0};
 int procid = getpid();
 // 获取进程名
 char szCmdline[64] = {0};
 snprintf(szCmdline, sizeof(szCmdline), "/proc/%d/cmdline", procid);
 int fcmdline = open(szCmdline, O_RDONLY);
 if (fcmdline > 0) {
 ssize_t result = read(fcmdline, szProcName, sizeof(szProcName) - 1);
 if (result < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: read cmdline failed.";
 }
 close(fcmdline);
 }
 if (szProcName[0] == '0円') return;
 const DexFile* dex_file = artmethod->GetDexFile();
 const uint8_t* begin_ = dex_file->Begin();
 size_t size_ = dex_file->Size();
 int size_int = static_cast<int>(size_);
 // 路径拼接
 std::string baseDir = "/sdcard/fart/";
 std::string processDir = baseDir + szProcName;
 mkdir(baseDir.c_str(), 0777);
 mkdir(processDir.c_str(), 0777);
 // 保存 dex 文件
 std::string dexPath = processDir + "/" + std::to_string(size_int) + "_dexfile.dex";
 int dexfilefp = open(dexPath.c_str(), O_RDONLY);
 if (dexfilefp > 0) {
 close(dexfilefp);
 } else {
 int fp = open(dexPath.c_str(), O_CREAT | O_APPEND | O_RDWR, 0666);
 if (fp > 0) {
 ssize_t w = write(fp, begin_, size_);
 if (w < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: write dexfile failed -> " << dexPath;
 }
 fsync(fp);
 close(fp);
 // 保存 class 列表
 std::string classListPath = processDir + "/" + std::to_string(size_int) + "_classlist.txt";
 int classlistfile = open(classListPath.c_str(), O_CREAT | O_APPEND | O_RDWR, 0666);
 if (classlistfile > 0) {
 for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
 const dex::ClassDef& class_def = dex_file->GetClassDef(i);
 const char* descriptor = dex_file->GetClassDescriptor(class_def);
 ssize_t w1 = write(classlistfile, descriptor, strlen(descriptor));
 if (w1 < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: write class descriptor failed";
 }
 ssize_t w2 = write(classlistfile, "\n", 1);
 if (w2 < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: write newline failed";
 }
 }
 fsync(classlistfile);
 close(classlistfile);
 }
 }
 }
 // 保存指令码
 const dex::CodeItem* code_item = artmethod->GetCodeItem();
 if (LIKELY(code_item != nullptr)) {
 uint8_t* item = (uint8_t*)code_item;
 int code_item_len = 0;
 CodeItemDataAccessor accessor(*dex_file, code_item);
 if (accessor.TriesSize() > 0) {
 const uint8_t* handler_data = accessor.GetCatchHandlerData();
 uint8_t* tail = codeitem_end(&handler_data);
 code_item_len = static_cast<int>(tail - item);
 } else {
 code_item_len = 16 + accessor.InsnsSizeInCodeUnits() * 2;
 }
 uint32_t method_idx = artmethod->GetDexMethodIndex();
 int offset = static_cast<int>(item - begin_);
 pid_t tid = gettidv1();
 std::string insPath = processDir + "/" + std::to_string(size_int) + "_ins_" + std::to_string(tid) + ".bin";
 int fp2 = open(insPath.c_str(), O_CREAT | O_APPEND | O_RDWR, 0666);
 if (fp2 > 0) {
 lseek(fp2, 0, SEEK_END);
 std::string header = "{name:" + artmethod->PrettyMethod() +
 ",method_idx:" + std::to_string(method_idx) +
 ",offset:" + std::to_string(offset) +
 ",code_item_len:" + std::to_string(code_item_len) +
 ",ins:";
 ssize_t w3 = write(fp2, header.c_str(), header.length());
 if (w3 < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: write header failed";
 }
 long outlen = 0;
 char* base64result = base64_encode((char*)item, (long)code_item_len, &outlen);
 if (base64result != nullptr) {
 ssize_t w4 = write(fp2, base64result, outlen);
 if (w4 < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: write base64 ins failed";
 }
 free(base64result);
 }
 ssize_t w5 = write(fp2, "};", 2);
 if (w5 < 0) {
 LOG(ERROR) << "ArtMethod::dumpArtMethod: write tail failed";
 }
 fsync(fp2);
 close(fp2);
 }
 }
}

dumpDexFileByExecute 函数同样调整如下:

//add
extern "C" void dumpDexFileByExecute(ArtMethod* artmethod) REQUIRES_SHARED(Locks::mutator_lock_) {
 char szCmdline[64] = {0};
 char szProcName[256] = {0};
 int procid = getpid();
 snprintf(szCmdline, sizeof(szCmdline), "/proc/%d/cmdline", procid);
 int fcmdline = open(szCmdline, O_RDONLY);
 if (fcmdline > 0) {
 ssize_t result = read(fcmdline, szProcName, sizeof(szProcName) - 1);
 if (result < 0) {
 LOG(ERROR) << "dumpDexFileByExecute: Failed to read cmdline";
 }
 close(fcmdline);
 }
 if (szProcName[0] == '0円') return;
 const DexFile* dex_file = artmethod->GetDexFile();
 const uint8_t* begin_ = dex_file->Begin();
 size_t size_ = dex_file->Size();
 int size_int = static_cast<int>(size_);
 std::string base_dir = "/sdcard/fart/";
 std::string app_dir = base_dir + szProcName;
 std::string dex_path = app_dir + "/" + std::to_string(size_int) + "_dexfile_execute.dex";
 std::string classlist_path = app_dir + "/" + std::to_string(size_int) + "_classlist_execute.txt";
 mkdir(base_dir.c_str(), 0777);
 mkdir(app_dir.c_str(), 0777);
 int dexfilefp = open(dex_path.c_str(), O_RDONLY);
 if (dexfilefp > 0) {
 close(dexfilefp);
 } else {
 int fp = open(dex_path.c_str(), O_CREAT | O_APPEND | O_RDWR, 0666);
 if (fp > 0) {
 ssize_t w1 = write(fp, begin_, size_);
 if (w1 < 0) {
 LOG(ERROR) << "dumpDexFileByExecute: Failed to write dex file";
 }
 fsync(fp);
 close(fp);
 int classlistfile = open(classlist_path.c_str(), 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);
 
 ssize_t w2 = write(classlistfile, descriptor, strlen(descriptor));
 if (w2 < 0) {
 LOG(ERROR) << "dumpDexFileByExecute: Failed to write class descriptor";
 }
 ssize_t w3 = write(classlistfile, "\n", 1);
 if (w3 < 0) {
 LOG(ERROR) << "dumpDexFileByExecute: Failed to write newline";
 }
 }
 fsync(classlistfile);
 close(classlistfile);
 }
 }
 }
}

完整源码

开源地址:https://github.com/CYRUS-STUDIO/FART

相关文章:

About

移植 FART 到 Android 10,ART 环境下基于主动调用的自动化脱壳方案(Porting FART to Android 10: An Automated Unpacking Solution in the ART Environment Based on Active Invocation)

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Java 62.5%
  • C++ 23.2%
  • Python 12.8%
  • JavaScript 1.5%

AltStyle によって変換されたページ (->オリジナル) /