本文基于Android系统源码8.0版本进行hook
抛出问题
- AMS是什么?
- 从启动Activity的角度看app如何和AMS交互
- hook点在哪里?
AMS是什么?
AMS是Android框架层用来管理四大组件的管家类并且负责进程的启动消亡和优先级的调度,是Android系统的核心服务。
从启动Activity的角度看app如何和AMS交互
我们知道activity的启动是从startActivity开始的,startActivity调用的是ComtextImpl.startActivity()
ContextImpl
final @NonNull ActivityThread mMainThread;
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
//下面ActivityThread & Instrumentation
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
ActivityThread
public Instrumentation getInstrumentation()
{
return mInstrumentation;
}
Instrumentation
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
...
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
通过以上了解到使用ActivityManager.getService()
的startActivity方法
android.app.ActivityManagerNative
static public IActivityManager getDefault() {
return ActivityManager.getService();
}
android.app.ActivityManager
/**
* @hide
*/
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
所以最后焦点就落到了IActivityManagerSingleton这个单例对象身上。因为它保存着和AMS交互的Binder代理对象IActivityManager。其中Binder代理对象保存到IActivityManagerSingleton
对象的mInstance
变量中。
android.util.Singleton
package android.util;
/**
* @hide
*/
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
hook点在哪里?
通过以上分析,我们就可以将hook点锁定到ActivityManager中mInstance变量上。因为它是与AMS交互在app进程中的Binder代理对象。
项目代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
hookAMS();
}
private void hookAMS() {
try {
Class activityManagerNativeClass = Class.forName("android.app.ActivityManager");
Field getDefault = activityManagerNativeClass.getDeclaredField("IActivityManagerSingleton");
getDefault.setAccessible(true);
Object IActivityManagerSingleton = getDefault.get(null);
Class<?> singleton = Class.forName("android.util.Singleton");
Field mInstanceField = singleton.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
Object rawIActivityManager = mInstanceField.get(IActivityManagerSingleton);//gDefault单例对象里面的mInstance值
//由于IActivityManager.class是隐藏interface所以使用Class.forName("");
Class IActivityManagerClass = Class.forName("android.app.IActivityManager");
Object hookOActivityManager = Proxy.newProxyInstance(IActivityManagerClass.getClassLoader(), new Class[]{IActivityManagerClass}, new HookHandler(rawIActivityManager));
mInstanceField.set(IActivityManagerSingleton,hookOActivityManager);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class HookHandler implements InvocationHandler {
private static final String TAG = "HookHandler";
private Object mBase;
public HookHandler(Object base) {
mBase = base;
}
/**
* @param proxy 代理本身(由于返回this并不是代理本身,所以需要传入proxy)
* @param method 使用代理执行方法的Method对象
* @param args 使用代理执行方法传入的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.d(TAG, "method:" + method.getName() + " called with args:" + Arrays.toString(args));
return method.invoke(mBase, args);
}
}
PMS的hook
ContextImpl.java
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
由于系统的执行肯定在我们代码之前,所以系统先生成了一个pm,这个是原生的pm然后保存在ApplicationPackageManager中,使得以后使用ContextImp.getPackageManager()都返回这个IPackageManager 对象。就算我们后来替换了ActivityThread.getPackageManager(),但是也不影响mPackageManager 里面之前包装好的。所以我们还需要改变mPackageManager 里面的原来的pm对象。
protected ApplicationPackageManager(ContextImpl context,IPackageManager pm) {
mContext = context;
mPM = pm;
}
变更ActivityThread
中的sPackageManager
引用,然后看代码
ActivityThread.java
PMS代理流程获取源码如下:
static volatile IPackageManager sPackageManager;
private void attach(boolean system) {
...
sCurrentActivityThread = this;
...
}
public static ActivityThread currentActivityThread() {
return sCurrentActivityThread;
}
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
sPackageManager = IPackageManager.Stub.asInterface(b);
return sPackageManager;
}
Hook PMS项目代码
private void hookPMS() {
try {
// 获取全局的ActivityThread对象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
Object currentActivityThread = currentActivityThreadMethod.invoke(null);//得到ActivityThread对象
// 获取ActivityThread里面原始的 sPackageManager
Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
sPackageManagerField.setAccessible(true);
Object sPackageManager = sPackageManagerField.get(currentActivityThread);
// 准备好代理对象, 用来替换原始的对象
Class<?> iPackageManagerInterface = Class.forName("android.content.pm.IPackageManager");
Object proxy = Proxy.newProxyInstance(iPackageManagerInterface.getClassLoader(),
new Class<?>[]{iPackageManagerInterface},
new HookHandler(sPackageManager));
// 1. 替换掉ActivityThread里面的 sPackageManager 字段
sPackageManagerField.set(currentActivityThread, proxy);
// 2. 替换 ApplicationPackageManager里面的 mPM对象
PackageManager pm = this.getPackageManager();
Field mPmField = pm.getClass().getDeclaredField("mPM");
mPmField.setAccessible(true);
mPmField.set(pm, proxy);
} catch (Exception e) {
e.printStackTrace();
}
}