杀掉本地进程其实很简单,取得进程ID后,调用OpenProcess函数打开进程句柄,然后调用TerminateProcess函数就可以杀掉进程了。有些情况下并不能直接打开进程句柄,例如WINLOGON等系统进程,因为权限不够。这个时候我们就得先提升自己的进程的权限了。提升权限过程也不复杂,先调用GetCurrentProcess函数取得当前进程的句柄,然后调用OpenProcessToken打开当前进程的访问令牌,接着调用LookupPrivilegeValue函数取得你想提升的权限的值,最后调用AdjustTokenPrivileges函数给当前进程的访问令牌增加权限就可以了。一般有了SeDebugPrivilege特权后,就可以杀掉除Idle外的所有进程了。
RM%Z"pc Y6 OK!那如何杀掉远程进程呢?说起来有点复杂,但其实也不难。
_Co
v >6_i <1>与远程系统建立IPC连接
iRW5*-66f <2>在远程系统的系统目录admin$\system32中写入一个文件killsrv.exe
.aK=z) <3>调用函数OpenSCManager打开远程系统的Service Control Manager[SCM]
[;toumv <4>调用函数CreateService在远程系统创建一个服务,服务指向的程序是在<2>中写入的程序killsrv.exe
2l+'p[b0> <5>调用函数StartService启动刚才创建的服务,把想杀掉的进程的ID作为参数传递给它
02^\np <6>服务启动后,killsrv.exe运行,杀掉进程
Zia6m[ ^Q <7>清场
1-4[w
*u> 嗯!这样看来,我们需要两个程序了。Killsrv.exe的源代码如下:
_{B2z[G} /***********************************************************************
JqN$B\J, Module:Killsrv.c
NXOvC!< Date:2001/4/27
e \kR/<L Author:ey4s
P4MP`A Http://www.ey4s.org 6QPbmO]z ***********************************************************************/
8z&/{:Z@pH #include
f4X}F|!h #include
'/ueY#eG #include "function.c"
+~
S7]AZ #define ServiceName "PSKILL"
4^6Oh#p0 >Zf*u;/dW$ SERVICE_STATUS_HANDLE ssh;
FNl^ lj`Y SERVICE_STATUS ss;
rhQO#_` /////////////////////////////////////////////////////////////////////////
$Ixd;`l* void ServiceStopped(void)
da8
R.1o {
bx" .<q ( ss.dwServiceType=SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS;
hg+;!|ha ss.dwCurrentState=SERVICE_STOPPED;
N7s9"i ss.dwControlsAccepted=SERVICE_ACCEPT_STOP;
k[1[Y{n. ss.dwWin32ExitCode=NO_ERROR;
O1]XoUH< ss.dwCheckPoint=0;
9 771D ss.dwWaitHint=0;
uxq#q1 SetServiceStatus(ssh,&ss);
M
8mNeh return;
1-! |_<EW1 }
kl&_O8E+K /////////////////////////////////////////////////////////////////////////
a ?wg~|g void ServicePaused(void)
BIvz55g {
Y(R],9h8 ss.dwServiceType=SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS;
zzKU s "u ss.dwCurrentState=SERVICE_PAUSED;
127@
TN" ss.dwControlsAccepted=SERVICE_ACCEPT_STOP;
KA`)dMWL ss.dwWin32ExitCode=NO_ERROR;
wp/x|AV ss.dwCheckPoint=0;
P}PMRAek ss.dwWaitHint=0;
2[Qzx%Vp SetServiceStatus(ssh,&ss);
+hWeN&A return;
xJvalb }
mL,{ZL ^ void ServiceRunning(void)
l4^8$@;s {
NXE1v~9V ss.dwServiceType=SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS;
8,m: ss.dwCurrentState=SERVICE_RUNNING;
8HSGOs =8 ss.dwControlsAccepted=SERVICE_ACCEPT_STOP;
Ujly\ix` ss.dwWin32ExitCode=NO_ERROR;
%N<>3c<8P ss.dwCheckPoint=0;
C|ou7g4'p ss.dwWaitHint=0;
%ZlnGr SetServiceStatus(ssh,&ss);
y2C/DyuAY| return;
5_L43- }
Rn whkb&& /////////////////////////////////////////////////////////////////////////
y+VRD void WINAPI servier_ctrl(DWORD Opcode)//服务控制程序
~-(X\:z} {
;Y &2G' switch(Opcode)
tkix@Q!;\ {
9+>%U~U< case SERVICE_CONTROL_STOP://停止Service
KEr?&e ServiceStopped();
u-dF~.x break;
E~Y%x/oX case SERVICE_CONTROL_INTERROGATE:
%A(hmC SetServiceStatus(ssh,&ss);
]<O- break;
D
<Fl7QAb }
o\yqf:V8 return;
kZ
9n@($B }
)4/UzR$ //////////////////////////////////////////////////////////////////////////////
:Z5kiEwYM //杀进程成功设置服务状态为SERVICE_STOPPED
yj`xOncE} //失败设置服务状态为SERVICE_PAUSED
odq3@
ziO //
tbi(e49S void WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)
gem+$TFq {
n<sA?T ssh=RegisterServiceCtrlHandler(ServiceName,servier_ctrl);
xJ|Z]m=d
if(!ssh)
O$peCv {
YpbJoHiSH ServicePaused();
`JG7Pl/ih return;
EY!P"u; }
$%J$ ServiceRunning();
o Bp.|8- Sleep(100);
5 s2/YG= //注意,argv[0]为此程序名,argv[1]为pskill,参数需要递增1
e-o$bf% //argv[2]=target,argv[3]=user,argv[4]=pwd,argv[5]=pid
!]WC~#|{B if(KillPS(atoi(lpszArgv[5])))
ok9G 9|HA ServiceStopped();
%6<2~ else
*FoPs ServicePaused();
A}n5dg0u return;
AwGDy + }
TsZX'Yn /////////////////////////////////////////////////////////////////////////////
E@;v|Xc void main(DWORD dwArgc,LPTSTR *lpszArgv)
X<$8'/p r {
: ]JsUb{YK SERVICE_TABLE_ENTRY ste[2];
\"@ `Rf
ste[0].lpServiceName=ServiceName;
N6-bUM6%I ste[0].lpServiceProc=ServiceMain;
GEf[k OQ ste[1].lpServiceName=NULL;
K,GX5c5 ste[1].lpServiceProc=NULL;
;%aWA StartServiceCtrlDispatcher(ste);
ol8uV{:" return;
_^0)T@ }
15~+Ga4 /////////////////////////////////////////////////////////////////////////////
r;aP`MVO< function.c中有两个函数,一个是提升权限的,一个是提供进程ID,杀进程的。代码如
&@xeWB 下:
&28n1 /***********************************************************************
Sst`*PX: Module:function.c
zn{[]J Date:2001/4/28
Tn3f5ka' Author:ey4s
su]ywVoRT Http://www.ey4s.org (wsvj61 ***********************************************************************/
mkmVDRK #include
4&LoE~ ////////////////////////////////////////////////////////////////////////////
x@>^ c:-f BOOL SetPrivilege(HANDLE hToken,LPCTSTR lpszPrivilege,BOOL bEnablePrivilege)
O/R>&8R$ {
> 'KQL?!F TOKEN_PRIVILEGES tp;
#8jH_bi LUID luid;
=!Y{Mz /%GMbO_ if(!LookupPrivilegeValue(NULL,lpszPrivilege,&luid))
OL"So
u4 {
KbV%8nx!! printf("\nLookupPrivilegeValue error:%d", GetLastError() );
zoBjrAyD return FALSE;
>'zp }
Y:="vWWG tp.PrivilegeCount = 1;
V/-~L]G tp.Privileges[0].Luid = luid;
=8fZG
t if (bEnablePrivilege)
@'!61'}f tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
OG}D;Ew else
QWGFXy,=1 tp.Privileges[0].Attributes = 0;
w]0jq
U6 // Enable the privilege or disable all privileges.
gBG.3\[ AdjustTokenPrivileges(
Uyyw'Ni hToken,
k||DcwO FALSE,
J#W>%2"s &tp,
&hYjQ&n sizeof(TOKEN_PRIVILEGES),
jNNl5. (PTOKEN_PRIVILEGES) NULL,
t|zLR (PDWORD) NULL);
6Gs,-Kb: // Call GetLastError to determine whether the function succeeded.
&_E*]Sj\ if (GetLastError() != ERROR_SUCCESS)
#0 WO~wL {
HCifO printf("AdjustTokenPrivileges failed: %u\n", GetLastError() );
,P d2ZfZ return FALSE;
0-+`{j }
Vkb&'
rXw+ return TRUE;
pf`li]j'V }
2={ g'k( ////////////////////////////////////////////////////////////////////////////
uQ.VW/> BOOL KillPS(DWORD id)
BPd]L=,/ {
r4qFEFV3% HANDLE hProcess=NULL,hProcessToken=NULL;
<cz~q=%v2& BOOL IsKilled=FALSE,bRet=FALSE;
",rA __try
u$[T8UqF {
),6Z1 K1 g%<7Px[W if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hProcessToken))
Va/p
{
~+$l9~`{ printf("\nOpen Current Process Token failed:%d",GetLastError());
6dmTv9e __leave;
/qL&)24 }
n{Mj<\kL //printf("\nOpen Current Process Token ok!");
Ve8`5
if(!SetPrivilege(hProcessToken,SE_DEBUG_NAME,TRUE))
i9)y| {
. yu __leave;
q+o(`N'~G }
{_/6,22j(V printf("\nSetPrivilege ok!");
wL 5).`oq q#Qr@Jf if((hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,id))==NULL)
?t}[Wi}7 {
TCF[iE{ printf("\nOpen Process %d failed:%d",id,GetLastError());
r/O(EW#=8 __leave;
Qzh:*O }
gi@+27; //printf("\nOpen Process %d ok!",id);
T+4Musu{V if(!TerminateProcess(hProcess,1))
g%=\Wiit] {
\aUbBa%! printf("\nTerminateProcess failed:%d",GetLastError());
IW1]H~1w __leave;
$9 DZ5" }
tXKhkt` IsKilled=TRUE;
1=(i{D~ }
Qw5M\
__finally
C.(ZXU7 {
h=4{.EegG& if(hProcessToken!=NULL) CloseHandle(hProcessToken);
9Jk(ID'c if(hProcess!=NULL) CloseHandle(hProcess);
iQGoy@<R }
"3j0) return(IsKilled);
G:e} >' }
{@,
L //////////////////////////////////////////////////////////////////////////////////////////////
IB*%PMTF OK!服务端的程序已经好了。接下来还需要一个客户端。如果通过在客户端运行的时候,把killsrv.exe COPY到远程系统上,那么就需要提供两个exe文件给用户,这样显得不是很专业,呵呵。不如我们就把killsrv.exe的二进制码作为buff保存在客户端吧,这样在运行的时候,我们直接把buff中的内容写过去,这样提供给用户一个exe文件就可以了。Pskill.c的源代码如下:
U0N[~yW(t1 /*********************************************************************************************
3.d=1|E ModulesKill.c
d=4MqX r Create:2001/4/28
d$2{_6 Modify:2001/6/23
cW GU?cv} Author:ey4s
3iEcLhe"4 Http://www.ey4s.org BS|-E6E< PsKill ==>Local and Remote process killer for windows 2k
{U(h]' **************************************************************************/
$uLzC] #include "ps.h"
VBCj.dw #define EXE "killsrv.exe"
QX]tD4OH #define ServiceName "PSKILL"
(I~,&aBr n`:l`n>N$ #pragma comment(lib,"mpr.lib")
\AK|~:\] //////////////////////////////////////////////////////////////////////////
5^d%+*l;q //定义全局变量
s_*eX N SERVICE_STATUS ssStatus;
&gEu%s^wR SC_HANDLE hSCManager=NULL,hSCService=NULL;
}5] s+m BOOL bKilled=FALSE;
.D>lv_kp char szTarget[52]=;
\iE'E //////////////////////////////////////////////////////////////////////////
Om1z
BOOL ConnIPC(char *,char *,char *);//建立IPC连接函数
tt[_+e\4 BOOL InstallService(DWORD,LPTSTR *);//安装服务函数
q3P3euK3 BOOL WaitServiceStop();//等待服务停止函数
8m*\"_S{ BOOL RemoveService();//删除服务函数
W>Rv /////////////////////////////////////////////////////////////////////////
s{:
Mu~v int main(DWORD dwArgc,LPTSTR *lpszArgv)
g*tLqV {
1VZ>*Tl BOOL bRet=FALSE,bFile=FALSE;
<?J7Z| char tmp[52]=,RemoteFilePath[128]=,
+`4}bc,G szUser[52]=,szPass[52]=;
b{dzbmak HANDLE hFile=NULL;
z~Pmh%b DWORD i=0,dwIndex=0,dwWrite,dwSize=sizeof(exebuff);
``E;!r="v F'~/ //杀本地进程
i ('EBO
if(dwArgc==2)
*HXq`B {
X%F9.<4 if(KillPS(atoi(lpszArgv[1])))
vaxg^n|v9 printf("\nLoacl Process %s have beed killed!",lpszArgv[1]);
G[^G~U\+! else
&S-& 'ZAY printf("\nLoacl Process %s can't be killed!ErrorCode:%d",
0,A?*CO lpszArgv[1],GetLastError());
Em]T.'y return 0;
!KlSw,&=.6 }
CM#EA"9 //用户输入错误
0$_imjZ else if(dwArgc!=5)
d!LV@</ {
<V8i>LBlz printf("\nPSKILL ==>Local and Remote Process Killer"
Z{CL! "\nPower by ey4s"
jI V? p "\nhttp://www.ey4s.org 2001/6/23"
/&|pXBY$; "\n\nUsage:%s <==Killed Local Process"
$tKATL* "\n %s <==Killed Remote Process\n",
:cEe4a
lpszArgv[0],lpszArgv[0]);
&Egn`QU return 1;
[:=[QlvV }
<&Uk!1Jd //杀远程机器进程
G7202(w
< strncpy(szTarget,lpszArgv[1],sizeof(szTarget)-1);
.5ycO strncpy(szUser,lpszArgv[2],sizeof(szUser)-1);
*h%G 4M strncpy(szPass,lpszArgv[3],sizeof(szPass)-1);
KN`z68c4L C}kJGi //将在目标机器上创建的exe文件的路径
k:qou})#4 sprintf(RemoteFilePath,"\\%s\admin$\system32\%s",szTarget,EXE);
7fEV/j __try
,Df36-74v5 {
F@lpjW //与目标建立IPC连接
hpyre B if(!ConnIPC(szTarget,szUser,szPass))
Sp )} {
(qP$I:Q4]v printf("\nConnect to %s failed:%d",szTarget,GetLastError());
R
_Y&Y- return 1;
8WGM%n#q }
:V2Q n-N printf("\nConnect to %s success!",szTarget);
}:8>>lQ //在目标机器上创建exe文件
Q(IS= 8JrGZ8Q4RM hFile=CreateFile(RemoteFilePath,GENERIC_ALL,FILE_SHARE_READ|FILE_SHARE_WRIT
!491
\W0ZH E,
E! <$J^ NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
9C 05 if(hFile==INVALID_HANDLE_VALUE)
//,'oh~W {
<`*P/V printf("\nCreate file %s failed:%d",RemoteFilePath,GetLastError());
#]N9/Hij#g __leave;
U:|v(U$"? }
zLqp@\sT //写文件内容
#dt2'V- , while(dwSize>dwIndex)
b?NeSiswn {
)89jP088V 11T\2&Q if(!WriteFile(hFile,&exebuff[dwIndex],dwSize-dwIndex,&dwWrite,NULL))
8'[wa {
-8jqC6mQ printf("\nWrite file %s
=4
H K failed:%d",RemoteFilePath,GetLastError());
bx^EaXj(r __leave;
eM"mP&TTL }
]."c4S_)| dwIndex+=dwWrite;
W>bW1h }
?t42=nvf //关闭文件句柄
UhTr<(@ CloseHandle(hFile);
kf!/9 bFile=TRUE;
zs:7! //安装服务
j1C.#-P[ if(InstallService(dwArgc,lpszArgv))
P0(~~z&%[ {
PZR%8 m}]u //等待服务结束
@b{u/:y if(WaitServiceStop())
&FVlTo1 {
hNo>)$v!s //printf("\nService was stoped!");
IR8&4qOs }
mO>
M=2A else
@<=#i {
an`(?6d //printf("\nService can't be stoped.Try to delete it.");
ncr-i!Jjk }
e:D"_B Sleep(500);
9y*!W //删除服务
DOIWhd5: RemoveService();
-\$cGIL }
jFTV\|C }
26VdRy{[ __finally
XL=R]IC<. {
g VJ#LJ //删除留下的文件
5(7MQuRR if(bFile) DeleteFile(RemoteFilePath);
BQ:Kx _
//如果文件句柄没有关闭,关闭之~
R<-C>D if(hFile!=NULL) CloseHandle(hFile);
15 11<, //Close Service handle
'aP*++^ if(hSCService!=NULL) CloseServiceHandle(hSCService);
}2A1Yt:^P //Close the Service Control Manager handle
`>EvT7u if(hSCManager!=NULL) CloseServiceHandle(hSCManager);
5 hadA>d //断开ipc连接
Hk*cO;c wsprintf(tmp,"\\%s\ipc$",szTarget);
O9X:1>a@i WNetCancelConnection2(tmp,CONNECT_UPDATE_PROFILE,TRUE);
D>e\OfTR: if(bKilled)
C'2 =0oou printf("\nProcess %s on %s have been
Pq>[q?>? killed!\n",lpszArgv[4],lpszArgv[1]);
~+ wamX3 else
g
Pj0H&,. printf("\nProcess %s on %s can't be
hr6e 1Er killed!\n",lpszArgv[4],lpszArgv[1]);
2\\3< }
@h$0S+?: return 0;
1 "7#|=1/ }
cu?(P;mQi //////////////////////////////////////////////////////////////////////////
tB=D&L3 BOOL ConnIPC(char *RemoteName,char *User,char *Pass)
N pND/ {
cu`J2vm3 NETRESOURCE nr;
vW-`=30 char RN[50]="\\";
-b0'Q "HfU,$[ strcat(RN,RemoteName);
{ah~q}(P strcat(RN,"\ipc$");
uEGPgYY ( ,1;8DfVZV nr.dwType=RESOURCETYPE_ANY;
+Cg"2~ nr.lpLocalName=NULL;
}lTZq|;A nr.lpRemoteName=RN;
ls7A5 < nr.lpProvider=NULL;
U.7y8#qf3R `N.$LY;8 if(WNetAddConnection2(&nr,Pass,User,FALSE)==NO_ERROR)
eoe^t:5& return TRUE;
<ii1nz else
E5BgQ5'
return FALSE;
LZC?383' }
y2$;t' /////////////////////////////////////////////////////////////////////////
5 t`ap BOOL InstallService(DWORD dwArgc,LPTSTR *lpszArgv)
^+Vk#_2Q {
,Zf!KQw BOOL bRet=FALSE;
J-\?,4mcP __try
!GGGh0Bj {
TWR$D //Open Service Control Manager on Local or Remote machine
jJ"EGFa8 hSCManager=OpenSCManager(szTarget,NULL,SC_MANAGER_ALL_ACCESS);
s
P4,S(+e if(hSCManager==NULL)
71" JL", {
ERRT_G? printf("\nOpen Service Control Manage failed:%d",GetLastError());
53t-'K0l __leave;
8{<[fZyC }
[&qbc#L //printf("\nOpen Service Control Manage ok!");
a950M7 //Create Service
:6j :9lYL2 hSCService=CreateService(hSCManager,// handle to SCM database
*Z]WaDw ServiceName,// name of service to start
/3[9{r ServiceName,// display name
42>m,fb2[ SERVICE_ALL_ACCESS,// type of access to service
Fv);5LD SERVICE_WIN32_OWN_PROCESS,// type of service
^_KD&%M6 SERVICE_AUTO_START,// when to start service
1:x nD SERVICE_ERROR_IGNORE,// severity of service
%FyygT b;S failure
r%,H*DOu EXE,// name of binary file
_7#tgZyv NULL,// name of load ordering group
]AA%J@ NULL,// tag identifier
U\Ar*b) /T NULL,// array of dependency names
bLM"t0 NULL,// account name
Lcs{OW, NULL);// account password
u[i7:V% //create service failed
7IT l3> if(hSCService==NULL)
1.0!H.>q {
}S
vw,c //如果服务已经存在,那么则打开
>U~|R=* if(GetLastError()==ERROR_SERVICE_EXISTS)
DqzA U7 {
.?0>5-SfY //printf("\nService %s Already exists",ServiceName);
l/ rZcf8z //open service
Lubs{-5lk hSCService = OpenService(hSCManager, ServiceName,
!-5S8b SERVICE_ALL_ACCESS);
<P^hYj-swh if(hSCService==NULL)
5M Wvu,'%8 {
nSxb-Ce printf("\nOpen Service failed:%d",GetLastError());
hyOm9WU __leave;
q^N0abzgP }
;sChxQ=.^ //printf("\nOpen Service %s ok!",ServiceName);
SCurO9RN }
!/nx=vgp else
Itr7lv'5xx {
e*P=2*]M printf("\nCreateService failed:%d",GetLastError());
A} -&C __leave;
\POnsM)+l }
\|~?x#aA }
^b"bRQqm //create service ok
1O9p YW5J else
q qe2,X? {
nQ642i%RQ //printf("\nCreate Service %s ok!",ServiceName);
!)%>AH' }
d=?Mj] 3Rd`Ysp // 起动服务
Jh\:X<q if ( StartService(hSCService,dwArgc,lpszArgv))
j6e}7 {
7rdw` //printf("\nStarting %s.", ServiceName);
{x[;5TM Sleep(20);//时间最好不要超过100ms
X7H'Uk9: while( QueryServiceStatus(hSCService, &ssStatus ) )
;V~rWzKM( {
kG$E
tE# if ( ssStatus.dwCurrentState == SERVICE_START_PENDING)
'(*&Ax {
jJUGZVM6) printf(".");
&]VQR2J}: Sleep(20);
!{Q:(B#ec }
{xv?wenE else
o9ctJf=qn break;
%GX uuE}mX }
R VkU+7 if ( ssStatus.dwCurrentState != SERVICE_RUNNING )
5pM&h~M printf("\n%s failed to run:%d",ServiceName,GetLastError());
`V&1]C8x }
`*NO_K else if(GetLastError()==ERROR_SERVICE_ALREADY_RUNNING)
hV-VeKjZ( {
~!ZmF(: //printf("\nService %s already running.",ServiceName);
T A\4uy6o }
ou'~{-_xd else
NfTCpA {
X&(<G printf("\nStart Service %s failed:%d",ServiceName,GetLastError());
*K(k Kph __leave;
V06CCy8n }
z.3<{-n}0i bRet=TRUE;
;8ET!&k*>E }//enf of try
.hX0c"f]b __finally
V uG?B{ {
:K~rvv\L7 return bRet;
BTTLy^ }
46bl>yk9< return bRet;
pWs\.::B }
g@~!kh,TH /////////////////////////////////////////////////////////////////////////
](W5.a,-$L BOOL WaitServiceStop(void)
D XV@DQ {
7}4'dW. BOOL bRet=FALSE;
<nWKR, //printf("\nWait Service stoped");
, 3X: ) while(1)
TN35CaSmq {
F{k$Atb?g/ Sleep(100);
jt{9e:2% if(!QueryServiceStatus(hSCService, &ssStatus))
>Mvka;T] {
yiVG ]s printf("\nQueryServiceStatus failed:%d",GetLastError());
(j' {~FB break;
7qe7Fl3 }
EntF@ln! if(ssStatus.dwCurrentState==SERVICE_STOPPED)
keLR1qf {
e~{^oM bKilled=TRUE;
FR
x6c bRet=TRUE;
E *F*nd]K break;
9>by~4An? }
A4G,}r *n if(ssStatus.dwCurrentState==SERVICE_PAUSED)
(CdJ;-@D {
VF)uu[
f9 //停止服务
Y1{B c<tC bRet=ControlService(hSCService,SERVICE_CONTROL_STOP,NULL);
D ]OD. break;
xvU]jl6d }
d0(Cn}m"c else
mxQR4"]jY {
c$0_R;4/ //printf(".");
P+<BOG|m continue;
^P`NMSw }
?Z q_9T7 }
_!n}P5 return bRet;
i S% }
OJAx:&