1.今天我们对报文加密的app进行分析,请出我们的第一个app案例
2.我们先抓包看一下,抓到的包是什么样的,可以看到抓包出来,已经做了报文全加密,无法进行测试。
方案一:使用hook框架去获取明文报文。
1.我们怎么办呢?还是和之前一样我们先上算法助手,打印一下加解密相关的堆栈情况。
2.我们看到了里面有http相关的,去看一下反编译后的相关代码
3.这里我们对这里进行hook,不会安装frida的,去看入门教程:https://blog.csdn.net/qq_1290259791/article/details/100381831
function main() {
Java.perform(function () {
let RequestUtil = Java.use("com.xxxxxx.xxxxx.http.RequestUtil");
RequestUtil["paraMap"].overload('java.util.Map', 'java.lang.String', 'java.lang.String').implementation = function (addMap, append, sign) {
console.log(`RequestUtil.paraMap is called: addMap=${addMap}, append=${append}, sign=${sign}`);
let result = this["paraMap"](addMap, append, sign);
console.log(`RequestUtil.paraMap result=${result}`);
return result;
};
RequestUtil["decodeDesJson"].implementation = function (json, desKey, desIV) {
console.log(`RequestUtil.decodeDesJson is called: json=${json}, desKey=${desKey}, desIV=${desIV}`);
let result = this["decodeDesJson"](json, desKey, desIV);
console.log(`RequestUtil.decodeDesJson result=${result}`);
return result;
};
});
}
setTimeout(main, 500);
4.经过hook,发现我们hook到了明文,RequestUtil.paraMap里的result里是请求体内容,RequestUtil.decodeDesJson里的result里是响应体内容,就是我们需要的,接下来我们要写一个简单的hook脚本,把我们需要的内容发送到burp上,实现篡改明文请求及响应。
Java.perform(function () {
// 获取并拦截类 "com.xxxxxx.xxxxx.http.RequestUtil"
let RequestUtil = Java.use("com.xxxxxx.xxxxx.http.RequestUtil");
// Hook RequestUtil 类中的 "paraMap" 方法,该方法有三个参数:'java.util.Map','java.lang.String' 和 'java.lang.String'
RequestUtil["paraMap"].overload('java.util.Map', 'java.lang.String', 'java.lang.String').implementation = function (addMap, append, sign) {
// 打印 paraMap 方法调用时的输入参数
console.log(`RequestUtil.paraMap is called: addMap=${addMap}, append=${append}, sign=${sign}`);
// 调用原始的 paraMap 方法并保存返回结果
let result = this["paraMap"](addMap, append, sign);
// 打印原始方法返回的结果
console.log(`RequestUtil.paraMap result=${result}`);
console.log("data" + result);
// 将结果转换为字符串形式
let data = result.toString();
// 将请求体数据发送给 Frida 客户端,以便进一步分析
let sendData = {"TAG": "Request", "RequestBody": data}
send(sendData);
// 定义一个空对象,用于存储修改后的请求体
let reqModify = {}
// 接收来自 Frida 客户端的修改请求体并等待该操作完成
recv(function (reqObj) {
reqModify.reqModfyStr = reqObj.modify_requestBody; // 获取修改后的请求体
}).wait();
// 返回修改后的请求体
return reqModify.reqModfyStr;
};
// Hook RequestUtil 类中的 "decodeDesJson" 方法,拦截该方法的输入和输出
RequestUtil["decodeDesJson"].implementation = function (json, desKey, desIV) {
// 打印 decodeDesJson 方法调用时的输入参数
console.log(`RequestUtil.decodeDesJson is called: json=${json}, desKey=${desKey}, desIV=${desIV}`);
// 调用原始的 decodeDesJson 方法并保存返回结果
let result = this["decodeDesJson"](json, desKey, desIV);
// 打印原始方法返回的结果
console.log(`RequestUtil.decodeDesJson result=${result}`);
// 将解密后的响应体数据发送给 Frida 客户端
let data = result;
let sendData = {"TAG": "Response", 'ResponseBody': data};
send(sendData);
// 定义一个空对象,用于存储修改后的响应体
let respModify = {}
// 接收来自 Frida 客户端的修改响应体并等待该操作完成
recv(function (respObj) {
respModify.respModfyStr = respObj.modify_responseBody; // 获取修改后的响应体
}).wait();
// 返回修改后的响应体
return respModify.respModfyStr;
};
});
5.上面的代码主要是js相关的代码,若想正常使用,还要写一个用于frida rpc的python脚本
import argparse
import urllib
from urllib.parse import quote, unquote
from threading import Thread
from http.server import HTTPServer, BaseHTTPRequestHandler
import sys
import requests
import frida
import re
# 定义一个继承自BaseHTTPRequestHandler的请求处理类
class RequestHandler(BaseHTTPRequestHandler):
# 处理请求方法
def do_REQUEST(self):
content_length = int(self.headers.get('content-length', 0)) # 获取请求体长度
self.send_response(200) # 设置响应状态码为200
self.send_header('Content_Length', str(content_length)) # 添加响应头
self.send_header('X-Mirror-Server', 'True')
self.send_header('TMF_apiName', self.headers.get('TMF_apiName')) # 获取并设置请求中的TMF_apiName头
self.end_headers() # 结束头部设置
self.wfile.write(self.rfile.read(content_length)) # 将请求体数据作为响应体返回
# 处理响应方法
def do_RESPONSE(self):
content_length = int(self.headers.get('content-length', 0)) # 获取响应体长度
self.send_response(200) # 设置响应状态码为200
self.send_header('Content_Length', str(content_length)) # 添加响应头
self.send_header('X-Mirror-Server', 'True')
self.end_headers() # 结束头部设置
self.wfile.write(self.rfile.read(content_length)) # 将响应体数据返回给客户端
# 启动回显服务器
def echo_server_thread():
print('start echo server at port {}'.format(28080))
server = HTTPServer(('', 28080), RequestHandler)
server.serve_forever() # 永久运行服务器
# 使用线程启动镜像服务器
t = Thread(target=echo_server_thread)
t.daemon = True # 设置为守护线程
t.start()
proxies = {'http': 'http://127.0.0.1:8080'} # 设置代{过}{滤}理
# 处理 Frida 中发送的数据
def on_message(message, data):
if message['type'] == 'send': # 处理从 JS 发送来的数据
payload = message['payload']
TAG = payload['TAG']
# 处理请求数据
if TAG == 'Request':
RequestBody = unquote(payload["RequestBody"]) # 解码请求体
requestHeaders = {'X-Turbo_Intruder': 's'} # 设置请求头
requestURL = "http://127.0.0.1:28080/Request/" # 发送到镜像服务器的URL
request = requests.request("REQUEST", requestURL, proxies=proxies, headers=requestHeaders, data=RequestBody.encode("utf-8")) # 发送请求
request.encoding = 'utf-8' # 设置编码
script.post({"modify_requestBody": request.text}) # 将修改后的请求体发送给JS
# 处理响应数据
elif TAG == 'Response':
ResponseBody = payload["ResponseBody"] # 获取响应体
responseURL = "http://127.0.0.1:28080/Response" # 发送到镜像服务器的URL
response = requests.request("RESPONSE", responseURL, proxies=proxies, data=ResponseBody.encode('utf-8')) # 发送响应
script.post({"modify_responseBody": response.text}) # 将修改后的响应体发送给JS
else:
print("error", message) # 错误处理
# 连接到远程设备并附加到进程
process = frida.get_device_manager().add_remote_device('127.0.0.1:26666').attach('中文包名')
# 读取并加载JS脚本
with open("dodonew.js", "r", encoding='utf-8') as f:
js_code = f.read()
script = process.create_script(js_code)
# 监听来自JS的消息
script.on('message', on_message)
script.load() # 加载脚本
sys.stdin.read() # 保持主线程运行
6.脚本写完之后,我们就可以准备运行脚本看看效果了
7.这样我们基本上实现了报文的hook解密