h5 sig
'{ "appid": 330002, "app_key_vs": "1.0.0", "app_key": "0n003Fo004931Z20" }',
url = "https://cs-ol.sns.sohu.com/330002/v8/userapi/user/show"
params = {
"profile_user_id": "1140727494190770176",
"flyer": "1744199170717",
"appid": "330002",
"app_key_vs": "1.0.0",
"sig": "be9e2476455f4b7479e942a5131a6794"
}
params 按Key排序拼接后md5得出sig:
app_key_vs=1.0.0appid=330002flyer=1744199170717profile_user_id=11407274941907701760n003Fo004931Z20
sig为:be9e2476455f4b7479e942a5131a6794
s-pid 为 1140727494190770176
import hashlib
def calculate_sig(params,appkey):
keys = sorted(params.keys())
param_str = ""
for key in keys:
if key!= "sig":
param_str += f"{key}={params[key]}"
param_str = param_str+appkey
md5 = hashlib.md5()
md5.update(param_str.encode('utf-8'))
new_sig = md5.hexdigest()
return new_sig
new_sig = calculate_sig(params = {
"profile_user_id": "1140727494190770176",
"flyer": "1744199170717",
"appid": "330002",
"app_key_vs": "1.0.0",
"sig": "be9e2476455f4b7479e942a5131a6794"
},appkey="0n003Fo004931Z20")
print(new_sig)
小程序sig
小程序和h5一样,换下app_key就行。
解包搜索即可找到app_key
APPID=330008
app_key_vs:"6.4.0"
app_key: "760W*******140F"
app sig
可找到 @hy.sohu.com.app.common.net;
简单hook:
Java.perform(function () {
console.log("1111")
Java.openClassFile('/data/local/tmp/r0gson.dex').load()
const gson = Java.use('com.r0ysue.gson.Gson')
let a = Java.use("hy.sohu.com.app.common.net.a");
a["getSignMap"].implementation = function (requestBaseMap) {
console.log(`start : ${gson.$new().toJson(requestBaseMap)}`)
let result = this["getSignMap"](requestBaseMap);
console.log(`end : ${gson.$new().toJson(result)}`);
return result;
};
});
start : {"circle_id":"1105277072533822848","S-CID":"011285761868497073152","count":10,"extras":"1","withTop":1,"exposed_circle_pos_feed_id":"","stpl":"1,2,3,4,7,9,11,12","app_key_vs":"6.7.0","flyer":"1744203686922","list_type":2,"score":0.0,"tpl":"1,3,24,26","log_user_id":"1211457320777882752","S-PPID":"1816720971126923264@sohu.com","S-PID":"1211457320777882752","appid":"330000"}
end : {"circle_id":"1105277072533822848","count":10,"extras":"1","withTop":1,"exposed_circle_pos_feed_id":"","stpl":"1,2,3,4,7,9,11,12","app_key_vs":"6.7.0","flyer":"1744203686922","sig":"5aee33621de4878c09a0b2c361335a5b","list_type":2,"score":0.0,"tpl":"1,3,24,26","log_user_id":"1211457320777882752","appid":"330000"}
String sig = sa.a.f53141a.cscd130065c407(treeMap, null);
hook可知
let a = Java.use("sa.a");
a["cscd130065c407"].implementation = function (treeMap, str) {
console.log(`start [Method] a.cscd130065c407 is called: treeMap=${treeMap}, str=${str}`);
let result = this["cscd130065c407"](treeMap, str);
console.log(`end [Method] a.cscd130065c407 result=${result}`);
return result;
};
start [Method] a.cscd130065c407 is called: treeMap={S-CID=011285761868497073152, S-PID=1211457320777882752, S-PPID=1816720971126923264@sohu.com, app_key_vs=6.7.0, appid=330000, circle_id=1105277072533822848, count=10, exposed_circle_pos_feed_id=, extras=1, flyer=1744204049807, list_type=2, log_user_id=1211457320777882752, score=0.0, stpl=1,2,3,4,7,9,11,12, tpl=1,3,24,26, withTop=1}, str=null
end [Method] a.cscd130065c407 result=587f1d45b193158d64041d5f513b56e4
找到 System.loadLibrary("CtaApiJni");
IDA直接搜 cscd130065c407
cscd130065c407伪代码的关键部分:
void __fastcall Java_sa_a_cscd130065c407(__int64 a1, __int64 a2, __int64 a3, __int64 a4)
{
unsigned __int64 v4; // x22
if ( v8 ){
#省略
}
else
{
# 省略部分
sub_69600(&v32, &v30);
sub_6A290(&v32);
if ( word_E4E10 & 1 )
v18 = (char *)qword_E4E20;
else
v18 = (char *)&word_E4E10 + 1;
if ( word_E4E28 & 1 )
v19 = (char *)qword_E4E38;
else
v19 = (char *)&word_E4E28 + 1;
if ( (unsigned int)strcmp(v19, "sleep,") )
{
if ( strstr(v19, "cdt1")
|| strstr(v19, "cdt2-1")
|| strstr(v19, "cdt2-2")
|| strstr(v19, "cdt3")
|| strstr(v19, "cdt4") )
{
std::__ndk1::operator+<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>(
"cjf---check_log: ",
&word_E4E28);
sub_67E70(v5, &v21);
if ( v21 & 1 )
operator delete(v22);
LABEL_30:
if ( *(_QWORD *)(v4 + 40) == v36 )
exit(0LL);
return;
}
}
else
{
#省略
}
else if ( *(_QWORD *)(v4 + 40) == v36 ){v7();}}
sub_67804 ,将传入的Java Map对象遍历,转换为key=value格式的字符串
v8是传入的app_key,这里v8=null
sub_69600是哈希算法的Final阶段实现,负责数据填充和结果生成,大概率是 MD5算法 的实现。
sub_6A290该函数将 result + 92 处的二进制数据转换为十六进制字符串, 符合MD5的输出特征。
hook sub_6a290
const module = Process.getModuleByName("libCtaApiJni.so");
const funcOffset = 0x6a290;
const funcPtr = module.base.add(funcOffset);
Interceptor.attach(funcPtr, {
onEnter: function(args) {
const context = this.context;
this.inputPtr = context.x0.add(92);
this.a3 = context.x8;
this.inputData = Memory.readByteArray(this.inputPtr, 16);
},
onLeave: function(retVal) {
console.log("原始数据 (HEX):", hexdump(this.inputData));
const outputStruct = this.a3;
const capacity = outputStruct.readU64();
const length = outputStruct.add(8).readU64();
let dataPtr;
if (length > 0x16) {
dataPtr = outputStruct.add(16).readPointer();
} else {
dataPtr = outputStruct.add(1);
}
const outputBytes = Memory.readByteArray(dataPtr, Number(length));
console.log("加密结果 (HEX):", hexdump(outputBytes));
try {
console.log("加密结果 (UTF-8):", Memory.readUtf8String(dataPtr));
} catch(e) {
console.log("加密结果非 UTF-8 字符串");
}
}
});
结果确实是md5,和抓包一致
hook sub_69600
可发现填充salt:
app端计算sig时,需要把S-CID、S-PPID、S-PID加入params一同计算。
各端salt整理
【温馨提示:此处隐藏内容需要付费订阅后才能查看!】