如果是被人从TaskMgr杀掉的,那么便很难从被杀进程的用户态DUMP文件中找到线索。正像用户态栈中所显示的,普通线程大都数时候都是在等待,此时线程实际上是在内核态的,大多时候是在睡觉。这时有人要杀它,其实也就是调用TerminateProcess API,对应的也就是NtTerminateProcess内核服务。这个内核服务检查权限没有问题后,就开始下手了,清理这个进程了,也就是说用户态的代码根本没机会执行,在“睡梦”中就结束使命了。
下面是TaskMgr在执行杀进程动作时的过程:
0:000> kvn # ChildEBP RetAddr Args to Child 00 0007f694 0100c22c 000000a0 00000001 000a07b6 kernel32!TerminateProcess (FPO: [2,0,0])01 0007f6d0 0100ceef 00001630 00000000 00330728 taskmgr!CProcPage::KillProcess+0xaf (FPO: [2,8,0])02 0007f6e4 0100d1d0 000003f2 000a07b6 0007f7b8 taskmgr!CProcPage::HandleWMCOMMAND+0x40 (FPO: [2,0,4])03 0007f750 7e418724 00330728 00000111 000003f2 taskmgr!ProcPageProc+0x249 (FPO: [4,20,4])
其中a0是被杀进程的进程句柄,1是所谓的退出代码:
BOOL WINAPI TerminateProcess( __in HANDLE hProcess, __in UINT uExitCode);就连这个退出代码,在用户态的转储中也看不到。如果是在收到进程退出事件时通过内核会话来看进程的EPROCESS结构,那么可以看到这个ExitCode,保存在ExitStatus字段中:
lkd> dt _EPROCESS 89a04da0 -y exitnt!_EPROCESS +0x078 ExitTime : _LARGE_INTEGER 0x1ca0dcb`bdf5b880 +0x24c ExitStatus : 1
可以看到,与从TaskMgr的栈回溯中看到的一样。