模拟PspTerminateProcess结束进程-学习笔记

时间:2022-02-14 15:56:23

此文是阅读黑防上胡文亮大牛《模拟实现NT系统通用PspTerminateProcess》后作为学习笔记记录下来的,仅作学习记录,理解错的请勿拍砖。和通过特征暴力搜索定位PspTerminateProcess的地址的方法相比,亮点就是模拟了实现PspTerminateProcess,PspTerminateThreadByPointer等函数。

此前先看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权限就可以了,若别人有了保护,那就要发挥你的能力了。

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

有了上面的了解,就可以隐约得出一个实现PspTerminateProcess的流程,就好比要干掉一个组织,你得先从茫茫人海根据该组织人员的特征去找该组织成员,然后找到一个杀一个,直到杀光后这个组织也就完了。就是枚举出目标进程的线程,然后通过PspTerminateThreadByPointer 去结束线程。 代码如下:

PS:

模拟PspTerminateProcess 一下命名为ForceTerminateProcess

ForceTerminateThread 是模拟PspTerminateThreadByPointer 阅读时注意

NTSTATUS ForceTerminateProcess(PEPROCESS Process)
{
ULONG i;
PETHREAD txtd;
PEPROCESS txps;
NTSTATUS st = STATUS_UNSUCCESSFUL;
for (i=8;i<=65536;i=i+4)
{
st = PsLookupThreadByThreadId(i,&txtd);
if ( NT_SUCCESS(st) )
{
txps=IoThreadToProcess(txtd);
if ( txps == Process )
{
ForceTerminateThread(txtd);
}
}
}
return STATUS_SUCCESS;
}
这个自己实现的PspTerminateProcess和原来的PspTerminateProcess有点区别。原来的PspTerminateProcess是通过PEPROCESS的hreadListHead链表来获取所有线程。这里是作者用来一个认为足够大的数字(65536)来枚举出目标进程的所有线程。理论上线程ID上限为2的32次方-1,因此在不考虑极端现象,使用足够大的数字来枚举。
其过程为:循环用{ PsLookupThreadByThreadId传入线程ID获取线程结构指针,再通过IoThreadToProcess传入线程指针结构,返回线程所属的进程指针,然后对比确定该线程属于目标进程后,调用PspTerminateThreadBypointer传入该线程结构指针,日掉它}。
如果打个比喻说上面的模拟PspTerminateProcess的作用是从茫茫人海找出组织成员的话,那么杀手就是PspTerminateThreadBypointer了(这里是ForceTerminateThread)。那么这个杀手PspTerminateThreadBypointer是怎么杀死线程的呢?再回头拜读PJF的《进程终止的内幕》可知,具体模拟代码如下:

NTSTATUS ForceTerminateThread(PETHREAD Thread)
{
ULONG SYS_THREAD = 0x10;
NTSTATUS st = STATUS_UNSUCCESSFUL;
ULONG Size = 0;
ULONG i = 0;
PKAPC pApc = 0;
if ( MmIsAddressValid((PVOID)Thread) == TRUE)//判断是否有效地址
{
pApc = ExAllocatePool(NonPagedPool, sizeof(KAPC));//分配内存
//Fix Thread Type To SYSTEM THREAD
*(PULONG)((ULONG)Thread+EToffSET)=SYS_THREAD; //XP=0x248, 2K3=0x240, VISTA+2k8=0x260, Win7=0x280 //给CrossThreadFlags赋值
//If APC is OK
if (pApc)
{
KeInitializeApc(pApc, Thread, OriginalApcEnvironment, ApcCallBack, 0, 0, KernelMode, 0);//初始化APC
KeInsertQueueApc(pApc, pApc, 0, 2);//插入APC队列
}
st = STATUS_SUCCESS;
}
return st;
}

其主要实现为,用KeInitializeApc初始化APC,再用KeInsertQueueApc插入线程。APC的回调过程为:

