1.开门见山,机票数据都需要一个blackbox的数据,这个就是由无感相关生成的。直接搜索Blackbox就可以找到最后赋值的地方,然后下断点刷新,往上跟调用栈就可以找到回调函数
//oooooQ()函数生成的值就是blackbox
function OOO0OO() {
if (O0QQ0Q) return;
O0QQ0Q = true, O00Q0Q(Qoo0oO["success"]) && Qoo0oO["success"](oooooQ());
}
这个函数是走下面的else的,因为status为255,在前面发完profile.json这个包之后设置了status=255,这个tokens就是tokenId.
function oooooQ() {
oOOo00["blackBox"] = {}, oOOo00["blackBox"]["v"] = Qoo0oO["version"], oOOo00["blackBox"]["os"] = 3;
if (Qoo0oO["status"] % 255) {
if (window["navigator"] && window["navigator"]["cookieEnabled"]) {
if (!Qoo0oO["strictMode"] && o0O00Q && oooQO0 && o0O00Q["length"] === 16 && oooQO0["length"] === 16 && localStorage && localStorage[o0O00Q] && localStorage[oooQO0] && new window["Date"]()["getTime"]() - Number(localStorage[oooQO0]) <= 86400000) {
_fmOpt["blackBoxType"] = 1;
var OQoOo = Q00000(localStorage[o0O00Q]);
if (Qoo0oO["collectBehavior"] && Qoo0oO["behaviorUrl"] && window["FormData"]) {
window["_fmBehaviorBlackbox"] = OQoOo;
}
return OQoOo;
}
}
O00Q0O(oOOo00["deviceInfo"]), oOOo00["blackBox"]["e"] = Qoo0oO["status"], _fmOpt["blackBoxType"] = 2, oOOo00["blackBox"]["d"] = window["JSON"]["stringify"](oOOo00["deviceInfo"]);
} else {
//这部分就是通过profile.json接口返回的token生成blackbox, 用到Q00000方法
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (Qoo0oO["tokens"]) {
oOOo00["blackBox"] = Qoo0oO["tokens"], _fmOpt["blackBoxType"] = 1, setTimeout(function () {
try {
if (window["localStorage"] && o0O00Q && oooQO0 && o0O00Q["length"] === 16 && oooQO0["length"] === 16) {
localStorage[oooQO0] = new window["Date"]()["getTime"](), localStorage[o0O00Q] = oOOo00["blackBox"];
}
} catch (error) {
}
}, 0);
var QOQ0O = Q00000(oOOo00["blackBox"]); // 这个地方是真正的blackbox
if (Qoo0oO["collectBehavior"] && Qoo0oO["behaviorUrl"] && window["FormData"]) {
window["_fmBehaviorBlackbox"] = QOQ0O;
}
return QOQ0O;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
O00Q0O(oOOo00["deviceInfo"]), oOOo00["blackBox"]["msg"] = "no token returned", oOOo00["blackBox"]["e"] = Qoo0oO["status"], oOOo00["blackBox"]["d"] = window["JSON"]["stringify"](oOOo00["deviceInfo"]), _fmOpt["blackBoxType"] = 3;
}
if (Qoo0oO["collectBehavior"] && Qoo0oO["behaviorUrl"] && window["FormData"]) {
window["_fmBehaviorBlackbox"] = "tdfp" + OoQooO(window["JSON"]["stringify"](oOOo00["blackBox"]), 1);
}
return "tdfp" + OoQooO(window["JSON"]["stringify"](oOOo00["blackBox"]), 1);
}
Q00000函数如下,这个方法固定的可以直接用,用tokenid生成blackbox:
function Q00000(OQoOo) {
{
if (OQoOo["length"] !== 23) {
return OQoOo;
}
var ooQ00 = "";
var o0O00 = ["ghijklmnopqrstuv"["charAt"]("0123456789abcdef"["indexOf"](OQoOo["substring"](0, 1))), OQoOo["substring"](1, 4), OQoOo["substring"](4, 14), OQoOo["substring"](14, 22), OQoOo["substring"](22, 23)];
var oOoQo = ["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"];
var OoQoQ = [];
var OOo00 = 0;
var OOoOo = 75;
while (OOoOo) {
switch (OOoOo) {
case 77:
OOo00++;
OOoOo = 75;
break;
case 76:
OoQoQ = [oOoQo[parseInt(window["Math"]["random"]() * 62)], oOoQo[parseInt(window["Math"]["random"]() * 62)], oOoQo[parseInt(window["Math"]["random"]() * 62)]];
if (o0QOOO["length"] > 1000 || o0QOOO["indexOf"]("" + OoQoQ[0] + OoQoQ[1] + OoQoQ[2]) === -1) {
OOo00 = 1000, o0QOOO["push"]("" + OoQoQ[0] + OoQoQ[1] + OoQoQ[2]), ooQ00 = "" + o0O00[0] + o0O00[1] + OoQoQ[0] + o0O00[2] + OoQoQ[1] + o0O00[3] + OoQoQ[2] + o0O00[4];
}
OOoOo = 77;
break;
case 75:
OOoOo = OOo00 < 1000 ? 76 : 0;
break;
}
}
if (ooQ00["length"] !== 26) {
ooQ00 = "" + o0O00[0] + o0O00[1] + OoQoQ[0] + o0O00[2] + OoQoQ[1] + o0O00[3] + OoQoQ[2] + o0O00[4];
}
return ooQ00;
}
}
2.接下来看怎么通过profile.json发包获取tokenid,继续向上跟调用栈。其实这里就是拼接网址发包拿到数据回调处理,把tokenId赋值给tokens
function OOo0oQ() {
{
Qoo0oO["status"] = 4, QoooO0(Qoo0oO["fpHost"] + Qoo0oO["jsonUrl"] , function (OQoOo) { // 发包成功回调函数
{
var OOoOo = OQoOo["result"];
var ooQ00 = OOoOo === undefined ? {} : OOoOo;
Qoo0oO["timer"] && clearTimeout(Qoo0oO["timer"]);
if (!ooQ00["tokenId"]) {
Qoo0oO["status"] = 200;
} else {
var OoQoQ = function QOQ0O() {
{
var Q0oooQ = document["createElement"]("iframe");
Q0oooQ["sandbox"] = "allow-scripts";
var OOo00 = Qoo0oO["iUrl"];
if (OOo00 && OOo00[OOo00["length"] - 1] !== "/") {
OOo00 += "/";
}
Q0oooQ["src"] = OOo00 + "i.html", Q0oooQ["width"] = 0, Q0oooQ["height"] = 0, (Q0oooQ["frameElement"] || Q0oooQ)["style"]["cssText"] = "position:absolute !important; z-index:-9999 !important; visibility:hidden !important;border:0 !important";
var QOQ0O = function OOo00(OQoOo) {
if (OQoOo["data"] === "i init ok" && Q0oooQ["contentWindow"] && Q0oooQ["contentWindow"]["postMessage"]) {
var QOQ0O = Q0O00O["get"](O00o0Q, 255, 2);
Qoo0oO["pxy"] = QOQ0O || "-", Q0oooQ["contentWindow"]["postMessage"](window["JSON"]["stringify"](Qoo0oO), "*");
}
};
if (window["addEventListener"]) {
window["addEventListener"]("message", QOQ0O);
} else if (window["attachEvent"]) {
window["attachEvent"]("onmessage", QOQ0O);
}
document["body"] && document["body"]["appendChild"](Q0oooQ);
}
};
oOOQOo = ooQ00["xxid"];
try {
if (ooQ00["c"]) {
if (ooQ00["c"]["factor"] !== undefined) {
if (window["navigator"] && window["navigator"]["cookieEnabled"]) {
localStorage["_TDfactor"] = ooQ00["c"]["factor"];
}
Q000oo["factor"] = ooQ00["c"]["factor"];
} else {
if (window["navigator"] && window["navigator"]["cookieEnabled"]) {
localStorage["_TDfactor"] = 0;
}
Q000oo["factor"] = 0;
}
if (ooQ00["c"]["op"] !== undefined) {
if (window["navigator"] && window["navigator"]["cookieEnabled"]) {
localStorage["_TDopnum"] = ooQ00["c"]["op"];
}
Q000oo["op"] = ooQ00["c"]["op"];
} else {
if (window["navigator"] && window["navigator"]["cookieEnabled"]) {
localStorage["_TDopnum"] = 0;
}
Q000oo["op"] = 0;
}
if (window["navigator"] && window["navigator"]["cookieEnabled"]) {
localStorage["_TDctimestamp"] = new window["Date"]()["getTime"]();
}
}
} catch (OOQ0QQ) {
}
if (oOOQOo) {
Q0O00O["set"](OQQo0o, oOOQOo);
}
//tokenId赋值
Qoo0oO["tokens"] = ooQ00["tokenId"], Qoo0oO["_xid"] = ooQ00["xdid"];
if (Qoo0oO["_xid"]) {
Q0O00O["set"](OoOQQQ, Qoo0oO["_xid"]);
}
if (!Qoo0oO["noIframe"] && OQQ0oO()) {
OoQoQ();
}
//修改状态
Qoo0oO["status"] = 255;
}
//这个是最上面那个调用success函数
OOO0OO();
}
}, oOOo00["deviceInfo"], function () {
OOO0OO();
});
if (Qoo0oO["partnerSendSwitch"]) {
try {
QoooO0(Qoo0oO["partnerFpUrl"], null, oOOo00["deviceInfo"]);
} catch (e2788) {
oO0o0O(e2788);
}
}
oOOo00["pageInfo"] = {};
if (Qoo0oO["detectSwitch"]) {
oOOo00["pageInfo"]["partnerCode"] = _fmOpt["partner"], oOOo00["pageInfo"]["token_id"] = _fmOpt["token"], oOOo00["pageInfo"]["appName"] = _fmOpt["appName"], oOOo00["pageInfo"]["paramz"] = o0oOo0(), QoooO0(Qoo0oO["fpHost"] + Qoo0oO["detectUrl"], null, oOOo00["pageInfo"]);
}
if (Qoo0oO["partnerSendSwitch"]) {
try {
QoooO0(Qoo0oO["partnerDetectUrl"], null, oOOo00["pageInfo"]);
} catch (e2788) {
oO0o0O(e2788);
}
}
}
}
QoooO0是发包函数,O0ooOO["src"] = OoQOO就是profile.json的网址,这里可以看到网址的拼接过程:
v:随js返回版本号
idf:时间戳加密
w:v加密
ct:时间差加密
h:前面所有参数拼接的网址hash
function QoooO0(OQoOo, OOo0QO, OoQoQ, QOQ0Q0) {
{
var QQoOQ0 = QOOo0Q();
if (QQoOQ0 && QQoOQ0 <= 8) {
OQoOo = OQoOo["replace"](/\/web.+\/profile\.json/, "/web3_7/profile.json");
}
var OoOo0o = false;
var O0ooOO = document["createElement"]("script");
var Oo00Q0 = {};
var O00o00 = QoQQ00(OOo0QO, Oo00Q0, QOQ0Q0);
var OoQOO = OQoOo;
var Q0OQO = [];
OoQoQ["v"] = Qoo0oO["version"], OoQoQ["idf"] = Qoo0oO["timestamp"], OoQoQ["w"] = QQ0QQQ(Qoo0oO["version"]), OoQoQ["ct"] = QQ0QQQ(new window["Date"]()["getTime"]() - Qoo0oO["jsDownloadedTime"]);
if (!QQoOQ0 || QQoOQ0 > 8) {
var QO0QO = new OQOooQ();
QO0QO["setPublicKey"](QQQQQ0), OoQoQ["idf"] = QO0QO["encrypt"](Qoo0oO["timestamp"]);
}
for (var QQQOO in OoQoQ || {}) {
Q0OQO["push"](QQQOO + "=" + encodeURIComponent(OoQoQ[QQQOO]));
}
Q0OQO["push"]("_callback=" + O00o00), OoQOO += OoQOO["indexOf"]("?") > 0 ? "&" : "?", OoQOO += Q0OQO["join"]("&"), OoQOO += "&h=" + OOQQ0O["hash128"](OoQOO["replace"](OQoOo, "")), O0ooOO["id"] = O00o00, O0ooOO["onload"] = function oO0oO() {
if (!OoOo0o && (!this["readyState"] || this["readyState"] === "loaded" || this["readyState"] === "complete")) {
OoOo0o = true, O0ooOO["onload"] = null, O0ooOO["onreadystatechange"] = null, Oo00Q0["t"] && clearTimeout(Oo00Q0["t"]);
if (OOo0QO) {
var OQoOo = O00o00;
if (window[OQoOo]) {
if (QQoOQ0 && QQoOQ0 <= 8 && Qoo0oO["status"] === 4) {
O00Q0Q(QOQ0Q0) && QOQ0Q0();
}
Qoo0oO["status"] = 203;
}
}
}
}, O0ooOO["onreadystatechange"] = O0ooOO["onload"], O0ooOO["onerror"] = function oOO0O() {
if (OOo0QO) {
Qoo0oO["status"] = 202, Oo00Q0["t"] && clearTimeout(Oo00Q0["t"]);
}
O00Q0Q(QOQ0Q0) && QOQ0Q0();
}, O0ooOO["src"] = OoQOO, setTimeout(function () {
OQOoo0["insertBefore"](O0ooOO, OQOoo0["firstChild"]);
}, 0);
}
}
e的生成函数:
function oO00Q0() {
{
var ooQ00 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var OOoOo = "";
for (var OoQoQ = 0, OOo00 = ooQ00["length"]; OoQoQ < 127; OoQoQ++) {
OOoOo += ooQ00["charAt"](window["Math"]["floor"](window["Math"]["random"]() * OOo00));
}
var QOQ0O = OOoOo["split"]("");
QOQ0O["splice"](window["Math"]["floor"](window["Math"]["random"]() * (ooQ00["length"] - 1)), 0, "\\");
return QOQ0O["join"]("");
}
}
i,j,k,l,o(也有可能是a,b,c,d之类的,是因为有两个版本js)都是环境检测相关的,然后通过加密生成,生成位置如下:
OOoOoo["forEach"](function (OQoOo, QOQ0O) {
var OoOoQo = [];
var QQoooO = QOQ0O > 3 ? QOQ0O + 2 : QOQ0O;
var Q0OOoo = new window["Date"]()["getTime"]()["toString"](32);
OQoOo["forEach"](function (OQoOo, QOQ0O) {
var OoQoQ = void 0;
if (OQoOo["z"]) {
var OOo00 = {};
OOo00["task"] = typeof OQoOo["y"] === "function" ? OQoOo["y"]() : OQoOo["y"], OOo00["index"] = QQoooO, OOo00["tIndex"] = QOQ0O, OOo00["values"] = OoOoQo, OOo00["type"] = OQ0QQQ["indexOf"](OQoOo["m"]), OOo00["now"] = Q0OOoo, oOQ0oo["push"](OOo00), OoOoQo["push"]("-");
return;
}
if (OQoOo["w"]) {
var OOoOo = {};
OOoOo["task"] = OQoOo["y"], OOoOo["index"] = QQoooO, OOoOo["tIndex"] = QOQ0O, OOoOo["values"] = OoOoQo, OOoOo["type"] = OQ0QQQ["indexOf"](OQoOo["m"]), OOoOo["now"] = Q0OOoo, QOQ00Q["push"](OOoOo), OoOoQo["push"]("-");
return;
}
OoQoQ = oQO0OO[OQoOo["x"]](OQoOo);
OoOoQo["push"](Q0ooQQ(OoQoQ, OQ0QQQ["indexOf"](OQoOo["m"]))); //执行检测环境函数
}), window[OO0Q0O](oOOo00["deviceInfo"], window["String"]["fromCharCode"](97 + QQoooO), QQ0QQQ, OoOoQo, Q0OOoo); //环境检测完拿到的结果进行加密,并存入deviceInfo
})