dex保护总结

dex保护总结

android程序启动过程

http://blog.csdn.net/qianhaifeng2012/article/details/52039053
1.Launcher.startActivitySafely

点击图标,Launcher的onClick方法相应,然后根据传入参数View v的v.getTag()方法得到被点击应用图标的ShortcutInfo,然后得到Intent数据。通过final Intent intent = ((ShortcutInfo) tag).intent。语句得到数据。有了一个应用的Intent就可以启动一个应用了。

Launcher.startActivitySafely-> startActivity

2.Activity.startActivity

Activity是Launcher父类

Activity.startActivity->Activity.startActivityForResult

3.Activity.startActivityForResult

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Instrumentation.ActivityResult ar =  
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
```

这里的mInstrumentation是Activity类的成员变量,它的类型是Intrumentation,定义在Instrumentation.java文件中,它用来监控应用程序和系统的交互。
这里的mMainThread也是Activity类的成员变量,它的类型是ActivityThread,它代表的是应用程序的主线程。这里通过mMainThread.getApplicationThread获得它里面的ApplicationThread成员变量,它是一个Binder对象,ActivityManagerService会使用它来和ActivityThread来进行进程间通信。
**这里的mMainThread代表的是Launcher应用程序运行的进程。**


Instrumentation.execStartActivity
->(**ActivityManagerService**)ActivityManagerNative.getDefault()
->ActivityManagerProxy.startActivity

ActivityManagerProxy是一个代理类,通过IPC的Binder联系到ActivityManagerService,最后会调用ActivityManagerService的startActivity方法。

4.ActivityManagerService.startActivity

startActivity->startActivityAsUser->mStackSupervisor.startActivityMayWait

(ActivityStackSupervisor)mStackSupervisor

5.ActivityStackSupervisor.startActivityMayWait

涉及两个函数:

ActivityInfo aInfo =
resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);

...

int res = startActivityLocked(caller, intent, resolvedType, aInfo,
voiceSession, voiceInteractor, resultTo, resultWho,
requestCode, callingPid, callingUid, callingPackage,
realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
componentSpecified, null, container, inTask);

1
2
3
4

其中的resolveActivity方法主要是获得对参数intent的内容进行解析,得到MainActivity的相关信息,保存在aInfo变量中.

6.ActivityStackSupervisor.startActivityLocked

final int startActivityLocked(IApplicationThread caller,
Intent intent, String resolvedType, ActivityInfo aInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode,
int callingPid, int callingUid, String callingPackage,
int realCallingPid, int realCallingUid, int startFlags, Bundle options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
ActivityContainer container, TaskRecord inTask)

1
2
3
4

从传进来的参数caller得到调用者的进程信息,并保存在callerApp变量中,这里就是Launcher应用程序的进程信息了。 前面说过,参数resultTo是Launcher这个Activity里面的一个Binder对象,通过它可以获得Launcher这个Activity的相关信息,保存在sourceRecord变量中。

记录启动的Activity的相关信息:

ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
requestCode, componentSpecified, voiceSession != null, this, container, options);

1
2


err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, true, options, inTask);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
7.ActivityStackSupervisor.startActivityUncheckedLocked

这个方法主要用于创建Acitivity栈,根据Activity的启动模式,由于是点击图标进来的,一开始也设置了标志位Intent.FLAG_ACTIVITY_NEW_TASK,所以会新创建一个Activity栈。如果之前已经有栈,且不是singleinstance,就不会再创建新的栈,会将待启动的Activity添加到原来的栈中。

startActivityUncheckedLocked->ActivityStack.resumeTopActivitiesLocked


8.ActivityStack.resumeTopActivitiesLocked

resumeTopActivitiesLocked
->resumeTopActivityInnerLocked
->ActivityStackSupervisor.startSpecificActivityLocked

9.ActivityStackSupervisor.startSpecificActivityLocked

```java
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);

r.task.stack.setLaunchTime(r);

if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}

// If a dead object exception was thrown -- fall through to
// restart the application.
}

mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}

当第一次启动应用程序的Activity,取回来的app为null。在Activity应用程序中的AndroidManifest.xml配置文件中,我们没有指定Application标签的process属性,系统就会默认使用package的名称。每一个应用程序都有自己的uid,因此,这里uid + process的组合就可以为每一个应用程序创建一个ProcessRecord。

