【Android 安全】DEX 加密 ( Application 替换 | 分析 Activity 组件中获取的 Application | ActivityThread | LoadedApk )
文章目錄
- 一、 Activity 中的 getApplication() 方法分析
- 二、 ActivityThread 中的 H 處理 消息及 handleLaunchActivity 方法操作
- 三、 ActivityThread 中的 performLaunchActivity 方法
- 四、 LoadedApk 中的 mApplication 成員
- 五、 ActivityThread 涉及源碼
- 六、 Instrumentation 涉及源碼
- 七、 LoadedApk 涉及源碼
一、 Activity 中的 getApplication() 方法分析
在 Activity 中調用 getApplication() 方法 , 獲取 Application 的過程分析 ;
下面就是調用的 Activity 的 getApplication() 方法 , 其獲取的是 Application mApplication 成員 ;
而 mApplication 成員是在 attach() 方法中賦值的 ;
public class Activity extends ContextThemeWrapperimplements LayoutInflater.Factory2,Window.Callback, KeyEvent.Callback,OnCreateContextMenuListener, ComponentCallbacks2,Window.OnWindowDismissedCallback, WindowControllerCallback,AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {@UnsupportedAppUsageprivate Application mApplication;/** Return the application that owns this activity. */public final Application getApplication() {return mApplication;}@UnsupportedAppUsagefinal void attach(Context context, ActivityThread aThread,Instrumentation instr, IBinder token, int ident,Application application, Intent intent, ActivityInfo info,CharSequence title, Activity parent, String id,NonConfigurationInstances lastNonConfigurationInstances,Configuration config, String referrer, IVoiceInteractor voiceInteractor,Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {attachBaseContext(context);mApplication = application;} }參考源碼路徑 : frameworks/base/core/java/android/app/Activity.java
二、 ActivityThread 中的 H 處理 消息及 handleLaunchActivity 方法操作
在 ActivityThread 中 , 創建并啟動一個 Activity , H ( Handler 子類 ) 接到一個 LAUNCH_ACTIVITY 消息 , 在相應的處理該 LAUNCH_ACTIVITY 消息的 handleMessage 方法中 , 調用了 handleLaunchActivity 方法 ;
public final class ActivityThread {private class H extends Handler {public static final int LAUNCH_ACTIVITY = 100;public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {case LAUNCH_ACTIVITY: {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");final ActivityClientRecord r = (ActivityClientRecord) msg.obj;r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);// ★ 調用 handleLaunchActivity 方法處理該消息handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);} break;} // switch} // handleMessage} // private class H extends Handler}參考路徑 : frameworks/base/core/java/android/app/ActivityThread.java
三、 ActivityThread 中的 performLaunchActivity 方法
handleLaunchActivity 方法中調用了 performLaunchActivity 方法 , 在該方法中通過 mInstrumentation.newActivity 創建 Activity , Instrumentation 創建 Activity 是通過反射進行的 ;
performLaunchActivity 方法中創建了 Activity 后 , 就調用了 Activity 的 attach 方法 , 為 Activity 中的 Application mApplication 成員賦值 ;
activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.configCallback);在調用的 activity.attach 中第六個參數 app 就是設置的 Application , app 的創建代碼如下 , 這里是傳入 Activity attach 方法中的 Application , 賦值給 Activity 中的 mApplication 成員 , packageInfo 就是 LoadedApk , LoadedApk 的 makeApplication 直接使用的就是 LoadedApk 中的 mApplication 成員 ;
Application app = r.packageInfo.makeApplication(false, mInstrumentation);主要源碼 :
public final class ActivityThread {private class H extends Handler {public static final int LAUNCH_ACTIVITY = 100;public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {case LAUNCH_ACTIVITY: {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");final ActivityClientRecord r = (ActivityClientRecord) msg.obj;r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);// ★ 調用 handleLaunchActivity 方法處理該消息handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);} break;} // switch} // handleMessage} // private class H extends Handlerprivate void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {// ★ 此處創建了一個 Activity Activity a = performLaunchActivity(r, customIntent);}private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");ActivityInfo aInfo = r.activityInfo;ContextImpl appContext = createBaseContextForActivity(r);// ★ 聲明 Activity Activity activity = null;try {java.lang.ClassLoader cl = appContext.getClassLoader();// ★ 創建 Activity , 與創建 Application 類似 activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);} catch (Exception e) {}try {// ★ 這里是傳入 Activity attach 方法中的 Application , 賦值給 Activity 中的 mApplication 成員 Application app = r.packageInfo.makeApplication(false, mInstrumentation);if (activity != null) {appContext.setOuterContext(activity);// ★ 此處調用了 Activity 的 attach 方法 , 給 Activity 中的 mApplication 成員賦值activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.configCallback);return activity;}}參考路徑 : frameworks/base/core/java/android/app/ActivityThread.java
四、 LoadedApk 中的 mApplication 成員
LoadedApk 中的 mApplication 成員已經替換成了自定義的 Application , 不再是代理的 Application , 因此從 Activity 中獲取的 Application 是已經替換后的用戶自定義的 Application , 不是代理 Application ;
Application 已經執行完畢 , Application 替換操作是在 Application 的 onCreate 方法中執行的 , 此處的 Activity 執行肯定在 Application 創建完畢之后執行的 ;
主要源碼 :
public final class LoadedApk {public Application makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation) {// ★ 如果之前創建過 Application , 就直接使用 if (mApplication != null) {return mApplication;}} }參考路徑 : frameworks/base/core/java/android/app/LoadedApk.java
五、 ActivityThread 涉及源碼
public final class ActivityThread {private class H extends Handler {public static final int LAUNCH_ACTIVITY = 100;public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {case LAUNCH_ACTIVITY: {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");final ActivityClientRecord r = (ActivityClientRecord) msg.obj;r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);// ★ 調用 handleLaunchActivity 方法處理該消息handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);} break;} // switch} // handleMessage} // private class H extends Handlerprivate void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {// If we are getting ready to gc after going to the background, well// we are back active so skip it.unscheduleGcIdler();mSomeActivitiesChanged = true;if (r.profilerInfo != null) {mProfiler.setProfiler(r.profilerInfo);mProfiler.startProfiling();}// Make sure we are running with the most recent config.handleConfigurationChanged(null, null);if (localLOGV) Slog.v(TAG, "Handling launch of " + r);// Initialize before creating the activityWindowManagerGlobal.initialize();// ★ 此處創建了一個 Activity Activity a = performLaunchActivity(r, customIntent);if (a != null) {r.createdConfig = new Configuration(mConfiguration);reportSizeConfigurations(r);Bundle oldState = r.state;handleResumeActivity(r.token, false, r.isForward,!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);if (!r.activity.mFinished && r.startsNotResumed) {// The activity manager actually wants this one to start out paused, because it// needs to be visible but isn't in the foreground. We accomplish this by going// through the normal startup (because activities expect to go through onResume()// the first time they run, before their window is displayed), and then pausing it.// However, in this case we do -not- need to do the full pause cycle (of freezing// and such) because the activity manager assumes it can just retain the current// state it has.performPauseActivityIfNeeded(r, reason);// We need to keep around the original state, in case we need to be created again.// But we only do this for pre-Honeycomb apps, which always save their state when// pausing, so we can not have them save their state when restarting from a paused// state. For HC and later, we want to (and can) let the state be saved as the// normal part of stopping the activity.if (r.isPreHoneycomb()) {r.state = oldState;}}} else {// If there was an error, for any reason, tell the activity manager to stop us.try {ActivityManager.getService().finishActivity(r.token, Activity.RESULT_CANCELED, null,Activity.DONT_FINISH_TASK_WITH_ACTIVITY);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}}}private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");ActivityInfo aInfo = r.activityInfo;if (r.packageInfo == null) {r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,Context.CONTEXT_INCLUDE_CODE);}ComponentName component = r.intent.getComponent();if (component == null) {component = r.intent.resolveActivity(mInitialApplication.getPackageManager());r.intent.setComponent(component);}if (r.activityInfo.targetActivity != null) {component = new ComponentName(r.activityInfo.packageName,r.activityInfo.targetActivity);}ContextImpl appContext = createBaseContextForActivity(r);// ★ 聲明 Activity Activity activity = null;try {java.lang.ClassLoader cl = appContext.getClassLoader();// ★ 創建 Activity , 與創建 Application 類似 activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);StrictMode.incrementExpectedActivityCount(activity.getClass());r.intent.setExtrasClassLoader(cl);r.intent.prepareToEnterProcess();if (r.state != null) {r.state.setClassLoader(cl);}} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to instantiate activity " + component+ ": " + e.toString(), e);}}try {// ★ 這里是傳入 Activity attach 方法中的 Application , 賦值給 Activity 中的 mApplication 成員 Application app = r.packageInfo.makeApplication(false, mInstrumentation);if (localLOGV) Slog.v(TAG, "Performing launch of " + r);if (localLOGV) Slog.v(TAG, r + ": app=" + app+ ", appName=" + app.getPackageName()+ ", pkg=" + r.packageInfo.getPackageName()+ ", comp=" + r.intent.getComponent().toShortString()+ ", dir=" + r.packageInfo.getAppDir());if (activity != null) {CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());Configuration config = new Configuration(mCompatConfiguration);if (r.overrideConfig != null) {config.updateFrom(r.overrideConfig);}if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "+ r.activityInfo.name + " with config " + config);Window window = null;if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {window = r.mPendingRemoveWindow;r.mPendingRemoveWindow = null;r.mPendingRemoveWindowManager = null;}appContext.setOuterContext(activity);// ★ 此處調用了 Activity 的 attach 方法 , 給 Activity 中的 mApplication 成員賦值activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.configCallback);if (customIntent != null) {activity.mIntent = customIntent;}r.lastNonConfigurationInstances = null;checkAndBlockForNetworkAccess();activity.mStartedActivity = false;int theme = r.activityInfo.getThemeResource();if (theme != 0) {activity.setTheme(theme);}activity.mCalled = false;if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}if (!activity.mCalled) {throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() +" did not call through to super.onCreate()");}r.activity = activity;r.stopped = true;if (!r.activity.mFinished) {activity.performStart();r.stopped = false;}if (!r.activity.mFinished) {if (r.isPersistable()) {if (r.state != null || r.persistentState != null) {mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,r.persistentState);}} else if (r.state != null) {mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);}}if (!r.activity.mFinished) {activity.mCalled = false;if (r.isPersistable()) {mInstrumentation.callActivityOnPostCreate(activity, r.state,r.persistentState);} else {mInstrumentation.callActivityOnPostCreate(activity, r.state);}if (!activity.mCalled) {throw new SuperNotCalledException("Activity " + r.intent.getComponent().toShortString() +" did not call through to super.onPostCreate()");}}}r.paused = true;mActivities.put(r.token, r);} catch (SuperNotCalledException e) {throw e;} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to start activity " + component+ ": " + e.toString(), e);}}return activity;}}
參考路徑 : frameworks/base/core/java/android/app/ActivityThread.java
六、 Instrumentation 涉及源碼
Instrumentation 中創建 Activity 的 newActivity 方法 ;
public class Instrumentation {/*** Perform instantiation of an {@link Activity} object. This method is intended for use with* unit tests, such as android.test.ActivityUnitTestCase. The activity will be useable* locally but will be missing some of the linkages necessary for use within the system.* * @param clazz The Class of the desired Activity* @param context The base context for the activity to use* @param token The token for this activity to communicate with* @param application The application object (if any)* @param intent The intent that started this Activity* @param info ActivityInfo from the manifest* @param title The title, typically retrieved from the ActivityInfo record* @param parent The parent Activity (if any)* @param id The embedded Id (if any)* @param lastNonConfigurationInstance Arbitrary object that will be* available via {@link Activity#getLastNonConfigurationInstance()* Activity.getLastNonConfigurationInstance()}.* @return Returns the instantiated activity* @throws InstantiationException* @throws IllegalAccessException*/public Activity newActivity(Class<?> clazz, Context context, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id,Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException {Activity activity = (Activity)clazz.newInstance();ActivityThread aThread = null;activity.attach(context, aThread, this, token, 0 /* ident */, application, intent,info, title, parent, id,(Activity.NonConfigurationInstances)lastNonConfigurationInstance,new Configuration(), null /* referrer */, null /* voiceInteractor */,null /* window */, null /* activityConfigCallback */);return activity;}}參考路徑 : frameworks/base/core/java/android/app/Instrumentation.java
七、 LoadedApk 涉及源碼
LoadedApk 中相關源碼 :
public final class LoadedApk {public Application makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation) {// ★ 如果之前創建過 Application , 就直接使用 if (mApplication != null) {return mApplication;}Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");Application app = null;String appClass = mApplicationInfo.className;if (forceDefaultAppClass || (appClass == null)) {appClass = "android.app.Application";}try {java.lang.ClassLoader cl = getClassLoader();if (!mPackageName.equals("android")) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"initializeJavaContextClassLoader");initializeJavaContextClassLoader();Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);appContext.setOuterContext(app);} catch (Exception e) {if (!mActivityThread.mInstrumentation.onException(app, e)) {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);throw new RuntimeException("Unable to instantiate application " + appClass+ ": " + e.toString(), e);}}mActivityThread.mAllApplications.add(app);mApplication = app;if (instrumentation != null) {try {instrumentation.callApplicationOnCreate(app);} catch (Exception e) {if (!instrumentation.onException(app, e)) {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);throw new RuntimeException("Unable to create application " + app.getClass().getName()+ ": " + e.toString(), e);}}}// Rewrite the R 'constants' for all library apks.SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers();final int N = packageIdentifiers.size();for (int i = 0; i < N; i++) {final int id = packageIdentifiers.keyAt(i);if (id == 0x01 || id == 0x7f) {continue;}rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);}Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);return app;}}參考路徑 : frameworks/base/core/java/android/app/LoadedApk.java
總結
以上是生活随笔為你收集整理的【Android 安全】DEX 加密 ( Application 替换 | 分析 Activity 组件中获取的 Application | ActivityThread | LoadedApk )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 安全】DEX 加密 (
- 下一篇: 【Android 安全】DEX 加密 (