4.4 美团

笔者的 app 版本:11.13.408

加密定位

搜索关键字:mtgsig

点进去看看,发现是一个类变量

查找用例看看都有什么地方在使用

发现只有 7 个位置,我们需要重点关注 xxx.put 的位置,这些才是放置参数的代码,所以有以下几个位置:

jSONObject3.put(MTGConfigs.MTG_SIG_HEADER, new JSONObject((Map) this.mRequestSignatureMethodV4.invoke(null, optString, optString2, optString3, optString4, optString5, bArr)));


hashMap.put(MTGConfigs.MTG_SIG_HEADER, commonCandyInterceptor.getRequestSignature(str, uri, str2, str3, str4, bArr));

hashMap.put(MTGConfigs.MTG_SIG_HEADER, makeHeader);

createMap.putString(MTGConfigs.MTG_SIG_HEADER, com.sankuai.waimai.store.util.h.a((Map) this.mRequestSignatureMethodV4.invoke(null, string, a2, string3, string4, string5, bArr)));

逐个去分析,最后是用的第三个找到的,步骤如下:

加密入口为:com.meituan.android.common.mtguard.NBridge.main

使用 Frida 进行验证

let NBridge = Java.use("com.meituan.android.common.mtguard.NBridge");
        NBridge["main"].implementation = function (i, objArr) {

            let result = this["main"](i, objArr);
            HookBox.log(
                "NBridge.main",
                0,
                `i=${i}`,
                `objArr=${objArr}`,
                `result=${result}`,
            )



            return result;
        };

发现好像没什么问题!

so 文件定位

知道了加密入口,要定位 so 文件就更简单了,我们只需要 hook 一下 registNatives 就可以了,脚本在:https://raw.githubusercontent.com/lasting-yang/frida_hook_libart/master/hook_RegisterNatives.js

不做介绍, so 文件为 libmtguard.so

unidbg

1. 模板搭建

package com.meituan;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.AbstractJni;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.memory.Memory;

import java.io.File;

public class mtgsig extends AbstractJni {
    private final AndroidEmulator emulator;
    private final VM vm;
    private final String dirPath = "unidbg-android/src/test/resources";
    private final Module module;

    mtgsig() {
        // 模拟器,设置进程名为 com.sankuai.meituan
        emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.sankuai.meituan").build();
        // 模拟器的内存操作接口
        final Memory memory = emulator.getMemory();
        // 23版本的sdk
        memory.setLibraryResolver(new AndroidResolver(23));
        vm = emulator.createDalvikVM(new File(dirPath + "/mt1113408.apk"));
        // 打印日志
        vm.setVerbose(true);
        // 设置JNI,类必须extends AbstractJni -> 用于补环境
        vm.setJni(this);
        // 加载 so 文件, 因为传入 app, 所以可以直接写 so 文件的名字, 去掉 开头的 lib 和 结尾的 .so
        DalvikModule dm = vm.loadLibrary("mtguard", true);
        module = dm.getModule(); // 获取so模块的句柄
        dm.callJNI_OnLoad(emulator); // 调用JNI_OnLoad
    }

    public static void main(String[] args) {
        mtgsig ins = new mtgsig();
    }

}

搭完架子之后运行,发现其有几个 so 文件依赖,我们可以补一下

![image-20230609104908876](/Users/Kem/Library/Application Support/typora-user-images/image-20230609104908876.png)

new JniGraphics(emulator, vm).register(memory);
new AndroidModule(emulator, vm).register(memory);

补完之后运行,发现还有一个依赖的 so 文件, 先不补了

![image-20230609105207644](/Users/Kem/Library/Application Support/typora-user-images/image-20230609105207644.png)

2. 入参构建

构建很简单,使用 frida hook 一下,分析参数,然后自己构造即可,需要注意的就是里面有一个参数不好打印,可以使用以下脚本

function b2s(array) {
    var buffer = Java.array('byte', array);
    var result = "";
    for (var i = 0; i < buffer.length; ++i) {
        result += (String.fromCharCode(buffer[i] & 0xff)); // here!!
    }
    return result
}


