- 检查 Application
- 在调用 attachBaseContext 之前检测签名
- 检查 IPackageManager 有没有被动态代理
- 使用别的 API 去获取
检查 Application
他替换掉了 Application 为他自己的,那么变化的太多了,Application 的类名 / 方法数 / 字段数 / AndroidManifast 中 Application 节点的 name,都会变。我们这里以检查 Application 的类名为例:
/**
-
校验 application
*/
private boolean checkApplication(){
Application nowApplication = getApplication();
String trueApplicationName = “MyApp”;
String nowApplicationName = nowApplication.getClass().getSimpleName();
return trueApplicationName.equals(nowApplicationName);
} -
先定义我们自己的 Application ——「MyApp」
-
然后通过 getApplication() 获取到 Application 实例
-
然后通过 getClass() 获取到类信息
-
然后通过 getSimpleName() 获取到类名
-
与正确的值比对然后返回
可以看到可以检测出被二次打包
在 attachBaseContext 之前检测
只要我们检测的够早,他就追不上我们。不,他会 hook 到我们的几率就越小
A: 要有多早?
B: emm,就在 Application 的构造方法里检测吧
A: 那,,,没 context 呀
B: 那就自己造一个 context!
A: 你放屁!
B: 走你
通过学习 Application 的创建流程可知,Context 是通过 LoadedApk 调用 createAppContext 方法实现的
// LoadedApk.java
package android.app;
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
函数原型为
// ContextImpl.java
package android.app;
@UnsupportedAppUsage
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
return createAppContext(mainThread, packageInfo, null);
}
第一个参数好说,因为这是个单例类,调用 currentActivityThread 即可获取 ActivityThread 对象
// ActivityThread.java
package android.app;
@UnsupportedAppUsage
private static volatile ActivityThread sCurrentActivityThread;
@UnsupportedAppUsage
public static ActivityThread currentActivityThread() {
return sCurrentActivityThread;
}
但是需要注意的是有 「@UnsupportedAppUsage」修饰,需要反射