mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
401 字
1 分钟
[破碎数据研究组] ██请求签名解析

保管时间 026/02/10 保管单位 Redstix 等级 main#


学海签名方式解析#

前言#

在 ZTY/ZTP⁽¹⁾ 中,学海通过对 okhttp 的定制实现了对几乎所有 ztp.yunzuoye.net REST API⁽²⁾ 的请求的签名,从而加大了 API 研究的难度, 比如直接访问 ztp.yunzuoye.net/api/v2/platform/apk 就会显示 Missing sign parameter!!!
本文记录了学海的这种签名方式。

源码原理#

注意到,在智通云/智通平台的 OkHttpClientManager 中,学海添加了一个 RequestSignInterceptor ⁽³⁾,它负责拦截请求,签名,再把它发出去。

RequestSignInterceptor 调用了 RequestSignUtil 中的 addRestfulVerifyData 进行了具体的签名,它长这样

public static String addRestfulVerifyDataV2(String str, String str2, String str3, String str4, String str5, String str6, SignListener signListener) {
long jCurrentTimeMillis = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
sb.append(str);
sb.append(str2);
sb.append(jCurrentTimeMillis);
sb.append(str4);
if (!needCombineBodyDataIntoUrl(str) && !isEmpty(str5) && str5.getBytes().length < 1048576) {
sb.append(str5);
}
if (str6 != null) {
sb.append("Authorization: " + str6);
}
String string = sb.toString();
if (signListener != null) {
signListener.onSignatureBodyReady(string);
}
String strEncode = MD5Util.encode(string);
StringBuilder sb2 = new StringBuilder(str2);
if (str2.contains("?")) {
sb2.append(ContainerUtils.FIELD_DELIMITER);
} else {
sb2.append("?");
}
sb2.append("sign");
sb2.append(ContainerUtils.KEY_VALUE_DELIMITER);
sb2.append(strEncode);
sb2.append(str3);
sb2.append(ContainerUtils.FIELD_DELIMITER);
sb2.append("t");
sb2.append(ContainerUtils.KEY_VALUE_DELIMITER);
sb2.append(jCurrentTimeMillis);
return sb2.toString();
}

这就是学海的具体签名函数了⁽⁴⁾。

分析#

为了清晰的表述其工作方式,注释后的代码如下,删去了许多内容

/**
* 注释版
*
* @param method 请求方式
* @param url 原始URL
* @param signatureKey SignatureKey
* @param requestBody 请求体
* @param authHeader 请求头中的Authorization
* @return String 签好的新 URL
*/
public static String addRestfulVerifyData(String method,String url,String
,String requestBody,String authHeader) {
long timestamp = System.currentTimeMillis();
String rawSignString = method + url + timestamp + signatureKey;
// 不是GET/DELETE、Body非空且Body小于1MB时
if (!needCombineBodyDataIntoUrl(method)
&& !isEmpty(requestBody)
&& requestBody.getBytes().length < 1048576) {
rawSignString+=requestBody;
}
// 如果有认证头,也参与签名
if (authHeader != null) {
rawSignString+="Authorization: "+authHeader;
}
String sign = MD5Util.encode(rawSignString);
StringBuilder finalUrlBuilder = new StringBuilder(url);
// 处理URL连接符
if (url.contains("?")) {
finalUrlBuilder.append("&");
} else {
finalUrlBuilder.append("?");
}
finalUrlBuilder.append("sign=").append(sign);
finalUrlBuilder.append("&t=").append(timestamp);
return finalUrlBuilder.toString();
}

请求方式是待签名请求方法的大写名字,如 GETPATCH

其中,signatureKey通过JNI层访问xhcore.so中 Java_com_xh_xhcore_jni_XHCoreJni_getSignatureKey 的获取, 它就是 eptim]q34imt5b]-q04i5q=fdkfjfsadlkjfasdfrt573df4pltoy]-pn965498d⁽⁵⁾,我们有理由怀疑这是学海程序猿手在键盘上滚出来的

一个签名示例

[*] 待签名串: GEThttps://ztp.yunzuoye.net/api/v2/platform/apk?appId=mdm_stu_to_c&versionCode=10210061770653399094eptim]q34imt5b]-q04i5q=fdkfjfsadlkjfasdfrt573df4pltoy]-pn965498d
[*] 最终 URL: https://ztp.yunzuoye.net/api/v2/platform/apk?appId=mdm_stu_to_c&versionCode=1021006&sign=314aafb4083bcfef7ed0ffba1bd0334f&t=1770653399094

Python实现

def get_zty_sign_url_3(method, url, request_body=None, auth_header=None):
signature_key="eptim]q34imt5b]-q04i5q=fdkfjfsadlkjfasdfrt573df4pltoy]-pn965498d"
timestamp = str(int(time.time() * 1000))
raw_sign_string = f"{method}{url}{timestamp}{signature_key}"
if method not in ["GET", "DELETE"] and request_body and len(request_body.encode('utf-8')) < 1048576:
raw_sign_string += request_body
if auth_header:
raw_sign_string += f"Authorization: {auth_header}"
sign = hashlib.md5(raw_sign_string.encode('utf-8')).hexdigest()
if "?" in url:
final_url = f"{url}&sign={sign}&t={timestamp}"
else:
final_url = f"{url}?sign={sign}&t={timestamp}"
return final_url

注1: 由于目前未分析学海的其它软件,暂时无法确定该签名的覆盖软件范围
注2: 同理,暂时无法确定该签名的覆盖API范围,不过若代码里是用LRequest发起请求的,则一定是签名了
注3: 具体位置 com.xh.xhcore.common.http.strategy.okhttp.interceptors.RequestSignUtil
注4:在代码中,还有 RequestSignInterceptorV2,但并未被使用,猜测为学海史山代码遗留
注5:SignatureKey 最终在 IDA 虚拟地址 0000708C 中可找到

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

[破碎数据研究组] ██请求签名解析
https://k.asxz.one/posts/xuehai-sign/
作者
Redstix
发布于
2026-07-23
许可协议
CC-0

部分信息可能已经过时

目录