let NBridge = Java.use("com.meituan.android.common.mtguard.NBridge");
        NBridge["main"].implementation = function (i, objArr) {

            let result = this["main"](i, objArr);
            if (i === 2) {
                console.log(objArr[1].$className)
                HookBox.log(
                    "NBridge.main",
                    0,
                    `i=${i}`,
                    `objArr[0]=${objArr[0]}`,
                    `objArr[1]=${b2s(objArr[1])}`,
                    `objArr[2]=${objArr[2]}`,
                    `result=${result}`,
                )
            }






            return result;
        };

可以看出来参数都是什么

3. 模拟调用

先编写一个调用方法

    public void callMain() {
        DvmClass clazz = vm.resolveClass("com/meituan/android/common/mtguard/NBridge");

        StringObject appkey = new StringObject(vm, "9b69f861-e054-4bc4-9daf-d36ae205ed3e");
        vm.addLocalObject(appkey);

        String urlObj = "GET /abtest/v1/getAllStrategys __reqTraceID=5a7a93aa-1a0b-4e67-b27c-95f5e3f59c18&app=group&ci=1&msid=&platform=android&userid=-1&utm_campaign=AgroupBgroupC0E0Ghomepage&utm_content=ef9abda42ada49248c5c4c4c45443fbea167994434606354397&utm_medium=android&utm_source=yijia5&utm_term=1100130408&uuid=0000000000000F4D4F832198E4FDA96343456BADD2441A167994434590459712&version_name=11.13.408";
        ByteArray urlBytes = new ByteArray(vm, urlObj.getBytes());


        DvmObject<?> ret = clazz.callStaticJniMethodObject(
                emulator,
                "main(I[Ljava/lang/Object;)[Ljava/lang/Object;",
                2,
                vm.addLocalObject(new ArrayObject(appkey, urlBytes, null))
        );

        System.out.println("================================================");
        System.out.println(ret.getValue());
        System.out.println("================================================");
    }

调用一下试试,发现直接报错了

果然大厂没有这么容易,猜测可能是有什么初始化的步骤,先分析一下源码看看能不能找到,使用查找用例

发现第一行可能是的,那就先试试,在调用函数之前主动初始化一下,发现结果还是不行!

所以直接用 frida hook 一下,看看在调用 main 之前都做了什么

let NBridge = Java.use("com.meituan.android.common.mtguard.NBridge");
        NBridge["main"].implementation = function (i, objArr) {

            let result = this["main"](i, objArr);
            HookBox.log(
                "NBridge.main",
                0,
                `i=${i}`,
                `objArr=${objArr}`,
            
                `result=${result}`,
            )






            return result;
        };

查看日志发现调用了 1 和 3,我们都写上看看

public void callInit() {
    DvmClass clazz = vm.resolveClass("com/meituan/android/common/mtguard/NBridge");
    clazz.callStaticJniMethodObject(
            emulator,
            "main(I[Ljava/lang/Object;)[Ljava/lang/Object;",
            1,
            vm.addLocalObject(new ArrayObject())
    );
    clazz.callStaticJniMethodObject(
            emulator,
            "main(I[Ljava/lang/Object;)[Ljava/lang/Object;",
            3,
            vm.addLocalObject(new ArrayObject())
    );

}

再跑一下,发现跑通了,简直不要太 nice!

4. 环境补充

开始枯燥的补环境了!

com/meituan/android/common/mtguard/NBridge->getClassLoader()Ljava/lang/ClassLoader;

要参考一下 jadx 里面的代码来补环境

case "com/meituan/android/common/mtguard/NBridge->getClassLoader()Ljava/lang/ClassLoader;":
    return vm.resolveClass("dalvik/system/PathClassLoader").newObject(this.getClass().getClassLoader());

java/lang/ClassLoader->loadClass(Ljava/lang/String;)Ljava/lang/Class;

最后更新于

这有帮助吗?