杀掉本地进程其实很简单,取得进程ID后,调用OpenProcess函数打开进程句柄,然后调用TerminateProcess函数就可以杀掉进程了。有些情况下并不能直接打开进程句柄,例如WINLOGON等系统进程,因为权限不够。这个时候我们就得先提升自己的进程的权限了。提升权限过程也不复杂,先调用GetCurrentProcess函数取得当前进程的句柄,然后调用OpenProcessToken打开当前进程的访问令牌,接着调用LookupPrivilegeValue函数取得你想提升的权限的值,最后调用AdjustTokenPrivileges函数给当前进程的访问令牌增加权限就可以了。一般有了SeDebugPrivilege特权后,就可以杀掉除Idle外的所有进程了。
GH1"xR4! OK!那如何杀掉远程进程呢?说起来有点复杂,但其实也不难。
5L,}e<S$ <1>与远程系统建立IPC连接
n\z,/'d" <2>在远程系统的系统目录admin$\system32中写入一个文件killsrv.exe
~@.%m"<. <3>调用函数OpenSCManager打开远程系统的Service Control Manager[SCM]
6/V3.UP- <4>调用函数CreateService在远程系统创建一个服务,服务指向的程序是在<2>中写入的程序killsrv.exe
*3/T;x. <5>调用函数StartService启动刚才创建的服务,把想杀掉的进程的ID作为参数传递给它
mZz="ZLa: <6>服务启动后,killsrv.exe运行,杀掉进程
mtz#}qD66 <7>清场
03E4cYxt5 嗯!这样看来,我们需要两个程序了。Killsrv.exe的源代码如下:
/,=@8k!t? /***********************************************************************
mE%$HZ} Module:Killsrv.c
3I\n_V< Date:2001/4/27
l>*"mh Author:ey4s
+l3=3 Http://www.ey4s.org Ig]iT ***********************************************************************/
+5VLw #include
Suk #include
h\v'9 #include "function.c"
evkH05+;W #define ServiceName "PSKILL"
c:Wze*vI; b306&ZVEk SERVICE_STATUS_HANDLE ssh;
J:&[59 SERVICE_STATUS ss;
)XcOl7XLN /////////////////////////////////////////////////////////////////////////
^uv<6 void ServiceStopped(void)
`\Hf]b {
>SPh2[f ss.dwServiceType=SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS;
H"ZZ.^"5FV ss.dwCurrentState=SERVICE_STOPPED;
yE[#ze ss.dwControlsAccepted=SERVICE_ACCEPT_STOP;
otggN:^Qw ss.dwWin32ExitCode=NO_ERROR;
mU}F!J#6 ss.dwCheckPoint=0;
2^8%>, ss.dwWaitHint=0;
E4m` SetServiceStatus(ssh,&ss);
jck}" N return;
K2%w0ohC }
a5a($D /////////////////////////////////////////////////////////////////////////
y~()|L[ void ServicePaused(void)
NaX {
23~Sjr
ss.dwServiceType=SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS;
>4t+:Ut: ss.dwCurrentState=SERVICE_PAUSED;
>jD[X5Y ss.dwControlsAccepted=SERVICE_ACCEPT_STOP;
B&D}F=U ss.dwWin32ExitCode=NO_ERROR;
cM&{+el ss.dwCheckPoint=0;
y!!2WHvE ss.dwWaitHint=0;
jH_JmYd SetServiceStatus(ssh,&ss);
Q7W>qe%4 return;
B^g ?=|{ }
E*+{t~ void ServiceRunning(void)
B(M6@1m_ {
GvBHd%Ot ss.dwServiceType=SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS;
nqLA}u4IM ss.dwCurrentState=SERVICE_RUNNING;
9-MUX^?u ss.dwControlsAccepted=SERVICE_ACCEPT_STOP;
I_RsYw ss.dwWin32ExitCode=NO_ERROR;
hP15qKy ss.dwCheckPoint=0;
812$`5l ss.dwWaitHint=0;
}sxYxn~ SetServiceStatus(ssh,&ss);
<>Hj
;q5p return;
yj\Nkh }
qT+%;( /////////////////////////////////////////////////////////////////////////
.0es3Rj void WINAPI servier_ctrl(DWORD Opcode)//服务控制程序
55z]&5N {
)rC6*eR switch(Opcode)
I"GB<oB {
H-
$)3"K case SERVICE_CONTROL_STOP://停止Service
AB4(+S*LA ServiceStopped();
fZoHf\B]{ break;
O&Y*pOg case SERVICE_CONTROL_INTERROGATE:
DP|D\+YyYA SetServiceStatus(ssh,&ss);
,k;^G><
= break;
.hifsB~ }
P}4QQw return;
!4X
f~P }
Fx2bwut.K //////////////////////////////////////////////////////////////////////////////
h5^Z2:# //杀进程成功设置服务状态为SERVICE_STOPPED
sc}~8T //失败设置服务状态为SERVICE_PAUSED
lz?$f4TzA //
GaK-t*Q void WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)
,=[?yJy {
ye,>A. ssh=RegisterServiceCtrlHandler(ServiceName,servier_ctrl);
oaIi2=Tf if(!ssh)
++^l]8 {
z62;cv ServicePaused();
r/u A.Aou^ return;
TIQkW, }
QD0"rxZJ ServiceRunning();
q-}Fvel u Sleep(100);
T[g[&K1Y //注意,argv[0]为此程序名,argv[1]为pskill,参数需要递增1
<4HDZ{"M //argv[2]=target,argv[3]=user,argv[4]=pwd,argv[5]=pid
1ng!G 7g if(KillPS(atoi(lpszArgv[5])))
@}}$zv6l, ServiceStopped();
2h5nMI]' else
YTUZoW2 ServicePaused();
sTn<#l6 return;
-;^j:L{ }
zem8G2#c /////////////////////////////////////////////////////////////////////////////
CEX"D` void main(DWORD dwArgc,LPTSTR *lpszArgv)
|#]@Z)xa {
BRgXr SERVICE_TABLE_ENTRY ste[2];
P\1L7%*lU ste[0].lpServiceName=ServiceName;
UG+d-&~Ll ste[0].lpServiceProc=ServiceMain;
\1D<!k\S ste[1].lpServiceName=NULL;
E2R&[Q"% ste[1].lpServiceProc=NULL;
Uq^#r iq StartServiceCtrlDispatcher(ste);
jIC_[ return;
DH\0z[ }
:bwjJ}F /////////////////////////////////////////////////////////////////////////////
TJK[ev};S function.c中有两个函数,一个是提升权限的,一个是提供进程ID,杀进程的。代码如
ChGYTn`X 下:
Egg=yF>T /***********************************************************************
1Q<^8N)pf Module:function.c
}fb#G<3 Date:2001/4/28
L^@'q6*} Author:ey4s
'
aq!^!z Http://www.ey4s.org RtTJ5@V( ***********************************************************************/
Enum/O5 #include
7z JRJ*NB ////////////////////////////////////////////////////////////////////////////
<
$J>9k BOOL SetPrivilege(HANDLE hToken,LPCTSTR lpszPrivilege,BOOL bEnablePrivilege)
6dabU* {
"{@A5A TOKEN_PRIVILEGES tp;
/:~\5}tW LUID luid;
,(qRc(Ho [>8}J" if(!LookupPrivilegeValue(NULL,lpszPrivilege,&luid))
;oW6 NJ {
Z}mLLf E printf("\nLookupPrivilegeValue error:%d", GetLastError() );
[ 9 {*94M return FALSE;
CZud&
< }
xS4w5i2 tp.PrivilegeCount = 1;
TC!Yb_H}gN tp.Privileges[0].Luid = luid;
=,spvy'"*C if (bEnablePrivilege)
52:HNA\E/ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
p>RNPrT else
3er nTD*` tp.Privileges[0].Attributes = 0;
~zCEpU|@N // Enable the privilege or disable all privileges.
=RA / AdjustTokenPrivileges(
x+Ttl4 hToken,
y"bByd|6 FALSE,
k1w_[w[ &tp,
KHe=O1 %QO sizeof(TOKEN_PRIVILEGES),
ehzM)uK (PTOKEN_PRIVILEGES) NULL,
-lbm*
-( (PDWORD) NULL);
|=Eo?Q_ // Call GetLastError to determine whether the function succeeded.
Cn'(<bl if (GetLastError() != ERROR_SUCCESS)
'&x#rjo# {
ZZ2vvtlyG printf("AdjustTokenPrivileges failed: %u\n", GetLastError() );
@e(o129 return FALSE;
8ja$g, }
G`SUxhC k return TRUE;
U
9_9l7&r }
>80;8\ ////////////////////////////////////////////////////////////////////////////
-I*^-+>H BOOL KillPS(DWORD id)
hL/)|N~ {
4 !i$4 HANDLE hProcess=NULL,hProcessToken=NULL;
7S '%
E BOOL IsKilled=FALSE,bRet=FALSE;
6h|q'.Y __try
~zHjMo2 {
B:5Rr}eY+ +o\:d1y if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hProcessToken))
X
iS1\* {
E@@5BEB ~ printf("\nOpen Current Process Token failed:%d",GetLastError());
~HTmO;HNf" __leave;
H5DC[bZMb% }
tjIl-IQ //printf("\nOpen Current Process Token ok!");
veMH if(!SetPrivilege(hProcessToken,SE_DEBUG_NAME,TRUE))
>p)MawT] {
Q\^O64geD __leave;
|v \_@09= }
iP
=V8g?L printf("\nSetPrivilege ok!");
&~8oQC-eF ]JCvyz
H
if((hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,id))==NULL)
DK$X2B"c V {
&M46&^Jho printf("\nOpen Process %d failed:%d",id,GetLastError());
sx7eC __leave;
CnpV:>V= }
W#^2#sjO //printf("\nOpen Process %d ok!",id);
l n{e1':$" if(!TerminateProcess(hProcess,1))
< vL,*.zd {
dYT% printf("\nTerminateProcess failed:%d",GetLastError());
NG--6\ __leave;
=y
[M\m }
SG6kud\b IsKilled=TRUE;
{9?Jj A }
S]bmS6# __finally
BUWqIdg {
ZvNJ^Xz if(hProcessToken!=NULL) CloseHandle(hProcessToken);
kO,zZF& if(hProcess!=NULL) CloseHandle(hProcess);
G}:w@}h/ }
kw#;w=\>R{ return(IsKilled);
RX>xB }
M.x=<:upp //////////////////////////////////////////////////////////////////////////////////////////////
% 5m/ OK!服务端的程序已经好了。接下来还需要一个客户端。如果通过在客户端运行的时候,把killsrv.exe COPY到远程系统上,那么就需要提供两个exe文件给用户,这样显得不是很专业,呵呵。不如我们就把killsrv.exe的二进制码作为buff保存在客户端吧,这样在运行的时候,我们直接把buff中的内容写过去,这样提供给用户一个exe文件就可以了。Pskill.c的源代码如下:
",^Mxm{ /*********************************************************************************************
=T-&j60 ModulesKill.c
!F1M(zFD Create:2001/4/28
,I7E[LU Modify:2001/6/23
d9B]fi} Author:ey4s
/q<__N Http://www.ey4s.org j"}*T PsKill ==>Local and Remote process killer for windows 2k
=7w\
7-.m **************************************************************************/
V,mw[Hw #include "ps.h"
,24p%KJ*X #define EXE "killsrv.exe"
)Hpa}FGT #define ServiceName "PSKILL"
x,rlrxI d*jMZ%@uS #pragma comment(lib,"mpr.lib")
+@94;me //////////////////////////////////////////////////////////////////////////
Yn@lr6s //定义全局变量
mp=z SERVICE_STATUS ssStatus;
W yB3ls~ SC_HANDLE hSCManager=NULL,hSCService=NULL;
8kU!8^mH BOOL bKilled=FALSE;
2^y^q2(r char szTarget[52]=;
v*;-yG& //////////////////////////////////////////////////////////////////////////
C1jHz BOOL ConnIPC(char *,char *,char *);//建立IPC连接函数
q?4p)@# BOOL InstallService(DWORD,LPTSTR *);//安装服务函数
bL'aB{s BOOL WaitServiceStop();//等待服务停止函数
zbk q BOOL RemoveService();//删除服务函数
}\%Fi/6Z{ /////////////////////////////////////////////////////////////////////////
y`F3Hr c int main(DWORD dwArgc,LPTSTR *lpszArgv)
jBgP$g {
O_ChxX0KP BOOL bRet=FALSE,bFile=FALSE;
_I)U%?V+ char tmp[52]=,RemoteFilePath[128]=,
j/fzzI0@ szUser[52]=,szPass[52]=;
<~6h|F8 HANDLE hFile=NULL;
n\xX}, DWORD i=0,dwIndex=0,dwWrite,dwSize=sizeof(exebuff);
ToJ$A`_!` E7.2T^o;M //杀本地进程
#:[t^} if(dwArgc==2)
Tw""}|] g {
V!lZ\) if(KillPS(atoi(lpszArgv[1])))
1DE1.1 printf("\nLoacl Process %s have beed killed!",lpszArgv[1]);
Ov-icDMm else
%>~sJ0 printf("\nLoacl Process %s can't be killed!ErrorCode:%d",
\HKxh:F' lpszArgv[1],GetLastError());
MRb-H1+Xf return 0;
Y8m1M-#w }
d/[;
`ZD+ //用户输入错误
umiBj)r else if(dwArgc!=5)
*M:B\D {
M_"L9^^>N printf("\nPSKILL ==>Local and Remote Process Killer"
%kS(LlL+6 "\nPower by ey4s"
l038%U~U! "\nhttp://www.ey4s.org 2001/6/23"
N+Y]st+ "\n\nUsage:%s <==Killed Local Process"
BI3@|,._N "\n %s <==Killed Remote Process\n",
lu<xv lpszArgv[0],lpszArgv[0]);
.NYbi@bk(< return 1;
Jtr"NS?a] }
fA+,TEB~d //杀远程机器进程
nm6h%}xND< strncpy(szTarget,lpszArgv[1],sizeof(szTarget)-1);
j@SQ~AS strncpy(szUser,lpszArgv[2],sizeof(szUser)-1);
j`~Ms> strncpy(szPass,lpszArgv[3],sizeof(szPass)-1);
8=NM|i BW 4%l //将在目标机器上创建的exe文件的路径
Dpl A? sprintf(RemoteFilePath,"\\%s\admin$\system32\%s",szTarget,EXE);
U56G. __try
] Hzt b {
Dey<OE& //与目标建立IPC连接
]Q>.HH if(!ConnIPC(szTarget,szUser,szPass))
4\Tl\SZ? {
X*{2[+<o printf("\nConnect to %s failed:%d",szTarget,GetLastError());
nlW +.a[ return 1;
_V7r1fY: }
{bJ`~b9e printf("\nConnect to %s success!",szTarget);
FB{KH . //在目标机器上创建exe文件
6YGubH7%_ whi`Z:~ hFile=CreateFile(RemoteFilePath,GENERIC_ALL,FILE_SHARE_READ|FILE_SHARE_WRIT
KG|n E,
mP0yk| NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
^(f"v
e#7v if(hFile==INVALID_HANDLE_VALUE)
X voo= {
A
Q'J9 printf("\nCreate file %s failed:%d",RemoteFilePath,GetLastError());
0w&27wW __leave;
G
8g<>d{j }
kXi6lh //写文件内容
j4|N-: while(dwSize>dwIndex)
MP_ ~<Q {
<vONmE a }bdmomV if(!WriteFile(hFile,&exebuff[dwIndex],dwSize-dwIndex,&dwWrite,NULL))
;" dV"W
{
=a@j= printf("\nWrite file %s
}\\KYyjY failed:%d",RemoteFilePath,GetLastError());
mID"^NOi# __leave;
?o81E2TJO }
95A1:A^t dwIndex+=dwWrite;
<<+\X:, }
psg)*'r //关闭文件句柄
;7?kl>5] CloseHandle(hFile);
@~!wDDS bFile=TRUE;
1(I6.BHW //安装服务
RS)tO0 if(InstallService(dwArgc,lpszArgv))
xv(9IEjt0 {
"B3N*R([" //等待服务结束
g;qx">xJ`o if(WaitServiceStop())
`$,GzS ( {
YKH\rN6X //printf("\nService was stoped!");
~<_2WQ/$ }
ts\5uiB<% else
E"qRw_
~t {
X*/ho //printf("\nService can't be stoped.Try to delete it.");
$c]fPt"i }
9 7GV2]-M Sleep(500);
wy0tgy(' | //删除服务
8u6:=fxb RemoveService();
iBF|&h(\ }
mRL"nC }
2NC.Z; __finally
Sdt`i {
=G7m)! //删除留下的文件
ok!L.ac if(bFile) DeleteFile(RemoteFilePath);
.
$BUw //如果文件句柄没有关闭,关闭之~
-:|?h{q?u if(hFile!=NULL) CloseHandle(hFile);
"e.jZcN* //Close Service handle
L^}_~PO N5 if(hSCService!=NULL) CloseServiceHandle(hSCService);
AK'[c+2[ //Close the Service Control Manager handle
Q.l}NtHwV if(hSCManager!=NULL) CloseServiceHandle(hSCManager);
YC++&Nk //断开ipc连接
^hc!FD wsprintf(tmp,"\\%s\ipc$",szTarget);
)bS yB29S WNetCancelConnection2(tmp,CONNECT_UPDATE_PROFILE,TRUE);
9oYgl1}d if(bKilled)
f .Q\Z'S^ printf("\nProcess %s on %s have been
&J[:awQX killed!\n",lpszArgv[4],lpszArgv[1]);
ED=V8';D else
w65K[l;2 printf("\nProcess %s on %s can't be
)J2mM killed!\n",lpszArgv[4],lpszArgv[1]);
&]`(v}`] }
]V^iN=(_5 return 0;
r[|Xy>Zj }
ULs\+U //////////////////////////////////////////////////////////////////////////
OI|[roMK BOOL ConnIPC(char *RemoteName,char *User,char *Pass)
e?0l" {
A)bWcB}U NETRESOURCE nr;
EK{Eo9l char RN[50]="\\";
|2O]R s (SpX w,: strcat(RN,RemoteName);
-`'I{g&A strcat(RN,"\ipc$");
jyZ (RB d' !]ZWe nr.dwType=RESOURCETYPE_ANY;
((H^2KJn nr.lpLocalName=NULL;
ZGexdc% nr.lpRemoteName=RN;
O#ai)e_uQk nr.lpProvider=NULL;
6a[}'/ mWoAO@}Y if(WNetAddConnection2(&nr,Pass,User,FALSE)==NO_ERROR)
;rF\kX&Jh return TRUE;
$Q &lSVQ else
NCiW^#b return FALSE;
6 eLR2 }
-.1y(k^4E /////////////////////////////////////////////////////////////////////////
XW[j!`nlk BOOL InstallService(DWORD dwArgc,LPTSTR *lpszArgv)
Si_ _8D {
LhA*F[6$M BOOL bRet=FALSE;
}JF13beU __try
A
9( x {
`#rL*;\uV //Open Service Control Manager on Local or Remote machine
umjt]Gu[ hSCManager=OpenSCManager(szTarget,NULL,SC_MANAGER_ALL_ACCESS);
qB5j;@r if(hSCManager==NULL)
Ur9?Td'*> {
"Lzi+1 printf("\nOpen Service Control Manage failed:%d",GetLastError());
NSxoF3 __leave;
ASKf'\,dV }
$Ipg&`S" //printf("\nOpen Service Control Manage ok!");
yQU{zY //Create Service
SEo'(-5 hSCService=CreateService(hSCManager,// handle to SCM database
Z/W:97M ServiceName,// name of service to start
APvDP? ServiceName,// display name
R cAwrsd SERVICE_ALL_ACCESS,// type of access to service
"i
nd$Z`c SERVICE_WIN32_OWN_PROCESS,// type of service
dzARI` SERVICE_AUTO_START,// when to start service
C_(
*>!Z% SERVICE_ERROR_IGNORE,// severity of service
O9G[j=U failure
fa-IhB1!K EXE,// name of binary file
V\>K]mwD NULL,// name of load ordering group
/z4$gb7Y NULL,// tag identifier
YJ^]
u} NULL,// array of dependency names
7r7YNn/? NULL,// account name
B~6&{7xc% NULL);// account password
*F+KqZ.2 //create service failed
vleS2-]| if(hSCService==NULL)
o
m^0}$V {
tClg*A;|B //如果服务已经存在,那么则打开
:G [|CPm- if(GetLastError()==ERROR_SERVICE_EXISTS)
hW%TM3l} {
4;w;'3zq //printf("\nService %s Already exists",ServiceName);
|N4.u
_hM //open service
&TnS4O hSCService = OpenService(hSCManager, ServiceName,
xR-%L SERVICE_ALL_ACCESS);
P9GN}GN%v if(hSCService==NULL)
u7Y
WnD {
Us)Z^s printf("\nOpen Service failed:%d",GetLastError());
?~l6K(*2 __leave;
"~#3&3HVS }
&4 {KV. //printf("\nOpen Service %s ok!",ServiceName);
srr
:!5 }
F5LuSy+v else
Umz KY {
yg`j-9[8 printf("\nCreateService failed:%d",GetLastError());
-Y1e8H =' __leave;
%oF}HF. }
TC N8a/@z }
5 f@)z"j //create service ok
XR8,Vt)= else
J}*,HT * {
qt"G[9; //printf("\nCreate Service %s ok!",ServiceName);
")_|69 VX }
Nu0C;B66 !SC`D])l // 起动服务
Z EXc%-M if ( StartService(hSCService,dwArgc,lpszArgv))
4{}FL {
2n,*Nd` //printf("\nStarting %s.", ServiceName);
gcii9vz
` Sleep(20);//时间最好不要超过100ms
jk"`Z<j~ while( QueryServiceStatus(hSCService, &ssStatus ) )
{i1|R"ta {
wc0jhHZO
? if ( ssStatus.dwCurrentState == SERVICE_START_PENDING)
$CxKuB( {
P]<4R:yb printf(".");
?# Mr Sleep(20);
Z_PNI#h* }
H;D>|q else
Y_Eb'*PY break;
)}''L{k- }
_ftI*ni:< if ( ssStatus.dwCurrentState != SERVICE_RUNNING )
b[__1E9v' printf("\n%s failed to run:%d",ServiceName,GetLastError());
NWP5If|'X }
ZufR{^W else if(GetLastError()==ERROR_SERVICE_ALREADY_RUNNING)
7@#>bE6 {
fs|)l$Rd //printf("\nService %s already running.",ServiceName);
YSs)HV.8 }
V@\gS"Tu else
&d9{k5/+\ {
BoA/6FRi[ printf("\nStart Service %s failed:%d",ServiceName,GetLastError());
ZkgV_<M| __leave;
T`/AY?# }
IWBX'|}K bRet=TRUE;
6T>mW#E& }//enf of try
MtM%{=&_ __finally
sJ\BF {
Dw|}9;5:A return bRet;
`+`Z7 }
+O'3|M return bRet;
,t}vz 7 }
_my"%@n /////////////////////////////////////////////////////////////////////////
6.FY0. i BOOL WaitServiceStop(void)
PEN\-*Pv {
_t:$XJ`bTk BOOL bRet=FALSE;
~Xr=4V:a+ //printf("\nWait Service stoped");
2C2fGYu while(1)
liEPCWl& {
-VZ-<\uH Sleep(100);
?=>+LqP if(!QueryServiceStatus(hSCService, &ssStatus))
?m![Pg% {
R[Ll59- printf("\nQueryServiceStatus failed:%d",GetLastError());
YgKZ#?* break;
[vge56h }
z|fmrwkN'$ if(ssStatus.dwCurrentState==SERVICE_STOPPED)
<m:m &I
8@ {
V=)_yIS bKilled=TRUE;
6\L0mcXR!
bRet=TRUE;
8'n/?.7cX break;
aGK?x1_ }
_AYXc] 4% if(ssStatus.dwCurrentState==SERVICE_PAUSED)
,_|]Ufr!a {
>oea{u //停止服务
l;af~ef)' bRet=ControlService(hSCService,SERVICE_CONTROL_STOP,NULL);
sLh==V;9 break;
A2^\q>_# }
"~E[)^ANxD else
5>VY LI {
nv)2!mAh\ //printf(".");
@|LBn6q continue;
]e>RK' }
F1 iGMf-8 }
L{:9Cx!F return bRet;
Z -,J)gW }
*ohL&