public void applicationOnCreate(final Context baseContext) {
initPlugin(baseContext);
}
private void initPlugin(Context baseContext) {
long b = System.currentTimeMillis();
try {
try {
fixMiUiLbeSecurity();
} catch (Throwable e) {
Log.e(TAG, "fixMiUiLbeSecurity has error", e);
}
try {
PluginProcessManager.installHook(baseContext);
} catch (Throwable e) {
Log.e(TAG, "installHook has error", e);
}
try {
if (PluginProcessManager.isPluginProcess(baseContext)) {
PluginProcessManager.setHookEnable(true);
} else {
PluginProcessManager.setHookEnable(false);
}
} catch (Throwable e) {
Log.e(TAG, "setHookEnable has error", e);
}
try {
PluginManager.getInstance().addServiceConnection(PluginHelper.this);
PluginManager.getInstance().init(baseContext);
} catch (Throwable e) {
Log.e(TAG, "installHook has error", e);
}
} finally {
Log.i(TAG, "Init plugin in process cost %s ms", (System.currentTimeMillis() - b));
}
}
public static void installHook(Context hostContext) throws Throwable {
HookFactory.getInstance().installHook(hostContext, null);
}
public final void installHook(Context context, ClassLoader classLoader) throws Throwable {
installHook(new IClipboardBinderHook(context), classLoader);
//for ISearchManager
installHook(new ISearchManagerBinderHook(context), classLoader);
//for INotificationManager
installHook(new INotificationManagerBinderHook(context), classLoader);
installHook(new IMountServiceBinder(context), classLoader);
installHook(new IAudioServiceBinderHook(context), classLoader);
installHook(new IContentServiceBinderHook(context), classLoader);
installHook(new IWindowManagerBinderHook(context), classLoader);
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP_MR1) {
installHook(new IGraphicsStatsBinderHook(context), classLoader);
}
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
installHook(new IMediaRouterServiceBinderHook(context), classLoader);
}
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
installHook(new ISessionManagerBinderHook(context), classLoader);
}
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
installHook(new IWifiManagerBinderHook(context), classLoader);
}
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2) {
installHook(new IInputMethodManagerBinderHook(context), classLoader);
}
installHook(new IPackageManagerHook(context), classLoader);
installHook(new IActivityManagerHook(context), classLoader);//以此为案例,做分析
installHook(new PluginCallbackHook(context), classLoader);
installHook(new InstrumentationHook(context), classLoader);
installHook(new LibCoreHook(context), classLoader);
installHook(new SQLiteDatabaseHook(context), classLoader);
}
public void installHook(Hook hook, ClassLoader cl) {
try {
hook.onInstall(cl);
synchronized (mHookList) {
mHookList.add(hook);
}
} catch (Throwable throwable) {
Log.e(TAG, "installHook %s error", throwable, hook);
}
}
public abstract class Hook {
private boolean mEnable = false;
protected Context mHostContext;
protected BaseHookHandle mHookHandles;
public void setEnable(boolean enable, boolean reInstallHook) {
this.mEnable = enable;
}
public final void setEnable(boolean enable) {
setEnable(enable, false);
}
public boolean isEnable() {
return mEnable;
}
protected Hook(Context hostContext) {
mHostContext = hostContext;
mHookHandles = createHookHandle();
}
protected abstract BaseHookHandle createHookHandle();
protected abstract void onInstall(ClassLoader classLoader) throws Throwable;
protected void onUnInstall(ClassLoader classLoader) throws Throwable {
}
}
public abstract class ProxyHook extends Hook implements InvocationHandler {
protected Object mOldObj;
public ProxyHook(Context hostContext) {
super(hostContext);
}
public void setOldObj(Object oldObj) {
this.mOldObj = oldObj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (!isEnable()) {
return method.invoke(mOldObj, args);
}
HookedMethodHandler hookedMethodHandler = mHookHandles.getHookedMethodHandler(method);
if (hookedMethodHandler != null) {
return hookedMethodHandler.doHookInner(mOldObj, method, args);
}
return method.invoke(mOldObj, args);
} catch (InvocationTargetException e) {
Throwable cause = e.getTargetException();
if (cause != null && MyProxy.isMethodDeclaredThrowable(method, cause)) {
throw cause;
} else if (cause != null) {
RuntimeException runtimeException = !TextUtils.isEmpty(cause.getMessage()) ? new RuntimeException(cause.getMessage()) : new RuntimeException();
runtimeException.initCause(cause);
throw runtimeException;
} else {
RuntimeException runtimeException = !TextUtils.isEmpty(e.getMessage()) ? new RuntimeException(e.getMessage()) : new RuntimeException();
runtimeException.initCause(e);
throw runtimeException;
}
} catch (Throwable e) {
if (MyProxy.isMethodDeclaredThrowable(method, e)) {
throw e;
} else {
RuntimeException runtimeException = !TextUtils.isEmpty(e.getMessage()) ? new RuntimeException(e.getMessage()) : new RuntimeException();
runtimeException.initCause(e);
throw runtimeException;
}
}
}
}
public class HookedMethodHandler {
private static final String TAG = HookedMethodHandler.class.getSimpleName();
protected final Context mHostContext;
private Object mFakedResult = null;
private boolean mUseFakedResult = false;
public HookedMethodHandler(Context hostContext) {
this.mHostContext = hostContext;
}
public synchronized Object doHookInner(Object receiver, Method method, Object[] args) throws Throwable {
long b = System.currentTimeMillis();
try {
mUseFakedResult = false;
mFakedResult = null;
boolean suc = beforeInvoke(receiver, method, args);
Object invokeResult = null;
if (!suc) {
invokeResult = method.invoke(receiver, args);
}
afterInvoke(receiver, method, args, invokeResult);
if (mUseFakedResult) {
return mFakedResult;
} else {
return invokeResult;
}
} finally {
long time = System.currentTimeMillis() - b;
if (time > 5) {
Log.i(TAG, "doHookInner method(%s.%s) cost %s ms", method.getDeclaringClass().getName(), method.getName(), time);
}
}
}
public void setFakedResult(Object fakedResult) {
this.mFakedResult = fakedResult;
mUseFakedResult = true;
}
/**
* 在某个方法被调用之前执行,如果返回true,则不执行原始的方法,否则执行原始方法
*/
protected boolean beforeInvoke(Object receiver, Method method, Object[] args) throws Throwable {
return false;
}
protected void afterInvoke(Object receiver, Method method, Object[] args, Object invokeResult) throws Throwable {
}
public boolean isFakedResult() {
return mUseFakedResult;
}
public Object getFakedResult() {
return mFakedResult;
}
}
public class IActivityManagerHook extends ProxyHook {
private static final String TAG = IActivityManagerHook.class.getSimpleName();
public IActivityManagerHook(Context hostContext) {
super(hostContext);
}
@Override
public BaseHookHandle createHookHandle() {
return new IActivityManagerHookHandle(mHostContext);
}
@Override
public void onInstall(ClassLoader classLoader) throws Throwable {
//TODO ------解析来分析-------
}
}
@Override
public void onInstall(ClassLoader classLoader) throws Throwable {
Class cls = ActivityManagerNativeCompat.Class();
Object obj = FieldUtils.readStaticField(cls, "gDefault");
if (obj == null) {
ActivityManagerNativeCompat.getDefault();
obj = FieldUtils.readStaticField(cls, "gDefault");
}
if (IActivityManagerCompat.isIActivityManager(obj)) {
setOldObj(obj);
Class> objClass = mOldObj.getClass();
List<Class>> interfaces = Utils.getAllInterfaces(objClass);
Class[] ifs = interfaces != null && interfaces.size() > 0 ? interfaces.toArray(new Class[interfaces.size()]) : new Class[0];
Object proxiedActivityManager = MyProxy.newProxyInstance(objClass.getClassLoader(), ifs, this);
FieldUtils.writeStaticField(cls, "gDefault", proxiedActivityManager);
Log.i(TAG, "Install ActivityManager Hook 1 old=%s,new=%s", mOldObj, proxiedActivityManager);
} else if (SingletonCompat.isSingleton(obj)) {
Object obj1 = FieldUtils.readField(obj, "mInstance");
if (obj1 == null) {
SingletonCompat.get(obj);
obj1 = FieldUtils.readField(obj, "mInstance");
}
setOldObj(obj1);
List<Class>> interfaces = Utils.getAllInterfaces(mOldObj.getClass());
Class[] ifs = interfaces != null && interfaces.size() > 0 ? interfaces.toArray(new Class[interfaces.size()]) : new Class[0];
final Object object = MyProxy.newProxyInstance(mOldObj.getClass().getClassLoader(),ifs, IActivityManagerHook.this);
Object iam1 = ActivityManagerNativeCompat.getDefault();
//这里先写一次,防止后面找不到Singleton类导致的挂钩子失败的问题。
FieldUtils.writeField(obj, "mInstance", object);
//这里使用方式1,如果成功的话,会导致上面的写操作被覆盖。
FieldUtils.writeStaticField(cls, "gDefault", new android.util.Singleton<Object>() {
@Override
protected Object create() {
Log.e(TAG, "Install ActivityManager 3 Hook old=%s,new=%s", mOldObj, object);
return object;
}
});
Log.i(TAG, "Install ActivityManager Hook 2 old=%s,new=%s", mOldObj.toString(), object);
Object iam2 = ActivityManagerNativeCompat.getDefault();
// 方式2
if (iam1 == iam2) {
//这段代码是废的,没啥用,写这里只是不想改而已。
FieldUtils.writeField(obj, "mInstance", object);
}
} else {
throw new AndroidRuntimeException("Can not install IActivityManagerNative hook");
}
}
setOldObj(obj);
Class> objClass = mOldObj.getClass();
List<Class>> interfaces = Utils.getAllInterfaces(objClass);
Class[] ifs = interfaces != null && interfaces.size() > 0 ? interfaces.toArray(new Class[interfaces.size()]) : new Class[0];
Object proxiedActivityManager = MyProxy.newProxyInstance(objClass.getClassLoader(), ifs, this);
FieldUtils.writeStaticField(cls, "gDefault", proxiedActivityManager);
Log.i(TAG, "Install ActivityManager Hook 1 old=%s,new=%s", mOldObj, proxiedActivityManager);
public IActivityManagerHookHandle(Context hostContext) {
super(hostContext);
}
@Override
protected void init() {
sHookedMethodHandlers.put("startActivity", new startActivity(mHostContext));
sHookedMethodHandlers.put("startActivityAsUser", new startActivityAsUser(mHostContext));
sHookedMethodHandlers.put("startActivityAsCaller", new startActivityAsCaller(mHostContext));
sHookedMethodHandlers.put("startActivityAndWait", new startActivityAndWait(mHostContext));
sHookedMethodHandlers.put("startActivityWithConfig", new startActivityWithConfig(mHostContext));
sHookedMethodHandlers.put("startActivityIntentSender", new startActivityIntentSender(mHostContext));
sHookedMethodHandlers.put("startVoiceActivity", new startVoiceActivity(mHostContext));
sHookedMethodHandlers.put("startNextMatchingActivity", new startNextMatchingActivity(mHostContext));
sHookedMethodHandlers.put("startActivityFromRecents", new startActivityFromRecents(mHostContext));
sHookedMethodHandlers.put("finishActivity", new finishActivity(mHostContext));
sHookedMethodHandlers.put("registerReceiver", new registerReceiver(mHostContext));
sHookedMethodHandlers.put("broadcastIntent", new broadcastIntent(mHostContext));
sHookedMethodHandlers.put("unbroadcastIntent", new unbroadcastIntent(mHostContext));
sHookedMethodHandlers.put("getCallingPackage", new getCallingPackage(mHostContext));
sHookedMethodHandlers.put("getCallingActivity", new getCallingActivity(mHostContext));
sHookedMethodHandlers.put("getAppTasks", new getAppTasks(mHostContext));
sHookedMethodHandlers.put("addAppTask", new addAppTask(mHostContext));
sHookedMethodHandlers.put("getTasks", new getTasks(mHostContext));
sHookedMethodHandlers.put("getServices", new getServices(mHostContext));
sHookedMethodHandlers.put("getProcessesInErrorState", new getProcessesInErrorState(mHostContext));
sHookedMethodHandlers.put("getContentProvider", new getContentProvider(mHostContext));
sHookedMethodHandlers.put("getContentProviderExternal", new getContentProviderExternal(mHostContext));
sHookedMethodHandlers.put("removeContentProviderExternal", new removeContentProviderExternal(mHostContext));
sHookedMethodHandlers.put("publishContentProviders", new publishContentProviders(mHostContext));
sHookedMethodHandlers.put("getRunningServiceControlPanel", new getRunningServiceControlPanel(mHostContext));
sHookedMethodHandlers.put("startService", new startService(mHostContext));
sHookedMethodHandlers.put("stopService", new stopService(mHostContext));
sHookedMethodHandlers.put("stopServiceToken", new stopServiceToken(mHostContext));
sHookedMethodHandlers.put("setServiceForeground", new setServiceForeground(mHostContext));
sHookedMethodHandlers.put("bindService", new bindService(mHostContext));
sHookedMethodHandlers.put("publishService", new publishService(mHostContext));
sHookedMethodHandlers.put("unbindFinished", new unbindFinished(mHostContext));
sHookedMethodHandlers.put("peekService", new peekService(mHostContext));
sHookedMethodHandlers.put("bindBackupAgent", new bindBackupAgent(mHostContext));
sHookedMethodHandlers.put("backupAgentCreated", new backupAgentCreated(mHostContext));
sHookedMethodHandlers.put("unbindBackupAgent", new unbindBackupAgent(mHostContext));
sHookedMethodHandlers.put("killApplicationProcess", new killApplicationProcess(mHostContext));
sHookedMethodHandlers.put("startInstrumentation", new startInstrumentation(mHostContext));
sHookedMethodHandlers.put("getActivityClassForToken", new getActivityClassForToken(mHostContext));
sHookedMethodHandlers.put("getPackageForToken", new getPackageForToken(mHostContext));
sHookedMethodHandlers.put("getIntentSender", new getIntentSender(mHostContext));
sHookedMethodHandlers.put("clearApplicationUserData", new clearApplicationUserData(mHostContext));
sHookedMethodHandlers.put("handleIncomingUser", new handleIncomingUser(mHostContext));
sHookedMethodHandlers.put("grantUriPermission", new grantUriPermission(mHostContext));
sHookedMethodHandlers.put("getPersistedUriPermissions", new getPersistedUriPermissions(mHostContext));
sHookedMethodHandlers.put("killBackgroundProcesses", new killBackgroundProcesses(mHostContext));
sHookedMethodHandlers.put("forceStopPackage", new forceStopPackage(mHostContext));
sHookedMethodHandlers.put("getRunningAppProcesses", new getRunningAppProcesses(mHostContext));
sHookedMethodHandlers.put("getRunningExternalApplications", new getRunningExternalApplications(mHostContext));
sHookedMethodHandlers.put("getMyMemoryState", new getMyMemoryState(mHostContext));
sHookedMethodHandlers.put("crashApplication", new crashApplication(mHostContext));
sHookedMethodHandlers.put("grantUriPermissionFromOwner", new grantUriPermissionFromOwner(mHostContext));
sHookedMethodHandlers.put("checkGrantUriPermission", new checkGrantUriPermission(mHostContext));
sHookedMethodHandlers.put("startActivities", new startActivities(mHostContext));
sHookedMethodHandlers.put("getPackageScreenCompatMode", new getPackageScreenCompatMode(mHostContext));
sHookedMethodHandlers.put("setPackageScreenCompatMode", new setPackageScreenCompatMode(mHostContext));
sHookedMethodHandlers.put("getPackageAskScreenCompat", new getPackageAskScreenCompat(mHostContext));
sHookedMethodHandlers.put("setPackageAskScreenCompat", new setPackageAskScreenCompat(mHostContext));
sHookedMethodHandlers.put("navigateUpTo", new navigateUpTo(mHostContext));
sHookedMethodHandlers.put("serviceDoneExecuting", new serviceDoneExecuting(mHostContext));
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (!isEnable()) {
return method.invoke(mOldObj, args);
}
HookedMethodHandler hookedMethodHandler = mHookHandles.getHookedMethodHandler(method);
if (hookedMethodHandler != null) {
return hookedMethodHandler.doHookInner(mOldObj, method, args);
}
return method.invoke(mOldObj, args);
} catch (InvocationTargetException e) {
Throwable cause = e.getTargetException();
if (cause != null && MyProxy.isMethodDeclaredThrowable(method, cause)) {
throw cause;
} else if (cause != null) {
RuntimeException runtimeException = !TextUtils.isEmpty(cause.getMessage()) ? new RuntimeException(cause.getMessage()) : new RuntimeException();
runtimeException.initCause(cause);
throw runtimeException;
} else {
RuntimeException runtimeException = !TextUtils.isEmpty(e.getMessage()) ? new RuntimeException(e.getMessage()) : new RuntimeException();
runtimeException.initCause(e);
throw runtimeException;
}
} catch (Throwable e) {
if (MyProxy.isMethodDeclaredThrowable(method, e)) {
throw e;
} else {
RuntimeException runtimeException = !TextUtils.isEmpty(e.getMessage()) ? new RuntimeException(e.getMessage()) : new RuntimeException();
runtimeException.initCause(e);
throw runtimeException;
}
}
}
private static class startActivity extends HookedMethodHandler {
public startActivity(Context hostContext) {
super(hostContext);
}
protected void doReplaceIntentForStartActivityAPIHigh(Object[] args) throws RemoteException {
int intentOfArgIndex = findFirstIntentIndexInArgs(args);
if (args != null && args.length > 1 && intentOfArgIndex >= 0) {
Intent intent = (Intent) args[intentOfArgIndex];
//XXX String callingPackage = (String) args[1];
ActivityInfo activityInfo = resolveActivity(intent);
if (activityInfo != null && isPackagePlugin(activityInfo.packageName)) {
ComponentName component = selectProxyActivity(intent);
if (component != null) {
Intent newIntent = new Intent();
try {
ClassLoader pluginClassLoader = PluginProcessManager.getPluginClassLoader(component.getPackageName());
setIntentClassLoader(newIntent, pluginClassLoader);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
newIntent.setComponent(component);
newIntent.putExtra(Env.EXTRA_TARGET_INTENT, intent);
String callingPackage = (String) args[1];
if (TextUtils.equals(mHostContext.getPackageName(), callingPackage)) {
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
args[intentOfArgIndex] = newIntent;
args[1] = mHostContext.getPackageName();
} else {
Log.w(TAG, "startActivity,replace selectProxyActivity fail");
}
}
}
}
private void setIntentClassLoader(Intent intent, ClassLoader classLoader) {
try {
Bundle mExtras = (Bundle) FieldUtils.readField(intent, "mExtras");
if (mExtras != null) {
mExtras.setClassLoader(classLoader);
} else {
Bundle value = new Bundle();
value.setClassLoader(classLoader);
FieldUtils.writeField(intent, "mExtras", value);
}
} catch (Exception e) {
} finally {
intent.setExtrasClassLoader(classLoader);
}
}
protected void doReplaceIntentForStartActivityAPILow(Object[] args) throws RemoteException {
int intentOfArgIndex = findFirstIntentIndexInArgs(args);
if (args != null && args.length > 1 && intentOfArgIndex >= 0) {
Intent intent = (Intent) args[intentOfArgIndex];
ActivityInfo activityInfo = resolveActivity(intent);
if (activityInfo != null && isPackagePlugin(activityInfo.packageName)) {
ComponentName component = selectProxyActivity(intent);
if (component != null) {
Intent newIntent = new Intent();
newIntent.setComponent(component);
newIntent.putExtra(Env.EXTRA_TARGET_INTENT, intent);
if (TextUtils.equals(mHostContext.getPackageName(), activityInfo.packageName)) {
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
args[intentOfArgIndex] = newIntent;
} else {
Log.w(TAG, "startActivity,replace selectProxyActivity fail");
}
}
}
}
@Override
protected boolean beforeInvoke(Object receiver, Method method, Object[] args) throws Throwable {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
doReplaceIntentForStartActivityAPILow(args);
} else {
doReplaceIntentForStartActivityAPIHigh(args);
}
return super.beforeInvoke(receiver, method, args);
}
}
protected void doReplaceIntentForStartActivityAPILow(Object[] args) throws RemoteException {
int intentOfArgIndex = findFirstIntentIndexInArgs(args);
if (args != null && args.length > 1 && intentOfArgIndex >= 0) {
Intent intent = (Intent) args[intentOfArgIndex];
ActivityInfo activityInfo = resolveActivity(intent);
if (activityInfo != null && isPackagePlugin(activityInfo.packageName)) {
ComponentName component = selectProxyActivity(intent);
if (component != null) {
Intent newIntent = new Intent();
newIntent.setComponent(component);
newIntent.putExtra(Env.EXTRA_TARGET_INTENT, intent);
if (TextUtils.equals(mHostContext.getPackageName(), activityInfo.packageName)) {
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
args[intentOfArgIndex] = newIntent;
} else {
Log.w(TAG, "startActivity,replace selectProxyActivity fail");
}
}
}
}