某某热点app登录sign值逆向分析
北海 发表于 广东 技术文章 551浏览 · 2024-11-30 03:09

环境

淘最热点app 2.6.6
pixel2

正文

来到登录点

针对登录点进行抓包

系统代理抓不到包,于是尝试vpn代理,成功抓到了

下面来分析一下sign值是怎么生成的

使用网上大神的java层算法自吐脚本来hook一下,打印调用栈
java层算法自吐脚本:https://blog.51cto.com/u_13389043/6230053

使用jadx反编译apk

不过在分析MhRequestUtil类之前,先来看看wifi代理无法抓包的原因

System.getProperty是java中的一个方法,它用于获取系统属性。系统属性是一些在java虚拟机启动时被设置的属性,它们可以包含关于系统环境的信息。
其中,http.proxyHost这个属性表示HTTP代理服务器的主机名。如果这个属性被设置了,它通常意味着系统或应用程序配置了HTTP代理。http.proxyPort这个属性表示HTTP代理服务器的端口号。如果这个属性被设置了,它通常与http.proxyHost一起使用,以指示代理服务器的完整地址

搜索getProperty关键字

果然这里设置了http代理检测,如果检测到存在代理,那么返回true

通过快捷键X查看交叉引用

进入第一个查看,可以直到这段代码是向服务器发送一个包含设备信息和应用信息的POST请求,并根据服务器的响应来更新应用程序的状态,但是如果CommUtils.a函数(即:代理检测方法)返回true就直接return了

弄清楚代理检测之后,回归到sign追溯分析

搜索 com.maihan.tredian.net.MhRequestUtil类,可以看到sign这个函数

map.put("sign", TreUtil.sign(a(map, false, false)));

先下拉看看a方法

编写代码hook一下
先不重载参数

可以通过报错看到参数类型: .overload('java.util.Map', 'boolean', 'boolean')

最终hook代码

function hook_a(){
    Java.perform(function () {
        var MhRequestUtil = Java.use("com.maihan.tredian.net.MhRequestUtil");

        MhRequestUtil.a.implementation = function (a1, a2, a3) {
            var ret = this.a(a1, a2, a3);
            console.log("a=======================>:" + ret);
            return ret;
        }
    })
}
function main() {
    hook_a();
}
setImmediate(main);

hook结果

sign函数应该是对这个字符串进行处理

android_id=c7d6e3b83a3ea950&app_ver=87&channel=aliapp&code=1234&device_id=3f4cd28edd6f18f9b5e7abf46c806f35&device_name=google Pixel 2&device_udid=aa8665f814b51ac0231cc7960a586c0d&from=app&getui_push_id=722ec4b874f67b5d1f96de6e757da7d4&imei1=&imei2=&mac=9A:E2:8A:ED:F5:A3&nonce=67wqsl1732873801016&os_ver_code=29&phone=11111111111&system=1&timestamp=1732873801

追溯这个sign函数发现它是一个jni函数

接着找到libtre.so文件


pull下来,使用ida反编译
然后搜索sign函数

修改第一个参数为JNIEnv*


修改了之后就可以看到一些函数出现了

通过简单分析,可以发现其核心功能是对Java层传入的字符串进行签名处理,具体步骤如下:

  • 使用GetStringUTFChars从JNI环境获取Java字符串的C风格字符串表示。

  • 将获取的字符串与一个固定的字符串(可能是密钥)拼接。

  • 用j_base64_encode_new函数对拼接后的字符串进行处理。

  • 使用j_SHA1Input和j_SHA1Result对前面的结果进行处理

  • 将前面的结果转换为十六进制字符串。

  • 最终将十六进制字符串转换为Java字符串并返回。

由分析可知,sign函数中使用了j_base64_encode_new,j_SHA1Input和j_SHA1Result对字符串进行了处理。通过他们的名字判断可能是base64和sha

接下来我们通过hook来验证我们的判断
网上大神的hook代码

function print_arg(addr){
    try {
        var module = Process.findRangeByAddress(addr);
        if(module!= null){
            return hexdump(addr) + "\n";
        }
        return ptr(addr) + "\n";
    } catch (e) {
        console.error("Error in print_arg while processing address: ", addr, e);
        return "Error processing address" + "\n";
    }
}
function hook_native_addr(funcPtr, paramsNum){
    var module = Process.findModuleByAddress(funcPtr);
    Interceptor.attach(funcPtr, {
        onEnter: function(args) {
            this.logs = []
            this.params = []
            this.logs.push("call" + module.name + "!!!!!" + ptr(funcPtr).sub(module.base) + "\n")
            for(var i=0; i<paramsNum; i++){
                this.params.push(args[i])
                this.logs.push("这里是参数----->>>this.arg" + i + "进入:" + print_arg(args[i]))
            }
        }, onLeave: function(retval) {
            for(let i=0; i<paramsNum; i++){
                this.logs.push("这里是参数----->>>this.arg" + i + "返回:" + print_arg(this.params[i]))
            }
            this.logs.push("这里是返回值------>>>retval 离开:" + print_arg(retval) + "\n")
            console.log(this.logs)
        }
    })
}

function hook_sha1result() {
    console.log("Searching for module: libtre.so");
    var soAddr = Module.findBaseAddress("libtre.so");
    if (soAddr === null) {
        console.error("Module not found: libtre.so");
    } else {
        console.log("Module found at address: " + soAddr);
        // 继续执行 hook 代码
        var SHA1Result = soAddr.add(0x14C8 + 1);
        hook_native_addr(SHA1Result, 2);
    }
}

function hook_base64(){
    console.log("Searching for module: libtre.so");
    var soAddr = Module.findBaseAddress("libtre.so");
    if (soAddr === null) {
        console.error("Module not found: libtre.so");
    } else {
        console.log("Module found at address: " + soAddr);
        // 继续执行 hook 代码
        var Base64 = soAddr.add(0x13B4 + 1);
        hook_native_addr(Base64, 3);
    }
}

setImmediate(hook_sha1result());

hook一下发现确实是这个sign函数产生了我们请求包的sign值,说明我们追溯的函数没错

hook一下base64函数
可以看出是把请求包的基本参数传入作为明文

由于hexdump截断了,我们另写脚本打印arg0和retvar

function main(){
    console.log("Searching for module: libtre.so");
    var soAddr = Module.findBaseAddress("libtre.so");
    if (soAddr === null) {
        console.error("Module not found: libtre.so");
    } else {
        console.log("Module found at address: " + soAddr);
        // 继续执行 hook 代码
        var Base64 = soAddr.add(0x13B4 + 1);
    }
    var module = Process.findModuleByAddress(Base64);
    Interceptor.attach(Base64, {
        onEnter: function(args) {
            console.log("明文为----------------->>>",args[0].readCString());

        }, onLeave: function(retval) {
            console.log("编码后----------------->>>",retval.readCString());

        }
    })
}
setImmediate(main);

hook结果如下

使用在线解码网站可以确认就是base64编码

同时我们也可以在base64_encode_new中找到字母表

接着来确认一下sha1
通过对比也可以确认是sha1

到此,对请求包中sign值生成的分析就结束了

0 条评论
某人
表情
可输入 255
目录