杀掉本地进程其实很简单,取得进程ID后,调用OpenProcess函数打开进程句柄,然后调用TerminateProcess函数就可以杀掉进程了。有些情况下并不能直接打开进程句柄,例如WINLOGON等系统进程,因为权限不够。这个时候我们就得先提升自己的进程的权限了。提升权限过程也不复杂,先调用GetCurrentProcess函数取得当前进程的句柄,然后调用OpenProcessToken打开当前进程的访问令牌,接着调用LookupPrivilegeValue函数取得你想提升的权限的值,最后调用AdjustTokenPrivileges函数给当前进程的访问令牌增加权限就可以了。一般有了SeDebugPrivilege特权后,就可以杀掉除Idle外的所有进程了。
hwPw]Ln/ OK!那如何杀掉远程进程呢?说起来有点复杂,但其实也不难。
4.k0< <1>与远程系统建立IPC连接
@D]5c ivm_ <2>在远程系统的系统目录admin$\system32中写入一个文件killsrv.exe
^ sOQi6pL <3>调用函数OpenSCManager打开远程系统的Service Control Manager[SCM]
=J18eH!] <4>调用函数CreateService在远程系统创建一个服务,服务指向的程序是在<2>中写入的程序killsrv.exe
&xU[E!2H% <5>调用函数StartService启动刚才创建的服务,把想杀掉的进程的ID作为参数传递给它
ZJnYIK <6>服务启动后,killsrv.exe运行,杀掉进程
`"Jj1O@ <7>清场
Q$a{\*[:+ 嗯!这样看来,我们需要两个程序了。Killsrv.exe的源代码如下:
+! ]zA4x /***********************************************************************
6]&OrS[ Module:Killsrv.c
.6ylZ Date:2001/4/27
evya7^,F Author:ey4s
3$jT*OyG# Http://www.ey4s.org )cX*I gO ***********************************************************************/
Ab~3{Q]# #include
qFicBpB #include
B~'vCuE #include "function.c"
Q3XpHnufu+ #define ServiceName "PSKILL"
P9/q|>F `}D,5^9] SERVICE_STATUS_HANDLE ssh;
kI,yU}<Fq SERVICE_STATUS ss;
g!FuY/%+ /////////////////////////////////////////////////////////////////////////
Giid~e33 void ServiceStopped(void)
S){)Z {
8f_l}k$Eg ss.dwServiceType=SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS;
1gE [v ss.dwCurrentState=SERVICE_STOPPED;
L 8c0lx}Nn ss.dwControlsAccepted=SERVICE_ACCEPT_STOP;
sG(~^hJ_ ss.dwWin32ExitCode=NO_ERROR;
9Uh"iMB ss.dwCheckPoint=0;
/Y/UM3/ ss.dwWaitHint=0;
u]g%@3Pn SetServiceStatus(ssh,&ss);
5 )A1\ return;
*1ilkmL% }
|5X^u+_ /////////////////////////////////////////////////////////////////////////
jSJqE_ 1 void ServicePaused(void)
M f}~{+ {
c_dVWh e ss.dwServiceType=SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS;
~G)S
ss.dwCurrentState=SERVICE_PAUSED;
I
)~GZ ss.dwControlsAccepted=SERVICE_ACCEPT_STOP;
;d@#XIS&-( ss.dwWin32ExitCode=NO_ERROR;
!`M,XSp( ss.dwCheckPoint=0;
3#WT.4k ss.dwWaitHint=0;
I:E`PZ SetServiceStatus(ssh,&ss);
df*#!D7oz return;
EZgq ?l~5O }
cF\;_0u void ServiceRunning(void)
5u,{6 {
1;JEc9#h ss.dwServiceType=SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS;
l94b^W}1)W ss.dwCurrentState=SERVICE_RUNNING;
1ufp qqk ss.dwControlsAccepted=SERVICE_ACCEPT_STOP;
J9..P&c\ ss.dwWin32ExitCode=NO_ERROR;
ISzqEi ss.dwCheckPoint=0;
:W"~
{~#? ss.dwWaitHint=0;
?3/qz(bM SetServiceStatus(ssh,&ss);
Je';9(ZK return;
gl~ecc }
Z< 1 /////////////////////////////////////////////////////////////////////////
rbul8(1h void WINAPI servier_ctrl(DWORD Opcode)//服务控制程序
Z@yW bjE7Z {
3>3 Kwc~E switch(Opcode)
D+#E-8 {
?Lx24*5% case SERVICE_CONTROL_STOP://停止Service
.zr-:L5{ ServiceStopped();
$6qh|
>z. break;
gLb`pCo/ case SERVICE_CONTROL_INTERROGATE:
2ElJbN# SetServiceStatus(ssh,&ss);
UI0(=>L break;
;RH;OE,A }
2my_ ;!6T[ return;
C/_ZUF(V }
Tg7an&# //////////////////////////////////////////////////////////////////////////////
FX;QG94! //杀进程成功设置服务状态为SERVICE_STOPPED
O5!7'RZ //失败设置服务状态为SERVICE_PAUSED
%9
SJ
E //
i9rN9Mq?O void WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)
@g|v;B|{ {
W4t;{b ssh=RegisterServiceCtrlHandler(ServiceName,servier_ctrl);
2_)\a(.Qu if(!ssh)
{Je[ZQ$ {
?)/#+[xa ServicePaused();
W= ig.- return;
*tGY6=7O }
*}Xf!"I#]N ServiceRunning();
:Oy%a'w
Sleep(100);
[m->5H //注意,argv[0]为此程序名,argv[1]为pskill,参数需要递增1
SDL7<ZaE //argv[2]=target,argv[3]=user,argv[4]=pwd,argv[5]=pid
Eu0akqZ if(KillPS(atoi(lpszArgv[5])))
'Oxy$U
ServiceStopped();
XUrXnz|> else
q~rEq%tk ServicePaused();
]yV! return;
)"qa kT }
at @G/? /////////////////////////////////////////////////////////////////////////////
*$#W]bO void main(DWORD dwArgc,LPTSTR *lpszArgv)
&g#@3e1> {
}?lrU.@zg SERVICE_TABLE_ENTRY ste[2];
[]D&bYpv ste[0].lpServiceName=ServiceName;
t1]K<>g ste[0].lpServiceProc=ServiceMain;
md+nj{Ib ste[1].lpServiceName=NULL;
=-tw5],
L ste[1].lpServiceProc=NULL;
'_<{p3M StartServiceCtrlDispatcher(ste);
sXqz+z$* return;
bkRLC_/d }
-<6\1J /////////////////////////////////////////////////////////////////////////////
} j<)L, function.c中有两个函数,一个是提升权限的,一个是提供进程ID,杀进程的。代码如
QemyCCP+ 下:
j*d
yp /***********************************************************************
S2E8Gq9 Module:function.c
GeI-\F7b Date:2001/4/28
65L6:}# Author:ey4s
_ "E$v&_ Http://www.ey4s.org B)$| vK= ***********************************************************************/
S&e0u%8mc #include
I) rCd/ ////////////////////////////////////////////////////////////////////////////
uMUBh 80,L BOOL SetPrivilege(HANDLE hToken,LPCTSTR lpszPrivilege,BOOL bEnablePrivilege)
9X[kEl {
.GbX]?dN TOKEN_PRIVILEGES tp;
57aXQ8u{ LUID luid;
(XVw"m/ye ~Cbc<[} if(!LookupPrivilegeValue(NULL,lpszPrivilege,&luid))
AJt+p&I[J {
`K*Q5n printf("\nLookupPrivilegeValue error:%d", GetLastError() );
w?3p';C return FALSE;
PYiU_ }
>u>5{4 tp.PrivilegeCount = 1;
)S3\,S-. tp.Privileges[0].Luid = luid;
>1s*
at/h if (bEnablePrivilege)
>/{@C tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
w2Us!<x else
&]V.S7LC# tp.Privileges[0].Attributes = 0;
7Sf
bx~48 // Enable the privilege or disable all privileges.
Uq[>_"} AdjustTokenPrivileges(
uyO/55;HO hToken,
m&xW6!x FALSE,
``V"
D &tp,
Y)1PB+ sizeof(TOKEN_PRIVILEGES),
lvdf^b/
j (PTOKEN_PRIVILEGES) NULL,
A8xvo/n$ (PDWORD) NULL);
v>:Ur}u!D // Call GetLastError to determine whether the function succeeded.
f<
ia(d if (GetLastError() != ERROR_SUCCESS)
ks&*O!h {
Ki4r<>\l{H printf("AdjustTokenPrivileges failed: %u\n", GetLastError() );
Ac96
[ return FALSE;
)(A]Ln4 }
q6@Lp^f return TRUE;
tI]Q%S, }
$:BKzHmg ////////////////////////////////////////////////////////////////////////////
l~1Oef#y BOOL KillPS(DWORD id)
&]g}u5J!= {
6uv#de HANDLE hProcess=NULL,hProcessToken=NULL;
bNm#tmSt BOOL IsKilled=FALSE,bRet=FALSE;
6O|@xvg __try
oOnop-z7 {
7z/|\D_{ ?OId\'q if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hProcessToken))
O $LfuL {
rr+|Zt
Y printf("\nOpen Current Process Token failed:%d",GetLastError());
l#m#c6;= __leave;
kC WEtbz1 }
oNr-Q& C, //printf("\nOpen Current Process Token ok!");
R(!s if(!SetPrivilege(hProcessToken,SE_DEBUG_NAME,TRUE))
0[A[U_b {
t=rEt>n~L __leave;
mkMq }
yu;+o3WlK printf("\nSetPrivilege ok!");
t!* ?dr kv]~'Srk if((hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,id))==NULL)
Z"Zmo>cV4 {
\@WDV printf("\nOpen Process %d failed:%d",id,GetLastError());
E08klC0 __leave;
>x/z7v?^I }
k;2GEa]w //printf("\nOpen Process %d ok!",id);
wZG\>9~ if(!TerminateProcess(hProcess,1))
l-fi%Z7C {
5k!g%sZ printf("\nTerminateProcess failed:%d",GetLastError());
* ;-*x6 __leave;
1uG"f<TsR }
"&%I)e^ IsKilled=TRUE;
0+iu(VbF }
Y}x>t* I __finally
4^:\0UF {
4Z1ST; if(hProcessToken!=NULL) CloseHandle(hProcessToken);
:X0k]p if(hProcess!=NULL) CloseHandle(hProcess);
%WSo b@f8 }
s&A}
h return(IsKilled);
BD68$y }
@"hb) 8ng //////////////////////////////////////////////////////////////////////////////////////////////
nePfuG]Q OK!服务端的程序已经好了。接下来还需要一个客户端。如果通过在客户端运行的时候,把killsrv.exe COPY到远程系统上,那么就需要提供两个exe文件给用户,这样显得不是很专业,呵呵。不如我们就把killsrv.exe的二进制码作为buff保存在客户端吧,这样在运行的时候,我们直接把buff中的内容写过去,这样提供给用户一个exe文件就可以了。Pskill.c的源代码如下:
5*E]ETo@R /*********************************************************************************************
uvMy^_}L ModulesKill.c
0QFS Create:2001/4/28
zxMXXm; Modify:2001/6/23
^2+yHw Author:ey4s
,">]`|? Http://www.ey4s.org
7_%"BVb" PsKill ==>Local and Remote process killer for windows 2k
{`J)j6; **************************************************************************/
Hv!U|L #include "ps.h"
`lQ3C{} #define EXE "killsrv.exe"
'r4/e-`pK #define ServiceName "PSKILL"
]*vdSr-J j`oy`78O #pragma comment(lib,"mpr.lib")
tU4s'J //////////////////////////////////////////////////////////////////////////
3XL#0\im?s //定义全局变量
\Npxv SERVICE_STATUS ssStatus;
mIurA?&7! SC_HANDLE hSCManager=NULL,hSCService=NULL;
^]7}YF2| BOOL bKilled=FALSE;
(^s>m,h char szTarget[52]=;
O9vQp //////////////////////////////////////////////////////////////////////////
,X#2\r<| BOOL ConnIPC(char *,char *,char *);//建立IPC连接函数
9G9fDG#F\I BOOL InstallService(DWORD,LPTSTR *);//安装服务函数
"k/;[ Wt] BOOL WaitServiceStop();//等待服务停止函数
w0ht BOOL RemoveService();//删除服务函数
S)lkz'tdk /////////////////////////////////////////////////////////////////////////
#EO9UW5 int main(DWORD dwArgc,LPTSTR *lpszArgv)
t=|evOz] {
(gy#js# BOOL bRet=FALSE,bFile=FALSE;
&{ay=Mj char tmp[52]=,RemoteFilePath[128]=,
0":ib0= szUser[52]=,szPass[52]=;
T29Dt HANDLE hFile=NULL;
YX=a#%vrl DWORD i=0,dwIndex=0,dwWrite,dwSize=sizeof(exebuff);
kv3E4,<9 3_txg>P" //杀本地进程
4~y(`\0?4 if(dwArgc==2)
tro7Di2Q {
?h.wK if(KillPS(atoi(lpszArgv[1])))
TX$r`~ printf("\nLoacl Process %s have beed killed!",lpszArgv[1]);
JM=JH
51` else
GYJ80k| printf("\nLoacl Process %s can't be killed!ErrorCode:%d",
MJOz.=CbhR lpszArgv[1],GetLastError());
;hYS6 return 0;
6;u$&&c( }
3
N.~mR //用户输入错误
'3_]Gu-D else if(dwArgc!=5)
Ge2q% {
*-MM<|Qt printf("\nPSKILL ==>Local and Remote Process Killer"
O/,aJCe
"\nPower by ey4s"
Ai:BEPKe "\nhttp://www.ey4s.org 2001/6/23"
{/"2Vk<H8 "\n\nUsage:%s <==Killed Local Process"
-j%,Oo "\n %s <==Killed Remote Process\n",
&f"-d lpszArgv[0],lpszArgv[0]);
1>*#%R?W return 1;
9XPo3; }
u\ #"L //杀远程机器进程
a&tSj35*6 strncpy(szTarget,lpszArgv[1],sizeof(szTarget)-1);
" 7!;KHc strncpy(szUser,lpszArgv[2],sizeof(szUser)-1);
5Y.vJz strncpy(szPass,lpszArgv[3],sizeof(szPass)-1);
V@Rrn <l WfWN(:dF //将在目标机器上创建的exe文件的路径
t?q@H8 sprintf(RemoteFilePath,"\\%s\admin$\system32\%s",szTarget,EXE);
DBPRGQ __try
y&Mr=5:y {
Z9MdD>uwi //与目标建立IPC连接
WP?TX b`5 if(!ConnIPC(szTarget,szUser,szPass))
kgnmGuka {
3|WWo1 printf("\nConnect to %s failed:%d",szTarget,GetLastError());
!u_Y7i3^ return 1;
}lh I\q }
eAXc:222 printf("\nConnect to %s success!",szTarget);
N03HQp)g //在目标机器上创建exe文件
2r!s*b\Ix Zw*v hFile=CreateFile(RemoteFilePath,GENERIC_ALL,FILE_SHARE_READ|FILE_SHARE_WRIT
)^m%i]L_ E,
aa?w:3 NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
whpfJNz if(hFile==INVALID_HANDLE_VALUE)
E}Y!O"CAV {
hJn%mdx~w| printf("\nCreate file %s failed:%d",RemoteFilePath,GetLastError());
crqpV F]1] __leave;
V=zi
>o` }
Y,WuBH //写文件内容
#cnq(S=. while(dwSize>dwIndex)
XM1WfjE\ {
[onGNq?# lp<g\ if(!WriteFile(hFile,&exebuff[dwIndex],dwSize-dwIndex,&dwWrite,NULL))
vV[eWd.o6M {
lLp^Gt^}w( printf("\nWrite file %s
"$N#p5 failed:%d",RemoteFilePath,GetLastError());
'qjeXqGH$ __leave;
>H'4{| }
m1),;RsH dwIndex+=dwWrite;
$UgA0]qn }
R#2 t)y //关闭文件句柄
MOsl_^c CloseHandle(hFile);
vg
D77 bFile=TRUE;
])L
A42| //安装服务
CZ(/=3,3n if(InstallService(dwArgc,lpszArgv))
& @s!<9$W {
KHgBo}6 //等待服务结束
@n(Z$)8tR if(WaitServiceStop())
2ggdWg7z {
q8^^H$<Db //printf("\nService was stoped!");
%F!1 }
#>%X_o-o23 else
X=hYB}}nu {
BDq%'~/^ //printf("\nService can't be stoped.Try to delete it.");
9:,V5n= }
\<y`!"c
Sleep(500);
!OBEM1~
1 //删除服务
x*?x=^I{ RemoveService();
,17hGKM }
>+]_5qc }
wW#}:59} __finally
+w.JpbQ& {
_C(m<n //删除留下的文件
c}y [[EX if(bFile) DeleteFile(RemoteFilePath);
!X"K=zt" //如果文件句柄没有关闭,关闭之~
<(-3_s6- if(hFile!=NULL) CloseHandle(hFile);
AI,(z;{P //Close Service handle
$/.zm;D if(hSCService!=NULL) CloseServiceHandle(hSCService);
Eve.QAl| //Close the Service Control Manager handle
mMb'@ if(hSCManager!=NULL) CloseServiceHandle(hSCManager);
UG)8D5 //断开ipc连接
QS{1CC9$ wsprintf(tmp,"\\%s\ipc$",szTarget);
W0epAGrB WNetCancelConnection2(tmp,CONNECT_UPDATE_PROFILE,TRUE);
Ys,{8Y,7 if(bKilled)
t*>R`,j printf("\nProcess %s on %s have been
enp)-nS0 killed!\n",lpszArgv[4],lpszArgv[1]);
7qj9&bEy else
t: #6sF printf("\nProcess %s on %s can't be
Ttxqf:OMf killed!\n",lpszArgv[4],lpszArgv[1]);
GFel(cx:K }
6
G3\=) return 0;
fcNL$U&-,i }
.2>p3|F //////////////////////////////////////////////////////////////////////////
>p.O0G
gg BOOL ConnIPC(char *RemoteName,char *User,char *Pass)
QAvir%Y9Q {
%,D<O,N NETRESOURCE nr;
|g
#K]v char RN[50]="\\";
jFA{+Yr1 _Y8hb!#( strcat(RN,RemoteName);
^@qvl%j strcat(RN,"\ipc$");
Y}uCP1v 4eikLRD, nr.dwType=RESOURCETYPE_ANY;
7b<je=G6PA nr.lpLocalName=NULL;
/%&2HDA) nr.lpRemoteName=RN;
*M$0J'-BQ nr.lpProvider=NULL;
gF$V$cU n@U n if(WNetAddConnection2(&nr,Pass,User,FALSE)==NO_ERROR)
f}1&HI8r return TRUE;
:{IO=^D=$ else
UEozAY return FALSE;
=$nB/K,8AX }
.G+Pe'4a /////////////////////////////////////////////////////////////////////////
M@?xa/E64 BOOL InstallService(DWORD dwArgc,LPTSTR *lpszArgv)
p;W.lcO`0 {
DdVF, BOOL bRet=FALSE;
2I&o69x? __try
0&/b42W {
9'{}!-(xR //Open Service Control Manager on Local or Remote machine
l2l(_$@3 hSCManager=OpenSCManager(szTarget,NULL,SC_MANAGER_ALL_ACCESS);
q|8{@EMT if(hSCManager==NULL)
M-[$L XR {
^4,a 8` printf("\nOpen Service Control Manage failed:%d",GetLastError());
(cN}Epi(D __leave;
i { \%e }
\'9PZ6q{ //printf("\nOpen Service Control Manage ok!");
cG?cUw).E //Create Service
G(~;]xNW+ hSCService=CreateService(hSCManager,// handle to SCM database
r8,romE$ ServiceName,// name of service to start
7vABq( ServiceName,// display name
( YQWbOk SERVICE_ALL_ACCESS,// type of access to service
*,Za6.= SERVICE_WIN32_OWN_PROCESS,// type of service
w9o^s5n SERVICE_AUTO_START,// when to start service
e _/b2"{ SERVICE_ERROR_IGNORE,// severity of service
j{NNSi3 failure
/Wy.>YC| EXE,// name of binary file
'Er:a?88l NULL,// name of load ordering group
]R=,5kK3 NULL,// tag identifier
#{=;NuP NULL,// array of dependency names
x-?{E NULL,// account name
:PtF+{N> NULL);// account password
ppFe-wY //create service failed
tUgEeh6 if(hSCService==NULL)
nv0]05.4 {
t`+'r}=d //如果服务已经存在,那么则打开
h}]fnA if(GetLastError()==ERROR_SERVICE_EXISTS)
~M\I;8ne {
5!EJxP9 //printf("\nService %s Already exists",ServiceName);
v@wb"jdFi$ //open service
[+OnV& hSCService = OpenService(hSCManager, ServiceName,
7^Ns&Q SERVICE_ALL_ACCESS);
v{9t]s>B if(hSCService==NULL)
X`fn8~5
{
C&6IU8l\ printf("\nOpen Service failed:%d",GetLastError());
7f~Sf __leave;
_L@2_#h! }
,2j.<g&
//printf("\nOpen Service %s ok!",ServiceName);
rtL}W__ }
.N*Pl(<[ else
VMCLHpSfW {
({NAMc* printf("\nCreateService failed:%d",GetLastError());
kiRa+w: __leave;
CYKr\DA }
jiYmb8Q4D }
ZKXo-~=> //create service ok
!>>f(t4 else
.VkbYK {
Dgx8\~(E' //printf("\nCreate Service %s ok!",ServiceName);
J]q%gcM }
1c;6xc,ub #'q<v"w // 起动服务
v*9<c{a if ( StartService(hSCService,dwArgc,lpszArgv))
3 q`)* {
SL,p36N //printf("\nStarting %s.", ServiceName);
2e|N@j
& Sleep(20);//时间最好不要超过100ms
^qC;Nh4F while( QueryServiceStatus(hSCService, &ssStatus ) )
Ton94:9bZ {
3;8!rNN if ( ssStatus.dwCurrentState == SERVICE_START_PENDING)
ZvUCI8 {
Y&
F=t/U2 printf(".");
&`fhEN Sleep(20);
{&"L~>/o }
(I@rLvZr{ else
eQVZO>)P1+ break;
J@OB`2?Zv }
H<QT3RF2 if ( ssStatus.dwCurrentState != SERVICE_RUNNING )
J7v|vjI printf("\n%s failed to run:%d",ServiceName,GetLastError());
MSV2ip3 }
A.D{.a else if(GetLastError()==ERROR_SERVICE_ALREADY_RUNNING)
l27\diKPJ {
1]}#)- //printf("\nService %s already running.",ServiceName);
8HZs>l }
lhi_6&&[8 else
fPR$kch
{
tw(JZDc printf("\nStart Service %s failed:%d",ServiceName,GetLastError());
[2dn\z28 __leave;
(E,Yo }
Raw)9tUt bRet=TRUE;
/'hC i]b@v }//enf of try
\T;\XAGr __finally
ru`U' {
9W8]8sUeG return bRet;
nN~~cV }
gN>2xnh'm return bRet;
r@{~ 5&L }
^+
wD43 /////////////////////////////////////////////////////////////////////////
{<5ybbhLV BOOL WaitServiceStop(void)
R@wjccu {
4pln5v= BOOL bRet=FALSE;
Qjnd6uv{I //printf("\nWait Service stoped");
[j"9rO" + while(1)
*#TYqCc+g {
{VP$J"\e Sleep(100);
k64."*X if(!QueryServiceStatus(hSCService, &ssStatus))
TI !a )X {
|TE}`?y[g printf("\nQueryServiceStatus failed:%d",GetLastError());
gh>>Ibf break;
1lsLJ4P }
IQ!\w- if(ssStatus.dwCurrentState==SERVICE_STOPPED)
gaf$uT2
{
k@ K7yK bKilled=TRUE;
3b YCOqG bRet=TRUE;
~Aq5XI%i break;
720)VzT }
Pub0IIs if(ssStatus.dwCurrentState==SERVICE_PAUSED)
7 t?* {
(n1Bh~R^ //停止服务
=0-
$W5E bRet=ControlService(hSCService,SERVICE_CONTROL_STOP,NULL);
xP=/N!,# break;
lKkN_ (/j }
S2>c#BQ else
s!9dQ. {
|8bq>01~ //printf(".");
fgj^bcp- continue;
OgcHS? }
!6G?zipB }
j&