最近为了app隐私hook了pms,记录一下PMS的hook方法,程序员不多说,先贴代码
hook主类
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import com.xckj.utils.LogEx;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
/**
*
* @author worm
*/
@SuppressWarnings("MultipleStringLiterals")
public final class HookHelper {
private static final StringPACKAGE_FILED_NAME ="sPackageManager";
private static final StringPM_FILED_NAME ="mPM";
private static final StringPACKAGE_MANAGER_CLASS_NAME ="IPackageManager";
private static final StringAT_CLASS_NAME ="android.app.ActivityThread";
private static final StringAT_FILED_NAME ="sCurrentActivityThread";
/**
* hook PMS的getInstalledPackages方法
* 建议在application的初始化中调用
*
* @param context
* @param hookPackinfo getInstalledPackages中需要返回的内容
*/
public static void hookPackageManager(Context context, PackageInfo hookPackinfo) {
try {
// 获取全局的ActivityThread对象
Object currentActivityThread = RefInvoke.getStaticFieldObject(AT_CLASS_NAME, AT_FILED_NAME);
// 获取ActivityThread里面原始的 sPackageManager
Object packageManager = RefInvoke.getFieldObject(currentActivityThread, PACKAGE_FILED_NAME);
// 准备好代理对象, 用来替换原始的对象
Class packageManagerInterface = Class.forName(PACKAGE_MANAGER_CLASS_NAME);
Object proxy = Proxy.newProxyInstance(packageManagerInterface.getClassLoader(),
new Class[]{packageManagerInterface},
new HookHandler(packageManager, hookPackinfo));
// 替换掉ActivityThread里面的 sPackageManager 字段
setFieldObject(currentActivityThread.getClass(), currentActivityThread, PACKAGE_FILED_NAME, proxy);
// 替换 ApplicationPackageManager里面的 mPm对象
PackageManager pm = context.getPackageManager();
setFieldObject(pm.getClass(), pm, PM_FILED_NAME, proxy);
}catch (Exception e) {
LogEx.e("hook pms error " + e.getMessage());
}
}
/**
* hook PMS
* 建议在application的初始化中调用
*
* @param context
*/
public static void hookPackageManager(Context context) {
try {
// 获取全局的ActivityThread对象
Object currentActivityThread = RefInvoke.getStaticFieldObject(AT_CLASS_NAME, AT_FILED_NAME);
// 获取ActivityThread里面原始的 sPackageManager
Object packageManager = RefInvoke.getFieldObject(currentActivityThread, PACKAGE_FILED_NAME);
// 准备好代理对象, 用来替换原始的对象
Class packageManagerInterface = Class.forName(PACKAGE_MANAGER_CLASS_NAME);
Object proxy = Proxy.newProxyInstance(packageManagerInterface.getClassLoader(),
new Class[]{packageManagerInterface},
new HookHandler(packageManager));
// 替换掉ActivityThread里面的 sPackageManager 字段
setFieldObject(currentActivityThread.getClass(), currentActivityThread, PACKAGE_FILED_NAME, proxy);
// 替换 ApplicationPackageManager里面的 mPm对象
PackageManager pm = context.getPackageManager();
setFieldObject(pm.getClass(), pm, PM_FILED_NAME, proxy);
}catch (Exception e) {
LogEx.e("hook pms error " + e.getMessage());
}
}
public static void setFieldObject(Class clazz, Object obj, String filedName, Object filedVaule) {
try {
Field field = clazz.getDeclaredField(filedName);
field.setAccessible(true);
field.set(obj, filedVaule);
}catch (Exception e) {
e.printStackTrace();
}
}
}
HookHandler类
import android.content.pm.PackageInfo;
import com.xckj.utils.LogEx;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
*
*/
class HookHandlerimplements InvocationHandler {
private ObjectmBase;
private PackageInfomPackageInfo;
/**
* 针对PMS的hook初始化函数
*
* @param base
* @param packageInfo
*/
HookHandler(Object base, PackageInfo packageInfo) {
mBase = base;
mPackageInfo = packageInfo;
}
HookHandler(Object base) {
mBase = base;
}
@Override
public Objectinvoke(Object proxy, Method method, Object[] args)throws Throwable {
LogEx.d("hook pms");
LogEx.d("method:" + method.getName() +" called with args:" + Arrays.toString(args));
if (method.getName().equals("getInstalledPackages")) {
return handlerPMS();
}
return method.invoke(mBase, args);
}
private ObjecthandlerPMS() {
if (mPackageInfo ==null) {
return null;
}
List packageList =new ArrayList<>();
packageList.add(mPackageInfo);
return packageList;
}
}