20145307陈俊达_安卓逆向分析_软件包签名研究
引言
写这篇文章的原因有两点,一,之前打算写两篇cydia逆向分析,可惜手机不能Cydia不支持5.0以上系统,无奈放弃。二,在写之前的博客的时候重新打包后传到安卓手机上的时候,出现了签名有问题,不能进行安装的问题,这就促使我想写一篇关于软件签名的文章。
start
安卓系统禁用更新签名不一致的apk,所以我们打包新的apk是肯定不能安装的。那么我们怎么来研究呢?推荐一款签名软件,鼎鼎大名的auto-sign,我们下载后进行解压,右键用VS code打开sign.bat文件。
同时readme文件也帮助我们又一个很好的理解,两个签名密钥信息加上一个jar文件是这个程序的核心。testkey.x509.pem这个公钥文件和testkey.pk8这个私钥文件对xxx.apk签名之后变为signed的apk
testkey.pk8 is the private key that is compatible with the recovery image included in this zip file
testkey.x509.pem is the corresponding certificate/public key
使用方法:
java -jar signapk.jar testkey.x509.pem testkey.pk8 update.zip update_signed.zip
那么我们来看看签名前后有什么变化,签名后多了一个叫做META-INF的文件夹,里面有三个文件,分别为 MANIFEST.MF 、 CERT.SF 、 CERT.RSA
我们用jd-gui工具打开signapk.jar,找到主函数 main 看看代码
public static void main(String[] args) {
if (args.length != 4) {
System.err.println("Usage: signapk publickey.x509[.pem] privatekey.pk8 input.jar output.jar");
System.exit(2);
}
JarFile inputJar = null;
JarOutputStream outputJar = null;
try
{
X509Certificate publicKey = readPublicKey(new File(args[0]));
PrivateKey privateKey = readPrivateKey(new File(args[1]));
inputJar = new JarFile(new File(args[2]), false);
outputJar = new JarOutputStream(new FileOutputStream(args[3]));
outputJar.setLevel(9);
Manifest manifest = addDigestsToManifest(inputJar);
manifest.getEntries().remove("META-INF/CERT.SF");
manifest.getEntries().remove("META-INF/CERT.RSA");
outputJar.putNextEntry(new JarEntry("META-INF/MANIFEST.MF"));
manifest.write(outputJar);
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(privateKey);
outputJar.putNextEntry(new JarEntry("META-INF/CERT.SF"));
writeSignatureFile(manifest, new SignatureOutputStream(outputJar, signature));
outputJar.putNextEntry(new JarEntry("META-INF/CERT.RSA"));
writeSignatureBlock(signature, publicKey, outputJar);
copyFiles(manifest, inputJar, outputJar);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
} finally {
try {
if (inputJar != null) inputJar.close();
if (outputJar != null) outputJar.close();
}
catch (IOException e) { e.printStackTrace();
System.exit(1);
}
}
}
addDigestsToManifest 这个函数,遍历 Apk 中所有文件,对非文件夹非签名文件的文件逐个生成 SHA1 数字签名信息,再 base64 编码。再写入我们之前提到过的manifest.mf文件中。
大概格式
Manifest-Version: 1.0
Created-By: 1.0 (Android)
Name: res/drawable-xhdpi/ic_launcher.png
SHA1-Digest: xxxxxxxxxxxx
Name: AndroidManifest.xml
SHA1-Digest: xxxxxxxxxxxx
如果你修改了apk的文件,那么它的sha1值肯定会对应改变,肯定是不会安装成功的。
接下来对之前生成的 manifest 使用 SHA1withRSA 算法, 用私钥签名,writeSignatureFile 这个函数,最后生成 CERT.SF 文件
总结
这篇文主要是一些理论的东西,没有太多的实践操作,所以我没有贴太多的图片,主要是三个文件结合保证了apk文件下所有的每个文件都有对应的密钥进行加密保证了唯一性,不会被其他的文件篡改。所以也就解决了之前的疑问,为什么会出现了签名错误的问题。下篇文章打算做一些实际的东西,实际的软件,实际的游戏,去hack it