一、tiktok抓包sslpinning绕过
tiktok使用了Chomium的网络协议栈组件Cronet,位于apk lib目录下libsscronet.so,sslpinning功能通过导入ssl库函数SSL_CTX_set_custom_verify实现,可以将第二个参数校验模式置0,或者第三个参数回调函数的返回值置0完成绕过。
方式一:hook绕过
// frida -U --no-pause -f com.zhiliaoapp.musically -l ./ttandroidpass.js
function main() {
try {
console.log('66666');
var android_dlopen_ext = Module.getExportByName(null, 'android_dlopen_ext');
console.error("android_dlopen_ext -->", android_dlopen_ext);
if (android_dlopen_ext) {
console.log('55555');
Interceptor.attach(android_dlopen_ext, {
onEnter: function (args) {
var soName = args[0].readCString();
console.log("soName -->", soName);
console.log(soName.indexOf('libsscronet.so'));
if (soName.indexOf('libsscronet.so') != -1) {
console.log('77777');
this.hook = true;
}
}, onLeave: function () {
if (this.hook) {
console.log('88888');
console.error('启动成功');
var scronet = Module.findBaseAddress("libsscronet.so");
var ver = Module.findExportByName("libsscronet.so", "SSL_CTX_set_custom_verify");
var custome_verify = new NativeFunction(ver, 'pointer', ['pointer', 'int', 'pointer']);
var self = new NativeCallback(function (arg1, arg2, arg3) {
console.log("custom_verify is calling", arg2, arg3);
return custome_verify(arg1, 0, arg3);
}, 'pointer', ['pointer', 'int', 'pointer']);
Interceptor.replace(ver, self);
console.log('注入成功')
}
}
});
}
} catch (error) {
console.error("find error: ", error);
}
}
setImmediate(main);
方式二:patch绕过
来回调函数返回处,利用异常退出代码的8字节空间进行插入MOV X0, #0的指令,做到修改的代码最少,修改的点位最少的效果。
patch前:
patch后:
二、加密参数定位
hook libc strlen函数可以看到请求头中的四个加密参数X-Argus、X-Gorgon、X-Khronos、X-Ladon来自libmetasec_ov.so。根据网上搜索的文章,libmetasec_ov.so在java层的native函数就是调用加密参数算法的接口,需要的数据为url和header字符串,生成加密参数。
通过hook JNI registerNative方法,打印metasec在java层的native方法:
Name[ms.bd.o.k a] Sig[(IIJLjava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;] Addr[0x77f063f43c]
但是在参数和返回值里根本看不到相关的数据,与网上文章的经验并不适用,推测是因为我使用的是最新版本的tiktok。
再次进行定位,重点关注网络库libsscronet.so对libmetasec_ov.so的调用,这里应该是最直接调用加密算法的地方,成功定位到libsscronet.so 对 libmetasec.so中的加密函数的调用,最终sscronet调用metasec的地方,sscronet的0x37C294跳转x23方法,x23的地址为metasec的0x7C3D0。
sscronet中特征值"x-metasec-bypass-ttnet-features"和"Tt-Forbid-Reuse: 1"快速定位到BLR X23间接跳转的地址
第一个参数为url,第二个参数为header,返回值是最终的加密参数结果。
第一个参数为url
第二个参数为header
返回值
三、主动调用验证
为了快速验证这四个加密参数是否会带来提量效果,先使用黑盒调用测试一下。
黑盒1代
设备1作为黑盒,调用metasec_ov.so 0x7C3D0地址,传入url和headers,得到4个加密参数,
对于search 接口,经过测试是必须要有x-g、x-k这两个加密参数,也可以添加x-a、x-l这两个参数共4个参数。
-
只添加x-g、x-k两个参数,设备1原始串用黑盒通过,设备2原始串用黑盒通过。
-
全添加4个参数,设备1原始串用黑盒通过,设备2原始串用黑盒不通过。
经过测试,如果添加了x-a、x-l这两个参数,同app版本设备2原始串用黑盒不通过,可以猜测黑盒的输入不止url和headers,还在黑盒过程中添加了其他参数,来绑定x-a、x-l这两个参数。通过测试,发现将设备2的原始串的url中的iid和device_id更换成设备1的iid和device_id,重新黑盒生成x-a、x-l加密参数,可以通过服务端的校验。由此说明,黑盒过程中添加了iid和device_id。
经过hook打印日志分析,确认是单独读取了device_id及一些其他参数,但是固定app版本下这些参数不影响加密参数的正确生成,所以不用处理。
strlen Addr[0x6ee7580474] str[0x6f911e3bc0]:[1233]
strlen Addr[0x6ee7580474] str[0x6f348625a0]:[7173498079207196165]
strlen Addr[0x6ee7580474] str[0x6f34515b90]:[2142840551]
strlen Addr[0x6ee7580474] str[0x6f347c4a70]:[24.7.3]
strlen Addr[0x6ee7580474] str[0x6ee75e4160]:[v04.03.09-ov-android]
strlen Addr[0x6ee7580474] str[0x6f34862520]:[AYF7O7O64nQGpEtEEPvme-Z8s]
strlen Addr[0x6ee7580474] str[0x6f8915ab54]:[none]
替换黑盒中单独读取的参数device_id
替换之后通过了search 接口的验证测试
四、其他分析
aid=1233 测试发现没绑定
device_id= 7173498079207196165
lc_id=2142840551
version_name=24.7.3 测试发现没绑定
sdk_ver=v04.03.09-ov-android
-
对于feed流接口,原始的URL和headers头去黑盒,只有x-g x-k参数,缺失x-a、x-l参数,经过测试,需要在原始url后拼上header里的x-common-params-v2的值,核心是aid=1233这个值,有了这个值,就会有x-a、x-l参数
-
x-ss-stub是post数据的md5
-
24.7.3版本的tt设备注册接口post内容已经加密成二进制数据,不再是明文