在使用4G上网浏览网页的时候,经常会出现下面这个气泡。即使是用电脑使用了手机的个人热点也不能例外。

流量框

有的时候,这个东西可以说很贴心,它可以实时告诉你还剩多少流量,是该猛着用还是省着用。当你不小心使用电脑狂用自己个人热点的流量的时候,这个流量气泡也会提醒你“你在烧钱ing!”,能够防止更大的损失。

不过也有时候,这个东西会非常烦人。譬如,它偶尔会弹广告!建议您办理每月400元的移动豪华套餐,or 参与大富豪抽奖……老子忙着呢,抽你妹啊!

它的实现原理是什么呢?中国移动,如何能够在任意浏览的网页里,插入自己的内容?
其实很简单,中国移动只是嵌入一段很短的js标签,这个标签所指向内容的代码就会运行,接下来10086就可以在整个页面里兴风作浪了,增加一个iframe,在iframe里实现自己的气泡、各种流量查询功能、积分、广告……

下面是插入的javascript的内容:

1
2
3
4
<script type="text/javascript" id="1qa2ws"
src="http://221.179.140.145:9090/tlbsgui/baseline/scg.js"
mtid="4" mcid="2" ptid="4" pcid="2">
</script>

当然我不确定那个id是不是会泄露自己的信息,我也不知道别人的id是不是也是这个,但为了友好还是写出来了。By the way, 这个script在非移动网络是失效的。当你使用的不是中国移动蜂窝网络,是无法链接221.179.140.145的。

当然了,即使在蜂窝网络下:

1
2
3
4
5
6
7
8
9
zach$ ping -c 5 221.179.140.145
PING 221.179.140.145 (221.179.140.145): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
--- 221.179.140.145 ping statistics ---
5 packets transmitted, 0 packets received, 100.0% packet loss

在蜂窝网络下也访问不了?并不是,这最多说明中国移动把ICMP关了吧。

不管它的访问地址了,先看看js代码里有什么猫腻。打开sript标签中的js代码:

1
(function(){try{var h=function(){if(top.tlbs&&!top.tlbsEmbed){top.tlbsEmbed=true;var u=top.tlbs,y=top.tlbs.iframejs.split("|"),t='<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';for(var d=0;d<y.length;d++){t+='<script src="'+y[d]+'" defer charset="UTF-8"><\/script>'}t+="</head></html>";var v=document.createElement("iframe");v.style.display="none";document.body.appendChild(v);try{var x=v.contentWindow.document;x.write(t);x.close()}catch(w){if(/MSIE/g.test(navigator.userAgent)){if(location.href.indexOf("www.people.com.cn")>=0||location.href.indexOf("www.caijing.com.cn")>=0){return}}v.src="javascript:void((function(){document.open();document.domain='"+document.domain+"';document.write('"+t+"');document.close()})())"}}};var a=function(d){if(d.readyState){d.onreadystatechange=function(){if(d.readyState=="loaded"||d.readyState=="complete"){d.onreadystatechange=null;h()}}}else{d.onload=function(){h()}}};var r=function(e){var d=e.length,u="";for(var t=0;t<d;t++){if(!(/^(ptid|pcid|mcid|mtid|src|type|id)$/.test(e[t].name))){u=u+"&"+e[t].name+"="+e[t].value}}return u};var j=function(){var z=document,D=z.getElementById("1qa2ws"),e=D.getAttribute("mtid"),y=D.getAttribute("mcid"),C=D.getAttribute("src"),w=z.head||z.getElementsByTagName("head")[0],A=D.attributes,B=r(A);s=z.createElement("script");a(s);s.charset="UTF-8";var v=new Date();var x=v.getTime();if(/Windows NT/g.test(navigator.userAgent)){e=D.getAttribute("ptid")||e;y=D.getAttribute("pcid")||y}s.src=C.split("tlbsgui")[0]+"tlbsserver/jsreq?tid="+e+"&cid="+y+"&time="+x+encodeURI(B);w.appendChild(s)};if(parent==self){if(location.href.indexOf("nba.sina.cn")>=0){window.onload=function(){j()}}else{j()}}else{var g=top.window.document;if(null==g){return}var m=g.getElementById("1qa2ws");if(m!=null){return}else{var b=document.createElement("script"),n=document.getElementById("1qa2ws"),p=n.getAttribute("mtid"),f=n.getAttribute("mcid");b.setAttribute("type","text/javascript");b.setAttribute("id","1qa2ws");b.src=n.getAttribute("src");b.setAttribute("mtid",p);b.setAttribute("mcid",f);b.setAttribute("ptid",n.getAttribute("ptid")||p);b.setAttribute("pcid",n.getAttribute("pcid")||f);top.window.document.body.appendChild(b)}}}catch(k){var l=document;var q=l.getElementById("1qa2ws");var o=q.getAttribute("src");var i=k.message;i+="&time="+new Date().getTime();var c=document.createElement("script");c.onload=c.onreadystatechange=function(){if(!this.readyState||this.readyState==="loaded"||this.readyState==="complete"){c.onload=c.onreadystatechange=null;document.body.removeChild(c)}};c.src=o.split("tlbsgui")[0]+"tlbsserver/stagelog?"+i;document.body.appendChild(c)}})(window);

