免责声明:
- 本文章主要用于技术交流学习,作者不承担任何滥用技术所产生的法律责任。如有侵权,请联系作者删除!
流程分析


blackbox值







- 上面截图函数就是对tokenId做了处理 返回的值就是 使用的 blackbox 需要把这段代码扣下来
// 第一次流程简化
var ooOo0 = [oo0OOo[642][oo0OOo[1037]](oo0OOo[408][oo0OOo[354]](QOOO0[oo0OOo[1274]](0, 1))), QOOO0[oo0OOo[1274]](1, 4), QOOO0[oo0OOo[1274]](4, 14), QOOO0[oo0OOo[1274]](14, 22), QOOO0[oo0OOo[1274]](22, 23)];
// 手动还原后
var ooOo0 = [
'ghijklmnopqrstuv'['charAt'](
'0123456789abcdef'['indexOf'](
'3WPH1725435677YrufaTno6'['substring'](0, 1)
)
),
'3WPH1725435677YrufaTno6'['substring'](1, 4),
'3WPH1725435677YrufaTno6'['substring'](4, 14),
'3WPH1725435677YrufaTno6'['substring'](14, 22),
'3WPH1725435677YrufaTno6'['substring'](22, 23)
];

// 第二次流程简化
OQO0o = [OOo0o[parseInt(Q0Oo0O(window[OoOoo0[296]][OoOoo0[1385]](), 62))], OOo0o[parseInt(Q0Oo0O(window[OoOoo0[296]][OoOoo0[1385]](), 62))], OOo0o[parseInt(Q0Oo0O(window[OoOoo0[296]][OoOoo0[1385]](), 62))]];
// 手动还原后
function multiplication(data1, data2) {
return data1 * data2;
}
OQO0o = [
data[parseInt(
multiplication(Math['random'](), 62)
)],
data[parseInt(multiplication(Math['random'](), 62))],
data[parseInt(multiplication(Math['random'](), 62))]
];

