-
-
[分享]关于ZwTerminateProcess函数
-
发表于:
2014-2-26 14:09
7534
-
[分享]关于ZwTerminateProcess函数
某些ARK会用以下代码来结束进程,对于很多有进程保护的程序都很有效:
PsLookupProcessByProcessId();
KeStackAttachProcess();
ZwTerminateProcess(0,0);
注意ZwTerminateProcess函数的第一个参数,这是要结束进程的句柄。对于进程句柄来说,-1表示当前进程,而在这里为什么用0呢?我们来分析下NtTerminateProcess:
(图1)
图1中可以看到代码一开始先是获取当前线程的ETHREAD,然后获得当前先得的当前进程的KPROCESS(也就是EPROCESS),判断ProcessHandle是否为NULL,如果不为NULL则设置局部标志IsProcessHandleSpecified为TRUE,如果为NULL的话则先设置ProcessHandle为-1,然后把IsProcessHandleSpecified设置为FALSE。
图(2)
这里很简单,仅仅是根据传入的进程句柄得到对应的EPROCESS对象,这里我们称作TerminateProcess,也就是要结束的进程。
图(3)
图(3)就是一个循环,利用PsGetNextProcessThread来遍历进程中的每个线程,如果线程不是当前线程,就用PspTerminateThreadByPointer结束掉,显然,没有这个判断如果在遍历过程中遍历到当前线程,把自己结束了,就无法继续了。
转换成C代码就是:
for (Thread = PsGetNextProcessThread (Process, NULL);
Thread != NULL;
Thread = PsGetNextProcessThread (Process, Thread)) {
st = STATUS_SUCCESS;
if (Thread != SelfThread) {
PspTerminateThreadByPointer (Thread, ExitStatus, FALSE);
}
}
图(4)
图4可以看到,这里有两个判断,一个是判断TerminateProcess是不是当前进程,如果是的话再判断IsProcessHandleSpecified是不是TRUE,如果为真,则结束当前线程,如果不为真则不会结束当前线程。
这里是关键,在Attach环境下,虽然是在别的线程的地址空间,但是线程仍然是原始的线程,因此,上面的结束进程的代码可以结束掉其他进程,然后ProcessHandle设置为NULL,就会避免NtTerminateProcess把自己的线程也给结束掉。我写了个测试程序,在IOCTL里调用ZwTerminateProcess结束自己的进程,如果ProcessHandle设置为-1,则IsProcessHandleSpecified为TRUE,那么在上面的循环结束本进程的其他线程后,就会走到图4的代码段里,结束当前线程,这样进程就自杀了。而如果把ProcessHandle设置为0,会导致把本进程除当前线程外的线程都给杀掉,却无法结束当前线程,如果当前线程是主线程的话,就无法结束进程。因此在本文开始的代码中,ZwTerminateProcess的ProcessHandle参数必须设置为NULL才行。
此文为转载。我觉得很有意思,与大家分享。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)