您的位置:首页 > 移动开发 > Android开发

谈Android PowerManager的Hook技术

2017-03-29 11:20 701 查看
在插件中,需要禁止插件调用系统原生接口持有WakeLock,Hook技术是不错的解决方案。

通过阅读系统源码,可以了解到PowerManager持有WakeLock操作最后都通过Binder跨进程调到系统服务中,我们只要拦截这个Binder的所有调用即可。

思路是先通过反射拿到这个IPowerManager的Binder,然后动态生成该Binder的代理对象,再覆盖原有的Binder即可。

public class PowerManagerHook {

public static void hook(Context context) throws Throwable {
PowerManager manager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
Field field = FieldUtils.getField(PowerManager.class, "mService", true);

BinderHook hook = new BinderHook(field.get(manager), new BinderHook.BinderHookInvoker() {
@Override
public Object onInvoke(Object original, Method method, Object[] args) throws Throwable {
return method.invoke(original, args);
}
});

field.set(manager, hook.proxyInterface);
}
}


以下BinderHook是一个关于Binder Hook的通用类,可用于各类Android系统服务的Binder的Hook。

接下来介绍一下Binder Hook的核心原理,我们拿到Binder对象之后,首先要将其转成业务接口类,通常是通过Stub.asInterface,而Binder对象可能是Binder实体,也可能是Binder Proxy,然而不管怎样它们都是IBinder对象。Stub.asInterface的实现是先通过queryLocalInterface获取本地接口,如果返回非空,则表示当前进程和Binder实体是同一个进程,直接返回本地接口即可。如果返回为空,则表示当前进程和Binder实体分属不同进程,此时会将BinderProxy封装一层业务接口返回。所以可见这里的关键在于queryLocalInterface函数,这个函数属于IBinder的接口,所以我们拿到Binder对象之后,生成一个代理对象,拦截这个queryLocalInterface,返回我们生成的代理接口。

public class BinderHook {

public Class<?> binderIntfClazz;

public Object originalInterface;

public IBinder originalBinder;

public Object proxyInterface;

public IBinder proxyBinder;

public BinderHook(Object object, BinderHookInvoker invoker) {
this.originalInterface = object;
this.binderIntfClazz = BinderUtils.getBinderInterface(object);
this.originalBinder = getOriginalBinder();
this.proxyInterface = getProxyInterface(invoker);
this.proxyBinder = getProxyBinder();
}

private IBinder getOriginalBinder() {
Method method = MethodUtils.getAccessibleMethod(binderIntfClazz, "asBinder");
try {
return (IBinder) method.invoke(originalInterface);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}

private IBinder getProxyBinder() {
return (IBinder) Proxy.newProxyInstance(IBinder.class.getClassLoader(),
new Class<?>[]{IBinder.class}, new BinderHookHandler(originalBinder, "Binder") {
@Override
public Object onInvoke(Object original, Method method, Object[] args) throws Throwable {
if (method.getName().equals("queryLocalInterface")) {
return proxyInterface;
}
return method.invoke(original, args);
}
});
}

private Object getProxyInterface(final BinderHookInvoker invoker) {
return Proxy.newProxyInstance(originalInterface.getClass().getClassLoader(),
ClassUtils.getAllInterfaces(originalInterface.getClass()).toArray(new Class<?>[0]),
new BinderHookHandler(originalInterface, "Interface") {
@Override
public Object onInvoke(Object original, Method method, Object[] args) throws Throwable {
return invoker.onInvoke(original, method, args);
}
});
}

public interface BinderHookInvoker {
Object onInvoke(Object original, Method method, Object[] args) throws Throwable;
}

abstract static class BinderHookHandler implements InvocationHandler, BinderHookInvoker {

Object originalObject;

String tag;

public BinderHookHandler(Object originalObject, String tag) {
this.tag = tag;
this.originalObject = originalObject;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class == method.getDeclaringClass()) {
String name = method.getName();
if ("equals".equals(name)) {
return proxy == args[0];
} else if ("hashCode".equals(name)) {
return System.identityHashCode(proxy);
} else if ("toString".equals(name)) {
return proxy.getClass().getName() + "@" +
Integer.toHexString(System.identityHashCode(proxy));
} else {
throw new IllegalStateException(String.valueOf(method));
}
}
return onInvoke(originalObject, method, args);
}
}
}


源码 https://github.com/dingjikerbo/TechReports
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android Hook 插件