VOID ApcCallBack(PKAPC Apc,PKNORMAL_ROUTINE *NormalRoutine,PVOID *NormalContext,PVOID *SystemArgument1,PVOID *SystemArgument2)
{
ExFreePool(Apc);
PsTerminateSystemThread(STATUS_SUCCESS);
}
这样线程是在自己的执行环境调用PsTerminateSystemThread进行自杀了。因为PsTerminateSystemThread只能结束系统线程,而且只对当前线程有效。 因此,在初始化APC之前,我们得对线程结构的CrossThreadFlags动下手脚,这个是用来判断是否为系统线程的标志。我们将其赋值为0x10(系统线程标志常量PS_CROSS_THREAD_FLAGS_SYSTEM),这样就能让PsTerminateSystemThread以为是系统线程了。
其实现为:使用线程指针+CrossThreadFlags偏移来定位CrossThreadFlags,然后赋值。
( *(PULONG)((ULONG)Thread+EToffSET)=SYS_THREAD; //XP=0x248, 2K3=0x240, VISTA+2k8=0x260, Win7=0x280)
这里也是唯一使用硬编码的地方。不同版本的windows系统,ETHREAD结构的CrossThreadFlags偏移不同XP=0x248, 2K3=0x240, VISTA+2k8=0x260, Win7=0x280这样根据不同版本的系统选择不同的偏移量就能实现通用的PspTerminateProcess了。
作者文中的附带的驱动还实现了其它的功能,为了防止他人阅读混淆,我特地精简了一下,以及对分发函数的Control Code做了一点小改变。源码属于作者。我WInXP+WinDDK

MyKiller.c

//#define WINVER 0x0500 //VC6.0默认编译环境为WINVER=0x0400 
#include "ntddk.h"
#include <windef.h>
#include <stdlib.h>
#include "MyKiller.h"
//#include "dbghelp.h"

//===========================================
/*
typedef struct _KAPC_STATE
{
LIST_ENTRY ApcListHead[2];
PVOID Process;
BOOLEAN KernelApcInProgress;
BOOLEAN KernelApcPending;
BOOLEAN UserApcPending;
}KAPC_STATE, *PKAPC_STATE;
*/
typedef enum _KAPC_ENVIRONMENT
{
OriginalApcEnvironment,
AttachedApcEnvironment,
CurrentApcEnvironment,
InsertApcEnvironment
}KAPC_ENVIRONMENT;

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString);
NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
VOID DriverUnload(PDRIVER_OBJECT pDriverObj);
NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
/*
NTKERNELAPI VOID KeAttachProcess (PEPROCESS Process);
NTKERNELAPI VOID KeDetachProcess (VOID);
*/
NTKERNELAPI NTSTATUS PsLookupProcessByProcessId (IN ULONG ProcessId,OUT PEPROCESS *Process);
NTKERNELAPI NTSTATUS PsLookupThreadByThreadId (IN ULONG ThreadId,OUT PETHREAD *Thread);
NTKERNELAPI PEPROCESS IoThreadToProcess(IN PETHREAD Thread);
NTKERNELAPI BOOLEAN MmIsAddressValid(IN PVOID VirtualAddress);
NTKERNELAPI NTSTATUS PsTerminateSystemThread(IN NTSTATUS ExitStatus);
NTKERNELAPI VOID KeInitializeApc(PKAPC Apc,PETHREAD Thread,KAPC_ENVIRONMENT Environment,PKKERNEL_ROUTINE KernelRoutine,PKRUNDOWN_ROUTINE RundownRoutine,PKNORMAL_ROUTINE NormalRoutine,KPROCESSOR_MODE ProcessorMode,PVOID NormalContext);
NTKERNELAPI BOOLEAN KeInsertQueueApc(PKAPC Apc,PVOID SystemArgument1,PVOID SystemArgument2,KPRIORITY Increment);
//====================
PEPROCESS eProcess;
ULONG processID;
ULONG EToffSET=0x248; //default is XP
//====================

VOID ApcCallBack(PKAPC Apc,PKNORMAL_ROUTINE *NormalRoutine,PVOID *NormalContext,PVOID *SystemArgument1,PVOID *SystemArgument2)
{
ExFreePool(Apc);
PsTerminateSystemThread(STATUS_SUCCESS);
}

