某团mtgsig2.3-unidbg

这篇具有很好参考价值的文章主要介绍了某团mtgsig2.3-unidbg。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

只作学习研究,禁止用于非法用途,否则后果自负,如有侵权,请告知删除,谢谢!

最新的版本应该是2.4还是2.5了, 但是用unidbg调试会失败,所以用老版本2.3,但是api请求依然会403,所以只能构造出mtgsig(具体原因后面分析有写)

更新: 现在这版本的app已经无法正常使用了 让升级最新版本 文章看一看就好

开搞:

环境配置

软件 作用
jadx-gui 反编译
frida-16.0.10 hook

参考项目: https://github.com/irabbit666666/unidbg-mt-server23

0x1 jadx反编译分析

搜索mtgsig 找到这个类
某团mtgsig2.3-unidbg
某团mtgsig2.3-unidbg
应该是在这个getRequestSignature生成
某团mtgsig2.3-unidbg
进入这个a.a()方法,没有反编译出java代码, 但是可以看到是有put操作的
某团mtgsig2.3-unidbg

直接hook这个CommonCandyInterceptor.getRequestSignature会报错ClassNotFound,搜了一下好像是动态加载的原因,需要先找到classLoader,根据源码分析了一下大致的参数
public String getRequestSignature(String str, URI uri, String str2, String str3, String str4, byte[] bArr)

// 由于是动态加载 需要先找到classLoader 测试为loader的最后一个
function hook_getRequestSignature_with_loader() {
    // hook 动态加载的dex 类, 以及查看类的类名
    Java.perform(function () {
        // hook 动态加载的 dex
        console.log('----寻找loader start----');
        let loaders = new Array();
        Java.enumerateClassLoaders({
            onMatch(loader) {
                console.log(`找到loader: ${loader}`);
                loaders.push(loader);
            },
            onComplete() { }
        })
        console.log('----寻找loader end----');
        console.log(`共找到${loaders.length}个loader`);
        if (loaders.length == 0) {
            return;
        }
        // 测试为最后一个loader 设置为需要使用的类加载器
        const currentLoder = loaders[loaders.length - 1]
        Java.classFactory.loader = currentLoder;
        console.log(`设置loader为: ${currentLoder}`);
		
		const class_name = "com.meituan.android.common.mtguard.wtscore.plugin.sign.interceptors.CommonCandyInterceptor";
   	 	const CommonCandyInterceptor = Java.classFactory.use(class_name);
	    /**
	     * 
	     * @param {*} str1 猜测为post/get 即method 不区分大小写
	     * @param {*} uri 猜测为url
	     * @param {*} str2 猜测为useragent/useragent不存在则为固定值
	     * @param {*} str3 HttpHeaders.CONTENT_ENCODING gzip等
	     * @param {*} str4 猜测为Content-Type
	     * @param {*} bArr inputStream转byte[] 
	     */
	    CommonCandyInterceptor.getRequestSignature.implementation = function (str1, uri, str2, str3, str4, bArr) {
	        console.log('getRequestSignature start');
	
	        console.log(`str1: ${str1}`);
	        console.log(`uri: ${uri}`);
	        console.log(`str2: ${str2}`);
	        console.log(`str3: ${str3}`);
	        console.log(`str4: ${str4}`);
	        console.log(`bArr: ${bArr}`);
	        // 生成的mtgsig
	        const ret = this.getRequestSignature(str1, uri, str2, str3, str4, bArr);
	        console.log(ret);
	
	        console.log('getRequestSignature end');
	        return ret;
	    };        

    });
}

运行没有报ClassNotFound, 但是也不打印任何信息, 不应该啊,直接hook生成试试

