昨天收到一份安全检测报告,其中就有一个代码保护不足的问题,简单描述就是:通过反编译得到程序代码以后,恶意修改后重新编译再签名安装。针对这个问题简单的查了一些资料做一些记录。但这些处理也不是很好,只是让恶意破解麻烦了一点罢了(并未进行实践,有时间要试验一下)。
ToolBar+DrawerLayout使用
Android 自定义侧滑菜单效果(ViewDragHelper)
一站式CoordinatorLayout+ToolBar联动使用
多布局之RecyclerView与Json数据(GridLayoutManager实现)+多选
签名校验
反编译 dex,修改重新打包签名后 apk 的签名信息肯定会改变,所以可以在代码中判断签名信息是否不一致,不一致就不进入程序。
public static String getSignature(Context context) {
PackageManager pm = context.getPackageManager();
PackageInfo pi;
StringBuilder sb = new StringBuilder();
try {
pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
Signature[] signatures = pi.signatures;
for (Signature signature : signatures) {
sb.append(signature.toCharsString());
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return sb.toString();
}
拿到字符串以后,可以对字符串进行MD5加密等加密手段,然后与存放在本地的加密字符串作比较,不相等则不进入APP。originalSign
为自己打包签名文件所得到的字符串。
public static boolean verifySignature(Context context, String originalSign){
String currentSign = getSignature(context);
if (originalSign.equals(currentSign)) {
return true;//签名正确
}
return false;//签名被篡改
}
对classes.dex文件完整性校验
DEX文件打包在APK文件中,针对APK代码的篡改攻击就是针对该文件,比如使用apktool工具反编译文件,修改smali代码。以下就是通过检查classes.dex文件的CRC32值来判断文件是否被篡改。
其中R.string.str_code
是存放在本地的crc加密后的值,string.xml文件是不在dex文件中的,所以修改string.xml文件是不会造成crc值的变化(亲测),其实也可以把这个值存放在后台,通过请求网络来获取。(感觉没必要,为什么,往下看哈)
private void checkCRC() {
String orginalCrc = getString(R.string.str_code);
ZipFile zf;
try {
zf = new ZipFile(getApplicationContext().getPackageCodePath());
ZipEntry ze = zf.getEntry("classes.dex");
String strCrc = String.valueOf(ze.getCrc());
String MD5Crc = MD5Util.GetMD5Code(strCrc);
Log.e("checkcrc", MD5Crc);
if (!orginalCrc.equals(MD5Crc)) {
//ActivityManagerUtil.getScreenManager().removeAllActivity();
Process.killProcess(Process.myPid());
}
} catch (IOException e) {
e.printStackTrace();
}
}
还有其它几种方法,比如校验APK包的完整性、对签名文件中classes.dex哈希值的校验等。其实都大同小异。
把这些手段用在了程序中,但是通过多次反编译,都很容易确认程序在什么地方做了这些处理(可全局搜索关键词),恶意破解的话直接将修改返回值true或false,或者修改接收这个函数的if-else语句条件取个反,直接就绕过了判断。
比较科学一点的办法就是放在NDK层去校验了,这种校验稍微安全点,毕竟能逆向 C 和 C++ 的少一点。这里就要借鉴大佬的博客了(→点我←),里面有讲到如果在NDK层来做校验。