所以下面if (app != null && app.thread != null)条件不成立,那么条件里面realStartActivityLocked 方法就不会执行,而是执行ActivityManagerService.startProcessLocked函数进行下一步操作。

10.ActivityManagerService.startProcessLocked

app=null
|
V
app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
|
V
addProcessNameLocked
|
V
mProcessNames.put(proc.processName, proc.uid, proc);
有了进程信息之后
ActivityManagerService.startProcessLocked
|
V
Process.start

调用Process.start接口来创建一个新的进程,新的进程会导入android.app.ActivityThread类,并且执行它的main函数

1
2
3
4
5
entryPoint = "android.app.ActivityThread"  
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);

11.Process.start

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static final ProcessStartResult start(final String processClass,  
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}

startViaZygote会通过zygote机制开启一个新的进程。由于我们导入的类名是android.app.ActivityThread,开启一个ActivityThread进程,这也是为什么一个应用程序只有一个ActivityThread,然后会执行他的main方法。

12.ActivityThread.main

其中调用了

1
2
ActivityThread thread = new ActivityThread();  
thread.attach(false);
1
2
3
4
5
6
7
8
9
10
11
private void attach(boolean system) {  
.........
final IActivityManager mgr = ActivityManagerNative.getDefault();

try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {

}
..................
}

然后会执行mgr.attachApplication方法,mgr = ActivityManagerNative.getDefault(),通过前面分析它是ActivityManagerService的代理对象ActivityManagerProxy对象。所以最终会转向ActivityManagerService的attachApplication方法。

其中mAppThread是ApplicationThread,是一个Binder对象,用于ActivityManagerService与ActivityThread通信。

13.ActivityManagerService.attachApplication

attachApplication->attachApplicationLocked

1
2
3
4
5
6
7
8
9
10
ProcessRecord app;  
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
....

try {
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}

通过pid获取之前由Process.start创建的进程的信息记录,再由mStackSupervisor.attachApplicationLocked(app)执行

attachApplicationLocked:

1
2
3
4
try {  
if (realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}

调用mMainStack.realStartActivityLocked执行真正的Activity启动操作。这里要启动的Activity通过调用mMainStack.topRunningActivityLocked(null)从堆栈顶端取回来,这时候在堆栈顶端的Activity就是MainActivity了。

14.ActivityManagerService.realStartActivityLocked

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
final boolean realStartActivityLocked(ActivityRecord r,  
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {


.....................
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

..........................

return true;
}

app.thread是ApplicationThreadProxy对象,是一个代理对象,代理就是ApplicationThread,情况完全类似于ActivityManagerProxy代理类。所以逻辑转向了ApplicationThread的scheduleLaunchActivity方法。

15.ApplicationThread.scheduleLaunchActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,  
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

updateProcessState(procState, false);

ActivityClientRecord r = new ActivityClientRecord();

r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;

r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;

r.startsNotResumed = notResumed;
r.isForward = isForward;

r.profilerInfo = profilerInfo;

r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);

sendMessage(H.LAUNCH_ACTIVITY, r);
}

函数首先创建一个ActivityClientRecord实例,并且初始化它的成员变量,然后发送一个启动Activity的消息交给Handler处理.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...................................


}

16.ActivityThread.handleLaunchActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {    
......

Activity a = performLaunchActivity(r, customIntent);

if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward);

......
} else {
......
}
}

从上面的源码可以看出,performLaunchActivity最终完成了Activity对象的创建和启动过程,并且Activity通过handleResumeActivity方法来调用被启动Activity的onResume这一生命周期方法。而onCreate这个这个生命周期方法在performLaunchActivity方法中被回调。

17.ActivityThread.performLaunchActivity

这个方法主要完成了如下几件事

1)从ActivityClientRecord中获取待启动的Activity的组件信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}

2)通过Instrumenttation的newActivity方法使用类加载器创建Activity对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Activity activity = null;  
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
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);
}
}

3)通过LoadeApk的makeApplication方法来尝试创建Application对象

Application app = r.packageInfo.makeApplication(false, mInstrumentation);

makeApplication方法代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public Application makeApplication(boolean forceDefaultAppClass,  
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}

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")) {
initializeJavaContextClassLoader();
}
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)) {
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)) {
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(mActivityThread)
.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);
}

return app;
}

从makeApplication方法可以看出,通过mActivityThread.mInstrumentation.newApplication创建Application对象,然后通过callApplicationOnCreate方法间接回调onCreate方法。

