文章目录
- 一、前言
- 二、如何实现签名校验
- 三、案例:定位签名校验
一、前言
当我们说应用签名校验时,实际上是一种安全机制,用于确保移动应用在被安装和运行时没有被篡改或修改。这个机制通过在应用程序文件上附加一种数字签名的方式来实现。
想象一下,你制作了一个应用,并且你希望用户下载并安装这个应用。在你发布应用之前,你对这个应用进行了签名,就好像你在应用上盖了一个印章一样。这个印章是使用你的私钥生成的,只有你才有这个私钥。
现在,当用户下载你的应用时,操作系统会检查这个印章。它会使用你公开的公钥来验证这个印章是否与应用的内容匹配。如果匹配,就说明应用是原始未经修改的版本,因为只有你拥有私钥,其他人无法伪造相同的印章。
这个过程的目的是确保用户安装的应用是来自可信的源,并且没有被黑客篡改过。这对于防止应用被恶意修改、插入广告或其他不良行为非常重要。这就是应用签名校验的基本概念。
二、如何实现签名校验
通过反编译软件可以看到app签名信息
那么在app内可以通过对比SHA1
值进行校验
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.util.Base64;
import android.util.Log;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class AppSignatureVerifier {
// 获取应用签名的方法
public static String getAppSignature(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(
context.getPackageName(),
PackageManager.GET_SIGNATURES
);
// 获取第一个签名(通常应用只有一个签名)
Signature signature = packageInfo.signatures[0];
// 计算 SHA1 哈希值
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] signatureBytes = md.digest(signature.toByteArray());
// 将字节数组转换为 Base64 编码的字符串
return Base64.encodeToString(signatureBytes, Base64.NO_WRAP);
} catch (PackageManager.NameNotFoundException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
// 校验应用签名的方法
public static boolean verifySignature(Context context, String expectedSignature) {
String appSignature = getAppSignature(context);
// 对比期望的签名和实际的签名
return (appSignature != null && appSignature.equals(expectedSignature));
}
// 示例用法
public static void main(String[] args) {
Context context = /* 获取Android应用的上下文 */;
String expectedSignature = /* 期望的应用签名 */;
if (verifySignature(context, expectedSignature)) {
Log.d("AppSignatureVerifier", "应用签名校验通过");
} else {
Log.e("AppSignatureVerifier", "应用签名校验失败");
}
}
}
也存在其他的校验方法如对比hashcode
值
if(-19423432442 == context.getPackageManager().getPackageInfo(context.getPackageName(),64).signatures[0].hashCode(){
return true;
})
Process.killProcess(Process.myPid());
return true;
三、案例:定位签名校验
案例app下载
链接:https://pan.baidu.com/s/1lZ2Umucc0wgglDlSEuFK9w 提取码:9r9w
先反编译apk,再重新打包成apk
# 反编译apk
apktool d E:\apk\lesson3-com.chaozhuo.texteditor.apk
# 重新打包成apk
apktool b E:\apk\lesson3-com.chaozhuo.texteditor\
# 签名
keytool -genkey -keystore my-release-key.keystore -alias my_alias -keyalg RSA -keysize 4096 -validity 10000
jarsigner -sigalg MD5withRSA -digestalg SHA1 -keystore my-release-key.keystore -signedjar E:\apk\2.apk E:\apk\1.apk my_alias
# 安装重新打包好的apk
adb install E:\apk\2.apk
再次打开app,发现被检测,无法正常使用app如下:
通过java内置库android.content.pm.Signature
可以hook与签名相关的函数
# hook 内置类android.content.pm.Signature
var Signature = Java.use('android.content.pm.Signature')
# hook 内置类的hashCode方法
Signature.hashCode.implementation = function() {
console.log('hashCode')
return this.hashCode()
}
# hook 内置类的toByteArray方法
Signature.toByteArray.implementation = function() {
console.log('toByteArray')
return this.toByteArray()
}
并打印出堆栈
# hook 内置类的toByteArray方法
Signature.toByteArray.implementation = function() {
console.log('toByteArray')
printstack()
return this.toByteArray()
}
# 打印调用堆栈
function printstack() {
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
}
完整代码:github