function hook_mock_getRequestSignature() {
    console.log('hook start');
    const class_name = "com.meituan.android.common.mtguard.wtscore.plugin.sign.interceptors.CommonCandyInterceptor";
    const String = Java.use("java.lang.String");
    const URI = Java.use("java.net.URI");
    Java.perform(() => {
        const CommonCandyInterceptor = Java.use(class_name);
        const instance = CommonCandyInterceptor.$new();
        const str1 = String.$new("post");
        const uri = URI.$new("https://test.com/test");
        const str2 = String.$new("unknown");
        const str3 = String.$new("gzip");
        const str4 = String.$new("unknown");
        const bArr = Java.array('byte', [13, 37, 42, 66]);
        const ret = instance.getRequestSignature(str1, uri, str2, str3, str4, bArr);
        console.log(ret);

        CommonCandyInterceptor.getRequestSignature.implementation = function (str1, uri, str2, str3, str4, bArr) {
            console.log('getRequestSignature start');
    
            console.log(`str1: ${str1}`);
            console.log(`uri: ${uri}`);
            console.log(`str2: ${str2}`);
            console.log(`str3: ${str3}`);
            console.log(`str4: ${str4}`);
            console.log(`bArr: ${bArr}`);
            // 生成的mtgsig
            const ret = this.getRequestSignature(str1, uri, str2, str3, str4, bArr);
            console.log(ret);
    
            console.log('getRequestSignature end');
            return ret;
        };
    });
}

可以正常生成没问题,但是看了其他人的文章都会加载一个so,看看这个a.a()试试
这里确实调用了NBridge.main3()
某团mtgsig2.3-unidbg
某团mtgsig2.3-unidbg
NBridge.main3()调用main, main是一个native函数,果然有蹊跷
某团mtgsig2.3-unidbg
这里的main1和main3都会调用native main方法
NBridge里并没有发现System.loadLibrary方法, so不是在这个文件加载的

搜索NBridge.main试试, 这里有一个Init,点进去看看
某团mtgsig2.3-unidbg
看样子确实是有初始化操作,然后执行NBridge.main(4, new Object[1])
某团mtgsig2.3-unidbg
这里MTGConfigs.b = "mtguard" 加载的是libmtguard.so文件, 第二行debug语句也能看出来
某团mtgsig2.3-unidbg
某团mtgsig2.3-unidbg
加载完成后会调用NBridge.main3(1, new Object[]{sAppKey}), 这个也是后续unidbg要做的事情, 进行初始化,这里的sAppKey可以在AndroidManifest里找到
某团mtgsig2.3-unidbg
某团mtgsig2.3-unidbg
接下来hook一下main方法

function hook_main() {
    Java.perform(() => {
        const NBridge = Java.use("com.meituan.android.common.mtguard.NBridge");
        const String = Java.use("java.lang.String");
        const JavaByte = Java.use("[B");
        NBridge.main.implementation = function (i, args) {

            console.log('------- start -------');
            console.log(`参数(int)i ${i}`);
            console.log(`args length ${args.length}`)
            for (let i = 0; i < args.length; i++) {
                try {
                    // 强转为byte 不行的话直接走catch直接输出
                    const buffer = Java.cast(args[i], JavaByte);
                    // 创建byte数组
                    const result = Java.array('byte', buffer);
                    // 转string输出
                    const foramtStr = String.$new(result);
                    console.log(`格式化args[${i}] ${foramtStr}`);
                } catch (e) {
                    console.log(`普通args[${i}] ${args[i]}`);
                }
            }
            const ret = this.main(i, args);
            console.log('ret---')
            console.log(ret)

            console.log('------- end -------');
            return ret;
        }
    });
}

某团mtgsig2.3-unidbg
确实和分析的一样, 加载so后会调用NBridge.main3(1, new Object[]{"appKey"}), 返回0则init成功
某团mtgsig2.3-unidbg

0x2 unidbg调试

知道逻辑后就开始unidbg, 先搭好架子, 参考这个项目 (可以直接copy就用), 跑起来没问题

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.EmulatorBuilder;
import com.github.unidbg.Module;
import com.github.unidbg.file.FileResult;
import com.github.unidbg.file.IOResolver;
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.DvmClass;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.memory.Memory;

import java.io.File;

public class MtgsigHook extends AbstractJni implements IOResolver {

    private final AndroidEmulator emulator;
    private final VM vm;
    private final Module module;

    private final DvmClass NBridge;

    private static final String BASE_PATH = System.getProperty("user.dir") + "/data";
    private static final String APK_PATH = BASE_PATH + "/meituan.APK";