这么乱,连个换行都没有?!看个鬼啊!没关系,我们有JSNICE,一个让混淆过的JS更有亲和力的工具,自带缩进,自带类型提示,甚至会有一定的反混淆的功能,把混淆后的变量名尽可能地按照意思还原回去。棒!经过它的处理之后,代码变成了下面这个样子,是不是易读多了?

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
(function() {
try {
/**
* @return {undefined}
*/
var done = function() {
if (top.tlbs && !top.tlbsEmbed) {
/** @type {boolean} */
top.tlbsEmbed = true;
var topDocument = top.tlbs;
var codeSegments = top.tlbs.iframejs.split("|");
/** @type {string} */
var theChar = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
/** @type {number} */
var i = 0;
for (;i < codeSegments.length;i++) {
theChar += '<script src="' + codeSegments[i] + '" defer charset="UTF-8">\x3c/script>';
}
theChar += "</head></html>";
/** @type {Element} */
var iframe = document.createElement("iframe");
/** @type {string} */
iframe.style.display = "none";
document.body.appendChild(iframe);
try {
var iDoc = iframe.contentWindow.document;
iDoc.write(theChar);
iDoc.close();
} catch (w) {
if (/MSIE/g.test(navigator.userAgent)) {
if (location.href.indexOf("www.people.com.cn") >= 0 || location.href.indexOf("www.caijing.com.cn") >= 0) {
return;
}
}
/** @type {string} */
iframe.src = "javascript:void((function(){document.open();document.domain='" + document.domain + "';document.write('" + theChar + "');document.close()})())";
}
}
};
/**
* @param {Node} script
* @return {undefined}
*/
var loadScript = function(script) {
if (script.readyState) {
/**
* @return {undefined}
*/
script.onreadystatechange = function() {
if (script.readyState == "loaded" || script.readyState == "complete") {
/** @type {null} */
script.onreadystatechange = null;
done();
}
};
} else {
/**
* @return {undefined}
*/
script.onload = function() {
done();
};
}
};
/**
* @param {Array} a
* @return {?}
*/
var extend = function(a) {
var aLength = a.length;
/** @type {string} */
var destination = "";
/** @type {number} */
var i = 0;
for (;i < aLength;i++) {
if (!/^(ptid|pcid|mcid|mtid|src|type|id)$/.test(a[i].name)) {
/** @type {string} */
destination = destination + "&" + a[i].name + "=" + a[i].value;
}
}
return destination;
};
/**
* @return {undefined}
*/
var init = function() {
/** @type {HTMLDocument} */
var doc = document;
/** @type {(HTMLElement|null)} */
var element = doc.getElementById("1qa2ws");
/** @type {string} */
var guess = element.getAttribute("mtid");
/** @type {string} */
var dep = element.getAttribute("mcid");
/** @type {string} */
var expr = element.getAttribute("src");
var svg = doc.head || doc.getElementsByTagName("head")[0];
/** @type {(NamedNodeMap|null)} */
var map = element.attributes;
var marker = extend(map);
/** @type {Element} */
s = doc.createElement("script");
loadScript(s);
/** @type {string} */
s.charset = "UTF-8";
/** @type {Date} */
var defaultCenturyStart = new Date;
/** @type {number} */
var size = defaultCenturyStart.getTime();
if (/Windows NT/g.test(navigator.userAgent)) {
/** @type {string} */
guess = element.getAttribute("ptid") || guess;
/** @type {string} */
dep = element.getAttribute("pcid") || dep;
}
/** @type {string} */
s.src = expr.split("tlbsgui")[0] + "tlbsserver/jsreq?tid=" + guess + "&cid=" + dep + "&time=" + size + encodeURI(marker);
svg.appendChild(s);
};
if (parent == self) {
if (location.href.indexOf("nba.sina.cn") >= 0) {
/**
* @return {undefined}
*/
window.onload = function() {
init();
};
} else {
init();
}
} else {
/** @type {Document} */
var doc = top.window.document;
if (null == doc) {
return;
}
/** @type {(HTMLElement|null)} */
var m = doc.getElementById("1qa2ws");
if (m != null) {
return;
} else {
/** @type {Element} */
var script = document.createElement("script");
/** @type {(HTMLElement|null)} */
var n = document.getElementById("1qa2ws");
/** @type {string} */
var scriptID = n.getAttribute("mtid");
/** @type {string} */
var dataUri = n.getAttribute("mcid");
script.setAttribute("type", "text/javascript");
script.setAttribute("id", "1qa2ws");
/** @type {string} */
script.src = n.getAttribute("src");
script.setAttribute("mtid", scriptID);
script.setAttribute("mcid", dataUri);
script.setAttribute("ptid", n.getAttribute("ptid") || scriptID);
script.setAttribute("pcid", n.getAttribute("pcid") || dataUri);
top.window.document.body.appendChild(script);
}
}
} catch (e) {
/** @type {HTMLDocument} */
var _document = document;
/** @type {(HTMLElement|null)} */
var scriptNode = _document.getElementById("1qa2ws");
/** @type {string} */
var expr = scriptNode.getAttribute("src");
var data = e.message;
data += "&time=" + (new Date).getTime();
/** @type {Element} */
var node = document.createElement("script");
/** @type {function (): undefined} */
node.onload = node.onreadystatechange = function() {
if (!this.readyState || (this.readyState === "loaded" || this.readyState === "complete")) {
/** @type {null} */
node.onload = node.onreadystatechange = null;
document.body.removeChild(node);
}
};
/** @type {string} */
node.src = expr.split("tlbsgui")[0] + "tlbsserver/stagelog?" + data;
document.body.appendChild(node);
}
})(window);

