吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 14|回复: 0
收起左侧

[Android 原创] TikTok 45.4.3 抓包之双网络栈证书校验分析

[复制链接]
lichuntian00 发表于 2026-6-4 17:21
本帖最后由 lichuntian00 于 2026-6-5 08:53 编辑

工具链:google px4真机、proxypin 1.2.7、IDA 9.0。
某海外社交app。
先hook下connect函数,看下app使用的网络请求库有哪些。
图片1.png
可以看到网络请求是从libsscronet,so发起的,打开ida分析。
图片2.png
原来使用的是Cronet网络请求库。
源码地址在 https://chromium.googlesource.com/chromium/src/+/main/components/cronet/
net/socket/ssl_client_socket_impl.cc文件的 SSL_CTX_set_custom_verify是关键函数。
这里要注意,不是劫持该函数的返回值(在这里把返回值2改成0的没有用),而是修改它的第3个参数,证书验证回调。
Certificate is already set andVerifyCertChain has begun 这是特征字符串。
图片3.png
交叉引用定位到sub_2A0464,这个函数是VerifyCertChain的实现。
继续交叉引用。
图片4.png
是虚函数表。
图片5.png
那么,这里不能直接交叉引用找了,估计是BLR  X8间接调用了。
图片6.png
太多了,动态hook吧。
图片7.png 0x488570
这里发起的间接调用。
图片8.png
反汇编。
图片9.png
图片10.png
这一行对应的是BLR X8间接调用。
在函数sub_4884C4内调用的这个函数就是从ssl对象中调用证书链验证器。
交叉引用到。
图片11.png
sub_4899AC对应。
图片12.png
是tls_handshaker的verifycallback状态机。
注意这是quic验证的路径交叉引用。
图片13.png

图片14.png
这个就是传递给SSL_CTX_set_custom_verify的第三个参数,把返回值改了就行。
图片15.png
先返回2,再返回0。
先异步,再成功。
这是quic的证书验证链。
我开启Proxypin代理的时候,发现这一整条链路根本没被调用,走的是另一条verifycallback,也就是tcp 证书验证链。
继续交叉引用。
图片16.png
这个函数sub_41C7C0 对应的是quic证书验证回调。
继续交叉引用。
图片17.png
图片18.png
这里对应的是tcp验证链,所以要hook 2C7104返回0。
抓包看看。
Screenshot_20260604-163546.png
Screenshot_20260604-163623.png
抓包脚本。
[JavaScript] 纯文本查看 复制代码
'use strict';

const LIB_NAME = "libsscronet.so";
const OFF_SUB_2C7104 = 0x2C7104;

let hooked = false;

function info(addr) {
    try {
        const p = ptr(addr);
        const m = Process.findModuleByAddress(p);
        if (!m) {
            return p + " <unknown> " + DebugSymbol.fromAddress(p);
        }
        return p + " " + m.name + "!" + p.sub(m.base) + " " + DebugSymbol.fromAddress(p);
    } catch (e) {
        return addr + " <bad>";
    }
}

function hookSub2C7104() {
    if (hooked) {
        return;
    }

    const base = Module.findBaseAddress(LIB_NAME);
    if (!base) {
        return;
    }

    hooked = true;

    const target = base.add(OFF_SUB_2C7104);

    console.log("[+] " + LIB_NAME + " base =", info(base));
    console.log("[+] hook sub_2C7104 =", info(target));

    Interceptor.attach(target, {
        onEnter: function (args) {
            this.tid = Process.getCurrentThreadId();

            console.log("\n[+] sub_2C7104 ENTER");
            console.log("    tid       =", this.tid);
            console.log("    arg0/ssl  =", args[0]);
            console.log("    arg1/alert=", args[1]);
            console.log("    lr        =", info(this.context.lr));
        },

        onLeave: function (retval) {
            console.log("[+] sub_2C7104 LEAVE");
            console.log("    tid             =", this.tid);
            console.log("    original retval =", retval);

            retval.replace(0);

            console.log("    patched retval  = 0");
        }
    });
}

function hookDlopen() {
    hookSub2C7104();

    const android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
    if (!android_dlopen_ext) {
        console.log("[-] android_dlopen_ext not found");
        return;
    }

    Interceptor.attach(android_dlopen_ext, {
        onEnter: function (args) {
            this.match = false;

            try {
                if (args[0]) {
                    const path = args[0].readCString();
                    if (path.indexOf(LIB_NAME) >= 0) {
                        this.match = true;
                        console.log("[+] dlopen:", path);
                    }
                }
            } catch (e) {}
        },

        onLeave: function (retval) {
            if (this.match && !retval.isNull()) {
                hookSub2C7104();
            }
        }
    });
}

setImmediate(hookDlopen);

任何版本抓包。
[JavaScript] 纯文本查看 复制代码
setImmediate(function () {
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), {
        onEnter: function (args) {
            this.soPath = args[0].readCString();
        },
        onLeave: function (retval) {
            if (this.soPath && this.soPath.indexOf("libsscronet.so") >= 0) {
                var addr = Module.findExportByName("libsscronet.so", "SSL_CTX_set_custom_verify");
                
                Interceptor.attach(addr, {
                    onEnter: function (args) {
                        Interceptor.attach(args[2], {
                            onLeave: function (retval) {
                                retval.replace(0);
                            }
                        });
                    }
                });
            }
        }
    });
});

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-6-5 10:18

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表