0x1 简述
在对银行APP进行渗透测试时,遇到了APP被加壳以及流量被加密。此篇文章针对以上问题以修改SO文件方式进行绕过。
0x2 反编译APP
首先APP作了加固,加固方式无从得知,从MT管理器提供的加固方法为:娜迦加固。仔细分析发现并不是,说明了MT管理器有时候提供的加固方法也会出错。反编译截图如下:
由于反编译后的包较少,直接挨个查看发现了一个可疑函数:
private static void copyAssets(String output, String input, Context context) {
try {
InputStream inputStream = context.getAssets().open(input);
File localFile = new File(output);
byte[] bytes = new byte[65536];
BufferedInputStream bufferedInput = new BufferedInputStream(inputStream);
BufferedOutputStream bufferedOutput = new BufferedOutputStream(new FileOutputStream(localFile));
boolean first = true;
byte[] nagic = {78, 71, 0, 0};
byte[] magic = {100, 101, 120, 10};
while (true) {
int i = bufferedInput.read(bytes);
if (first) {
first = false;
if (!(output.endsWith(Defines._DEX) && bytes[0] == nagic[0] && bytes[1] == nagic[1] && bytes[2] == nagic[2] && bytes[3] == nagic[3]) && output.endsWith(Defines._DEX) && bytes[0] == 110 && bytes[1] == 97 && bytes[2] == 103 && bytes[3] == 97) {
System.arraycopy(magic, 0, bytes, 0, magic.length);
}
}
if (i <= 0) {
bufferedOutput.flush();
bufferedOutput.close();
bufferedInput.close();
return;
}
bufferedOutput.write(bytes, 0, i);
}
} catch (Exception e) {
}
}
仔细分析可以看出magic字段为:{100, 101, 120, 10},换算成ASCII码值为:dex ,可推测为dex文件的文件头,继续往下看会发现最后使用
bufferedOutput.write(bytes, 0, i);
将文件写出,往上追溯代码可以得出输出目录:
按住Ctrl并点击对应变量可以得到输出目录在应用程序的数据目录中.cache目录下,这样我们安装APP并运行后,前往该目录的.cache目录,便可以看到对应的dex文件,这就是原生的dex文件,将其导入IDA继续进行分析
我们在抓包时可以看到API目录为:mobile开头的,如下图所示:
接下来直接搜索mobile开头的API,找到其中一个查看源码,可以在源码附近发现加密函数:telecomSMEncrypt
跟进telecomSMEncrypt函数可以发现使用了Native调用so文件里的函数进行加解密:
0x3 分析so
那么我们便来分析一下这个so文件,使用ida打开so文件,在左侧函数框处直接搜索:getNativeSM4EncryptValue,发现搜索不到,于是搜索JNI_Onload函数,幸运的是这个函数并没有被混淆,于是开始分析:
进入后发现函数名显示出来了,我们进入:getNativeSM4EncryptValue函数
双击进入函数_Z10getSMValueP7_JNIEnvP8_jobjectP8jstringS4:
进入这个函数后发现使用return返回一个函数,继续往里跟:
跟进来发现有SM4加密的特征了,这里分析了一下,推测byte_1FFDB9为key值,a1为待加密的原文,我们看上面的byte_1FFDB9s是如何生成的:
分析出来key是32位byte_18703A数组的随机值,并且可以看到依据是byte_1FFDB8的值为0的情况下,推测为每次打开APP都会初始化这个key值。知道key值得生成方法后,我们需要确定SM4算法的模式是什么,我们跟进SM4Encrypt函数发现:
得了,ECB模式,不需要IV,所以这里就分析完SM4算法了。这里应该会有一个疑问:既然每次打开APP时,key都会变,我们都知道ECB模式的SM4算法是使用key进行解密的,服务端肯定不知道key是多少呀,那么是怎么去解密呢?既然如此,我们继续回头分析后面的代码:
我们注意到上方的代码中出现了:%s|%s|%s,回去观察请求体发现也出现了两个 | ,因此我们需要确定一下这三个 %s 都是什么,我们往前分析v12,v13和v8
可以看到v12是SM2加密key的值(但是SM2是非对称加密,没有私钥是无法解出key值的。而私钥只能在服务端有),下方图中可以看到v13是SM4加密的值
再来看v8的值,可以看出v8的值是HMAC加密后的值,这里应该是SM3加密后的值
那么其实我们只需要固定住key值,之后的所有密文都可以使用我们固定的key值进行加解密了,这里有一个思路:把前面的byte_18703A变量中的所有值改成同一个。
使用上方方法,修改如下,全部固定成大写的A:
这样做的好处就是获取的key值只能是32个A了,我们就可以直接使用32个A作为key去进行SM4解密了。
0x4 替换so
我们将修改好的so进行保存:Edit - Patch program - Apply patches input file...
然后将其替换值APK路径:/data/app/~~xxxxxxxxx==/lib/arm/目录下,重启应用程序进行抓包即可。