    public static void main(String[] args) {
        MtgsigHook hook = new MtgsigHook(true);
    }
    public MtgsigHook(boolean debug) {
        // 创建模拟器实例,要模拟32位或者64位,在这里区分
        EmulatorBuilder<AndroidEmulator> builder = AndroidEmulatorBuilder.for32Bit().setProcessName("com.sankuai.meituan");
        emulator = builder.build();
        // 模拟器的内存操作接口
        final Memory memory = emulator.getMemory();
        // 设置系统类库解析
        memory.setLibraryResolver(new AndroidResolver(23));

        // 创建Android虚拟机
        // vm = emulator.createDalvikVM(); // 只创建vm,用来读so,不加载apk
        vm = emulator.createDalvikVM(new File(APK_PATH));
        // 设置是否打印Jni调用细节
        vm.setVerbose(debug);
        vm.setJni(this);
        emulator.getSyscallHandler().addIOResolver(this);
        emulator.getSyscallHandler().setEnableThreadDispatcher(true);
        // 加载libttEncrypt.so到unicorn虚拟内存,加载成功以后会默认调用init_array等函数,这是直接读so文件
        // DalvikModule dm = vm.loadLibrary(TempFileUtils.getTempFile(LIBTT_ENCRYPT_LIB_PATH), false);
        // 这是搜索加载apk里的模块名,比如 libguard.so 那么模块名一般是guard
        DalvikModule dm = vm.loadLibrary("mtguard", false);
        // 手动执行JNI_OnLoad函数
        dm.callJNI_OnLoad(emulator);
        // 加载好的libttEncrypt.so对应为一个模块
        module = dm.getModule();

        dm.callJNI_OnLoad(emulator);
        NBridge = vm.resolveClass("com/meituan/android/common/mtguard/NBridge");
    }

    @Override
    public FileResult resolve(Emulator emulator, String s, int i) {
        System.out.println("pathname: " + pathname);
        return null;
    }
}

ps: 注意实现的这个接口IOResolver 后期需要用到

根据之前分析的逻辑, 写一个init调用试试

	private void init() {
        ArrayObject dvmObject = NBridge.callStaticJniMethodObject(emulator,
                "main(I[Ljava/lang/Object;)[Ljava/lang/Object;",
                1,
                ArrayObject.newStringArray(vm, "9b69f861-e054-4bc4-9daf-d36ae205ed3e"));
        String ret = dvmObject.getValue()[0].getValue().toString();
        int code = Integer.parseInt(ret);
        if (code != 0) {
            throw new RuntimeException("init失败: " + code);
        }
        System.out.println("init成功.");
    }

意料之中, 环境还没补全
某团mtgsig2.3-unidbg
补了两个classLoader后开始调用main2方法了
某团mtgsig2.3-unidbg
main2根据传入的int值返回对应的结果
某团mtgsig2.3-unidbg
注意调用main2的一定要补全, 不然直接返回null或者报错,

类/方法 需要补全
android/os/Build 补全机型信息
java/lang/System->getProperty 返回java.io.tmpdir和httpProxy信息
android/os/SystemProperties->get 基本上是获取一些usb信息
android/content/pm/ApplicationInfo->sourceDir 这里要求返回apk路径, 需要下一步使用

上面实现的IOResolver这时候就要用了, 第三个调用的就是apk路径
某团mtgsig2.3-unidbg
这里会读取apk,返回null的话会返回错误的状态码,init失败
最新版本的mtgsig这里返回apk会卡在这里,无法继续, 不知道什么原因
unidbg补完apk文件路径访问,并重定向到指定的apk文件后,程序一直卡住,不再往下运行了

某团mtgsig2.3-unidbg
补一下apk路径试试

	@Override
    public FileResult resolve(Emulator emulator, String pathname, int i) {
        System.out.println("pathname: " + pathname);
        if (pathname.equals("/data/app/com.sankuai.meituan-2nOCxLCJUl7lL3J_S7uSPA==/base.apk")) {
            return FileResult.success(new SimpleFileIO(i, new File(APK_PATH), pathname));
        }
        return null;
    }

某团mtgsig2.3-unidbg
写一个test试试调用, 生成mtgsig的参数 ->
private static native Object[] main(int i, Object[] objArr);

