攻防:如何防止动态hook绕过jni签名校验

简介: 攻我们知道jni校验签名也不可靠,可以被动态hook绕过。代码如下:


我们知道jni校验签名也不可靠,可以被动态hook绕过。代码如下:


class HookSignHandler(var base : Any) : InvocationHandler {
    companion object{
        internal var signature = "xxx"
        fun hook(context: Context){
            try{
                var activityThreadClass = Class.forName("android.app.ActivityThread")
                var currentActicityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread")
                var currentActivityThread = currentActicityThreadMethod.invoke(null)
                var sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager")
                sPackageManagerField.isAccessible = true;
                var sPackageManager = sPackageManagerField.get(currentActivityThread)
                var iPackageManagerInterface = Class.forName("android.content.pm.IPackageManager")
                var proxy = Proxy.newProxyInstance(iPackageManagerInterface.classLoader, arrayOf(iPackageManagerInterface), HookSignHandler(sPackageManager))
                sPackageManagerField.set(currentActivityThread, proxy)
                var pm = context.packageManager
                var mPMField = pm.javaClass.getDeclaredField("mPM")
                mPMField.isAccessible = true
                mPMField.set(pm, proxy)
            }
            catch (e : Exception){
                Log.e("hook", "hook", e)
            }
        }
    }
    override fun invoke(proxy: Any?, method: Method, args: Array<out Any>): Any {
        if("getPackageInfo".equals(method.name)){
            ...
        }
        return method.invoke(base, *args)
    }
}
复制代码


只要得到了签名的signature,并且在application中添加


HookSignHandler.Companion.hook(this);
复制代码


这时无论java层还是jni层,当获取getPackageManager()时,它的mPM都是已经被代理的对象,这样当执行getPackageInfo()函数(实际上是执行mPM的对应函数)就会返回设置好的signature,而不是当前app的签名,这样就绕过了。



那么怎么防止这种手段? 那就是每次使用getPackageManager()时都检查一下它是否被代理。代码如下:


try {
    Field mPM = getPackageManager().getClass().getDeclaredField("mPM");
    mPM.setAccessible(true);
    if(Proxy.isProxyClass(mPM.get(getPackageManager()).getClass())){
        Toast.makeText(this, "hook!!", Toast.LENGTH_LONG).show();
    }
} catch (Exception e) {
    e.printStackTrace();
}
复制代码


Proxy本身提供了一个函数isProxyClass来检查当前对象的类是否是代理类。

我们将mPM对象获取到,用isProxyClass验证它的class即可。

那么这个这就涉及到了动态代理proxy的原理了。


动态代理


首先,动态代理一定需要一个接口,就是说代理的类必须实现某个接口,否则无法代理该类。比如上面的mPM就是实现接口android.content.pm.IPackageManager

这是为什么?这也与动态代理的原理有关。

简单来说,当我们设置动态代理后,实际上会自动生成一个类


public final class $Proxy0 extends Proxy implements XXXXX
{
    public $Proxy0(InvocationHandler paramInvocationHandler) throws 
    {
        super(paramInvocationHandler);
    }
 ...
}
复制代码


这样就一下子清晰了,因为实现了同一个接口,所以可以设置给原对象而不产生问题。

但是它又继承了Proxy类,而且可以看到构造函数中将之前创建的InvocationHandler也传进来了,这样就可以调用到原对象的函数了。


它的详细代码就不展示和一一解释了,简单来说就是它实现了接口,在每个函数中再去执行InvocationHandler的invoke,就实现了代理。


这也是为什么动态代理一定需要一个接口的原因。


Proxy.newProxyInstance()函数就是创建一个$Proxy0这个类的对象,然后设置给原对象,就代理上了。

那么isProxyClass的原理就清晰了,我们只要知道这个对象是不是继承Proxy即可。代码:


public static boolean isProxyClass(Class<?> cl) {
    return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
}
复制代码


可以看到使用了isAssignableFrom,那么再来说一说这个函数。


isAssignableFrom和instanceof

这两个作用类似,从例子上看:B extends A

A.class.isAssignableFrom(B.class);  表示A是B的父类,注意两边都是Class

b instanceOf A  判断A是否是b对象的类。这里b是B类的对象。A是B的父类,所以也一样是b对象的类


目录
相关文章
|
小程序 Java 数据安全/隐私保护
基于微信小程序的音乐平台 毕业设计 JAVA+Vue+SpringBoot+MySQL
基于微信小程序的音乐平台 毕业设计 JAVA+Vue+SpringBoot+MySQL
237 1
|
Web App开发 数据采集 JSON
Python实现urllib3和requests库使用 | python爬虫实战之五
本节介绍了urllib3库和requests库中的一些方法的使用。
Python实现urllib3和requests库使用 | python爬虫实战之五
深入分析luait反编译之luajit-decomp
#背景 Luajit在游戏中应用广泛,在逆向分析游戏过程中免不了与luajit打交道,那网上有非常多关于luajit反编译的资料,汇总起来常用的两种方案:https://github.com/zzwlpx/ljd 和 https://github.com/bobsayshilol/luajit-decomp, 第一种方案相对来说可读性好但兼容性差经常出现反编译异常崩溃。第二种方案反编译
7834 0
|
数据采集 DataWorks 监控
DataWorks产品使用合集之数据指标是用来做什么的
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
214 2
|
Web App开发 自然语言处理 前端开发
可访问性测试(无障碍测试)
可访问性测试(无障碍测试)
447 0
可访问性测试(无障碍测试)
|
11月前
|
Java Android开发 Windows
玩转安卓之配置gradle-8.2.1
为安卓开发配置Gradle 8.2.1,包括下载和解压Gradle、配置环境变量、修改配置文件以增加国内镜像,以及在Android Studio中配置Gradle和JDK的过程。
820 0
玩转安卓之配置gradle-8.2.1
|
文字识别 前端开发 API
印刷文字识别操作报错合集之通过HTTPS连接到OCR服务的API时报错,该如何处理
在使用印刷文字识别(OCR)服务时,可能会遇到各种错误。例如:1.Java异常、2.配置文件错误、3.服务未开通、4.HTTP错误码、5.权限问题(403 Forbidden)、6.调用拒绝(Refused)、7.智能纠错问题、8.图片质量或格式问题,以下是一些常见错误及其可能的原因和解决方案的合集。
|
数据采集 人工智能 Serverless
AI 克隆声音,只需 3 分钟(附最全教程)
文章介绍了GPT-Sovits,一个开源的生成式语音模型,因其在声音克隆上的高质量和简易性而受到关注。阿里云函数计算(Function Compute)提供了一个快速托管GPT-Sovits的方法,让用户无需管理服务器即可体验和部署该模型。通过函数计算,用户可以便捷地搭建基于GPT-Sovits的文本到语音服务,并享受到按需付费和弹性扩展的云服务优势。此外,文章还列举了GPT-Sovits在教育、游戏、新能源等多个领域的应用场景,并提供了详细的步骤指导,帮助用户在阿里云上部署和体验GPT-Sovits模型。
36367 8
|
安全 Java Apache
十个方法破解Java生成随机密码的小窍门
十个方法破解Java生成随机密码的小窍门
|
机器人 开发工具 Android开发
flutter web 优化和flutter_admin_template
flutter web 优化和flutter_admin_template

热门文章

最新文章