├── ArtTest.zip ├── README.md ├── app-release.apk ├── app-release_jiami.apk ├── art_patch.txt ├── framework_patch.txt └── libcore_patch.txt /ArtTest.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jltxgcy/fart/ceb3241ada8b9904ae3b09ca9f8ca448d91f2e03/ArtTest.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FART:ART环境下基于主动调用的自动化脱壳方案,android源码修改公开,基于android-9.0.0_r36 2 | 3 | app-release.apk是原apk 4 | 5 | app-release_jiami.apk是加密后的apk 6 | 7 | ArtTest.zip是apk的源代码 8 | 9 | framework_patch.txt、libcore_patch.txt、art_patch.txt是修改android-9.0.0_r36源码的patch 10 | -------------------------------------------------------------------------------- /app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jltxgcy/fart/ceb3241ada8b9904ae3b09ca9f8ca448d91f2e03/app-release.apk -------------------------------------------------------------------------------- /app-release_jiami.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jltxgcy/fart/ceb3241ada8b9904ae3b09ca9f8ca448d91f2e03/app-release_jiami.apk -------------------------------------------------------------------------------- /art_patch.txt: -------------------------------------------------------------------------------- 1 | diff --git a/libdexfile/dex/standard_dex_file.h b/libdexfile/dex/standard_dex_file.h 2 | index 999e5b9..c5e699d 100644 3 | --- a/libdexfile/dex/standard_dex_file.h 4 | +++ b/libdexfile/dex/standard_dex_file.h 5 | @@ -35,7 +35,7 @@ class StandardDexFile : public DexFile { 6 | struct CodeItem : public DexFile::CodeItem { 7 | static constexpr size_t kAlignment = 4; 8 | 9 | - private: 10 | + public: 11 | CodeItem() = default; 12 | 13 | uint16_t registers_size_; // the number of registers used by this code 14 | diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h 15 | index c1fac36..5ae8144 100644 16 | --- a/runtime/art_method-inl.h 17 | +++ b/runtime/art_method-inl.h 18 | @@ -178,6 +178,21 @@ inline const DexFile* ArtMethod::GetDexFile() { 19 | return GetDexCache()->GetDexFile(); 20 | } 21 | 22 | +inline void ArtMethod::DumpArtMethod() { 23 | + const DexFile* dex_file = GetDexFile(); 24 | + const DexFile::CodeItem* code_item= GetCodeItem(); 25 | + if (dex_file != NULL && code_item != NULL && !dex_file->IsCompactDexFile()) 26 | + { 27 | + const StandardDexFile::CodeItem& standardCodeItem = down_cast(*code_item); 28 | + LOG(ERROR) << "fartlog, DumpArtMethod code_item length:" << standardCodeItem.insns_size_in_code_units_; 29 | + for (int i = 0 ; i < (int)standardCodeItem.insns_size_in_code_units_; i++) 30 | + { 31 | + LOG(ERROR) << "fartlog, DumpArtMethod code_item content:" << standardCodeItem.insns_[i]; 32 | + } 33 | + 34 | + } 35 | +} 36 | + 37 | inline const char* ArtMethod::GetDeclaringClassDescriptor() { 38 | uint32_t dex_method_idx = GetDexMethodIndex(); 39 | if (UNLIKELY(dex_method_idx == dex::kDexNoIndex)) { 40 | diff --git a/runtime/art_method.h b/runtime/art_method.h 41 | index 012d706..2e3d041 100644 42 | --- a/runtime/art_method.h 43 | +++ b/runtime/art_method.h 44 | @@ -579,6 +579,8 @@ class ArtMethod FINAL { 45 | 46 | const DexFile* GetDexFile() REQUIRES_SHARED(Locks::mutator_lock_); 47 | 48 | + void DumpArtMethod() REQUIRES_SHARED(Locks::mutator_lock_); 49 | + 50 | const char* GetDeclaringClassDescriptor() REQUIRES_SHARED(Locks::mutator_lock_); 51 | 52 | ALWAYS_INLINE const char* GetShorty() REQUIRES_SHARED(Locks::mutator_lock_); 53 | diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc 54 | index 637e7fa..6c109f4 100644 55 | --- a/runtime/native/dalvik_system_DexFile.cc 56 | +++ b/runtime/native/dalvik_system_DexFile.cc 57 | @@ -19,6 +19,7 @@ 58 | #include 59 | 60 | #include "android-base/stringprintf.h" 61 | +#include "art_method-inl.h" 62 | 63 | #include "base/file_utils.h" 64 | #include "base/logging.h" 65 | @@ -49,6 +50,7 @@ 66 | #include "scoped_thread_state_change-inl.h" 67 | #include "well_known_classes.h" 68 | #include "zip_archive.h" 69 | +#include "scoped_fast_native_object_access-inl.h" 70 | 71 | namespace art { 72 | 73 | @@ -287,7 +289,6 @@ static jobject DexFile_openDexFileNative(JNIEnv* env, 74 | dex_elements, 75 | /*out*/ &oat_file, 76 | /*out*/ &error_msgs); 77 | - 78 | if (!dex_files.empty()) { 79 | jlongArray array = ConvertDexFilesToJavaArray(env, oat_file, dex_files); 80 | if (array == nullptr) { 81 | @@ -816,6 +817,13 @@ static jlong DexFile_getStaticSizeOfDexFile(JNIEnv* env, jclass, jobject cookie) 82 | return static_cast(file_size); 83 | } 84 | 85 | +static void DexFile_dumpMethodCode(JNIEnv* env, jclass, jobject j_method) { 86 | + ScopedFastNativeObjectAccess soa(env); 87 | + ArtMethod* method = ArtMethod::FromReflectedMethod(soa, j_method); 88 | + LOG(ERROR) << "fartlog, method:" << method->GetName(); 89 | + method->DumpArtMethod(); 90 | +} 91 | + 92 | static void DexFile_setTrusted(JNIEnv* env, jclass, jobject j_cookie) { 93 | Runtime* runtime = Runtime::Current(); 94 | ScopedObjectAccess soa(env); 95 | @@ -877,7 +885,8 @@ static JNINativeMethod gMethods[] = { 96 | NATIVE_METHOD(DexFile, getStaticSizeOfDexFile, "(Ljava/lang/Object;)J"), 97 | NATIVE_METHOD(DexFile, getDexFileOptimizationStatus, 98 | "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"), 99 | - NATIVE_METHOD(DexFile, setTrusted, "(Ljava/lang/Object;)V") 100 | + NATIVE_METHOD(DexFile, setTrusted, "(Ljava/lang/Object;)V"), 101 | + NATIVE_METHOD(DexFile, dumpMethodCode, "(Ljava/lang/Object;)V") 102 | }; 103 | 104 | void register_dalvik_system_DexFile(JNIEnv* env) { 105 | -------------------------------------------------------------------------------- /framework_patch.txt: -------------------------------------------------------------------------------- 1 | diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java 2 | index 14a622a..6a6a5af 100644 3 | --- a/core/java/android/app/ActivityThread.java 4 | +++ b/core/java/android/app/ActivityThread.java 5 | @@ -182,6 +182,10 @@ import java.util.Map; 6 | import java.util.Objects; 7 | import java.util.TimeZone; 8 | import java.util.concurrent.Executor; 9 | +import java.lang.reflect.Constructor; 10 | +import java.lang.reflect.Field; 11 | +import java.lang.reflect.InvocationTargetException; 12 | +import java.lang.reflect.Method; 13 | 14 | final class RemoteServiceException extends AndroidRuntimeException { 15 | public RemoteServiceException(String msg) { 16 | @@ -2844,6 +2848,7 @@ public final class ActivityThread extends ClientTransactionHandler { 17 | 18 | /** Core implementation of activity launch. */ 19 | private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { 20 | + Log.e(TAG, "go into performLaunchActivity"); 21 | ActivityInfo aInfo = r.activityInfo; 22 | if (r.packageInfo == null) { 23 | r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, 24 | @@ -2951,10 +2956,161 @@ public final class ActivityThread extends ClientTransactionHandler { 25 | + ": " + e.toString(), e); 26 | } 27 | } 28 | - 29 | + Log.e(TAG, "app name:" + r.packageInfo.getPackageName()); 30 | + if (r.packageInfo.getPackageName().equals("com.example.jltxgcy.arttest")) { 31 | + ActivityThread.fartthread(); 32 | + } 33 | return activity; 34 | } 35 | 36 | + public static ClassLoader getClassloader() { 37 | + Object currentActivityThread = invokeStaticMethod("android.app.ActivityThread", "currentActivityThread", new Class[]{}, new Object[]{}); 38 | + Object mBoundApplication = getFieldOjbect("android.app.ActivityThread", currentActivityThread, "mBoundApplication"); 39 | + return ((Application) getFieldOjbect("android.app.LoadedApk", getFieldOjbect("android.app.ActivityThread$AppBindData", mBoundApplication, "info"), "mApplication")).getClassLoader(); 40 | + } 41 | + 42 | + public static Object invokeStaticMethod(String class_name, String method_name, Class[] pareTyple, Object[] pareVaules) { 43 | + try { 44 | + return Class.forName(class_name).getMethod(method_name, pareTyple).invoke(null, pareVaules); 45 | + } catch (IllegalAccessException e) { 46 | + e.printStackTrace(); 47 | + } catch (InvocationTargetException e) { 48 | + e.printStackTrace(); 49 | + } catch (NoSuchMethodException e) { 50 | + e.printStackTrace(); 51 | + } catch (ClassNotFoundException e) { 52 | + e.printStackTrace(); 53 | + } 54 | + return null; 55 | + } 56 | + 57 | + public static Object getFieldOjbect(String class_name, Object obj, String fieldName) { 58 | + try { 59 | + Class obj_class = Class.forName(class_name); 60 | + Field field = obj_class.getDeclaredField(fieldName); 61 | + field.setAccessible(true); 62 | + return field.get(obj); 63 | + } catch (ClassNotFoundException e) { 64 | + e.printStackTrace(); 65 | + } catch (NoSuchFieldException e) { 66 | + e.printStackTrace(); 67 | + } catch (IllegalAccessException e) { 68 | + e.printStackTrace(); 69 | + } 70 | + return null; 71 | + } 72 | + 73 | + public static Field getClassField(ClassLoader class_loader, String class_name, String fieldName) { 74 | + try { 75 | + Field field = class_loader.loadClass(class_name).getDeclaredField(fieldName); 76 | + field.setAccessible(true); 77 | + return field; 78 | + } catch (NoSuchFieldException e) { 79 | + e.printStackTrace(); 80 | + } catch (ClassNotFoundException e) { 81 | + e.printStackTrace(); 82 | + } 83 | + return null; 84 | + } 85 | + 86 | + public static Object getClassFieldObject(ClassLoader class_loader, String class_name, Object obj, String fieldName) { 87 | + try { 88 | + Field field = class_loader.loadClass(class_name).getDeclaredField(fieldName); 89 | + field.setAccessible(true); 90 | + return field.get(obj); 91 | + } catch (NoSuchFieldException e) { 92 | + e.printStackTrace(); 93 | + } catch (ClassNotFoundException e) { 94 | + e.printStackTrace(); 95 | + } catch (IllegalAccessException e) { 96 | + e.printStackTrace(); 97 | + } 98 | + return null; 99 | + } 100 | + 101 | + public static void fart() { 102 | + try { 103 | + ClassLoader class_loader = getClassloader(); 104 | + Method[] md = class_loader.loadClass("dalvik.system.DexFile").getDeclaredMethods(); 105 | + Method getClassNameListMethod = null; 106 | + Method dumpMethodCodeMethod = null; 107 | + int mdCount = md.length; 108 | + for (int i = 0; i < mdCount; i++) { 109 | + if (md[i].getName().equals("getClassNameList")) { 110 | + getClassNameListMethod = md[i]; 111 | + md[i].setAccessible(true); 112 | + } else if (md[i].getName().equals("dumpMethodCode")) { 113 | + dumpMethodCodeMethod = md[i]; 114 | + md[i].setAccessible(true); 115 | + } 116 | + } 117 | + 118 | + Object[] dexElementsObjs = (Object[]) getFieldOjbect("dalvik.system.DexPathList", getFieldOjbect("dalvik.system.BaseDexClassLoader", class_loader, "pathList"), "dexElements"); 119 | + Field dexFileField = getClassField(class_loader, "dalvik.system.DexPathList$Element", "dexFile"); 120 | + for (int i = 0; i < dexElementsObjs.length; i++) { 121 | + Object dexFileObj = dexFileField.get(dexElementsObjs[i]); 122 | + Object cookObj = getClassFieldObject(class_loader, "dalvik.system.DexFile", dexFileObj, "mCookie"); 123 | + String[] classNames = (String[]) getClassNameListMethod.invoke(dexFileObj, new Object[]{cookObj}); 124 | + for (int j = 0; j < classNames.length; j++) { 125 | + Log.e(TAG, "fart classNames:" + classNames[j]); 126 | + loadClassAndInvoke(class_loader, classNames[j], dumpMethodCodeMethod); 127 | + } 128 | + } 129 | + } catch (ClassNotFoundException e) { 130 | + Log.e(TAG, "fart ClassNotFoundException" + e.getMessage()); 131 | + e.printStackTrace(); 132 | + } catch (IllegalAccessException e) { 133 | + Log.e(TAG, "fart IllegalAccessException" + e.getMessage()); 134 | + e.printStackTrace(); 135 | + } catch (InvocationTargetException e) { 136 | + Log.e(TAG, "fart InvocationTargetException" + e.getMessage()); 137 | + e.printStackTrace(); 138 | + } 139 | + 140 | + } 141 | + 142 | + public static void loadClassAndInvoke(ClassLoader class_loader, String className, Method dumpMethodCodeMethod) { 143 | + try { 144 | + Class class1 = class_loader.loadClass(className); 145 | + Constructor[] constructors = class1.getDeclaredConstructors(); 146 | + for (int i = 0; i < constructors.length; i++) { 147 | + dumpMethodCodeMethod.invoke(null, new Object[]{constructors[i]}); 148 | + } 149 | + 150 | + Method[] methods = class1.getDeclaredMethods(); 151 | + for (int i = 0; i < methods.length; i++) { 152 | + dumpMethodCodeMethod.invoke(null, new Object[]{methods[i]}); 153 | + } 154 | + Log.e(TAG, "className:" + className + ",constructors length:" + constructors.length + ",method length:" + methods.length); 155 | + } catch (ClassNotFoundException e) { 156 | + Log.e(TAG, "fart ClassNotFoundException" + e.getMessage()); 157 | + e.printStackTrace(); 158 | + } catch (IllegalAccessException e) { 159 | + Log.e(TAG, "fart IllegalAccessException" + e.getMessage()); 160 | + e.printStackTrace(); 161 | + } catch (InvocationTargetException e) { 162 | + Log.e(TAG, "fart InvocationTargetException" + e.getMessage()); 163 | + e.printStackTrace(); 164 | + } 165 | + return; 166 | + } 167 | + 168 | + public static void fartthread() { 169 | + (new Thread(new Runnable() { 170 | + public void run() { 171 | + try { 172 | + Log.e("ActivityThread", "start sleep......"); 173 | + Thread.sleep(10000L); 174 | + } catch (InterruptedException interruptedException) { 175 | + interruptedException.printStackTrace(); 176 | + } 177 | + Log.e("ActivityThread", "sleep over and start fart"); 178 | + ActivityThread.fart(); 179 | + Log.e("ActivityThread", "fart run over"); 180 | + } 181 | + })).start(); 182 | + } 183 | + 184 | @Override 185 | public void handleStartActivity(ActivityClientRecord r, 186 | PendingTransactionActions pendingActions) { 187 | @@ -5583,6 +5739,7 @@ public final class ActivityThread extends ClientTransactionHandler { 188 | } 189 | 190 | private void handleBindApplication(AppBindData data) { 191 | + Log.e(TAG, "go into handleBindApplication"); 192 | // Register the UI Thread as a sensitive thread to the runtime. 193 | VMRuntime.registerSensitiveThread(); 194 | if (data.trackAllocation) { 195 | -------------------------------------------------------------------------------- /libcore_patch.txt: -------------------------------------------------------------------------------- 1 | diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java 2 | index afedba5..9f6fadf 100644 3 | --- a/dalvik/src/main/java/dalvik/system/DexFile.java 4 | +++ b/dalvik/src/main/java/dalvik/system/DexFile.java 5 | @@ -392,6 +392,7 @@ public final class DexFile { 6 | private static native Class defineClassNative(String name, ClassLoader loader, Object cookie, 7 | DexFile dexFile) 8 | throws ClassNotFoundException, NoClassDefFoundError; 9 | + private static native void dumpMethodCode(Object methodid); 10 | private static native String[] getClassNameList(Object cookie); 11 | private static native boolean isBackedByOatFile(Object cookie); 12 | private static native void setTrusted(Object cookie); 13 | --------------------------------------------------------------------------------