还原Android被inline Hook的服务对象
本帖最后由 LivedForward 于 2020-2-7 13:23 编辑本篇介绍如何还原Android被inlineHook的服务对象,以还原PMS为例。Android爆破签名校验原理是Hook了系统的PMS服务,那么我们如何还原被Hook的服务对象呢?下文介绍一种方案。
我们分析Android系统源码:
android.app.ActivityThread发现类里面有这样一个方法:
如果sPackageManager字段为空就会调用IPackageManager$Stub类的asInterface方法初始化IPackageManager对象,
那么Hook PMS就是将 sPackageManager 字段替换了,到这里我们就很容易得出一种还原PMS服务的方法:先将
sPackageManager 字段置空,然后反射调用getPackageManager方法,这样得到的IPM对象就是原始的服务对象,再
利用反射将PMS对象替换成原始的对象就好了
但是,我们这里不采用这种方式,因为跟进asInterface这个方法我们不难发现: 这里的queryLocalInterface方法也是一个Hook点。
那么new Stub.Proxy(binder);这条语句同样也是产生一个IPM对象,我们就从这里着手。
我们可以自己反射 IPackageManager$Stub$Proxy 这个类产生一个IPM对象,来替换
APP原始被Hook了的PMS服务对象。代码如下所示:
获取真实PMS服务对象之前: recoverPMS(this, getIPackageManager());
public static void recoverPMS(Context ct, Object ipm) {
try{
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod =
activityThreadClass.getDeclaredMethod("currentActivityThread");
Object currentActivityThread = currentActivityThreadMethod.invoke(null);
//1. 获取全局的ActivityThread对象
Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
sPackageManagerField.setAccessible(true);
/*通过置空系统IPM来迫使系统产生新的IPM对象,也是一种方法,但是这种方法也可以被HOOK.
IPackageManager$Stub.asInterface方法里存在Hook点,故不采用此方法.
sPackageManagerField.set(currentActivityThread, null);
//2. 将sPackageManager置空,让后面反射获取IPackageManager时系统再产生
//新的IPackageManager
Method getPackageManagerMethod = activityThreadClass.getDeclaredMethod("getPackageManager");
getPackageManagerMethod.setAccessible(true);
Object originalIPackageManager = getPackageManagerMethod.invoke(null);
//3. 获取到的新的IPackageManager,此IPackageManager没有被Hook */
sPackageManagerField.set(currentActivityThread, ipm);
//4. 替换掉ActivityThread里面的被Hook过的 sPackageManager 字段
PackageManager pm = ct.getPackageManager();
Field mPmField = pm.getClass().getDeclaredField("mPM");
mPmField.setAccessible(true);
mPmField.set(pm, ipm);
//5. 替换ApplicationPackageManager里面的被Hook过的mPM对象
}catch (Exception e){
Log.d("ysh", "recovery pms error:" + Log.getStackTraceString(e));
}
}
public static Object getIPackageManager(){
try{
Class<?> serviceManagerClass = Class.forName("android.os.ServiceManager");
Method getServiceMethod =serviceManagerClass.getDeclaredMethod("getService", String.class);
getServiceMethod.setAccessible(true);
Object iBinder = getServiceMethod.invoke(null, new String[]{"package"});
Class<?> iPackageManager$Stub$ProxyClass = Class.forName("android.content.pm.IPackageManager$Stub$Proxy");
Constructor constructor = iPackageManager$Stub$ProxyClass.getDeclaredConstructor(IBinder.class);
constructor.setAccessible(true);
Object iPackageManager$Stub$Proxy = constructor.newInstance(new Object[]{iBinder});
return iPackageManager$Stub$Proxy;
}catch (Exception e){
Log.d("ysh", "get IPackageManager error:" + Log.getStackTraceString(e));
}
return null;
}
有同学问我说Class这个类也可以被Hook啊,是的,你说的很对.那我这样回答好了,
就是Hook的函数多了,App运行会变得不稳定,你Hook了Java层的实现,我可以放到JNI层嘛,
或者使用另一种方式来实现.
MT管理器Native层Hook使用的是爱奇艺开源的XHook框架,Hook了open函数,针对这种,我们
从 /proc/self/maps 中解析 SO 符号表得到dlopen函数的地址,然后使用dlopen
再获取系统libc库open函数的地址就可以解决了.
MT在Java层则是重写了各种IO函数,达到IO重定向.
测试APP:
可以使用爆破签名校验之类的工具进行测试
https://pan.baidu.com/s/19VqYzGn2Y0n4quXAclwYKw
测试效果:
总体来说攻防相对,互相在彼此的脚印中发展,没有绝对的安全。Hook 系统的API越多,APP运行稳定性就会有一定降低,当APP无法正常运行时,我们是否就可以说,防护方面取得一定的成就。 感谢分享
感谢分享 好东西,感谢楼主分享。 排版处理下 感谢楼主分享技术贴,收藏细看 模拟器有什么好的方法检测么 本帖最后由 wujinhuangye 于 2019-11-11 17:53 编辑
public static void recoverPMS(Context ct, Object ipm) {
try {
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
Object currentActivityThread = currentActivityThreadMethod.invoke(null); //1. 获取全局的ActivityThread对象
Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
sPackageManagerField.setAccessible(true); /*通过置空系统IPM来迫使系统产生新的IPM对象,也是一种方法,但是这种方法也可以被HOOK.
IPackageManager$Stub.asInterface方法里存在Hook点,故不采用此方法.
sPackageManagerField.set(currentActivityThread, null); //2. 将sPackageManager置空,让后面反射获取IPackageManager时系统再产生
//新的IPackageManager
Method getPackageManagerMethod = activityThreadClass.getDeclaredMethod("getPackageManager");
getPackageManagerMethod.setAccessible(true);
Object originalIPackageManager = getPackageManagerMethod.invoke(null); //3. 获取到的新的IPackageManager,此IPackageManager没有被Hook*/
sPackageManagerField.set(currentActivityThread, ipm); //4. 替换掉ActivityThread里面的被Hook过的 sPackageManager 字段
PackageManager pm = ct.getPackageManager();
Field mPmField = pm.getClass().getDeclaredField("mPM");
mPmField.setAccessible(true);
mPmField.set(pm, ipm); //5. 替换ApplicationPackageManager里面的被Hook过的mPM对象
} catch (Exception e) {
Log.d("ysh", "recovery pms error:" + Log.getStackTraceString(e));
}
}
public static Object getIPackageManager() {
try {
Class<?> serviceManagerClass = Class.forName("android.os.ServiceManager");
Method getServiceMethod = serviceManagerClass.getDeclaredMethod("getService", String.class);
getServiceMethod.setAccessible(true);
Object iBinder = getServiceMethod.invoke(null, new String[]{"package"});
Class<?> iPackageManager$Stub$ProxyClass = Class.forName("android.content.pm.IPackageManager$Stub$Proxy");
Constructor constructor = iPackageManager$Stub$ProxyClass.getDeclaredConstructor(IBinder.class);
constructor.setAccessible(true);
Object iPackageManager$Stub$Proxy = constructor.newInstance(new Object[]{iBinder});
return iPackageManager$Stub$Proxy;
} catch (Exception e) {
Log.d("ysh", "get IPackageManager error:" + Log.getStackTraceString(e));
}
return null;
} 我能否以 修复前取得的 packageManager.getNameForUid(Binder.getCallingUid() 和修复后取得的名称做对比 作为判断 是否是分身软件的依据 谢谢分享
页:
[1]