// 处理tokenId
function getTokenId(tokenId) {
let result = '';
let data = [
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9"
];
function multiplication(data1, data2) {
return data1 * data2;
}
let list1 = ['ghijklmnopqrstuv'['charAt'](
'0123456789abcdef'['indexOf'](
tokenId['substring'](0, 1)
)
),
tokenId['substring'](1, 4),
tokenId['substring'](4, 14),
tokenId['substring'](14, 22),
tokenId['substring'](22, 23)
];
// console.log(list1);
let list2 = [
data[parseInt(
multiplication(Math['random'](), 62)
)],
data[parseInt(multiplication(Math['random'](), 62))],
data[parseInt(multiplication(Math['random'](), 62))]
];
// console.log(list2);
// 拼接
function spliceStr(data1, data2) {
return data1 + data2;
}
result = list1[0]+list1[1]+list2[0]+list1[2]+list2[1]+list1[3]+list2[2]+list1[4];
return result
}
console.log('3WPH1725435677YrufaTno6')
console.log(getTokenId('3WPH1725435677YrufaTno6'))
// 要注意ghijklmnopqrstuv 等一些固定值是不是变化的
-
这样就可以通过代码生成blackbox 但是还缺少 tokenId
分析 tokenId
// 这个请求返回的tokenId
https://fp.tongdun.net/web3_8/r.json?partner=jxhk&app_name=jxhk_web&token_id=cWPH1733109670mouV54Qzf&idf=1733109671990-15403305556&v=nmqSExS4nvV7l39nSgR0OabSEMMu0v0zACJulf3%2FJna%3D&w=EMyZht3WtNwm4HQ%2FZPCyPD7YjboTPsMA0ZUcDsajveL%2BSllDOeXLqMYWZU%2BJElGx&a=soUKxsAasXrEuiAnnlJ85ujsoJfkXXOttfH0L4kc6mmaAcf%2FNvP0lDtP4ZFIqmINg3GTrn3jTFleEAd04sUuoXCwugOG8PWWIps7OlaTLVhUZ6Sob2lKaupeDQYjWsSFJu6Qp%2But%2Bpp4RbRi443LMHGg6sUehOKkGZHfWqtj%2Fhqgq6namcw003fPyIFSIp39ladCqQy7%2BFMfXz2pK41LbXz5hCPSxfwnwQF23QSO2UkQDxUUlBMqx%2BB3eaX7rcCblKKRwesqUnPph2LvB9xJE%2FV4ht4Dp2K08MKVExAeOa1oys93nmEO%2BdjO9JDjSCoOe8lf5Z3vWvcKbIflpmnZRoh0wc27VGkTr746eBPOyNz2eCqDh8%2BMUmqz7L9GusKhDW6Uej33Bb4ruXnZy8hr4LWnjOsmRtgfQSj8MwXmE2vvYK%2F8YQaMntRdMNshgKPnVtgw0TCKA8GA9UNsFsgI1yDJN%2BTap%2BGOj5dJQ%2BzKoze0V1xLSObz5Ot%2F76jSbxb5R7LxKrQlJP7aeRYsbpfgMi8cbeDDDfgUCLorz3Zdm7iTepa7XvWscEhd3BT6i8tMX7wjRBjtCQNi82sEOfkFs55GSm9mOWl7ajFDcbMHR5tE2cyXPPVjcEU0XqILJLRlRUi6QMMPEIvR9XB%2BXzVUZ5OEmhOp36ExniVAciWTGGeyj4tQqdAAB1ME5f2Jz1Nt32Td%2FzDsUAhz2hKIX716y%2B0lQL6NU4hUeogZfrz97QKPS0PDuftpsrKzzSveatSo3j%2FC0Jx4EkoEakkpcWHs12Nx77MIDzgakWGu3FiXAPVkai4IGO3TdxuHrmJ84fpY6QS%2B8wmR%2B%2B2cfWYcL%2FXNetrsnlZAsTXEAwbDPO8sXVwl6qrliVuoYgsBogEShyEfiStxk%2BsdY1POKvrOCvcgkwXKSIFkOASmGUYdPV7MtgidfCZfPCTratSAotplZsAsF2JHcW3Q9lqX%2BicHpI5L1R%2FoUtrMXVhebem1FJQBW9wpQ%2FB61YbhGtvL81%2Bk2n2U1eBnfiSTGJwQANtw&ct=zPnXng%3D%3D


加密分析方案选择

// 需要使用ast对js混淆代码还原,替换js进行调试分析,扣取关键代码进行调用生成加密值,分析传入明文值的含义,哪些可以固定,或者被检测
// 这些第一次的环境值 如
[
"-",
"0",
"41913829c8252e9e775f5241891b77a2|01100100000111000011110011010010000011001010110001111111111011111",
"808287",
"-",
957,
"48000_2_1_0_2_explicit_speakers",
480,
"9fdd23d3687d1d914adcf0bfcbf84b23",
"1744797361808",
1920,
1080,
"4746e7f5fbc70ef2ccd365c30c93f66a|b0f2202fc3f0f72f424ca4fc6db815df",
"functiongetParameter(){[nativecode]}",
"-",
"-",
"-",
"-",
"-"
]
需要有相关的js补头的相关经验,或者自己有使用过相关开源的补环境框架,先分析js运行流程,使用挂上代理,运行js看报错信息,
缺啥补啥,尽量使其结果跟浏览器一致,补到运行js可以出加密值,或者关键位置为止,然后还有对相关的浏览器环境检测部分指纹进行对比,防止被检测
td补环境
// 我对ast还原js代码掌握的比较浅,不还原的话分析起来掉头发,而且听分析过td的朋友说,它的加密算法是动态的,所以就尝试用补环境的方式来分析
js运行逻辑简单分析
// 打开控制台 发现 blackbox 已经被打印输出
// 注意单独打开调试窗口,同一个页面打开有些值会被检测到 比如浏览器的一些宽高


