Frida挂钩Java层代码与协议分析

avatar
作者
猴君
阅读量:0

Hook类中普通方法

在本文中,我们继续以某嘟牛应用为例,在用户点击登录按钮后,哪个方法会被调用。我们在上一篇文章中提到,搜索关键词 “Encrypt” 后,发现两个包含该字符串的 Java 方法。接下来,我们通过 Frida 分别 Hook 这两个方法,以测试点击登录后会调用哪个方法。以下是 Frida 脚本代码:

function HookMethod() {     Java.perform(function () {         var JsonRequest = Java.use("com.dodonew.online.http.JsonRequest");         console.log("JsonRequest = ", JsonRequest);         JsonRequest.paraMap.implementation = function (addMap){             console.log("addMap = ", addMap);             this.paraMap(addMap);         }         JsonRequest.addRequestMap.overload('java.util.Map', 'int').implementation = function (arg0,arg1) {             console.log("addRequestMap params: ", arg0, arg1);             var HashMap_arg0 = Java.cast(arg0, Java.use("java.util.HashMap"));             console.log("addRequestMap params: ", HashMap_arg0.toString());             this.addRequestMap(arg0, arg1);         }     }); } function main () {     HookMethod(); } setImmediate(main); 

在终端中执行以下命令以注入我们的 JavaScript 代码:

frida -U -f com.dodonew.online -l .\demo.js --no-pause 

执行结果如下所示:
在这里插入图片描述
通过结果我们可以看出,点击登录后最终执行的方法为 addRequestMap。该方法的代码如下:

public void addRequestMap(Map<String, String> addMap, int a) {     // 获取当前系统时间的时间戳,并将其转换为字符串     String time = System.currentTimeMillis() + "";     // 如果传入的 addMap 为空,则初始化一个新的 HashMap     if (addMap == null) {         addMap = new HashMap<>();     }     // 将时间戳加入到 addMap 中,键为 "timeStamp"     addMap.put("timeStamp", time);     // 调用 RequestUtil 类的 paraMap 方法,对 addMap 进行参数处理,生成一个包含签名的字符串     String code = RequestUtil.paraMap(addMap, Config.BASE_APPEND, "sign");      // 调用 RequestUtil 类的 encodeDesMap 方法,对生成的字符串进行 DES 加密,得到加密后的字符串     String encrypt = RequestUtil.encodeDesMap(code, this.desKey, this.desIV);     // 创建一个新的 JSONObject 对象     JSONObject obj = new JSONObject();     try {         // 将加密后的字符串放入 JSON 对象中,键为 "Encrypt"         obj.put("Encrypt", encrypt);         // 将 JSON 对象转换为字符串,并赋值给 mRequestBody         this.mRequestBody = obj + "";     } catch (JSONException e) {         // 捕获并打印 JSON 异常         e.printStackTrace();     } } 

协议分析

通过以上终端的输出,我们可以得知,输入的手机号码和密码并没有进行加密。因此,我们需要继续跟进代码,首先进入 RequestUtil.paraMap 方法,代码如下:

public static String paraMap(Map<String, String> addMap, String append, String sign) {     try {         // 获取传入的 Map 的键集         Set<String> keyset = addMap.keySet();         // 用于拼接字符串的 StringBuilder         StringBuilder builder = new StringBuilder();         // 用于存储键值对的列表         List<String> list = new ArrayList<>();                  // 遍历键集,将每个键值对以 "key=value" 的形式添加到列表中         for (String keyName : keyset) {             list.add(keyName + "=" + addMap.get(keyName));         }          // 对列表进行排序         Collections.sort(list);         // 遍历排序后的列表,将每个键值对拼接到 StringBuilder 中,以 "&" 分隔         for (int i = 0; i < list.size(); i++) {             builder.append(list.get(i));             builder.append("&");         }         // 将追加字符串(append)拼接到字符串的末尾         builder.append("key=" + append);         // 计算字符串的 MD5 哈希值,并转换为大写         String checkCode = Utils.md5(builder.toString()).toUpperCase();         // 将计算出的签名(checkCode)放入传入的 Map 中,键为 "sign"         addMap.put("sign", checkCode);         // 将 Map 按键排序后转换为 JSON 字符串         String result = new Gson().toJson(sortMapByKey(addMap));         // 打印日志,调试用         Log.w(AppConfig.DEBUG_TAG, result + "   result");         // 返回生成的 JSON 字符串         return result;     } catch (Exception e) {         // 捕获并打印异常         e.printStackTrace();         return "";     } } 

在 paraMap 方法中,调用了 Utils.md5 方法(调用 Utils.md5 之前都是明文)。为了了解传入的值如何进行 MD5 加密,我们需要 Hook 这个方法,查看传入的数据和加密后的结果,代码如下:

var utils = Java.use("com.dodonew.online.util.Utils"); utils.md5.implementation = function (arg0) {     console.log("md5 params: ", arg0);     var retval = this.md5(arg0);     console.log("md5 retval: ", retval);     return retval; } 

运行结果如下:
在这里插入图片描述
通过测试可知,Utils.md5 为标准的 MD5 算法。

在执行完成 RequestUtil.paraMap 方法后,返回的为 JSON 格式的字符串。接着我们 Hook RequestUtil.encodeDesMap 方法,代码如下:

var RequestUtil = Java.use("com.dodonew.online.http.RequestUtil"); RequestUtil.encodeDesMap.overload('java.lang.String', 'java.lang.String', 'java.lang.String').implementation = function (arg0,arg1,arg2) {     console.log("encodeDesMap arg0: ", arg0);     console.log("encodeDesMap arg1: ", arg1);     console.log("encodeDesMap arg2: ", arg2);     var ret = this.encodeDesMap(arg0,arg1,arg2);     console.log("ret = ",ret);     return ret; } 

此时我们可以看到传入的三个参数,如下图:
在这里插入图片描述
至此我们已经看到了输入的明文账号和密码,以及加密后的数据。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!