前言 本节分析的是之前渗透时的一个APP,抓包后发现请求包和返回包都做了加密。
此处分析某保险的APP,具体分析情况如下:
开整开整开整~
抓包 目标接口:https://xxx.xxx.xxx/login.do
发现请求包和响应包的内容都是直接加密的,也没有什么提示信息,什么玩意???
分析 1、首先,查壳,未发现壳
2、将apk拖入到jadx中,搜索一些关键字符。如”encrypt”
发现在com.xxxx.core_library.util.encrypt这个package下,有AES和RSA的加密算法
查看相关代码后发现,疑似的关键代码是在AESUtil和 RSAUtils这两个类中的。
但具体加密逻辑是什么暂时不清楚。
3、这时候,可以用hook的神器objection来对这两个类下的所有方法hook,查看其加解密逻辑
android hooking watch class com.xxx.core_library.util.encrypt.AESUtil android hooking watch class com.xxx.core_library.util.encrypt.RSAUtils
4、点击登录,抓包,查看hook情况,如下:
整理一下,调用的函数有(按照调用顺序如下):
AESUtil.encrypt(java.lang.String) AESUtil.makeKey(java.lang.String) AESUtil.makeIv() AESUtil.decrypt([B) AESUtil.makeKey(java.lang.String) AESUtil.makeIv() AESUtil.decrypt([B) AESUtil.makeKey(java.lang.String) AESUtil.makeIv() AESUtil.decrypt([B) AESUtil.makeKey(java.lang.String) AESUtil.makeIv() AESUtil.decrypt([B) AESUtil.makeKey(java.lang.String) AESUtil.makeIv() RSAUtils.actRsaPubkeyEncry(java.lang.String) RSAUtils.decryptByPublicKey([B, java.lang.String) RSAUtils.Base64Decode(java.lang.String) AESUtil.decrypt([B, java.lang.String) AESUtil.makeKey(java.lang.String) AESUtil.makeIv()
整理去重后,主要是有以下几个函数
AESUtil.encrypt AESUtil.makeKey AESUtil.makeIv AESUtil.decrypt RSAUtils.actRsaPubkeyEncry RSAUtils.decryptByPublicKey RSAUtils.Base64Decode RSAUtils.actResPubkeyDes
先看加密,根据函数名,可以看到重要的函数起始就值有2个AESUtil.encrypt和 RSAUtils.actRsaPubkeyEncry
5、hook这两个关键函数(这块不用关注重载的情况,因为Objection默认hook一个函数是hook该函数的所有重载的)
android hooking watch class_method com.xxx.core_library.util.encrypt.AESUtil.encrypt --dump-args --dump-return --dump-backtrace android hooking watch class_method com.xxx.core_library.util.encrypt.RSAUtils.actRsaPubkeyEncry --dump-args --dump-return --dump-backtrace
对比抓包获取的密文内容,可以成功定位到具体的加密函数RSAUtils.actRsaPubkeyEncry:
同理,利用如上方法,可以定位到具体解密函数为 RSAUtils.actResPubkeyDes:
6、Frida编写脚本hook这两个函数
function printStack (name ) { Java .perform (function ( ) { var Exception = Java .use ("java.lang.Exception" ); var ins = Exception .$new("Exception" ); var straces = ins.getStackTrace (); if (straces != undefined && straces != null ) { var strace = straces.toString (); var replaceStr = strace.replace (/,/g , "\r\n" ); console .log ("=============================" + name + " Stack strat=======================" ); console .log (replaceStr); console .log ("=============================" + name + " Stack end=======================\r\n" ); Exception .$dispose(); } }); } function main ( ) { Java .perform (function ( ) { var claz = Java .use ('com.xxxx.core_library.util.encrypt.RSAUtils' ); claz.actRsaPubkeyEncry .implementation = function (str ) { printStack ('actRsaPubkeyEncry' ); console .log ("actRsaPubkeyEncry input: " + str); var result = this .actRsaPubkeyEncry (str); console .log ("actRsaPubkeyEncry result: " + result); return result; } claz.actResPubkeyDes .implementation = function (str ) { printStack ('actResPubkeyDes' ); console .log ("actResPubkeyDes input: " + str); var result = this .actResPubkeyDes (str); console .log ("actResPubkeyDes result: " + result); return result; } }); } setImmediate (main)
整理 主动调用 JS代码:
function encrypt (data ) { var result; Java .perform (function ( ) { var claz = Java .use ('com.xxx.core_library.util.encrypt.RSAUtils' ); result = claz.actRsaPubkeyEncry (data) }); return result; } function decrypt (data ) { var result; Java .perform (function ( ) { var claz = Java .use ('com.xxxx.core_library.util.encrypt.RSAUtils' ); result = claz.actResPubkeyDes (data) }); return result; } rpc.exports = { encrypt : encrypt, decrypt : decrypt };
Python实现主动调用:
Python实现主动调用:
import fridaimport timedef on_message (message, data ): if message['type' ] =='send' : print (message['payload' ]) device = frida.get_device_manager().add_remote_device("127.0.0.1:27042" ) pid = device.spawn('com.xxx.xxxx' ) device.resume(pid) time.sleep(1 ) session = device.attach(pid) with open ('rpc.js' ) as f: script = session.create_script(f.read()) script.on('message' , on_message) script.load() result = script.exports.encrypt('{"clientId":"65l2f2f0an526tc","imgCode":"1234","model":"SM-G988N","password":"e10adc3949ba59abbe56e057f20f883e","phone":"13888888888","phoneId":"08:00:27:51:bf:b2","runEnvironment":"2","system":"android","systemversion":"9"}' ) print (result)
批量RPC 基于flask,创建对外接口,实现POST传参调用接口,最后实现批量化主动调用:
import fridaimport timeimport jsonfrom flask import Flask, request, jsonifydef on_message (message, data ): if message['type' ] =='send' : print (message['payload' ]) device = frida.get_device_manager().add_remote_device("127.0.0.1:27042" ) pid = device.spawn('com.xxx.xxx' ) device.resume(pid) time.sleep(1 ) session = device.attach(pid) with open ('rpc.js' ) as f: script = session.create_script(f.read()) script.on('message' , on_message) script.load() app = Flask(__name__) @app.route('/encrypt' , methods=['POST' ] ) def encrypt (): data = request.get_data() json_data = json.loads(data.decode('utf-8' )) result = script.exports.encrypt(str (json_data)) return result @app.route('/decrypt' , methods=['POST' ] ) def decrypt (): data = request.get_data() string_data = data.decode('utf-8' ) result = script.exports.decrypt(string_data) return result if __name__ == '__main__' : app.run(debug=True , host='0.0.0.0' )
加密接口调用:
解密接口调用: