Android利用反射进行较强的签名校验

常见签名校验

一般来说,签名校验的方式有以下几种

  1. 通过安卓提供的api,利用packagemanager获取签名数据,和已存的正确值进行对比
  2. 在native中,反射Java的api,进行对比,本质上和1相同
  3. 自己读取apk文件,解压,校验META-INF里的RSA文件

第一种和第二种,是大多数软件在用的,但是很容易被逆向者过掉,甚至有工具可以一键过掉

第三种校验的准确性更高,缺点是效率低、易发生错误,并且v1以上的签名之后,并不生成RSA文件。那么校验文件也就不可取了。

这是常见的签名校验的示例:

/**

 * 常见的签名校验

 */

private boolean doNormalSignCheck() {

    String trueSignMD5 = "d0add9987c7c84aeb7198c3ff26ca152";

    String nowSignMD5 = "";

    try {

        // 得到签名的MD5

        PackageInfo packageInfo = getPackageManager().getPackageInfo(

                getPackageName(),

                PackageManager.GET_SIGNATURES);

        Signature[] signs = packageInfo.signatures;

        String signBase64 = Base64Util.encodeToString(signs[0].toByteArray());

        nowSignMD5 = MD5Utils.MD5(signBase64);

    } catch (PackageManager.NameNotFoundException e) {

        e.printStackTrace();

    }

    return trueSignMD5.equals(nowSignMD5);

}

归根结底,问题就在于如何准确的获取签名。

反射机制

反射是Java的一种机制

下面是百度百科的介绍:

0a34cc3423b147ca984bf7cce94ee31b.jpg

 

新的获取签名方式

一个通过反射获取Binder,进而获取签名值的示例。

val smc = Class.forName("android.os.ServiceManager")

val sCache = (smc.getDeclaredField("sCache").also {

    if (!it.isAccessible) it.isAccessible = true

}.get(smc) as ArrayMap<String, IBinder>).also { it.clear() } 

val gsm = smc.getDeclaredMethod("getService", String::class.java)

 

fun checkSignV2(context: Context, realSign: String): Boolean {

    kotlin.runCatching {

        if (sCache["package"] == null) { 

            val userId = Process.myUid() / 100000

            val binder = HiddenApi.getServiceByMethod("package")

            val bz = Class.forName("android.content.pm.IPackageManager\$Stub")

            val am = bz.getDeclaredMethod("asInterface", IBinder::class.java)

            val mmg = am.invoke(bz, binder)

            val ic = Class.forName("android.content.pm.IPackageManager")

            val gmi = ic.getDeclaredMethod("getPackageInfo", String::class.java, Int::class.java, Int::class.java)

            val  signatures: Array<Signature> = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {

                (gmi.invoke(mmg, context.packageName, PackageManager.GET_SIGNING_CERTIFICATES, userId) as PackageInfo).signingInfo.apkContentsSigners

            } else {

                (gmi.invoke(mmg, context.packageName, PackageManager.GET_SIGNATURES, userId) as PackageInfo).signatures

            }

            val builder = StringBuilder()

            signatures.forEach {

                builder.append(it.toCharsString())

            }

            return builder.toString() == realSign

        }

        return false

    }.onFailure {

        it.printStackTrace()

    }

    return true

}

之前查验签名的PackageManager是用bind系统服务(package)实现的。而这个,直接对接系统服务。

补充:

多种校验方式结合,配合着类名校验更佳。

 

参考:https://blog.xinrao.co/index.php/archives/28/

https://blog.csdn.net/qq_40948137/article/details/115866451

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值