4)创建ContextImpl对象并通过Activity的attach方法来完成一些重要数据的初始化

1
2
3
4
5
6
7
8
9
Context appContext = createBaseContextForActivity(r, activity);  
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
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);

ContextImpl是一个很重要的数据结构,它是Context的具体实现,Context中的大部分逻辑都是由ContextImpl来完成的。ContextImpl是通过Activity的attach方法来和Activity建立链接的,处理之外,在attach方法中Activity还会完成Window的创建并建立自己和Window的关联,这样当Window接受到外部输入事件后就可以将时间传递给Activity。

5)调用Activity的onCreate

mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);

最后回调Activity的onCreate方法。这也意味着应用已经启动起来了。

###总结

  Launcher会响应图标点击,开始开启Activity,应用图标的shortcutinfo的intent获得应用信息,通知ActivityManagerServer来启动Activity,首先需要获取Activity的信息,并存放Activity信息,为启动作准备(对应ActivityRecord和Activity栈)。信息有了之后就要为应用准备一个进程,zygotefork出一个进程后,执行ActivityThread的main方法,在该方法里会先准备好Looper和消息队列,再调用attach将这个进程绑定到ActivityManagerServer,之后就要准备启动Activity了,ActivityManagerServer这时候会保存一个应用进程的代理对象,这样ActivityManagerServer就可以对Activity进行管理了,ActivityManagerServer获取Activity栈中的Activity信息,来通知应用进程创建入口Activity的实例。

动态加载类

类加载器:
http://blog.csdn.net/jiangwei0910410003/article/details/41384667

ClassLoader:

代码动态加载:

  1. 接管系统加载,比源程序优先获取执行权利
  2. 利用ClassLoader进行源代码加载
  3. 还原程序执行环境
  4. 将执行权利移交给源程序

绑定Application

1
2
3
4
5
6
7
8
9
10
11
12
 at java.lang.Thread.dumpStack(Thread.java:505)
06-21 17:42:18.448 8620-8620/cn.terminal.egame.myphone W/System.err: at cn.terminal.egame.myphone.MyApplication.onCreate(MyApplication.java:13)
06-21 17:42:18.448 8620-8620/cn.terminal.egame.myphone W/System.err: at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1015)
06-21 17:42:18.448 8620-8620/cn.terminal.egame.myphone W/System.err: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4793)
06-21 17:42:18.449 8620-8620/cn.terminal.egame.myphone W/System.err: at android.app.ActivityThread.access$1600(ActivityThread.java:165)
06-21 17:42:18.449 8620-8620/cn.terminal.egame.myphone W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1437)
06-21 17:42:18.449 8620-8620/cn.terminal.egame.myphone W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102)
06-21 17:42:18.449 8620-8620/cn.terminal.egame.myphone W/System.err: at android.os.Looper.loop(Looper.java:150)
06-21 17:42:18.449 8620-8620/cn.terminal.egame.myphone W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5621)
06-21 17:42:18.449 8620-8620/cn.terminal.egame.myphone W/System.err: at java.lang.reflect.Method.invoke(Native Method)
06-21 17:42:18.449 8620-8620/cn.terminal.egame.myphone W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794)
06-21 17:42:18.449 8620-8620/cn.terminal.egame.myphone W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684)

  在ActivityThread的main方法中会执行ActivityThread对象的attach方法,回调了ActivityManagerService的远程接口本地代理对象ActivityManagerProxy的attachApplication函数通知attachApplication,并传入参数是mAppThread,这是ApplicationThread类型的Binder对象,用来接受ActivityManagerService的进程间消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public final class ActivityThread {

......

public static void main(String[] args) {
.....
ActivityThread thread = new ActivityThread();
thread.attach(false);
.....

}

private void attach(boolean system)
.......
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}

....
}
}

  ActivityManagerService在接受到attachApplication函数调用远程消息之后,一系列处理之后,会有两个重要Binder通信,一个就是通过传来的参数Binder参数ApplicationThread来通知ActivityThread中mAppThread远程中调用bindApplication(),另一个是scheduleLaunchActivity。在Ams中收到attachApplication时代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
AMS
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
//获取applicationThread的进程id(也就是淘宝应用进程)
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}


private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {

// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
} else {
app = null;
}

