Binder Hook技术实战(AudioService)
来源:互联网 发布:异人启示录 知乎 编辑:程序博客网 时间:2024/05/14 02:02
近期在工作中遇到了,需要按音量键跳转上一页或者下一页,但是有的Fragment页面包含视频播放功能,由于应用运行于手机锁屏状态,所以需要隐藏系统默认音量弹框的问题。最终虽然找到解决了音量框异常弹出的问题(由于VideoView设置viewController异常占用系统焦点,Activity无法正常接收到KeyEven按键事件,最终由系统AudioService响应引起),但是hook实现也记录下加深印象,仅供后来者参考。
源码如下:
Hook帮助类
/**
* Created by liuyutang on 16-12-28.
*/
public class HookHelper {
private static final String TAG = "HookHelper";
public static void initBinderHook(BinderHookHandler.IAdjustVolumeListener listener) {
try {
final String AUDIO_SERVICE = "audio";
final String MEDIA_SESSION_SERVICE = "media_session";
Class<?> serviceManager = Class.forName("android.os.ServiceManager");
Method getService = serviceManager.getDeclaredMethod("getService", String.class);
// ServiceManager里面管理的原始的AudioManager Binder对象
// 一般来说这是一个Binder代理对象
IBinder rawBinder = null;
if (android.os.Build.VERSION.SDK_INT >= 21) {
rawBinder = (IBinder) getService.invoke(null, MEDIA_SESSION_SERVICE);
} else if (android.os.Build.VERSION.SDK_INT >= 19) {
rawBinder = (IBinder) getService.invoke(null, AUDIO_SERVICE);
}
// Hook 掉这个Binder代理对象的 queryLocalInterface 方法
// 然后在 queryLocalInterface 返回一个IInterface对象, hook掉我们感兴趣的方法即可.
IBinder hookedBinder = (IBinder) Proxy.newProxyInstance(serviceManager.getClassLoader(),
new Class<?>[]{IBinder.class},
new BinderProxyHookHandler(rawBinder,listener));
// 把这个hook过的Binder代理对象放进ServiceManager的cache里面
// 以后查询的时候 会优先查询缓存里面的Binder, 这样就会使用被我们修改过的Binder了
Field cacheField = serviceManager.getDeclaredField("sCache");
cacheField.setAccessible(true);
Map<String, IBinder> cache = (Map) cacheField.get(null);
if (android.os.Build.VERSION.SDK_INT >= 21) {
cache.put(MEDIA_SESSION_SERVICE, hookedBinder);
} else if (android.os.Build.VERSION.SDK_INT >= 19) {
cache.put(AUDIO_SERVICE, hookedBinder);
}
} catch (Exception e) {
e.printStackTrace();
Log.d("LYT", "inithook=========error,msg=" + e.getStackTrace().toString());
}
}
}
Hook以后处理类:
/**
* Created by user on 16-12-27.
*/
public class BinderHookHandler implements InvocationHandler {
private static final String TAG = "BinderHookHandler";
// 原始的Service对象 (IInterface)
Object base;
IAdjustVolumeListener avlistener;
public BinderHookHandler(IBinder base, Class<?> stubClass, IAdjustVolumeListener listener) {
try {
Method asInterfaceMethod = stubClass.getDeclaredMethod("asInterface", IBinder.class);
this.base = asInterfaceMethod.invoke(null, base);
avlistener = listener;
} catch (Exception e) {
throw new RuntimeException("hooked failed!");
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.d(TAG, "hook method=" + method.getName());
if ("dispatchAdjustVolume".equals(method.getName())) {
if (null != avlistener) {
if (avlistener.isHookAble()) {
if (android.os.Build.VERSION.SDK_INT >= 21) {
if (args.length == 3) {
if (args[2] instanceof Integer) {
Integer tmp = (Integer) args[2];
args[2] = tmp | ~AudioManager.FLAG_SHOW_UI;
return base;
}
}
} else if (android.os.Build.VERSION.SDK_INT >= 19) {
if (args.length == 3) {
if (args[1] instanceof Integer) {
Integer tmp = (Integer) args[1];
args[1] = tmp | ~AudioManager.FLAG_SHOW_UI;
}
}
}
}
} else {
throw new Exception("avlistener is null");
}
}
return method.invoke(base, args);
}
/**
* 监听是否需要hook
*/
public interface IAdjustVolumeListener {
boolean isHookAble();
}
}
实现Service Hook的代理类源码:
/**
* Created by user on 16-12-27.
*/
public class BinderProxyHookHandler implements InvocationHandler {
private static final String TAG = "BinderProxyHookHandler";
// 绝大部分情况下,这是一个BinderProxy对象
// 只有当Service和我们在同一个进程的时候才是Binder本地对象
// 这个基本不可能
IBinder base;
Class<?> stub;
Class<?> iinterface;
BinderHookHandler.IAdjustVolumeListener avlistener;
public BinderProxyHookHandler(IBinder base,BinderHookHandler.IAdjustVolumeListener listener) {
this.base = base;
try {
if(android.os.Build.VERSION.SDK_INT >=21 ) {
this.stub = Class.forName("android.media.session.ISessionManager$Stub");
this.iinterface = Class.forName("android.media.session.ISessionManager");
}else if(android.os.Build.VERSION.SDK_INT >= 19){
this.stub = Class.forName("android.media.session.IAudioService$Stub");
this.iinterface = Class.forName("android.media.session.IAudioService");
}
avlistener = listener;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("queryLocalInterface".equals(method.getName())) {
Log.d(TAG, "hook queryLocalInterface");
// 这里直接返回真正被Hook掉的Service接口
// 这里的 queryLocalInterface 就不是原本的意思了
// 我们肯定不会真的返回一个本地接口, 因为我们接管了 asInterface方法的作用
// 因此必须是一个完整的 asInterface 过的 IInterface对象, 既要处理本地对象,也要处理代理对象
// 这只是一个Hook点而已, 它原始的含义已经被我们重定义了; 因为我们会永远确保这个方法不返回null
// 让 IClipboard.Stub.asInterface 永远走到if语句的else分支里面
return Proxy.newProxyInstance(proxy.getClass().getClassLoader(),
// asInterface 的时候会检测是否是特定类型的接口然后进行强制转换
// 因此这里的动态代理生成的类型信息的类型必须是正确的
new Class[] { IBinder.class, IInterface.class, this.iinterface},
new BinderHookHandler(base, stub,avlistener));
}
return method.invoke(base, args);
}
}
在Activity的OnCreate()中如下调用即可:
HookHelper.initBinderHook(listener);
- Binder Hook技术实战(AudioService)
- AudioService
- Android实战技术:理解Binder机制
- Android实战技术:理解Binder机制
- [转]Android实战技术:理解Binder机制
- android插件化(Binder Hook)
- HOOK技术(钩子)
- Rootkit/Hook/Binder- Android
- Android 插件化原理解析(3):Hook 机制之 Binder Hook
- Android Hook机制之Binder Hook
- 钩子技术、HOOK技术应用(一)
- 钩子技术、HOOK技术应用(二)
- 钩子技术、HOOK技术应用(三)
- Hook技术
- Hook技术
- HOOK技术
- hook技术
- Hook 技术
- 337. House Robber III 难度:medium
- 【转载】网络流学习笔记
- Spring Boot学习笔记 - 整合Swagger2自动生成RESTful API文档
- Qt实现图片的简单压缩
- chrome content scripts 开发
- Binder Hook技术实战(AudioService)
- BigZhuGod的粉丝 1001
- leetcode-190 reverse bits 位运算
- android中Butterknife使用
- JZOJ 3809. 【NOIP2014模拟8.25】设备塔
- 乐观的并发策略——基于CAS的自旋
- Javascript Array和String的互转换
- 翻纸牌游戏
- 网络请求库比较总结