参数 类型 说明
i int 初始化为1,生成mtgsig为2,也有其他的功能
objArr[0] string appKey 固定值
objArr[1] byte[] 按[method params(按A-za-z排序) ]的byte数组
objArr[2] byte[] host -> byte[]
	public void callTest() {
        StringObject arg1 = new StringObject(vm, "9b69f861-e054-4bc4-9daf-d36ae205ed3e");
        ByteArray arg2 = new ByteArray(vm, "GET /TEST/aaa=aa?bbb=bb".getBytes(StandardCharsets.UTF_8));
        ByteArray arg3 = new ByteArray(vm, "test.com".getBytes(StandardCharsets.UTF_8));
        ArrayObject dvmObject = NBridge.callStaticJniMethodObject(emulator,
                "main(I[Ljava/lang/Object;)[Ljava/lang/Object;",
                2,
                new ArrayObject(arg1, arg2, arg3));
        String ret = dvmObject.getValue()[0].getValue().toString();
        JSONObject jsonObject = JSONObject.parseObject(ret);
        System.out.println(jsonObject.toString(JSONWriter.Feature.PrettyFormat));
    }

报错, 需要补充其他的main2返回值
某团mtgsig2.3-unidbg
补充main2() -> 51 8 40 后生成成功
这里也是生成mtgsig里的a7和a8, 这里使用了固定(你用中文都行)
根据源码分析和别人的分析应该是服务器返回,还具有失效时间 只能构造出来 但是不能正常请求接口(最后有写原因)

				if (cmd == 51) {
                    //StringBuilder sb = new StringBuilder();
                    //sb.append(b.b());
                    //return sb.toString();
                    return new StringObject(vm, "2");
                }
                if (cmd == 8) {
                    // return MTGuard.DfpId;
                    return new StringObject(vm, "DAD72CE6E36048C4F132B89C1A61D3388C232E4BEE586E86458EDC83".toLowerCase());
                }
                if (cmd == 40) {
                    // a7,xid
                    return new StringObject(vm, "ChC0KOFzrx6Q9nknGeNbKBnVmztAE6LW2nMYbiTF+hjmHkf/ToA8SDLjODLlnPYhI4dat1iPZmZtHGm7NiPJLkhSwZzjBhbcTSP7RkK7kNk=");
                }

某团mtgsig2.3-unidbg
可以看到a7和a8就是上面填写的 一模一样

0x3 后续分析

相对于初始化,多出来的3个参数

参数 实际参数 作用(猜测)
51 b.b() 获取的应该是应用是否在运行, 返回2运行中 1没有运行
8 MTGuard.DfpId 设备指纹信息
40 SyncStoreManager.sXid.id 跟上面DfpId一样,也是一种设备Id

main2(51) 获取的应该是应用是否在运行, 返回2运行中 1没有运行
某团mtgsig2.3-unidbg
某团mtgsig2.3-unidbg
main2(8) 获取设备指纹信息, 可以看出就是mtgsig里a7的值,这里的dfpid应该是服务器生成再下发给客户端的, 在文章美团mtgsig2.1和mtgsig1.5区别里也提到 a7,a8是后台返回的
某团mtgsig2.3-unidbg
main2(40)获取xid, 也是跟设备信息有关,具有失效时间。这里也是作为a7的值某团mtgsig2.3-unidbg
所以只能生成mtgsig,用于请求的话a7, a8字段肯定是error的, 会返回403
所以只能生成mtgsig,用于请求的话a7, a8字段肯定是error的, 会返回403
所以只能生成mtgsig,用于请求的话a7, a8字段肯定是error的, 会返回403

通过main也可以生成xid和dfpId,由于是服务端下发,当然也不会生效

	public String getRandomDfpId() {
        ArrayObject dvmObject = NBridge.callStaticJniMethodObject(emulator, "main(I[Ljava/lang/Object;)[Ljava/lang/Object;", 47, new ArrayObject());
        String dfpId = dvmObject.getValue()[0].getValue().toString();
        System.out.println("dfpId: " + dfpId);
        return dfpId.toLowerCase(Locale.ROOT);
    }

    public String getRandomXid() {
        ArrayObject dvmObject = NBridge.callStaticJniMethodObject(emulator, "main(I[Ljava/lang/Object;)[Ljava/lang/Object;", 48, new ArrayObject());
        String xid = dvmObject.getValue()[0].getValue().toString();
        System.out.println("xid: " + xid);
        return xid;
    }

相当于main(47) main(48) 是生成a7 a8
main(8) main(40) 是获取a7 a8
但是生成的a7 a8可能是要经过服务器的 你直接构造出来是无法使用的文章来源地址https://www.toymoban.com/news/detail-464354.html