这个代码加长了之后有184行,所以还是有一些复杂的。不过大概还是分析一下架构:

主题分为这么几个部分,首先是一个外围的主函数function(){}(window);,主函数内部用一个try{}catch(e){}括起来,方便进行错误处理。

然后try内部定义了一些函数,包括

  • done : 用于最终的iframe构建
  • loadScript : 用于判断信息是否收集完全
  • extend : 用于把JS的Key-Value对转化为应对HTTP GET请求的&;串
  • init : 增加流量气泡的函数入口

为了方便理解,我做了一个调用init前的逻辑序列图:

init前逻辑过程

打开网页,script运行的时候,首先是不会管这些函数的,而是直接运行line120的判断语句。如果parent==self那么就运行init()
这里专门对于nba.sina.cn做了一个判断,我估计是作为一个体育网站,经常有直播的内容,而文字直播经常是用ajax实现的,或许和10086的这个添加的iframe有某些冲突,被专门投诉了吧,所以对于这个网站,加载方式不太一样,所以使用了onload函数,在加载页面的时候运行init。
sina.cn和sina.com.cn还不是完全一样,sina.cn默认是专门为手机浏览器设计的。

如果parent != self的话,就说明当前的视口不是顶级浏览器,很可能是出于某个iframe嵌套中,所以要找到顶级窗体的内容(var doc = top.window.document)然后在顶级窗体中进行处理。
第138行,找到ID为1qa2ws的项目,这个我在前面也说了,那个旧市script的ID。如果已经有这个ID了,那就说明,顶级的窗体已经家再过相应的script了,所以有一个气泡就够了,下层的就别操心了,所以139行检测到存在这个script,就直接退出了。
如果不存在,那就说明,作为下层iframe的内容,还需要再挣扎一下,142行到158行,就是在尝试构建上文中的那个script标签的内容,然后把这个script放置到顶层的浏览器视口中。

161行,cache error,如果出错了怎么办,首先找到刚才的script,把src值赋予expr,然后把错误信息综合进入data中吧,最后再使用document建立一个新的script - node,把data发送到tlbsserver/stagelog那边去,让它们在后台写入log,让开发人员慢慢分析去了。

