吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4572|回复: 9
收起左侧

[Android 原创] 还原Android被inline Hook的服务对象

  [复制链接]
LivedForward 发表于 2019-11-7 10:09
本帖最后由 LivedForward 于 2020-2-7 13:23 编辑

本篇介绍如何还原Android被inline  Hook的服务对象,以还原PMS为例。Android爆破签名校验原理是Hook了系统的PMS服务,那么我们如何还原被Hook的服务对象呢?下文介绍一种方案。

我们分析Android系统源码:

android.app.ActivityThread发现类里面有这样一个方法:

868227_FZTSNMUBQBSP7NN.jpg

如果sPackageManager字段为空就会调用IPackageManager$Stub类的asInterface方法初始化IPackageManager对象,

那么Hook PMS就是将 sPackageManager 字段替换了,到这里我们就很容易得出一种还原PMS服务的方法:先将

sPackageManager 字段置空,然后反射调用getPackageManager方法,这样得到的IPM对象就是原始的服务对象,再

利用反射将PMS对象替换成原始的对象就好了


但是,我们这里不采用这种方式,因为跟进asInterface这个方法我们不难发现: 这里的queryLocalInterface方法也是一个Hook点。


868227_688DYA2ECCSVB8X.jpg

那么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

测试效果:

868227_CKKGWAN4ETZBCSH.png


总体来说攻防相对,互相在彼此的脚印中发展,没有绝对的安全。Hook 系统的API越多,APP运行稳定性就会有一定降低,当APP无法正常运行时,我们是否就可以说,防护方面取得一定的成就。

免费评分

参与人数 4威望 +2 吾爱币 +12 热心值 +4 收起 理由
qtfreet00 + 2 + 9 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
onihot + 1 + 1 谢谢@Thanks!
hxw0204 + 1 + 1 热心回复!
fei8255 + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

BlueTears_ 发表于 2019-11-7 10:40
感谢分享
panxiansheng 发表于 2019-11-7 11:14
boell 发表于 2019-11-7 15:03
qtfreet00 发表于 2019-11-7 16:08
排版处理下
onihot 发表于 2019-11-9 11:06
感谢楼主分享技术贴,收藏细看
wujinhuangye 发表于 2019-11-11 15:01
模拟器有什么好的方法检测么
wujinhuangye 发表于 2019-11-11 17:48
本帖最后由 wujinhuangye 于 2019-11-11 17:53 编辑

[Java] 纯文本查看 复制代码
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;
    }
wujinhuangye 发表于 2019-11-11 20:07
我能否以 修复前取得的 packageManager.getNameForUid(Binder.getCallingUid() 和修复后取得的名称做对比 作为判断 是否是分身软件的依据
mephisto 发表于 2019-11-11 22:12
谢谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 19:24

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表