一、安卓逆向工程
1、逆向工程:直接从成品推导出产品的设计原理。
2、逆向工程分类:
-
静态分析:不执行程序情况下对程序进行分析
-
动态分析:程序运行时对程序进行调试分析。Hook技术就属于动态分析。
二、Hook
1、被hook的对象被称为hook点
2、Hook点要稳定、不易变化(如静态变量、单例)
3、分类:根据不同的规定可以有不同的划分,这里主要讲java代码Hook 实现原理需要知识点:
- 代理设计模式
- 反射
- 多态的理解(查找方法时,优先查找子类对象方法,找不到时再去查找父类对象中的方法。这点与双亲委派思想正好相反)
三、Hook startActivity
1、Hook Activity的startActivity方法
思路:startActivity 最终调用的是Instrumentation对象的execStartActivity方法。activity中有Instrumentation 的成员变量。我们搞个代理类代理Instrumentation 的execStartActivity 即可。然后把activity的成员Instrumentation 替换代理对象。这样执行startActivity 时会优先查找代理类的execStartActivity 方法。
2、Hook Context 的startActivity方法
context的startActivity方法是通过ContextImpl来实现的,最终表现为调用ActivityThread类的成员变量 Instrumentation来实现。所以代理 Instrumentation对象即可。这里我们把hook点换成 ActivityThread。即可。
3、实践
/**
* Created by sunnyday on 2021/3/26 11:03
*/
public class InstrumentationProxy extends Instrumentation {
private static final String TAG = "InstrumentationProxy";
private static final String EXEC_START_ACTIVITY = "execStartActivity";
private Instrumentation mInstrumentation;
public InstrumentationProxy(Instrumentation mInstrumentation) {
this.mInstrumentation = mInstrumentation;
}
/**
* 代理 Instrumentation 的 execStartActivity方法。
*/
@SuppressLint("DiscouragedPrivateApi")
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
Log.i(TAG, "execStartActivity () HooK 成功:" + who);
try {
Method clazz = Instrumentation.class.getDeclaredMethod(
EXEC_START_ACTIVITY,
Context.class,
IBinder.class,
IBinder.class,
Activity.class,
Intent.class,
int.class,
Bundle.class);
return (ActivityResult) clazz.invoke(mInstrumentation, who, contextThread, token, target, intent, requestCode, options);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
/**
* 工具类,替换Activity成员变量mInstrumentation。
* 把Activity Instrumentation 类型成员变量替换为InstrumentationProxy代理类类型。
*
* @param activity 要操作的activity
*/
public static void replaceActivityInstrumentation(Activity activity) {
try {
Field field = Activity.class.getDeclaredField("mInstrumentation");
field.setAccessible(true);
Instrumentation instrumentation = (Instrumentation) field.get(activity);
Instrumentation instrumentationProxy = new InstrumentationProxy(instrumentation);
field.set(activity, instrumentationProxy);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 工具类,替换ActivityThread 类成员变量mInstrumentation。
* 把ActivityThread Instrumentation 类型成员变量替换为InstrumentationProxy代理类类型。
*/
@SuppressLint("PrivateApi")
public static void replaceContextInstrumentation() {
try {
// 获取ActivityThread的class对象
Class<?> activityThreadClazz = Class.forName("android.app.ActivityThread");
// 获取ActivityThread类的字段。sCurrentActivityThread(ActivityThread类型)
Field sCurrentActivityThreadField = activityThreadClazz.getDeclaredField("sCurrentActivityThread");
sCurrentActivityThreadField.setAccessible(true);
// 获取类的静态字段值
Object sCurrentActivityThread = sCurrentActivityThreadField.get(null);//ActivityThread 不对开发者开发,这里就使用Object吧。
// 获取activityThread 内的instrumentation字段
Field instrumentationField = activityThreadClazz.getDeclaredField("mInstrumentation");
instrumentationField.setAccessible(true);
Instrumentation instrumentation = (Instrumentation) instrumentationField.get(sCurrentActivityThread);
// 替换字段值
Instrumentation instrumentationProxy = new InstrumentationProxy(instrumentation);
instrumentationField.set(sCurrentActivityThread, instrumentationProxy);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 1、Hook Activity的Instrumentation
// InstrumentationProxy.replaceActivityInstrumentation(this);
// this.startActivity(new Intent(this,SecActivity.class));
//2、Hook Context的Instrumentation
//安主P以上会抛出异常 程序不会crash(Instrumentation: Uninitialized ActivityThread, likely app-created Instrumentation, disabling AppComponentFactory)
InstrumentationProxy.replaceContextInstrumentation();
getApplicationContext().startActivity(new Intent(this,SecActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));