NTSTATUS ForceTerminateThread(PETHREAD Thread)
{
ULONG SYS_THREAD = 0x10;
NTSTATUS st = STATUS_UNSUCCESSFUL;
ULONG Size = 0;
ULONG i = 0;
PKAPC pApc = 0;
if ( MmIsAddressValid((PVOID)Thread) == TRUE)
{
pApc = ExAllocatePool(NonPagedPool, sizeof(KAPC));
//Fix Thread Type To SYSTEM THREAD
*(PULONG)((ULONG)Thread+EToffSET)=SYS_THREAD; //XP=0x248, 2K3=0x240, VISTA+2k8=0x260, Win7=0x280
//If APC is OK
if (pApc)
{
KeInitializeApc(pApc, Thread, OriginalApcEnvironment, ApcCallBack, 0, 0, KernelMode, 0);
KeInsertQueueApc(pApc, pApc, 0, 2);
}
st = STATUS_SUCCESS;
}
return st;
}

NTSTATUS ForceTerminateProcess(PEPROCESS Process)
{
ULONG i;
PETHREAD txtd;
PEPROCESS txps;
NTSTATUS st = STATUS_UNSUCCESSFUL;
for (i=8;i<=65536;i=i+4)
{
st = PsLookupThreadByThreadId(i,&txtd);
if ( NT_SUCCESS(st) )
{
txps=IoThreadToProcess(txtd);
if ( txps == Process )
{
ForceTerminateThread(txtd);
}
}
}
return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING ustrLinkName;
UNICODE_STRING ustrDevName;
PDEVICE_OBJECT pDevObj;
//dprintf("[MyKiller] DriverEntry: %S\n",pRegistryString->Buffer);
// Create dispatch points for device control, create, close.
pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
pDriverObj->DriverUnload = DriverUnload;
RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);
status = IoCreateDevice(pDriverObj,
0,
&ustrDevName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&pDevObj);
//dprintf("[MyKiller] Device Name %S",ustrDevName.Buffer);
if(!NT_SUCCESS(status))
{
//dprintf("[MyKiller] IoCreateDevice = 0x%x\n", status);
return status;
}
RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
status = IoCreateSymbolicLink(&ustrLinkName, &ustrDevName);
if(!NT_SUCCESS(status))
{
//dprintf("[MyKiller] IoCreateSymbolicLink = 0x%x\n", status);
IoDeleteDevice(pDevObj);
return status;
}
//dprintf("[MyKiller] SymbolicLink:%S",ustrLinkName.Buffer);
return STATUS_SUCCESS;
}

VOID DriverUnload(PDRIVER_OBJECT pDriverObj)
{
UNICODE_STRING strLink;
RtlInitUnicodeString(&strLink, LINK_NAME);
//
// Delete the symbolic link
//
IoDeleteSymbolicLink(&strLink);
//
// Delete the device object
//
IoDeleteDevice(pDriverObj->DeviceObject);
//dprintf("[MyKiller] Unloaded\n");
}

NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
//dprintf("[MyKiller] IRP_MJ_CREATE\n");
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}

NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
//dprintf("[MyKiller] IRP_MJ_CLOSE\n");
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}

NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
PIO_STACK_LOCATION pIrpStack;
ULONG uIoControlCode;
PVOID pIoBuffer;
ULONG uInSize;
ULONG uOutSize;
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch(uIoControlCode)
{
case IOCTL_ApcKps:
{
__try
{
memcpy(&processID,pIoBuffer,sizeof(processID));
PsLookupProcessByProcessId(processID,&eProcess);
ForceTerminateProcess(eProcess);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
;
}
break;
}
case IOCTL_OffSet:
{
__try
{
memcpy(&EToffSET,pIoBuffer,sizeof(EToffSET));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
;
}
break;
}
//OVER
}
if(status == STATUS_SUCCESS)
pIrp->IoStatus.Information = uOutSize;
else
pIrp->IoStatus.Information = 0;

pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);

return status;
}

{  MyKiller.h 头文件 }

#include <devioctl.h>

#ifndef _MYKILLER_H
#define _MYKILLER_H 1
//============================================
#define DEVICE_NAME L"\\Device\\devMyKiller" //Driver Name
#define LINK_NAME L"\\DosDevices\\MyKiller" //Link Name
//============================================
#define IOCTL_BASE 0x800

#define MY_CTL_CODE(i) \
CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_BASE+i, METHOD_BUFFERED, FILE_ANY_ACCESS)

