抖音 xgorgon 算法用 ollvm 混同了,次要是流程平坦化,流程混同和运算替换。
X-Gorgon 是对 cookie,X-SS-STUB,X-Khronos,Url 进行混合加密之后的参数。这里也辨别状况,有些接口只有 url 和 X -Khronos 参加接口加密,有些是 url,X-Khronos,X-SS-STUB 参加接口加密,有些则是所有都进行接口加密。
概述
抖音版本外面加了好几个算法,有 as,cp(晚期就这两个),mas,X-Gorgon,X-SS-STUB,X-Khronos 算法,很多要害 key 之间有互相关联,只有有一个环节算错了,就会申请不到数据。目前版本的抖音加了很多的验证,及代码混同,难度偏大。
初探
抖音的签名算法在 libcms.so 中,在 JNI_Onload 中动静注册 jni 函数。
算法用 ollvm 混同了,次要是流程平坦化,流程混同和运算替换
次要用到一些逆向工具 IDA,Xposed 框架
钻研
8.0 版本之后的算法次要是 X -Gorgon 和 X -SS-STUB. 之后通过抓包抖音接口,查看 Java 层,so 层代码,剖析如下原理。
- X-SS-STUB 是 post 申请时 body 局部的 md5 值,然而在为空的状况下,有时候不参加加密,有时候参加加密,具体接口须要具体分析
- X-Khronos 比较简单就是一个 unix 工夫戳
- X-Gorgon 是对 cookie,X-SS-STUB,X-Khronos,Url 进行混合加密之后的参数。这里也辨别状况,有些接口只有 url 和 X -Khronos 参加接口加密,有些是 url,X-Khronos,X-SS-STUB 参加接口加密,有些则是所有都进行接口加密。具体接口具体分析
剖析
明天有空分享一下抖音的加密算法,作为领有宏大用户量的 APP,其通信协议加密的强度必定是不弱的,要害算法被 VM,只能动态分析去了解。咱们通过抓包剖析,申请的 URL 上带有 AS、CP 两个加密字段,这两个字段是晚期版本算法,后又陆续增加了 MAS、X-GORGON 算法。咱们明天先对 AS、CP 两个字段进行剖析,这个只能通过动静调试去跟踪加密过程。
首先咱们通过工具调试定位到函数
- [IESAntiSpam testForAlert:msg:]
定位的具体过程疏忽……,进入持续调试后发现调用 SUB_102E3345 函数进行加密排序
1. 整顿剖析流程
1. 工夫戳转十六进制
2. 将工夫戳排序俩次,a1 v3 是排序 key
sprintf(byte_102323F30, "%08x", a1);
sprintf(byte_102323F3A, "%08x", v3);
3. 将 url 参数用 MD5 加密一次或俩次依据工夫戳 & 运算
4. 将第一次排序后果写入前 16 位地址加一写入(从 1 插入),隔一位插入,前边拼 a1
5. 将第二次排序后果写入后 16 位(从 0 插入)后边拼 e1
2. 后果排序
a1d5b43se234dccea7
456dcd5s2320cf3e1
&cp=456fcd5s2320cfs3e1&as=a1d5b43se234dccea7
拼接实现后就能够申请了
前期版本增加了 mas 算法和最新的 X -gorgon 算法,目前最新系列版本算法如果须要理解的话能够交换。
3. 流程详述
那么咱们就可能更加确信 header 里的 x -gorgon 对它进行了一次签名,所以咱们间接 jadx 上手浏览一波反编译后的代码,这里我间接搜寻了 x -gorgon 关键字,列出了以下后果:
那么咱们就可能更加确信 header 里的 x -gorgon 对它进行了一次签名,所以咱们间接 jadx 上手浏览一波反编译后的代码,这里我间接搜寻了 x -gorgon 关键字,列出了以下后果:
这里我抉择了 hashMap.put(“X-Gorgon”, a3); 这一行,跳转进去咱们来剖析一下它的代码
这里咱们看到有一个它的值是来自 a3,a3 则是通过 String a3 = a.a(com.ss.sys.ces.a.leviathan(i, currentTimeMillis, a.a(a2 + str4 + str5 + str6))); 这行代码进行获取到的后果,咱们看到它传了 4 个参数,咱们来认真看一下这 4 个参数具体都是什么内容:
a2 起源:
String b2 = tt.d(str);
d.a(b2);
str 它就是该办法传进来的参数,咱们前面能够通过 hook 形式来获取它的具体内容,而它会执行 tt.d()、d.a() 进行 2 次操作,咱们对其 tt.d() 跟进去
咱们看到它对这个字符串进行了取 ? 和 # 两头值,狐疑是 url,如果是 url 证实它只是取了 url 前面的参数,那么持续看它的下一个办法:d.a()
咱们看到这里就是进行了 MD5 签名取值,那么 a2 剖析到此结束,咱们持续剖析第 2 个参数
str4 起源:
这里非常简单,它就是枚举传进来的第二个参数 map,判断如果有 X -SS-STUB 这个值的话就获取,反之则填充 32 个 0,那么咱们抓包发现并没有 X -SS-STUB 这个参数,实际上如果咱们的包是 POST 的话它就会有,实际上它就是 POST 数据的一个 MD5 签名值。
str5 起源:
str5 也非常简单,也是枚举 map 外面有没有 COOKIE,如果有就把 COOKIE 进行 MD5,那么该参数也到此结束了
str6 起源:
String c2 = tt.e(str3);
if (c2 != null && c2.length() > 0) {str6 = d.a(c2);
StcSDKFactory.getInstance().setSession(c2);
}
这里咱们记得 str3 是 cookie,它执行了 tt.e(str3) 办法获取一个返回值,如果它不是空同样给这个返回值 md5,那么咱们跟进去看一下它是做了什么解决:
这里咱们看到它是枚举了 cookie 外面有没有 sessionid 这个值,如果有就取出来,那么 str6 到此结束
参数整顿:
a2 = md5(url) 疑似对网址的参数进行 md5
str4 = x-ss-stub,只有 post 时才无效,否则是 32 个 0
str5 = md5(cookie) 对 cookie 进行 md5
str6 = md5(cookie[‘sessionid’]) 对 cookie 外面对 sessionid 进行 md5,否则也是 32 个 0
咱们整顿完了这 4 条参数后,持续剖析,它将这 4 个参数进行了字符串合并,接着执行 a.a(a2+str4+str5+str6),咱们跟进去看看外面做了什么操作
咱们看到它这里循环了总长度 / 2 次,每次都是把 str[i] 转换成十进制左移 4,而后加上 str[i+1] 都一个简略运算,并返回后果,也就是原本是 4 个 32 位(128 位)而后通过加密后缩短成了 64 位长度。最初它执行了 com.ss.sys.ces.a.leviathan(i, currentTimeMillis, a.a(a2 + str4 + str5 + str6)) 进行计算,咱们看到它还传了 2 个参数,i 和 currentTimeMillis,咱们往前能够看到 i 是 -1,而 currentTimeMillis 是以后都十位工夫戳。
最初把计算好都 byteArray 通过位移转换成了 string 类型,并 put 到 map 外面,那么咱们也分明到看到,k-khronos 也就是刚刚到 currentTimeMillis 工夫戳了。咱们发现因为 om.ss.sys.ces.a.leviathan 是在 so 层到 libcms.so 文件,并且外面有大量到混同就没有再度剖析。咱们能够通过 xposed 或者 unidbg 到办法进行调用。
0x02:参数确认
这里咱们剖析完了它算法到具体参数结构实现后,咱们还须要确认它传到参数是否是咱们所联想到,那么这里咱们发现因为它这个办法是一个 callback,咱们往前跟一下,寻找一个适合到 hook 点,应用 frida 进行 hook
这里我对它进行了调用查找,看到只有 1 个中央,咱们跟进去看看,跟进去之后它就是以下内容,就只是一个简略对赋值给 sAddSecurityFactorProcessCallback,咱们在对它进行调用查找,看看是什么中央对它进行对调用。
public static void setAddSecurityFactorProcessCallback(a aVar) {
sAddSecurityFactorProcessCallback = aVar;
}
这里咱们看到它从这里取的回调指针变量,而后判断如果不为 null 则执行,那么咱们就能够间接 hook 这个办法:tryAddSecurityFactor$___twin___,这里我的 hook 代码也就比较简单,间接输入它传进去的 map 和 str 的值以及返回的 map 进行确认。
//frida -U com.ss.android.ugc.aweme -l test.js
Java.perform(function() {var NetworkParams = Java.use("com.bytedance.frameworks.baselib.network.http.NetworkParams");
NetworkParams['tryAddSecurityFactor$___twin___'].implementation = function(str,map){var keyset = map.keySet();
var it = keyset.iterator();
console.log("str:\t"+str)
while(it.hasNext()){var keystr = it.next().toString();
var valuestr = map.get(keystr).toString()
console.log("map:\t"+keystr+"\t"+valuestr)
}
var ret
ret = this.tryAddSecurityFactor$___twin___(str,map);
var keyset = ret.keySet();
var it = keyset.iterator();
while(it.hasNext()){var keystr = it.next().toString();
var valuestr = ret.get(keystr).toString()
console.log("ret map:\t"+keystr+"\t"+valuestr)
}
return ret;
}
});
绿色局部就是 str 参数 1 的值,黄色则是 map,蓝色则是返回的 map,咱们看下 charles 的这个包的 header 里的 xgorgon 是不是返回的值。
3. 总结:
以上就是对抖音对一个简略的 x -gorgon 的剖析笔记过程,心愿可能有所帮忙,也可能对本身的产品安全方面进行一个参考借鉴。
TiToData:业余的短视频数据接口服务平台。
更多信息请分割:TiToData
笼罩支流平台:抖音,快手,小红书,TikTok,Zynn,YouTube,1688,拼多多,淘宝,美团,饿了么,淘宝,微博