破解移动端APP报文加解密的潘多拉魔盒

发表于:2021-4-19 09:23

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:孙颖嘉    来源:51Testing软件测试网原创

  近日,收到了针对某移动APP实施安全渗透测试的任务,习惯性的使用Burp Suit进行抓包,发现请求报文进行了全部加密,立刻汗颜了,这可怎么完成测试工作呢!
  经过思考后通过APP反编译的方式获取源代码,并分析其加解密算法后实施破解,但事实给了我们一记响亮的耳光,经测试该APP进行了加壳处理,无法通过APP反编译的方式获取源代码。看来只能尝试采用APK脱壳的方式了,就是从这里开始一步步走向了成功。

  APP逆向
  一般情况,业内通过对APP进行逆向获取到源代码,分析源代码了解其业务逻辑,获取到关键业务算法,最终实现渗透入侵。所以获取APP源代码是很关键的一步,具体步骤如下:
  1、下载移动APP的安装包,扩展名为*.apk。
  2、将安装包的扩展名修改为.zip,用压缩工具进行解压。
  3、在解压缩的目录中找到classes.dex文件。
  4、命令行输入d2j-dex2jar.bat classes.dex,会生成一个classes-dex2jar.jar文件。
  5、使用jd-gui工具直接打开classes-dex2jar.jar文件,即可看到反编译后的源代码。
  另外,也可通过apktook工具将安装包反编译为smail语言,然后进行分析。
  但是,事实往往是残酷的,经过上面的一番操作,并没有获得该移动APP源代码!
图1

  上图所示,应该是该移动APP进行了加壳,隐藏了源代码。如何解决呢,请大家继续看下去。

  APK脱壳
  现在我们先来看看apk脱壳的一些基本知识,首先Android系统启动时会先启动init进程,init进程会启动zygote进程,该进程会为每个要启动的App进程孵化出一个Davlik虚拟机实例。
  Zygote进程还会启动optdex进程,这个进程将要运行App的DEX文件映射到内存中,经分析dexopt函数会调用dvmPreForDexOpt函数,其作用是对函数进行优化前,检测Dalivk虚拟机是否进入工作状态,如进入工作状态则调用dvmContinueOptimization函数对Dex文件进行优化。
  dvmContinueOptimization函数中调用了我们的主角 dvmDexFileOpenPartial函数 其主要功能就是完成将内存中DexDile 转化成DilivikVM的Dex文件DvmDex。
  自此我们只需要在该函数下断点,计算出内存地址和长度,即可采用Dump的方式转存内存中的源码了。
  目前有很多apk脱壳工具,就不一一介绍了,我使用的FRIDA-DEXDump工具,在命令行输入 python3 main.py即可开始进行apk脱壳。
图2

  如上图所示,通过FRIDA-DEXDump工具得到了dex文件,然后使用d2j-dex2jar工具将其转换为jar文件,然后使用jd-gui工具打开即可。
  经分析该APP采用了AES非对称算法进行加密,并使用了HMAC算法进行签名。

  hook加解密类获取秘钥
  经过对源代码分析得知,源代码中并未包含相关秘钥,应该是采用了动态秘钥机制,第一个参数是待加密解密的明文,第二个参数是秘钥,第三个参数是iv。
public static byte[] encrypt(byte[] param,byte[] key,byte[] iv)throws Exception{
    ......//算法内容
    return result;
}

  基于以上的分析,破解思路是首先通过hook获取到动态秘钥,将其保存为本地文件,最后开发Burp Suit插件读取秘钥并进行解密。现在先来hook动态秘钥吧!其思路是hook加解密函数,打印出来参数二和参数三,如下:
var hookClass2 = Java.use("xxx.xxxx.xxxx.xxxx.xxx");//要hook的类
hookClass2.加密方法.overload('[B', '[B', '[B').implementation = function (arg1, arg2, arg3) {
......//打印参数二和三
return result;
}

  打印的内容如下:
图3

  编写Burp Suit插件
  有了子弹,现在就来造枪了,即:Burp Suit插件。其思想是读取*.txt文件中的秘钥,然后调用云端加解密函数,调用签名函数替换报文中的签名,最后将解密后的明文显示在Burp Suit。另外,需要区分请求报文和响应报文,因此需要两对秘钥和签名秘钥,具体如下:
public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) {
    IRequestInfo requestInfo = this.helpers.analyzeRequest(messageInfo);
    List<String> a = requestInfo.getHeaders();//报文头
    if (((String)a.get(0)).startsWith("GET"))
        return;
    String u = "http://127.0.0.1:8080/demo1/1106.jsp";//云端加解密
    if (requestInfo.getUrl().getHost().equals("xxx.xxxx.com")) {//过滤URL
        if (messageIsRequest) {
            //请求报文的处理逻辑
  } else {
    //响应报文的处理逻辑
        }
    }
}

  实施加解密破解
  现在就让我们开始破解加解密吧!首先开启两个burpsuite,都导入Burp Suit这个插件,先不要启动插件。第一个burpsuite抓取app数据包,并设置转发到第二个burpsuite,设置为127.0.0.1:8888;第二个burpsuite拦截8888这个端口的请求。
图4

图5

图6

图7

  复制图3里的白色字体”明文”字段到1.txt,复制图3里的白色字体”sign”明文字段到2.txt,复制图3里的黄色字体”明文”字段到3.txt,复制图3里的黄色字体”sign2”字段到4.txt。
  最后,启动两个Burp Suit插件,设置代理启动APP进行抓包,发现原来的密文已经还原为明文了。

  至此,我们终于打开了报文加解密的潘多拉魔盒,该破解过程并非通用的方法,需要根据现实情况调整,希望对大家有所帮助。在打开潘多拉魔盒的过程是艰辛的,也是快乐的。希望大家都能够在技术的海洋中找到属于自己的快乐。
  我们写的测试用例也一样,可读性和可重用性也非常重要。测试的功能多了会发现所有的功能几乎都可以找到原型或者由几个原型组合。
  那么我们在写测试用例的时候就应该考虑到用例可读和重用两点,对于新的功能就不必每次都要重头设计测试用例,可以在原有用例的基础上修改和新增。复用测试用例可以在很大的程度上减少重复性的工作。



版权声明:本文出自《51测试天地》第六十一期。51Testing软件测试网及相关内容提供者拥有51testing.com内容的全部版权,未经明确的书面许可,任何人或单位不得对本网站内容复制、转载或进行镜像,否则将追究法律责任
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号