到这里这一层逻辑就结束了。

下面,关于init、extend、done、loadScript又是什么,它们之间的关系又是什么呢?
这里给一个init后的示意图:
init后函数过程

下面具体研究上述的四个函数。可以知道,入口函数肯定是init的,因为其他几个在主代码中都没有用到。init函数从86行开始到119行。
首先它找到1qa2ws的ID,也就是那个Script标签,然后获取一些feature,创建了一个新的script s,118行,把s放到svg中。svg就是head。

什么鬼?这个script中,最重要的init的目的,无非是由新增一个script到head中?

是的,就是这个样子,所以很多玄机应该都在这个s中罢。

具体地,这个s的内容是:

1
s.src = expr.split("tlbsgui")[0] + "tlbsserver/jsreq?tid=" + guess + "&cid=" + dep + "&time=" + size + encodeURI(marker);

其中的expr就是原来script的src部分,截取tlbsgui之前的部分,再加上后面一堆东西。
那么新的src应该就是

1
http://221.179.140.145:9090/tlbsserver/jsreq?tid=4&cid=2&time=1449641644008%MARKER

%SIZE的具体内容应该是得到的时间var size = defaultCenturyStart.getTime();defaultCenturyStart其实就是new Date(),故弄玄虚。
%MARKER的具体内容就是element.attributes了。extend函数就是把这些key-value对用&=连缀起来,作为GET的参数。

我用手机访问了一下http://221.179.140.145:9090/tlbsserver/jsreq?tid=4&cid=2&time=1449641644008,没有加MARKER,还好可以访问到,获得了一个应该是json。

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
top.tlbs=
{
name : '流量助手',
tlbaurl : '221.179.140.145:30000',
tid : '4',
cid : '2',
url : 'http://221.179.140.145:9090/',
css : 'http://221.179.140.145:9090/tlbsgui/baseline/L_bar/css/tlbs_min.css?vv=104|http://221.179.140.145:9090/tlbsgui/baseline/L_bar/buoy/css/fluxball_min.css?vv=104|http://221.179.140.145:9090/tlbsgui/customize/L_bar/bjyd/css/tlbs_min.css?vv=104',
iframejs : 'http://221.179.140.145:9090/tlbsgui/baseline/common/js/UA.js?v=20151209141500|http://221.179.140.145:9090/tlbsgui/customize/L_bar/bjyd/js/config.js?vv=104&uflag=20151120041024|http://221.179.140.145:30000/tlbagui/common/jquery/jquery-1.11.1.min.js|http://221.179.140.145:9090/tlbsgui/baseline/L_bar/js/tlbs_min.js?vv=104|http://221.179.140.145:9090/tlbsgui/customize/L_bar/bjyd/js/simplifiedCloseHandler.js?vv=104'
};
top.tlbs.config=
{
n:
{
t:-1,a:'',
c:'1',
s:40,
edv:0,
p:{}
}
};
top.tlbs.templatesettings =
{
resCode : '0',
dockingPosition : '0',
buoyPosition : '59.919,35.294,1'
};

好了,这应该就非常清晰了,因为这个json,把name、网址端口、css、js的地址都发送回来了,还有各种辅助的参数。拿到这些内容,就可以最终访问了。

有人会问,这个js地址,都用|来分隔了,键入这个地址肯定没法使用啊!别着急,这个并不是直接用的,而是用处理函数的,而具体的处理函数就在Done里面,对于|,见11行。

这个过程是:首先使用loadScript函数,检测一下相关的load工作有没有完成,完成了之后,就去运行Done函数。
Done函数就在读取这个json中的内容,Done函数的过程,就是建立一个iframe,把json中的参数填写进去,这个iframe的效果不是别的,就是那个流量气泡!

在Done的错误处理中,有一小段

1
2
3
4
5
if (/MSIE/g.test(navigator.userAgent)) {
if (location.href.indexOf("www.people.com.cn") >= 0 || location.href.indexOf("www.caijing.com.cn") >= 0) {
return;
}
}