#define IOCTL_ApcKps MY_CTL_CODE(1)
#define IOCTL_OffSet MY_CTL_CODE(2)
//============================================

#endif

附上本人driver通讯部分Delphi源码。

unit uMain;

{
MichaelJScofield
}

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ExtCtrls;

type
TfrmKiller = class(TForm)
lblInfo: TLabel;
edtOSVersion: TEdit;
lblPid: TLabel;
edtPID: TEdit;
btnKill: TButton;
btnLoad: TButton;
btnUnload: TButton;
lvProcessList: TListView;
tmrRefresh: TTimer;
procedure btnKillClick(Sender: TObject);
procedure btnLoadClick(Sender: TObject);
procedure btnUnloadClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure lvProcessListSelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean);
procedure tmrRefreshTimer(Sender: TObject);
private
procedure GetProcessList;
public
{ Public declarations }
end;

const
Windows_2000 = 0;
Windows_XP = 1;
Windows_2003 = 2;
Windows_Vista = 3;
Windows_7 = 4;

var
frmKiller: TfrmKiller;
function GetSystemVersion:string;


implementation
uses
PsAPI,
TlHelp32,
WinSvc,
PsClass,
IoCtrl;

var
// svrsta: SERVICE_STATUS;
PsDrvCtrl: TDriverControl;

{$R *.dfm}

{ Get Windows OS Version }
{
else if Win32Platform=VER_PLATFORM_WIN32_WINDOWS then
begin
if AWin32Version=4.0 then
Result := os + '95'
else if AWin32Version=4.1 then
Result := os + '98'
else if AWin32Version=4.9 then
Result := os + 'Me'
else
Result := os + '9x'
end
else if Win32Platform = VER_PLATFORM_WIN32_NT then
begin
if AWin32Version=3.51 then
Result := os + 'NT 3.51'
else if AWin32Version=4.0 then
Result := os + 'NT 4.0'
else if AWin32Version=5.0 then
Result := os + '2000'
else if AWin32Version=5.1 then
ShowMessage('xp系统')
else if AWin32Version=5.2 then
Result := os + '2003'
else if AWin32Version=6.0 then
begin
ShowMessage('vista系统')
end
else if AWin32Version=6.1 then
Result := os + '7'
else
Result := os ;
end
else
Result := os + '??';
Result:=Result + ' '+GetWIndowsVersionString;

}

{ 获取系统版本 }
function GetSystemVersion:string;
var
OSVerStatus: OSVERSIONINFO;
begin
OSVerStatus.dwOSVersionInfoSize := SizeOf(OSVerStatus);
if GetVersionEx(OSVerStatus) then
begin
if OSVerStatus.dwPlatformId=VER_PLATFORM_WIN32_NT then
begin
if OSVerStatus.dwMajorVersion=5 then // 写死了 5.0 200 5.1 XP 5.2 2003 其它版本的就放过吧
begin
case OSVerStatus.dwMinorVersion of
0:Result := 'Microsoft Windows 2000';
1:Result := 'Microsoft Windows XP';
2:Result := 'Microsoft Windows 2003';
end;
end else Result := 'Other Windows Version.';
end;
end else Result := 'Unknow System Version.';
end;

{ 获取windows版本 }
function GetSystemVersionID:Integer;
var
OSVerStatus: OSVERSIONINFO;
begin
OSVerStatus.dwOSVersionInfoSize := SizeOf(OSVerStatus);
if GetVersionEx(OSVerStatus) then
begin
if OSVerStatus.dwPlatformId=VER_PLATFORM_WIN32_NT then
begin
if OSVerStatus.dwMajorVersion=5 then // 写死了 5.0 200 5.1 XP 5.2 2003
begin
Result := OSVerStatus.dwMinorVersion;
end;
if OSVerStatus.dwMajorVersion=6 then //6.0 Vista 6.1 Win7
begin
if OSVerStatus.dwMinorVersion=0 then Result := 3;
if OSVerStatus.dwMinorVersion=1 then Result := 4;
end;
end;
end;
end;

{ 传输偏移地址 Control Code }
function IOCTL_Offset: DWORD;
begin
Result := CTL_CODE(FILE_DEVICE_UNKNOWN,$802,METHOD_BUFFERED,FILE_ANY_ACCESS);
end;

