17xx 物流查询平台 last-event-id 参数逆向分析
字数 1385 2025-08-20 18:18:10
17xx物流查询平台last-event-id参数逆向分析教学文档
一、逆向目标
目标:分析17xx物流查询平台的last-event-id参数生成机制
网站:aHR0cHM6Ly93d3cuMTd0cmFjay5uZXQvemgtY24= (已脱敏)
二、调试准备
1. 反调试处理
网站使用了debugger反调试技术,主要特征:
- 使用了ob混淆的JavaScript代码
- 包含检测代码格式化、debugger的函数
2. 反混淆工具
推荐使用以下工具进行反混淆:
- v_jstools - GitHub仓库: https://github.com/cilame/v_jstools
- AST Explorer - 在线分析工具: https://astexplorer.net
3. 代码替换工具
使用ReRes工具进行代码替换:
- GitHub地址: https://github.com/annnhan/ReRes
- 配置规则替换混淆代码为反混淆后的代码
三、参数定位与分析
1. 参数位置
通过搜索last-event-id可定位到参数生成代码位于反混淆后的文件中。
2. 关键依赖
_0x308754 = YQ.configs.md5来自首页HTML中- 请求需要携带cookie值
_yq_bid,且必须与生成last-event-id中的_yq_bid一致
四、核心算法解析
1. 主要函数说明
a. _0x5879b4 - 哈希计算函数
function _0x5879b4(_0x56b807, _0x3603af) {
var _0x2f5b4a = 1315423911 ^ _0x3603af << 16;
var _0x4844e9;
var _0x4d42c4;
for (_0x4844e9 = _0x56b807.length - 1; _0x4844e9 >= 0; _0x4844e9--) {
_0x4d42c4 = _0x56b807.charCodeAt(_0x4844e9);
_0x2f5b4a ^= (_0x2f5b4a << 5) + _0x4d42c4 + (_0x2f5b4a >> 2);
}
return _0x4243f2(4), Math.abs(_0x2f5b4a & 2147483647);
}
b. _0x1d212e - 另一种哈希算法
function _0x1d212e(_0x3ffdba) {
if (!_0x3ffdba)
return 0;
var _0x9920fa = 5381;
var _0x55570f = _0x3ffdba.length;
while (_0x55570f) {
_0x9920fa = _0x9920fa * 33 ^ _0x3ffdba.charCodeAt(--_0x55570f);
}
return _0x9920fa >>> 0;
}
c. _0x39b7cc - 字符串反转
function _0x39b7cc(_0x18dcad) {
return _0x18dcad.split("").reverse().join("");
}
d. _0x402770 - 字符串转16进制
function _0x402770(_0x1e4f12) {
var _0x3bcbe3 = "";
for (var _0x5f5a6c = 0; _0x5f5a6c < _0x1e4f12.length; _0x5f5a6c++) {
if (_0x3bcbe3 == "")
_0x3bcbe3 = _0x1e4f12.charCodeAt(_0x5f5a6c).toString(16);
else
_0x3bcbe3 += _0x1e4f12.charCodeAt(_0x5f5a6c).toString(16);
}
return _0x3bcbe3;
}
e. createGUID - 生成唯一ID
function createGUID(e, t) {
var o = (new Date).getTime();
return (e || "G-xxxxxxxxxxxxxxxx").replace(t || /[xy]/g, function(e) {
var t = (o + 16 * Math.random()) % 16 | 0;
return ("x" == e ? t : 7 & t | 8).toString(16).toUpperCase()
})
}
2. last-event-id生成主函数
function get_last_event_id(_0x19d69d, YQ_md5){
_yq_bid = createGUID();
_0x4566f3 = undefined;
_0x59789d(_0x19d69d, _0x19d69d.length, !![])
_0x6de72e = _0x187331(43)
var _0x5d4d80 = "yq-";
_0x58ecad = _0x6de72e;
// 指纹信息
cancas_fp = '24\r\nzh-CN\r\n-480\r\n1067x1707\r\ndata:image/png;base64,...';
var _0x2b62a6 = _0x1d212e(cancas_fp);
var _0x5d74a6 = _0x1d212e(_0x4566f3);
if (_0x6de72e == 0)
_0x5d4d80 += "random";
else {
_0x5d4d80 = "dropdown-menu-footer yq-user-footer clearfix";
}
_0x269b49 = _yq_bid;
_0x5d4d80 = _0x269b49;
(_0x58ecad = _0x58ecad * 50, _0x5d4d80 false 0x2b62a6 0x6de72e 0x58ecad);
_0x5d4d80 = Date.now().toString(16) + "/11/" + true + "/" +
new Date().getTimezoneOffset().toString(0x2b62a6 + "/" + YQ_md5 + 0x5d74a6;
_0x59789d(_0x5d4d80, _0x6de72e);
_0x5d4d80 = _0x402770(_0x39b7cc(_0x5d4d80));
_0x199099[0] = _0x5d4d80;
return [_0x199099.join(""), _yq_bid];
}
五、关键点总结
-
指纹信息:使用了canvas指纹,包含:
- 屏幕颜色深度
- 语言设置
- 时区偏移
- 屏幕分辨率
- canvas图像数据
-
随机数生成:
- 使用
_0x187331(43)生成随机数 - 乘以50作为时间戳的一部分
- 使用
-
GUID生成:
- 使用
createGUID函数生成_yq_bid - 必须与请求cookie中的
_yq_bid一致
- 使用
-
哈希计算:
- 对指纹信息进行哈希计算(
_0x1d212e) - 对部分参数进行哈希计算(
_0x5879b4)
- 对指纹信息进行哈希计算(
-
最终拼接:
- 包含时间戳(16进制)
- 固定值"11"
- 布尔值true
- 时区偏移
- MD5值
- 反转字符串并转为16进制
六、实现流程
- 生成
_yq_bid(GUID格式) - 获取canvas指纹信息
- 对指纹信息进行哈希计算
- 生成随机数并处理
- 拼接时间戳、时区等参数
- 对拼接结果进行反转和16进制转换
- 将各部分结果组合成最终
last-event-id
七、验证示例
console.log(get_last_event_id(
'{"data":[{"num":"LZ025387152CN","fc":0,"sc":0}],"guid":"","timeZoneOffset":-480}',
'22c342b'
));
输出格式为数组,包含:
- 生成的
last-event-id _yq_bid值(需设置为cookie)
八、注意事项
- cookie一致性:
_yq_bid必须与生成的last-event-id中的一致 - 指纹信息:canvas指纹需要模拟真实浏览器环境
- 时间戳:使用当前时间,转换为16进制
- 时区偏移:需要获取客户端的时区偏移量
- MD5值:来自
YQ.configs.md5,需从首页HTML中提取