我也没仔细看,估计是跟人民网、财经网有不兼容,或者这两个网跟中国移动说了“别再我的网站上加插件!”,所以检测到网址中有这个字符的时候,就不再挣扎着放置iframe了。
我觉得,也许不想让中国移动在自己的网页上放置气泡的方法,就是在自己的网址中放入”www.people.com.cn”字样。并没有测试,也没有完整追究这两个网站,仅仅是猜想。

我还尝试下载了上述一些js,再次强调只有移动网络内部才能够访问得到,其他网络是无法访问221.179.140.145等网址的。
其中http://221.179.140.145:9090/tlbsgui/baseline/common/js/UA.js?v=20151209141500这个js的内容很简单:

1
top.tlbs.blacklist =[]

随便找另一个js:http://221.179.140.145:9090/tlbsgui/customize/L_bar/bjyd/js/simplifiedCloseHandler.js?vv=104
它的内容是:

1
$(function(){function e(){$d.dialog.find("[name=toolbar-close]").bind("click",f)}var d=top.tlbs.url+"tlbsgui/customize/L_bar/bjyd/css/simplifiedClose_min.css",c='<t:d class= "close-contents"><t:ii class="intro-text">{$RES_SIMPLIFIED_PROMPT}</t:ii><t:ii class="ts-closeoption"><input type="radio" id="radio1" name="minimize" value="minimize" checked="checked"><t:d class="radioImg1"></t:d><span id ="label1" class="w-minimize">{$RES_SIMPLIFIED_MINIMIZE}</span></input><input type="radio" id="radio2" name="close" value="close"><t:d class="radioImg2"></t:d><span id ="label2" class="w-close">{$RES_SIMPLIFIED_CLOSE}</span></input></t:ii></t:d><t:d class="ts-action"><t:d class="ts-cancel"><t:ii class="ts-i">{$RES_SIMPLIFIED_CANCEL}</t:ii></t:d><t:d class="vertical-line"></t:d><t:d class="ts-yes"><t:ii class="ts-i">{$RES_SIMPLIFIED_CONFIRM}</t:ii></t:d></t:d>';$(document).ready(function(){e();params=top.tlbs.config.simplifiedCloseMenu;i(top.tlbs,$d.dialog,params);j()});var i=function(l,k,m){if(m==1){$(k).find("[name=toolbar-close]").empty();if($(k).find("ts-header").length<=0){}$(k).find("[name=toolbar-close]").css("display","block").append(c.res(top.tlbs.res,"RES")).siblings().hide();$(k).find("label").css("display","inline-block").css("font-size","0.8em");$(k).find(".ts-action").css("padding","0em").css("background","#fff");l.load.css(d)}};var j=function(){var n={w:0,h:0};resizeFactor=1;var k=navigator.userAgent;var l=function(){var o=tlbs.data.screen.width(),p=top.window.innerHeight;if(/Chrome/i.test(k)&&(Math.abs(n.w-o/resizeFactor)>10||Math.abs(n.h-p)>10)){m()}};setInterval(l,250);var m=function(){var o=tlbs.data.screen.width(),p=top.window.innerHeight;if(o==0||!$d.tlbs){setTimeout(m,100);return}else{if(!tlbs.ua.resize){return}}n={w:o,h:p};var q=(typeof window.orientation=="number"&&typeof window.onorientationchange=="object");if(q){if(top.window.orientation==0||top.window.orientation==180){$d.dialog.find(".radioImg2").removeClass("radioImg2lands");$d.dialog.find(".radioImg1").removeClass("radioImg1lands")}else{$d.dialog.find(".radioImg2").addClass("radioImg2lands");$d.dialog.find(".radioImg1").addClass("radioImg1lands")}}};return m};var f=function(m){var l=$(m.target).closest(".ts-cancel");var k=$(m.target).closest(".ts-yes");var q=$(m.target).closest("#label1");var p=$(m.target).closest("#label2");var o=$(m.target).closest(".radioImg1");var n=$(m.target).closest(".radioImg2");if(q.is("#label1")){top.document.getElementById("radio1").checked=1;top.document.getElementById("radio2").checked=0;$d.dialog.find(".radioImg2").css("background-image","url("+top.tlbs.format.url(top.tlbs.workspace)+"/images/content/radio_unCheck.png)");$d.dialog.find(".radioImg1").css("background-image","url("+top.tlbs.format.url(top.tlbs.workspace)+"/images/content/radio_check.png)")}else{if(p.is("#label2")){top.document.getElementById("radio2").checked=1;top.document.getElementById("radio1").checked=0;$($d.dialog).find(".radioImg2").css("background-image","url("+top.tlbs.format.url(top.tlbs.workspace)+"/images/content/radio_check.png)");$($d.dialog).find(".radioImg1").css("background-image","url("+top.tlbs.format.url(top.tlbs.workspace)+"/images/content/radio_unCheck.png)")}else{if(o.is(".radioImg1")){top.document.getElementById("radio1").checked=1;top.document.getElementById("radio2").checked=0;$d.dialog.find(".radioImg2").css("background-image","url("+top.tlbs.format.url(top.tlbs.workspace)+"/images/content/radio_unCheck.png)");$d.dialog.find(".radioImg1").css("background-image","url("+top.tlbs.format.url(top.tlbs.workspace)+"/images/content/radio_check.png)")}else{if(n.is(".radioImg2")){top.document.getElementById("radio2").checked=1;top.document.getElementById("radio1").checked=0;$d.dialog.find(".radioImg2").css("background-image","url("+top.tlbs.format.url(top.tlbs.workspace)+"/images/content/radio_check.png)");$d.dialog.find(".radioImg1").css("background-image","url("+top.tlbs.format.url(top.tlbs.workspace)+"/images/content/radio_unCheck.png)")}else{if(l.is(".ts-cancel")){top.tlbs.autohide.enable(true);top.tlbs.autohide.activate();$d.dialog.hide()}else{if(k.is(".ts-yes")){a();top.tlbs.autohide.enable(true);top.tlbs.autohide.activate();$d.dialog.hide()}}}}}}};function a(){var k=g();if(k=="close"){h();if(top.tlbs.config.SimplifiedCloseMenuOption==0){top.tlbs.log("type=1&op=5");top.tlbs.log("type=5&op=5&appid=010&functionId=005&tid="+top.tlbs.tid+"&cid="+top.tlbs.cid)}else{if(top.tlbs.config.SimplifiedCloseMenuOption==1){top.tlbs.log("type=1&op=3");top.tlbs.log("type=5&op=3&appid=010&functionId=003&tid="+top.tlbs.tid+"&cid="+top.tlbs.cid)}else{if(top.tlbs.config.SimplifiedCloseMenuOption==2){top.tlbs.log("type=1&op=4");top.tlbs.log("type=5&op=4&appid=010&functionId=004&tid="+top.tlbs.tid+"&cid="+top.tlbs.cid)}else{if(top.tlbs.config.SimplifiedCloseMenuOption==3){top.tlbs.log("type=1&op=6");top.tlbs.log("type=5&op=6&appid=010&functionId=006&tid="+top.tlbs.tid+"&cid="+top.tlbs.cid)}}}}}else{if(k=="minimize"){top.tlbs.autohide.activate();b()}else{alert("please select one radio button")}}}var b=function(){top.tlbs.animate.popup.hide(function(){top.tlbs.animate.content.hide(function(){top.tlbs.log("type=1&op=2");top.tlbs.log("type=5&op=2&functionId=002&tid="+top.tlbs.tid+"&cid="+top.tlbs.cid)})})};var h=function(){top.tlbs.animate.popup.hide(function(){top.tlbs.animate.content.hide(function(){$(top.document.body).children(".tlbs").css("display","none")})});if(top.tlbs.banner){top.tlbs.banner.elem.css("display","none");$(top.document.body).css("margin-top",0);top.tlbs.animate.resolveScroll.setMarginTop("0px")}if(top.tlbs.ball){top.tlbs.ball.hidden=true;top.tlbs.ball.mixedPkg=true;$("tlbs-flux",top.document).remove()}};function g(){var k;if(top.document.getElementById("radio2").checked){k=top.document.getElementById("radio2").value}else{if(top.document.getElementById("radio1").checked){k=top.document.getElementById("radio1").value}else{k=null}}return k}});

这个内容就多了,而且能够找到很多资源,譬如/images/content/radio_check.png等等,这些肯定就是最终的那些控件图标了。
又随便找一个css:http://221.179.140.145:9090/tlbsgui/baseline/L_bar/css/tlbs_min.css?vv=104,这个就复杂很多,有很多CSS内容。这也就最终支持了气泡的CSS样式吧。

好了,再深挖就不知道要挖到哪里去了,时间有限就先分享这么多了。