方案:使用动态代理,替换 PackageManager 里的签名信息
替换掉ActivityThread里面的 sPackageManager 字段
替换 ApplicationPackageManager里面的 mPM对象
获取PackageManager相关代码:
public static void hookPMS(Context context, String packageName, String sign) {
try {
SignatureFake.setSign(sign);
// 获取全局的ActivityThread对象
Object currentActivityThread = Reflect.onClass("android.app.ActivityThread")
.call("currentActivityThread").get();
Object sPackageManager = Reflect.onClass("android.app.ActivityThread").field("sPackageManager").get();
Class<?> iPackageManagerInterface = Reflect.onClass("android.content.pm.IPackageManager").type();
Object proxy = Proxy.newProxyInstance(
iPackageManagerInterface.getClassLoader(),
new Class<?>[]{iPackageManagerInterface},
new PmsHookBinderInvocationHandler(sPackageManager, packageName, 0));
// 1. 替换掉ActivityThread里面的 sPackageManager 字段
Reflect.on(currentActivityThread).set("sPackageManager",proxy);
// 2. 替换 ApplicationPackageManager里面的 mPM对象
PackageManager pm = context.getPackageManager();
Reflect.on(pm).set("mPM", proxy);
} catch (Exception e) {
Log.d(TAG, "hook pms error:" + Log.getStackTraceString(e));
}
}
InvocationHandler 回调
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//查看是否是getPackageInfo方法
if("getPackageInfo".equals(method.getName())){
if(DEBUG)
{
Log.d(TAG,"hook method:" + method.getName());
}
String pkgName = (String)args[0];
Integer flag = (Integer)args[1];
if(DEBUG)
{
Log.d(TAG, "hook pkgName:" + pkgName + " appPkgName:" + appPkgName + ",flaf:" + flag);
}
//是否是获取我们需要hook apk的签名
if((flag & PackageManager.GET_SIGNATURES) == PackageManager.GET_SIGNATURES && appPkgName.compareToIgnoreCase(pkgName) == 0){
//将构造方法中传进来的新的签名覆盖掉原来的签名
PackageInfo info = (PackageInfo) method.invoke(base, args);
info.signatures = SignatureFake.getSignature(info.signatures);
return info;
}
}
return method.invoke(base, args);
}