ua.js中arguments.callee.caller的应用
actionlog_js_ua.js混淆编程形式与执行主流程
ua.js中mousedown和mousemove事件自定义函数功能解析
ua.js中JSocket.getlso和JSocket.setlso代码分析
ua.js中arguments.callee.caller的应用
在ua.js文件中,用到arguments.callee和arguments.callee.caller的函数名为su。据我的理解,这个函数的作用是:在每一次UA更新时,获取当前更新UA的函数名,按照函数执行次序依次将函数名存储在变量uv5中。
1. arguments.callee
callee 是 arguments 对象的属性,在该函数的函数体内,它可以指向当前正在执行的函数;arguments.callee.caller返回调用当前正在执行的函数的函数。但是在ECMAScript 第五版 (ES5) 的 严格模式 中禁止使用 arguments.callee()和arguments.callee.caller,到这里查看原因。
2. 函数su的传入参数
函数su的调用处的调用形式全部一致:su(wjt(ovh(“” + arguments.callee)), “” + arguments.callee); 函数su及相关函数的代码如下。这里先认为函数ovh为加密函数,其作用是将当前正在执行的函数名加密后返回一个字符串str;假设函数wjt执行时的时间为time,那么结合函数wjt的代码可知su函数调用时的参数形式:hnp1[0]=str+time; hnp1[1]=aytz(time);tu= “”+ arguments.callee
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
su = function (hnp1, tu) { //tf在变量初始化时为false, 第一次调用su后会被置位true //那么该if语句仅在第一次调用时执行 if (!tf) { //变量vi记录的函数名为su,仅第一次调用su时,记录函数名su var vi = ovh("" + arguments["callee"]);// uv5["push"](vi); tf = true; } var sk2 = ovh("" + arguments["callee"]["caller"]); if (tu == "" || typeof tu == "undefined" || hnp1[0] != (sk2 + tno(hnp1[1]))) { f1(sk2, "r"); return; } uv5["push"](sk2); }; wjt = function (sb) { var dqto = new ere["Date"]()["getTime"](); return [sb + dqto, aytz(dqto)]; }; aytz = function (iqi, bgo) { var y = 4; var s1i = "";//空字符串 //uxkj为当前时间的16进制形式的字符串 var uxkj = (iqi)["toString"](16) for (var i = uxkj["length"]; i > 0; i = i - 4) { s1i = s1i + "" + window["String"]["fromCharCode"]("0x" + uxkj["substring"](i - 4, i)); } return s1i; }; tno = function (s1i, bgo) { var iqi = ""; var kdic = "" + s1i; for (var i = kdic["length"] - 1; i >= 0; i--) { var fd6 = kdic["charCodeAt"](i)["toString"](16); while (fd6["length"] != 4) { fd6 = "0" + fd6; } iqi = iqi + irt + fd6; } iqi = upc["parseInt"](iqi, 16); return iqi; }; ovh = function (er3k) { er3k = er3k["replace"](/[^g-km-svwyzG-KM-SVWYZ_$=]/g, irt); var sk2 = 31, i = 0, isr = er3k["length"]; while (i < isr) { //charCodeAt: 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数 sk2 ^= (sk2 << 5) + (sk2 >> 2) + er3k["charCodeAt"](i++); } return sk2; }; |
1 |
1 2 3 4 |
f1 = function (yu6, v7tw) { f(["ic", yu6, v7tw]); gby(); }; |
3. 函数su的执行逻辑
3.1 由su的代码可知,变量tf非常关键。变量tf初始化为false,第一次调用su后会被置为true。该变量初始化所在函数是ua.js最外层的匿名函数,所以除非ua.js的最外层匿名函数被重新调用,tf的值将保持为true。因此ua.js第一次调用时,会在uv5中存储su的函数名。
3.2 获取当前正在执行的su的调用函数Unicode编码,存入到变量sk2中。
3.3 判断条件if (tu == “” || typeof tu == “undefined” || hnp1[0] != (sk2 + tno(hnp1[1])))是否成立。函数su定义时需要输入两个参数{su = function (hnp1, tu)},所有调用su的地方均传入了两个参数,所以前两个条件均不会满足。另外tno与aytz互为反函数,所以第三个条件也不成立。因此理论上而言,该条件不会成立,所以该条件下的代码不会被执行。若万一此条件成立,会调用函数f1,而f1函数中会调用gby。在ua.js中网络超时检测函数 wql 功能分析一文中我们提到过gby是一个故障处理函数,所以基本可以认为若此条件成立,那必定是发生了异常。
3.4 当前调用su的函数存入到变量uv5中。
3.5 ua.js中还有一个函数与uv5相关。该函数在更新UA的函数vq4中调用,判断当前函数的调用者是否已经存在于uv5中,若存在该函数会返回true,而事实上,所有su调用的地方都在vq4函数之前,也就是说这个函数一定会返回true。与3.3中同样的道理,万一此函数返回false,会先调用故障处理函数,所以可以认为若在调用vq4时,调用vq4的函数名不在变量uv5中,那么程序将会抛出异常。
1 2 3 4 5 6 7 8 9 |
m2x = function (hnp1, l4xy) { for (var i = 0, isr = uv5["length"]; i < isr; i++) { if (hnp1 == uv5[i]) { return true; } } f1(hnp1, l4xy); return false; }; |
根据以上分析,函数su和变量uv5的作用基本可以认为是用于监控ua.js文件中执行流程是否有异常,若出现异常,程序将抛出异常;若无异常,则继续执行。而判断异常的标准由两点:a. 在函数su中检查传入的变量是否合理,合理的状况如3.3所述,否则为不合理。; b. 在vq4调用时,判断当前调用vq4的函数是否已经存在变量uv5中,若已存在为合理现象,若不存在则不合理。不知道这样认为是否合理?