ClipboardManager Hook总结
来源:互联网 发布:oa源码 java 编辑:程序博客网 时间:2024/05/29 17:06
最近学习了如何Hook Android中的剪贴板服务,特此写下一篇博客记录。
首先说明下什么是Hook,Hook即通过使用代理对象替换系统原有对象,达到增强或修改系统类的功能的手段。一般我们替换的对象都会选择不易改变的静态对象。
下面首先介绍Android中获取系统服务的步骤,然后再介绍如何Hook 剪贴板服务ClipboardManager。
以下代码版本为Android 4.4
首先我们调用Context的getSystemService方法,由于Context的实际功能实现类为 ContextImpl,故我们追踪ContextImpl的代码:
@Override public Object getSystemService(String name) { ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); return fetcher == null ? null : fetcher.getService(this); }
ContextImpl去检查了一个系统服务的缓存HashMap SYSTEM_SERVICE_MAP,如下所示(以下仅截取关键代码):
private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String, ServiceFetcher>(); private static void registerService(String serviceName, ServiceFetcher fetcher) { if (!(fetcher instanceof StaticServiceFetcher)) { fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++; } SYSTEM_SERVICE_MAP.put(serviceName, fetcher); } static { registerService(ALARM_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(ALARM_SERVICE); IAlarmManager service = IAlarmManager.Stub.asInterface(b); return new AlarmManager(service, ctx); }}); registerService(CLIPBOARD_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new ClipboardManager(ctx.getOuterContext(), ctx.mMainThread.getHandler()); }}); }
ServiceFetcher是ContextImpl的一个内部类,当我们初次调用getService方法时,会调用createService返回结果
SYSTEM_SERVICE_MAP通过静态代码块初始化注册完毕,其中主要的createService返回方式有两种:- 返回xxxManager(我们这次实验的剪贴板就是这种形式),其中一般在内部会有接口的缓存,初次获取缓存的方式与下一种方法相同
- 调用ServiceManager的getService方法返回一个通信用的IBinder,通过IInterface(即IxxxManager)的内部类Stub的asInterface方法转换为可用的接口(可能是实体也是能是代理)
ClipboardManager的关键代码如下:
public class ClipboardManager extends android.text.ClipboardManager { private static IClipboard sService; static private IClipboard getService() { synchronized (sStaticLock) { if (sService != null) { return sService; } IBinder b = ServiceManager.getService("clipboard"); sService = IClipboard.Stub.asInterface(b); return sService; } }}
ClipboardManager实际服务的提供都会使用getService来调用。
先来看看ServiceManager的getService方法:
public final class ServiceManager { private static final String TAG = "ServiceManager"; private static IServiceManager sServiceManager; private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>(); public static IBinder getService(String name) { try { IBinder service = sCache.get(name); if (service != null) { return service; } else { return getIServiceManager().getService(name); } } catch (RemoteException e) { Log.e(TAG, "error in getService", e); } return null; }}
该方法首先回去检查sCache的缓存service,如果没有则会调用IServiceManager去获取真正的Service服务。
接下来asInterface的关键代码如下(IClipboard.Stub类,实际就是AIDL自动生成的类文件):
/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements android.content.IClipboard {private static final java.lang.String DESCRIPTOR = "android.content.IClipboard";/** Construct the stub at attach it to the interface. */public Stub() {this.attachInterface(this, DESCRIPTOR);}/** * Cast an IBinder object into an android.content.IClipboard interface, * generating a proxy if needed. */public static android.content.IClipboard asInterface(android.os.IBinder obj) {if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof android.content.IClipboard))) {return ((android.content.IClipboard)iin);}return new android.content.IClipboard.Stub.Proxy(obj);}}
在asInterface方法中,首先调用了IBinder对象的queryLocalInterface方法来查找是否本地含有此接口(如果是同一进程就含有),如果不是则返回代理对象。
总的来说,Android获取系统服务步骤如下图所示:
其中我们可以进行Hook的点,主要是红色的两个部分:
- Hook xxxManager中的sService服务缓存
- 利用sCache缓存表Hook SystemService中getService返回的IBinder对象
/** * hook 方法1 * * @throws Exception */ public static void hook1() throws Exception { // 加载ClipboardManager类 Class<?> clipboardManagerClazz = Class .forName("android.content.ClipboardManager"); // 通过getService static方法获取真实IClipboard对象 Method getServiceMethod = clipboardManagerClazz .getDeclaredMethod("getService"); getServiceMethod.setAccessible(true); // 真实IClipboard对象 Object clipboardManager = getServiceMethod.invoke(null); // 获取sService的IClipboard缓存 Field sServiceFeild = clipboardManagerClazz .getDeclaredField("sService"); sServiceFeild.setAccessible(true); // 替换sService sServiceFeild.set(null, Proxy .newProxyInstance(clipboardManager.getClass().getClassLoader(), clipboardManager.getClass().getInterfaces(), new ClipboardManagerProxyHandler( clipboardManager))); }
Java动态代理的InvocationHandler接口如下:
/** * Created by superxlcr on 2016/9/20. * 剪贴板代理处理类 */public class ClipboardManagerProxyHandler implements InvocationHandler { // 真正的clipboardManager private Object clipboardManager; public ClipboardManagerProxyHandler(Object clipboardManager) { this.clipboardManager = clipboardManager; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { switch (method.getName()) { case "getPrimaryClip": // 粘贴内容 return ClipData.newPlainText(null, "you are hook!"); case "hasPrimaryClip": // 剪贴板永远有粘贴内容 return true; } // 其余情况由真实对象处理 return method.invoke(clipboardManager, args); }}
在这里我们替换掉了,判断剪贴板是否有内容的hasPrimaryClip方法与返回剪贴内容的getPrimaryClip方法,使剪贴板粘贴总是返回you are hook
方法二代码如下所示:
/** * hook方法2 * * @throws Exception */ public static void hook2() throws Exception { // 加载ServiceManager类 Class<?> serviceManagerClazz = Class .forName("android.os.ServiceManager"); // 获取getService方法 Method getServiceMethod = serviceManagerClazz .getMethod("getService", String.class); // 获取真正的clipboardManager对象 IBinder clipboardManagerIBinder = (IBinder) getServiceMethod .invoke(null, CLIPBOARD); // 获取sCache HashMap缓存 Field sCacheField = serviceManagerClazz.getDeclaredField("sCache"); // private变量 sCacheField.setAccessible(true); // static变量 HashMap<String, IBinder> sCache = (HashMap) sCacheField.get(null); // 把代理放入缓存 sCache.put(CLIPBOARD, (IBinder) Proxy.newProxyInstance( clipboardManagerIBinder.getClass().getClassLoader(), clipboardManagerIBinder.getClass().getInterfaces(), new ClipboardManagerIBinderProxyHandler( clipboardManagerIBinder))); }
其中对IBinder的动态代理如下:
/** * Created by superxlcr on 2016/9/21. * 剪贴板通信代理处理类 */public class ClipboardManagerIBinderProxyHandler implements InvocationHandler { // 真正的clipboardManagerIBinder private IBinder clipboardManagerIBinder; public ClipboardManagerIBinderProxyHandler( IBinder clipboardManagerIBinder) { this.clipboardManagerIBinder = clipboardManagerIBinder; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("queryLocalInterface")) { // 返回伪造代理对象 // 加载IClipboard内部类Stub Class<?> IClipboardStubClazz = Class .forName("android.content.IClipboard$Stub"); // 获取asInterface方法 Method asInterfaceMethod = IClipboardStubClazz .getMethod("asInterface", IBinder.class); // 通过asInterface static方法,得到真正IClipboard对象 Object clipboardManager = asInterfaceMethod .invoke(null, clipboardManagerIBinder); return Proxy.newProxyInstance( clipboardManager.getClass().getClassLoader(), clipboardManager.getClass().getInterfaces(), new ClipboardManagerProxyHandler(clipboardManager)); } return method.invoke(clipboardManagerIBinder, args); }}
这里我们修改了queryLocalInterface方法,使其返回我们代理的IClipboard接口对象,其余部分与方法一相同。
最后附上该工程的地址,有兴趣的同学可以下载看看:https://github.com/superxlcr/ClipboardManagerHook
0 0
- ClipboardManager Hook总结
- ClipboardManager
- Hook学习总结
- HOOK基础知识总结
- wordpress hook总结
- hook IE 总结
- API Hook总结之一
- Android xposed hook使用总结
- API Hook总结之二
- API Hook总结之三
- API Hook总结之四
- API Hook总结之五
- Android 开发之 ClipboardManager
- Android 开发之 ClipboardManager
- Android开发之ClipboardManager
- android ClipboardManager(剪贴板管理器)
- Android开发之ClipboardManager
- android开发之ClipboardManager
- JAVA基础 day11 多线程 同步代码块 死锁问题
- css优化、提高性能的方法
- CSS外边距叠加的问题
- Android系统篇之—-Binder机制和远程服务调用机制分析
- ie9下checkbox无法二次全选
- ClipboardManager Hook总结
- windows + caffe + 配置python接口
- js常用方法
- ios基础--内存案例
- Linux常用命令行
- java中的break、continue、return区别
- IPC进程之间通信的几种方式
- 一个迷你音频播放器项目
- Hadoop安装教程_单机/伪分布式配置_CentOS6.4/Hadoop2.6.0(转)