一、背景介绍
现在市面上,诸如:MT管理器、APK Editor等软件,可以对APK文件进行修改,提取AndroidManifest文件,修改包名、版本号、图标、应用名称等。
通过修改版本号,可以跳过应用升级检测,从而出现新版本修复的漏洞无法修复的情况;还会造成新功能无法使用,新推广的业务无法正常展开。
二、修改检测
通过研究,发现要达到上述修改目的,势必要对APK文件进行修改,再重新打包签名安装。
我们知道,Android在安装apk时,会在目录 /data/app/包名/ 路径拷贝一份APK文件:base.apk。因此,可以通过获取到base.apk文件,计算base.apk的MD5,检测文件是否被修改。
同时可以获取以下信息:app的 包名、版本号、名称、签名信息、md5,上报服务接口进行校验,从而阻止被修改的app继续使用。

三、客户端获取信息
1、AppInfoUtils
public class AppInfoUtils {
// 获取appid
public static String getAppId(Context context) {
return context == null ? "" : context.getPackageName();
}
// 获取app名称
public static String getAppName(Context context) {
return context == null ? "" : context.getString(context.getApplicationInfo().labelRes);
}
// 获取base.apk的路径
public static String getBaseApkPath(Context context) {
return context == null ? "" : context.getApplicationInfo().sourceDir;
}
// 获取appVersionName
public static String getAppVersionName(Context context) {
try {
return context == null ? "" : context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
// 获取appVersionCode
public static long getAppVersionCode(Context context) {
if (context == null) return 0;
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return AndroidSysUtils.isOverP9() ? packageInfo.getLongVersionCode() : packageInfo.versionCode;
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
// 获取签名文件的md5
public static String getSignMD5(Context context) {
if (context == null) return "";
try {
Signature[] signatures;
if (AndroidSysUtils.isOverP9()) {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNING_CERTIFICATES);
SigningInfo signingInfo = packageInfo.signingInfo;
signatures = signingInfo.getApkContentsSigners();
} else {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
signatures = packageInfo.signatures;
}
StringBuilder stringBuilder = new StringBuilder();
for (Signature signature : signatures) {
stringBuilder.append(MD5Utils.getMd5ByByteArray(signature.toByteArray())).append(",");
}
return stringBuilder.substring(0, stringBuilder.length() - 1);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
// 获取base.apk的md5
public static String getBaseApkMD5(Context context) {
try {
return context == null ? "" : MD5Utils.getMd5ByFile(getBaseApkPath(context));
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
}
2、MD5Utils
public class MD5Utils {
public static String getMd5ByFile(String fileName) {
FileInputStream in = null;
try {
in = new FileInputStream(fileName);
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] buffer = new byte[1024];
int readCound;
while ((readCound = in.read(buffer)) > 0) {
md5.update(buffer, 0, readCound);
}
BigInteger bi = new BigInteger(1, md5.digest());
return bi.toString(16);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return "";
}
public static String getMd5ByByteArray(byte[] byteArray) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(byteArray);
BigInteger bi = new BigInteger(1, md5.digest());
return bi.toString(16);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
}
网友评论