//因为进程由AMS启动,所以在AMS中一定会有ProcessRecord(进程记录)
//如果没有ProcessRecord,则需要杀死该进程并退出
if (app == null) {
```
    return false;
}

// If this application record is still attached to a previous
// process, clean it up now.
if (app.thread != null) {
    //如果从ProcessRecord中获取的IApplicationThread不为空,则需要处理该IApplicationThread
    //因为有可能此Pid为复用,旧应用进程刚释放,内部IApplicationThread尚未清空,
    //同时新进程又刚好使用了此Pid
    handleAppDiedLocked(app, true, true);
}


//创建死亡代理(进程kill后通知AMS)
AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);

//进程注册成功,移除超时通知
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

1
2
3
4
5
6
7
8
9
10
11
12
13
try {
//******绑定Application******
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());

updateLruProcessLocked(app, false, null);
} catch (Exception e) {
//bindApplication失败后,重启进程 startProcessLocked(app, "bind fail", processName); return false; } try { //******启动Activity(启动应用MainActivity)****** if (mStackSupervisor.attachApplicationLocked(app)) { didSomething = true;//didSomething表示是否有启动四大组件 } } catch (Exception e) { badApp = true; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    //绑定service和Broadcast的Application


if (badApp) {
//如果以上组件启动出错,则需要杀死进程并移除记录
app.kill("error during init", true);
handleAppDiedLocked(app, false, true);
return false;
}

//如果以上没有启动任何组件,那么didSomething为false
if (!didSomething) {
//调整进程的oom_adj值, oom_adj相当于一种优先级
//如果应用进程没有运行任何组件,那么当内存出现不足时,该进程是最先被系统“杀死”
updateOomAdjLocked();
}
return true;
}

从上午可以看到在attachApplicationLocked中有两个比较重要的方法函数:

1
2
thread.bindApplication(…) : 绑定Application到ActivityThread
mStackSupervisor.attachApplicationLocked(app) : 启动Activity(7.0前为mMainStack.realStartActivityLocked())

动态加载dex

外部类加载

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. Java反射允许我们修改Android中隐藏的类,以及其中的属性。
Android 基于Java开发,因此具有Java拥有的一切优势.因此允许在程序运行起来后动态地加载额外的代码.而这个代码加载器,称为ClassLoader。

时机

ActivityThread.main()
ActivityThread.attach()
ActivityManagerSevice.attachApplication->attachApplicationLocked
ActivityThread.BindApplication– BIND_APPLICATION消息–>handlBindApplication(内有等待java调试器挂接)
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
LoadedApk.java:
makeApplication->newApplication
Application.attach->Application.attachBaseContext
Instrumentation.callApplicationOnCreate(app);
callApplicationOnCreate->Application.onCreate()

Activity类 、Service类 、Application类本质上都是Context子类
创建Application 对象时(而且整个App共一个Application对象),创建Service对象时,创建Activity对象时,都会创建Context实例。
选择attachBaseContext作为修改加载Activity的入口再合适不过了。

实现步骤:

  1. 新建工程,完成主要代码,build之后提取dex文件(注意mulitDexEnable设置为false)
  2. 反编译dex,删除不需要的类,对应于smali文件
  3. 回编译dex,将dex放回工程目录(可对其加密处理)
  4. 工程中新建入口(即重载attachBaseContext),注意配置文件中启动Activity依然是原类名,添加启动Application类名

代码自修改

在源代码中写入虚假代码,载入内存后,利用先执行的native代码修改字节码实现逻辑代码修改。
在native代码中先获取到当前进程的内存信息(利用/proc/[pid]/maps) ,查找到dex段,搜索”dex\n035”magic值判断dex开头,利用dex文件格式获取对应方法地址,实现内存修改。

函数动态还原

利用外部类加载+native hook实现(对应于java层和native层的类加载部分):

  1. 抽取dex中需要加密的函数字节码,保存为文件,清空偏移
  2. 将提取字节码文件和dex文件移入工程,用以上方式加载
  3. 在native代码中,利用dexlib解析dex
  4. 利用hook框架实现对libdvm.so的dvmDefineClass
  5. 实现还原对应方法的字节码

dex文件格式

结构图:
a-c

字符串池索引过程:
header.string_ids_off -> string_id_list[0].string_data_off -> string_item[0]|(string_item_size+byte[size])

方法字节码索引过程:
AB135E84-4557-4F37-BE37-250B72DA71A4