终止进程的内幕

终止进程的内幕

转自: pjf

有来信询问进程结束的有关问题,下面就这个问题简单讨论一下(下面的讨论基于2000,其他NT系统也类似)。
首先看看一个应用程序想要强制结束另一个进程所要做的事:首先获得目标的进程ID,接着利用OpenProcess获取进程句柄(确保足够权限),最后将句柄传给TerminateProcess了结那个进程。
1、OpenProcess通过本机系统服务接口进入核心态,随后调用ntoskrnl的NtOpenProcess。在服务函数里,系统使用SeSinglePrivilegeCheck检查调用者是否有DEBUG权限(SeDebugPrivilege),若有,则修改AccessState使得在后面的操作中获取允许任意进程访问操作的句柄。最后通过ObOpenObjectByName或PsLookupProcess*** + ObOpenObjectByPointer来打开进程(创建并返回进程句柄)。
2、TerminateProcess通过本机系统服务接口进入核心态,随后调用ntoskrnl的NtTerminateProcess。系统首先调用ObReferenceObjectByHandle获取进程执行体块,执行体块的DebugPort指出进程是否处于调试状态,若处于调试状态且传入的ExitStatus为DBG_TERMINATE_PROCESS则返回失败禁止结束进程。随后服务函数转入正题:
系统利用ThreadListHead枚举进程的每一个线程,使用PspTerminateThreadByPointer来结束它们。注意并不是对每个线程系统都会忠实地执行你的命令:若枚举到的线程是系统线程则不会继续执行而是返回STATUS_INVALID_PARAMETER。判断的方法是线程的Teb为零或者Teb的值在内核地址空间。有人问2000下为何csrss.exe进程杀不死,很简单,打开IceSword,在进程栏利用右键菜单的“线程信息”看一下,看到那几个Teb为零的线程没有?(注意是针对windows2000,XP下不同。另外一点就是csrss中其它非系统线程的线程是很容易被杀死的,试图结束csrss时也可以看到在Teb为零的线程前面的线程已被杀掉,只是操作停在了Teb为零的线程这里) 再看看system进程,呵呵。IceSword也并未提供杀除这种进程的功能,因为觉得没有需求。在最后一个线程结束时,进程的生命也结束了,随着PspExitProcess/ObKillProcess灰飞烟灭。
另一方面,线程是怎样结束的呢。PspTerminateThreadByPointer并不是直接“杀掉”指定线程,实质上线程是“自杀”的,呵呵。系统简单的使用KeInitializeApc/KeinsertQueueApc插入了一个核心态的APC调用,若是用户线程,会再插入用户态的APC调用,最终线程在自己的执行环境中使用PspExitThread(…=>KeTerminateThread=>KiSwapThread)悲壮的自行了断。
有人问起为什么IceSword有时杀不死除那三个有系统线程的进程(两个是csrss、system,而idle是个非常奇特的存在,与众不同,这里不多废话了)外的其它进程。从上面的讨论可以找到答案。这种情况往往是目标进程的某用户态线程进入核心态后,系统出了某些问题挂死在核心态,无法返回执行Apc例程的缘故。IceSword未强制除去它们是考虑此刻系统可能已经有某些问题,强制删除操作更有可能使系统崩溃,不过有了不少用户要求有这项功能,所以以后有空可能会加上(已经有一大堆杂七杂八的要求了,很难有时间升级一下版本,~_~)。
一般来说,要干掉一个进程,有了Debug权限就可以了,若别人有了保护,那就要发挥你的能力了。

我想上面的讨论对于想要杀除进程、保护进程的人有一些启发了吧。

随机日志

发表评论

0 评论.

Leave a Reply



[ Ctrl + Enter ]

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word

CNXCT小组的博客 is Stephen Fry proof thanks to caching by WP Super Cache