到了这里,关于某团mtgsig2.3-unidbg的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【自制C++深度学习框架】前言

    此GitHub项目是一个初学者的深度学习框架,使用C++编写,旨在为用户提供一种简单、易于理解的深度学习实现方式。以下是本项目的主要特点和功能: 计算图:使用计算图来描述深度学习模型的计算过程,利用计算图将神经网络的计算过程视为一个有向无环图。通过构建计算

    2024年02月07日
    浏览(35)
  • Gowin FPGA学习记录——前言

            好久没有写博客了,想想是不是又该写点啥东西了么,准备写点国产FPGA的使用经历吧                  得益于目前国内的政策对国产化芯片扶持,越来越要求核心器件能够自主可控,因此作为核心芯片FPGA,国产FPGA的势头也发展很快。          现在FPGA的这

    2024年02月16日
    浏览(34)
  • FPGA学习实践之旅——前言及目录

    很早就有在博客中记录技术细节,分享一些自己体会的想法,拖着拖着也就到了现在。毕业至今已经半年有余,随着项目越来越深入,感觉可以慢慢进行总结工作了。趁着2024伊始,就先开个头吧,这篇博客暂时作为汇总篇,记录在这几个月以及之后从FPGA初学者到也算有一定

    2024年02月03日
    浏览(43)
  • 大数据、人工智能、机器学习、深度学习关系联系前言

    1.大数据和人工智能关系 2.机器学习、深度学习、人工智能关系 3.监督学习、无监督学习、半监督学习、强化学习、迁移学习关系 4.机器学习具体内容 1.数据驱动的人工智能 :人工智能系统需要大量的数据来进行训练和学习。大数据提供了海量的信息,可以用于训练机器学习

    2024年02月12日
    浏览(49)
  • 【C++初阶(一)】学习前言以及命名空间

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C++初阶之路⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习排序知识   🔝🔝 对于复杂的问题,规模较大的程序 需要高度的抽象和建模时 C语言不再适合应用于这种场景 于是在1982年 C++创始人 Bjarne Stroustrup 在C语言

    2024年02月11日
    浏览(45)
  • JS逆向之大众点评mtgsig

    本教程仅限于学术探讨,也没有专门针对某个网站而编写,禁止用于非法用途、商业活动、恶意滥用技术等,否则后果自负。观看则同意此约定。如有侵权,请告知删除,谢谢! 目录 前言 一、先分析下接口参数 二、开导mtgsig 1.找加密入口 2.扣算法 3.验证算法 最近了工作也

    2024年02月08日
    浏览(64)
  • Linux tcp/ip 网路协议栈学习-00 前言

    Linux tcp/ip 网路协议栈学习-00 前言 目录 Linux  tcp/ip 网路协议栈学习-00 前言 (1)预备知识  (2)前置知识 (3)学习目标 (4)总结     (1)预备知识  好工具事半功倍,做任何事情都需要有方法和工具,同样,阅读 Linux 内核源码也是如此。由于当前内核源码非常庞大,学习上,不能一

    2024年04月26日
    浏览(33)
  • 【C++初阶(一)】学习前言 命名空间与IO流

    本专栏内容为:C++学习专栏,分为初阶和进阶两部分。 通过本专栏的深入学习,你可以了解并掌握C++。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:C++ 🚚代码仓库:小小unicorn的代码仓库🚚 🌹🌹🌹关注我带你学习编程知识 C++是基于C语言而产生的,它既可以进行C语言的

    2024年02月08日
    浏览(88)
  • Web逆向-mtgsig1.2简单分析

    PS:  基于某评微信小程序的guard.js文件, 且文件经过简单的ast脱混淆. 1. 收集的环境 1.1 环境加密逻辑( a6 ). 主要是找到收集了哪些环境, 以及环境对应的值. 加密函数中只有常见的加密运算符, 没有检测环境的异常分支或其他坑. 所以逆向中遇到的加密函数直接 复制粘贴到自己

    2024年02月03日
    浏览(28)
  • 【C++初阶】前言——C++的发展简述及学习方法分享

     ========================================================================= 主页点击直达: 个人主页 我的小仓库: 代码仓库 C语言偷着笑: C语言专栏 数据结构挨打小记: 初阶数据结构专栏 Linux被操作记: Linux专栏 LeetCode刷题掉发记: LeetCode刷题 算法: 算法专栏  C++头疼记: C++专栏 ====

    2024年02月08日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包