APK安全性校驗(yàn)
獲取簽名證書keystore的SHA1值和完整性校驗(yàn)獲取的classes.dex的SHA-1哈希值字符串
- 建議后臺保存初始值與前端獲取sha1值做判斷是否可以進(jìn)行下一步操作
1. 簽名證書文件校驗(yàn)碼
獲取簽名證書的SHA1值
public static String getSign(Context ctx) {
try {
PackageInfo packageInfo = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(),
PackageManager.GET_SIGNATURES);
Signature[] signs = packageInfo.signatures;
Signature sign = signs[0];
MessageDigest md1 = MessageDigest.getInstance("MD5");
md1.update(sign.toByteArray());
byte[] digest = md1.digest();
String res = toHexString(digest);
MessageDigest md2 = MessageDigest.getInstance("SHA1");
md2.update(sign.toByteArray());
byte[] digest2 = md2.digest();
String res2 = toHexString(digest2);
return res2;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
2. 完整性校驗(yàn)
-
對簽名文件中classes.dex哈希值的校驗(yàn)
Android工程代碼經(jīng)編譯打包生成apk包后,開發(fā)者需要對其簽名才能在安卓市場上發(fā)布供用戶下載和安裝。對apk包簽名后,會(huì)在原apk包結(jié)構(gòu)基礎(chǔ)上加入META-INF文件目錄。
META-INF文件目錄下含有三個(gè)文件:MANIFEST.MF文件、ANDROIDD.SF文件、ANDROIDD.RSA文件,META_INF目錄文件結(jié)構(gòu)如下圖所示:
其中,MANIFEST.MF文件描述了在簽名時(shí),簽名工具對apk包中各個(gè)文件摘要計(jì)算后的哈希值,并對哈希值做了Base64編碼。MANIFEST.MF文件中描述的classes.dex文件的SHA-1哈希值如下圖所示:
一旦攻擊者對APK中反編譯并篡改代碼,經(jīng)二次打包簽名后的classes.dex文件的SHA-1必定改變,因此,我們可以將該文件中的classes.dex文件的SHA-1哈希值保存起來作為校驗(yàn)對比值,應(yīng)用程序啟動(dòng)時(shí)讀取apk安裝包中的MANIFEST.MF文件,解析出classes.dex的SHA-1哈希值,然后與原SHA-1哈希值進(jìn)行比較,判斷此APK包代碼文件是否被篡改。
通過檢查簽名文件classes.dex文件的哈希值來判斷代碼文件是否被篡改的java實(shí)現(xiàn)代碼如下所示:
通過檢查簽名文件classes.dex文件的哈希值來判斷代碼文件是否被篡改
@param orginalSHA 原始Apk包的SHA-1值
public static void apkVerifyWithSHA(Context context, String baseSHA) {
String apkPath = context.getPackageCodePath(); // 獲取Apk包存儲路徑
try {
MessageDigest dexDigest = MessageDigest.getInstance("SHA-1");
byte[] bytes = new byte[1024];
int byteCount;
FileInputStream fis = new FileInputStream(new File(apkPath)); // 讀取apk文件
while ((byteCount = fis.read(bytes)) != -1) {
dexDigest.update(bytes, 0, byteCount);
}
BigInteger bigInteger = new BigInteger(1, dexDigest.digest()); // 計(jì)算apk文件的哈希值
String sha = bigInteger.toString(16);
fis.close();
if (!sha.equals(baseSHA)) { // 將得到的哈希值與原始的哈希值進(jìn)行比較校驗(yàn)
Process.killProcess(Process.myPid()); // 驗(yàn)證失敗則退出程序
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
.
有問題歡迎學(xué)習(xí)交流,私信留言,共同學(xué)習(xí)