{ 传输进程PID Control Code }
function IOCTL_PID: DWORD;
begin
Result := CTL_CODE(FILE_DEVICE_UNKNOWN,$801,METHOD_BUFFERED,FILE_ANY_ACCESS);
end;

{ 获取进程列表 }
procedure TfrmKiller.GetProcessList;
var
hSnapshot,hProcess,hModule: THandle;
ProcessList: PROCESSENTRY32;
cbNeeded: DWORD;
PsPathBuf: array[0..MAX_PATH] of Char;
begin
hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
ProcessList.dwSize := SizeOf(PROCESSENTRY32);
if Process32First(hSnapshot,ProcessList) then
begin
while Process32Next(hSnapshot,ProcessList) do
begin
hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,
False,
ProcessList.th32ProcessID);
if hProcess<>0 then
begin
if EnumProcessModules(hProcess,@hModule,SizeOf(hModule),cbNeeded) then
begin
ZeroMemory(@PsPathBuf,MAX_PATH+1);
GetModuleFileNameEx(hProcess,hModule,PsPathBuf,SizeOf(PsPathBuf));
with lvProcessList.Items.Add do
begin
Caption := PsPathBuf;
SubItems.Add(IntToStr(ProcessList.th32ProcessID));
end;
end;
end;
end;
end;
CloseHandle(hSnapshot);
CloseHandle(hProcess);
// CloseHandle(hModule);
end;

{ 驱动通讯 }
procedure TfrmKiller.btnKillClick(Sender: TObject);
var
dwProcessId,dwReturn,dwOffset: DWORD;
begin
dwProcessId := StrToInt(Trim(edtPID.Text));
case GetSystemVersionID of
Windows_2000 : dwOffset := $240; //CrossThreadFlags 硬编码
Windows_XP : dwOffset := $248;
Windows_2003 : dwOffset := $240;
Windows_Vista : dwOffset := $260;
Windows_7 : dwOffset := $280;
end;
PsDrvCtrl.IoControl(IOCTL_Offset,
@dwOffset,
4,
@dwReturn,
SizeOf(DWORD));
PsDrvCtrl.IoControl(IOCTL_PID,
@dwProcessId,
4,
@dwReturn,
SizeOf(DWORD));
lvProcessList.Clear;
Sleep(1500);
Application.ProcessMessages;
lvProcessList.Clear;
GetProcessList;
end;

procedure TfrmKiller.btnLoadClick(Sender: TObject);
var
lpFilePart: PAnsiChar;
lpDrvPath: Array [0..255] of Char;
begin
edtOSVersion.Text := GetSystemVersion;
GetFullPathName('MyKiller.sys', 256, lpDrvPath, lpFilePart);
PsDrvCtrl := TDriverControl.Create(lpDrvPath, 'mykiller');
if not PsDrvCtrl.IsVaild then
begin
PsDrvCtrl.Free;
ShowMessage('无法加载驱动');
Exit;
end;

if not PsDrvCtrl.StartDriver then
begin
PsDrvCtrl.Free;
ShowMessage('无法启动驱动');
Exit;
end;

if not PsDrvCtrl.OpenDevice then
begin
PsDrvCtrl.StopDriver;
PsDrvCtrl.Free;
ShowMessage('无法打开驱动。');
Exit;
end;

ShowMessage('驱动已经成功启动。');
btnUnload.Enabled := True;
btnKill.Enabled := True;
btnLoad.Enabled := False;
end;

procedure TfrmKiller.btnUnloadClick(Sender: TObject);
begin
PsDrvCtrl.StopDriver;
PsDrvCtrl.Free;
ShowMessage('驱动已经卸载成功。');
btnUnload.Enabled := False;
btnKill.Enabled := False;
btnLoad.Enabled := True;
end;

procedure TfrmKiller.FormCreate(Sender: TObject);
begin
GetProcessList;
end;

procedure TfrmKiller.lvProcessListSelectItem(Sender: TObject;
Item: TListItem; Selected: Boolean);
begin
edtPID.Text := Item.SubItems.Text;
end;

procedure TfrmKiller.tmrRefreshTimer(Sender: TObject);
begin
lvProcessList.Clear;
GetProcessList;
end;

end.