// 让AI帮我们分析一下
// 同盾设备指纹服务(新版)
var _blackbox = "";
(function () {
window._fmOpt = {
partner: 'jxhk',
appName: 'jxhk_web',
token: 'jxhk' + "-" + new Date().getTime() + "-" + Math.random().toString(16).substr(2),
fmb: true,
success: function (data) {
_blackbox = data;
console.log('blackbox: ', data)
},
fpHost: "https://fp.tongdun.net"
};
var cimg = new Image(1, 1);
cimg.onload = function () {
_fmOpt.imgLoaded = true;
};
cimg.src = "https://fp.tongdun.net/fp/clear.png?partnerCode = jxhk & appName=jxhk_web & tokenId=" + _fmOpt.token;
var fm = document.createElement('script'); fm.type = 'text/javascript';
fm.async = true;
fm.src = ('https:' == document.location.protocol ? 'https://' : 'http://') +
'static.tongdun.net/v3/fm.js?ver=0.1&t=' + (new Date().getTime() / 3600000).toFixed(0);
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(fm, s);
})();
// 关键就在 fm.js 文件




// 流程大概就清楚了
// 同盾设备指纹服务(新版)
// 定义全局变量_blackbox,用于存储设备指纹数据
var _blackbox = "";
// 使用立即执行函数(IIFE)封装代码,避免污染全局作用域
(function () {
// 在同盾的全局配置对象window._fmOpt中设置参数
window._fmOpt = {
partner: 'jxhk', // 合作伙伴标识
appName: 'jxhk_web', // 应用名称
// 生成唯一token:合作伙伴+时间戳+16位随机数
token: 'jxhk' + "-" + new Date().getTime() + "-" + Math.random().toString(16).substr(2),
fmb: true, // 是否启用设备指纹的标记
// 设备指纹生成成功后的回调函数
success: function (data) {
_blackbox = data; // 将生成的设备指纹存入全局变量
console.log('blackbox: ', data) // 打印设备指纹(调试用)
},
fpHost: "https://fp.tongdun.net" // 设备指纹服务域名
};
// 创建一个1x1像素的隐藏图片(用于跟踪或清除缓存)
var cimg = new Image(1, 1);
// 图片加载完成后的回调
cimg.onload = function () {
_fmOpt.imgLoaded = true; // 标记图片已加载
};
// 设置图片源URL,携带合作伙伴和应用信息
cimg.src = "https://fp.tongdun.net/fp/clear.png?partnerCode=jxhk&appName=jxhk_web&tokenId=" + _fmOpt.token;
// 动态创建script标签加载设备指纹主脚本
var fm = document.createElement('script');
fm.type = 'text/javascript';
fm.async = true; // 异步加载
// 根据当前页面协议选择http/https,并添加时间戳参数避免缓存(每小时更新)
fm.src = ('https:' == document.location.protocol ? 'https://' : 'http://') +
'static.tongdun.net/v3/fm.js?ver=0.1&t=' + (new Date().getTime() / 3600000).toFixed(0);
// 获取页面第一个script元素
var s = document.getElementsByTagName('script')[0];
// 在第一个script标签前插入我们的脚本
s.parentNode.insertBefore(fm, s);
})();
// 生成加密值发包js代码
fm.js 文件 运行 -> blackbox: qWPHk1744798953UYMkWnFE9W2
// 那我们只要针对这两段js进行补环境就可以得到我们想要的值了
td补环境
// 建议找个补环境开源框架进行操作,节省时间,也可以自己写(注意原型链的补全和toString检测)
// 挂上代理看报错信息,缺啥补啥,尽量保持和浏览器一致,因为是本地挂代理运行,js的运行逻辑调试几遍也会更清晰

// tdjs访问的一些浏览器api 需要细心对比与浏览器运行出来的值的差异,有差异的地方要看一下会不会检测



// 使用生成blackbox 可以正常登录
我调试用的js关键部分打了断点可以方便分析
通过网盘分享的文件:调试.js
链接: https://pan.baidu.com/s/1sMehqnWLTuaK1gF9huWpaw?pwd=2qfc 提取码: 2qfc
