两个强制结束进程的方法

强制结束进程的两种方式

一、引言

在 Windows 内核开发中,进程和线程的终止是一个核心的操作场景。PspTerminateProcessPspTerminateThreadByPointer是 Windows 内核中未导出的核心函数,它们分别负责进程的终止和线程的终止操作。这两个函数由于未被微软正式文档化,通常需要通过逆向工程的方式来获取其地址并使用,在驱动开发、安全软件和恶意软件中都有广泛的应用场景。

二、函数定义与作用

1.1 PspTerminateProcess

PspTerminateProcess是 Windows 内核中用于终止指定进程的核心函数,它的定义通常如下(不同 Windows 版本可能有细微差异):

cpp 复制代码
typedef NTSTATUS(__stdcall* _PspTerminateProcess)(PEPROCESS TargetProcess, PEPROCESS SourceProcess, NTSTATUS ExitCode);

该函数的作用是终止指定的进程,同时会终止该进程下的所有线程。
参数列表

  • TargetProcess:目标进程的EPROCESS指针。
  • SourceProcess:发起进程的EPROCESS指针。
  • ExitCode:进程退出代码。

1.2 PspTerminateThreadByPointer

PspTerminateThreadByPointer是用于终止指定线程的核心函数,它的定义通常如下:

cpp 复制代码
typedef NTSTATUS(__stdcall* _PsTerminateThreadByPointer)(PETHREAD pThread, NTSTATUS exitCode, BOOLEAN bDirectTerminate);

该函数接收线程的ETHREAD结构体指针作为参数,以及线程的退出码,还有一个是否等待线程终止完成的标志位。该函数会直接终止指定的线程,是内核中线程终止操作的底层实现之一。

三、未导出函数地址的获取

3.1 通过特征码获取起始地址

  1. 由于PspTerminateProcessPspTerminateThreadByPointer是未导出函数,无法直接通过MmGetSystemRoutineAddress等常规方式获取其地址,通常需要通过特征码搜索导出函数的调用链获取。我们将使用此函数来搜索特征码:

    cpp 复制代码
    PVOID SearchPattern(PVOID baseAddr, SIZE_T size, UCHAR* pattern, const char* mask)
    {
       PVOID result = NULL;
       __int64 patternLength = strlen(mask);
       BOOLEAN found = FALSE;
       for (__int64 i = 0; i <= size - patternLength; i++) 
       {
          found = TRUE;
          for (__int64 j = 0; j < patternLength; j++) {
             if (mask[j] != '?' && *(UCHAR*)((DWORD_PTR)baseAddr + i + j) != pattern[j]) {
                found = FALSE;
                break;
             }
          }
          if (found) {
             result = (PVOID)((DWORD_PTR)baseAddr + i);
             break;
          }
       }
       return result;
    }
  2. 一条指令(如call指令)的最后四个字节通常为下一条指令起始地址相对目标地址的偏移,这个偏移的数据类型为INT32

3.1 PspTerminateThreadByPointer的获取方法

  1. 打开Ghidra,搜索导出函数PsTerminateSystemThread,此函数在内部会调用PspTerminateThreadByPointer。值得庆幸的是,PspTerminateThreadByPointer相对于PsTerminateSystemThread始终是第一个call指令,所以我们直接寻找PsTerminateSystemThread的第一个call指令的起始地址。

  2. 通过特征码搜索第一个call指令的起始地址,从而获取PspTerminateThreadByPointer的真实地址:

    cpp 复制代码
    PVOID FindPspTerminateThreadByPointer()
    {
        PVOID PspTerminateThreadByPointerAddr = NULL;
        UNICODE_STRING funcName = RTL_CONSTANT_STRING(L"PsTerminateSystemThread");
        PVOID pPsTerminateSystemThread = MmGetSystemRoutineAddress(&funcName);
        if (!pPsTerminateSystemThread)
        {
     	   return NULL;
        }
        BYTE pattern[] = { 0xe8,0x00,0x00,0x00,0x00 };
        // '?'为通配符
        char mask[] = "x????";
        DWORD_PTR uValueA = 0;
        INT32 iValueA = 0;
        uValueA = (DWORD_PTR)SearchPattern(pPsTerminateSystemThread, 0x2F, pattern, mask);
        if (!uValueA)
        {
     	   return NULL;
        }
        iValueA = *(INT32*)(uValueA + 1);
        uValueA += 5;
        PspTerminateThreadByPointerAddr = (PVOID)(uValueA + iValueA);
        return PspTerminateThreadByPointerAddr;
    }

3.2 PspTerminateProcess的获取方法

PspTerminateThreadByPointer不同的是,PspTerminateProcess的情况要稍复杂一些:前者的 call指令直接存在于导出函数 PsTerminateSystemThread内部,而 PspTerminateProcess则是被内核未导出的 NtTerminateProcess函数所调用,其对应的call指令也因此存在于这个未导出函数中。
NtTerminateProcess并非被其他内核函数直接调用,而是作为内核系统调用的实现函数,由导出函数ZwTerminateProcess通过 SSDT(系统服务描述符表)中对应的服务编号发起间接调用。

  1. 获取ZwTerminateProcess地址

    cpp 复制代码
    UNICODE_STRING funcName = RTL_CONSTANT_STRING(L"ZwTerminateProcess");
    PUCHAR pZwTerminateProcess = MmGetSystemRoutineAddress(&funcName);
    if (!pZwTerminateProcess) {
     DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "获取ZwTerminateProcess地址失败\n");
     return NULL;
    }
  2. 获取KeServiceDescriptorTable的地址

    在 64 位 Windows 内核中,KeServiceDescriptorTable(SSDT 的核心描述表)是未导出的全局变量,需要通过内核指令特征匹配 + MSR寄存器读取的方式逆向定位,其中syscall指令触发后会跳转到内核的KiSystemCall64函数地址存储在 MSR寄存器0xC0000082(LSTAR)中,可通过__readmsr(0xC0000082)读取。其中KeServiceDescriptorTable的结构定义和具体代码实现如下:

    cpp 复制代码
    typedef struct _KSERVICE_DESCRIPTOR_TABLE {
         PVOID KiServiceTable; // SSDT表基址
         PULONG ServiceCounterTableBase; // 服务调用计数表基址(通常为NULL)
         ULONG NumberOfServices; // SSDT中服务函数的个数(4字节)
         PVOID ParamTableBase; // 系统服务参数表基址(8字节)
     } KSERVICE_DESCRIPTOR_TABLE, * PKSERVICE_DESCRIPTOR_TABLE;
    
    NTSTATUS GetKeServiceDescriptorTableAddr(PKSERVICE_DESCRIPTOR_TABLE* pKeServiceDescriptorTable)
    {
       if (!pKeServiceDescriptorTable)
       {
          return STATUS_INVALID_PARAMETER;
       }
       PUCHAR KiSystemCall64_Address = SYSCALL_ADDRESS;
       PUCHAR uValueA = SearchPattern(KiSystemCall64_Address, 0x6080DC, (PUCHAR)"\x4c\x8d\x15\x00\x00\x00\x00", "xxx????");
       DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "uValue Address:%p\n", uValueA);
       if (!MmIsAddressValid(uValueA))
       {
          DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "uValueA is no memory");
          return STATUS_NO_MEMORY;
       }
       INT32 offset = *(INT32*)(uValueA + 3);
       *pKeServiceDescriptorTable = (PKSERVICE_DESCRIPTOR_TABLE)(uValueA + 7 + offset);
       return STATUS_SUCCESS;
    }
  3. 获取NtTerminateProcess的地址

    打开 WinDbg 内核调试模式,输入uf ZwTerminateProcess进行反汇编,输出如下:

    js 复制代码
    0: kd> uf ZwTerminateProcess
    nt!ZwTerminateProcess:
    fffff802`da29de70 488bc4          mov     rax,rsp
    fffff802`da29de73 fa              cli
    fffff802`da29de74 4883ec10        sub     rsp,10h
    fffff802`da29de78 50              push    rax
    fffff802`da29de79 9c              pushfq
    fffff802`da29de7a 6a10            push    10h
    fffff802`da29de7c 488d05dd5d0000  lea     rax,[nt!KiServiceLinkage (fffff802`da2a3c60)]
    fffff802`da29de83 50              push    rax
    fffff802`da29de84 b82c000000      mov     eax,2Ch
    fffff802`da29de89 e932730100      jmp     nt!KiServiceInternal (fffff802`da2b51c0)  Branch
    
    nt!KiServiceInternal:
    fffff802`da2b51c0 4883ec08        sub     rsp,8
    fffff802`da2b51c4 55              push    rbp
    fffff802`da2b51c5 4881ec58010000  sub     rsp,158h
    fffff802`da2b51cc 488dac2480000000 lea     rbp,[rsp+80h]
    fffff802`da2b51d4 48899dc0000000  mov     qword ptr [rbp+0C0h],rbx
    fffff802`da2b51db 4889bdc8000000  mov     qword ptr [rbp+0C8h],rdi
    fffff802`da2b51e2 4889b5d0000000  mov     qword ptr [rbp+0D0h],rsi
    fffff802`da2b51e9 48c7455800000000 mov     qword ptr [rbp+58h],0
    fffff802`da2b51f1 fb              sti
    fffff802`da2b51f2 65488b1c2588010000 mov   rbx,qword ptr gs:[188h]
    fffff802`da2b51fb 0f0d8b90000000  prefetchw [rbx+90h]
    fffff802`da2b5202 0fb6bb32020000  movzx   edi,byte ptr [rbx+232h]
    fffff802`da2b5209 40887da8        mov     byte ptr [rbp-58h],dil
    fffff802`da2b520d c6833202000000  mov     byte ptr [rbx+232h],0
    fffff802`da2b5214 4c8b9390000000  mov     r10,qword ptr [rbx+90h]
    fffff802`da2b521b 4c8995b8000000  mov     qword ptr [rbp+0B8h],r10
    fffff802`da2b5222 4c8d1d97030000  lea     r11,[nt!KiSystemServiceStart (fffff802`da2b55c0)]
    fffff802`da2b5229 e8f2ef4f00      call    nt!_guard_retpoline_switchtable_jump_r11 (fffff802`da7b4220)
    fffff802`da2b522e cc              int     3
    fffff802`da2b522f c3              ret

    b82c000000 mov eax,2ChZwTerminateProcess向内核传递NtTerminateProcess的 SSDT 系统服务编号,也是 Windows 内核系统调用的标准流程。

    我们继续反汇编KiSystemServiceRepeat,输出结果如下:

    js 复制代码
    nt!KiSystemServiceRepeat:
    fffff802`da2b55d4 4c8d15e5c2b400  lea     r10,[nt!KeServiceDescriptorTable (fffff802`dae018c0)]
    fffff802`da2b55db 4c8d1d9e0c9100  lea     r11,[nt!KeServiceDescriptorTableShadow (fffff802`dabc6280)]
    fffff802`da2b55e2 f7437880000000  test    dword ptr [rbx+78h],80h
    fffff802`da2b55e9 7413            je      nt!KiSystemServiceRepeat+0x2a (fffff802`da2b55fe)  Branch
    
    nt!KiSystemServiceRepeat+0x17:
    fffff802`da2b55eb f7437800002000  test    dword ptr [rbx+78h],200000h
    fffff802`da2b55f2 7407            je      nt!KiSystemServiceRepeat+0x27 (fffff802`da2b55fb)  Branch
    
    nt!KiSystemServiceRepeat+0x20:
    fffff802`da2b55f4 4c8d1d850d9100  lea     r11,[nt!KeServiceDescriptorTableFilter (fffff802`dabc6380)]
    
    nt!KiSystemServiceRepeat+0x27:
    fffff802`da2b55fb 4d8bd3          mov     r10,r11
    
    nt!KiSystemServiceRepeat+0x2a:
    fffff802`da2b55fe 413b443a10      cmp     eax,dword ptr [r10+rdi+10h]
    fffff802`da2b5603 0f83be080000    jae     nt!KiSystemServiceExitPico+0x31c (fffff802`da2b5ec7)  Branch
    
    nt!KiSystemServiceRepeat+0x35:
    fffff802`da2b5609 4d8b143a        mov     r10,qword ptr [r10+rdi]
    fffff802`da2b560d 4d631c82        movsxd  r11,dword ptr [r10+rax*4]
    fffff802`da2b5611 498bc3          mov     rax,r11
    fffff802`da2b5614 49c1fb04        sar     r11,4
    fffff802`da2b5618 4d03d3          add     r10,r11
    fffff802`da2b561b 83ff20          cmp     edi,20h
    fffff802`da2b561e 7550            jne     nt!KiSystemServiceGdiTebAccess+0x49 (fffff802`da2b5670)  Branch

    在得到49c1fb04 sar r11,4这串指令之后,我们就可以编写如下代码来计算系统调用函数的地址:

    cpp 复制代码
    /*
    4d631c82        movsxd  r11,dword ptr [r10+rax*4]
    498bc3          mov     rax,r11
    49c1fb04        sar     r11,4
    4d03d3          add     r10,r11
    */
    // syscallIndex = 2Ch
    PVOID GetSyscallAddress(PKSERVICE_DESCRIPTOR_TABLE table, ULONG syscallIndex) 
    {
       LONG offset = ((PLONG)table->KiServiceTable)[syscallIndex];
       return (PVOID)((ULONG_PTR)table->KiServiceTable + (offset >> 4));
    }
    • 首先movsxd r11,dword ptr [r10+rax*4]:从KiServiceTable(r10存储的是KiServiceTable的基地址)中取出对应索引rax的偏移量,转换为 64 位有符号数存储到r11中,这对应 C 代码中的((PLONG)table->KiServiceTable)[syscallIndex]
    • 然后mov rax,r11:将偏移量复制到rax中,暂时保存。
    • 接下来sar r11,4:将r11中的偏移量算术右移 4 位,还原真实的偏移量,对应 C 代码中的offset >> 4
    • 最后add r10,r11:将KiServiceTable的基地址r10加上还原后的偏移量r11,得到系统调用函数的地址,对应 C 代码中的(ULONG_PTR)table->KiServiceTable + (offset >> 4)
      结合上述代码,我们可以通过ZwTerminateProcess的地址获取NtTerminateProcess的地址:
    cpp 复制代码
    NTSTATUS GetSSDTNtFunc(PKSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable, PUCHAR pZwFuncAddr, PVOID* pNtFuncAddress)
    {
       PUCHAR uValueA = SearchPattern(pZwFuncAddr, 0x1E, (PUCHAR)"\xb8\x00\x00\x00\x00", "x??xx");
       if (!MmIsAddressValid(uValueA))
       {
          return STATUS_NO_MEMORY;
       }
       ULONG index = *(PULONG)(uValueA + 1);
       *pNtFuncAddress = GetSyscallAddress(KeServiceDescriptorTable, index);
       return STATUS_SUCCESS;
    }

    这样,我们就有能力获取到NtTerminateProcess了。

    1. 通过NtTerminateProcess获取PspTerminateProcess

    我们使用 WinDbg 反汇编NtTerminateProcess后输出结果如下:

    js 复制代码
    0: kd> uf nt!NtTerminateProcess
    nt!NtTerminateProcess:
    fffff802`d8d31500 4c8bdc          mov     r11,rsp
    fffff802`d8d31503 49895b10        mov     qword ptr [r11+10h],rbx
    fffff802`d8d31507 55              push    rbp
    fffff802`d8d31508 56              push    rsi
    fffff802`d8d31509 57              push    rdi
    fffff802`d8d3150a 4154            push    r12
    fffff802`d8d3150c 4155            push    r13
    fffff802`d8d3150e 4156            push    r14
    fffff802`d8d31510 4157            push    r15
    fffff802`d8d31512 4883ec40        sub     rsp,40h
    fffff802`d8d31516 65488b342588010000 mov   rsi,qword ptr gs:[188h]
    fffff802`d8d3151f 4533f6          xor     r14d,r14d
    fffff802`d8d31522 4d897308        mov     qword ptr [r11+8],r14
    fffff802`d8d31526 448be2          mov     r12d,edx
    fffff802`d8d31529 488bbeb8000000  mov     rdi,qword ptr [rsi+0B8h]
    fffff802`d8d31530 418d6e01        lea     ebp,[r14+1]
    fffff802`d8d31534 448abe32020000  mov     r15b,byte ptr [rsi+232h]
    fffff802`d8d3153b 4885c9          test    rcx,rcx
    fffff802`d8d3153e 0f84de000000    je      nt!NtTerminateProcess+0x122 (fffff802`d8d31622)  Branch
    
    nt!NtTerminateProcess+0x44:
    ...
    fffff802`d8d31568 e82303f1ff      call   nt!ObpReferenceObjectByHandleWithTag (fffff802`d8c41890)
    nt!NtTerminateProcess+0x75:
    ...
    nt!NtTerminateProcess+0x7e:
    ...
    fffff802`d8d31590 e8cb2eb2ff      call    nt!EtwpGetProcessStartKey (fffff802`d8854460)
    ...
    fffff802`d8d315a0 e89b0bb2ff      call    nt!PsGetProcessCreateTimeQuadPart (fffff802`d8852140)
    ...
    fffff802`d8d315c5 e806e6ffff      call    nt!PspTerminateProcess (fffff802`d8d2fbd0)
    ...

    可以看出e806e6ffff call nt!PspTerminateProcess (fffff802d8d2fbd0)NtTerminateProcess的第四个call指令,我们就能写出如下代码:

    cpp 复制代码
    // 在Windows 10中,NtTerminsteProcess的第二个call指令才是PspTerminateProcess
    // 为了保持兼容性,我们在这加以判断
    BOOLEAN IsWindows11()
    {
       OSVERSIONINFOW osInfo = { 0 };
       osInfo.dwOSVersionInfoSize = sizeof(osInfo);
       NTSTATUS status = RtlGetVersion(&osInfo);
       if (status)
       {
          return FALSE;
       }
       return osInfo.dwBuildNumber >= 22000;
    }
    
    PVOID FindPspTerminateProcess()
    {
       UCHAR pattern[] = { 0xe8,0x00,0x00,0x00,0x00 };
       PUCHAR uValueA = NULL;
       //KdBreakPoint();
       UNICODE_STRING funcName = RTL_CONSTANT_STRING(L"ZwTerminateProcess");
       PUCHAR pZwTerminateProcess = MmGetSystemRoutineAddress(&funcName);
       NTSTATUS status = GetSSDTNtFunc(gKeServiceDescriptorTable, pZwTerminateProcess, &uValueA);
       if (status)
       {
          DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed get SSDT NtFunc.\n");
          return NULL;
       }
       //KdBreakPoint();
       DWORD count = 2;
       if (IsWindows11()) { count = 4; }
       for (DWORD i = 0; i < count; i++)
       {
          uValueA = SearchPattern(uValueA, 0x106, pattern, "x????");
          uValueA += 1;
       }
       return (PVOID)((uValueA + 4) + *(INT32*)uValueA);
    }

四、使用方法

4.1 调用PspTerminateThreadByPointer结束进程

cpp 复制代码
typedef NTSTATUS(__stdcall* _PsTerminateThreadByPointer)(PETHREAD pThread, NTSTATUS exitCode, BOOLEAN bDirectTerminate);
_PsTerminateThreadByPointer gPsTerminateThreadByPointer = NULL;

VOID Init()
{
   gPsTerminateThreadByPointer=(_PsTerminateThreadByPointer)FindPspTerminateThreadByPointer();
}

NTSTATUS PsTerminateThreadByPointer(PETHREAD pThread, NTSTATUS exitCode, BOOLEAN bDirectTerminate)
{
	_PsTerminateThreadByPointer pPsTerminateThreadByPointer = gPsTerminateThreadByPointer;
	if (!pPsTerminateThreadByPointer)
	{
		return STATUS_NO_MEMORY;
	}
	return pPsTerminateThreadByPointer(pThread, exitCode, bDirectTerminate);
}
NTSTATUS PsTerminateProcessByPid(DWORD64 pid)
{
	NTSTATUS funcStatus = STATUS_SUCCESS;
	PETHREAD ethrd = NULL;
	PEPROCESS pProcess = NULL;
	for (DWORD64 tid = 4; tid < 262144; tid += 4)
	{
		NTSTATUS status = PsLookupThreadByThreadId((HANDLE)tid, &ethrd);
		if (!NT_SUCCESS(status))
		{
			continue;
		}
		pProcess = IoThreadToProcess(ethrd);
		if (!pProcess)
		{
			ObDereferenceObject(ethrd);
			ethrd = NULL;
			continue;
		}
		DWORD64 processId = (DWORD64)PsGetProcessId(pProcess);
		if (processId == pid)
		{
			status = PsTerminateThreadByPointer(ethrd, STATUS_SUCCESS, 0);
			if (status != STATUS_SUCCESS)
			{
				funcStatus = status;
			}
		}
		ObDereferenceObject(ethrd);
		ethrd = NULL;
		pProcess = NULL;
	}
	if (funcStatus == STATUS_SUCCESS)
	{
		//DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "TerminateProcess Success!");
	}
	return funcStatus;
}

4.2 调用PspTerminateProcess结束进程

  1. 代码实现

    cpp 复制代码
    #include <ntifs.h>
    #include <ntstrsafe.h>
    #include <intrin.h>
    typedef NTSTATUS(__stdcall* _PspTerminateProcess)(PEPROCESS TargetProcess, PEPROCESS AttackProcess, NTSTATUS ExitCode);
    #define SYSCALL_ADDRESS (PUCHAR)__readmsr(0xC0000082)
    _PspTerminateProcess gPspTerminateProcess = NULL;
    NTSTATUS PspTerminateProcessId(HANDLE pid)
    {
       PEPROCESS targetProcess = NULL;
       NTSTATUS status = PsLookupProcessByProcessId(pid, &targetProcess);
       if (status != STATUS_SUCCESS)
       {
          DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed get EPROCESS by PID\n");
          return status;
       }
       status = gPspTerminateProcess(targetProcess, IoGetCurrentProcess(), 1);
       DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "EPROCESS Address:%p\n",targetProcess);
       //__debugbreak();
       ObDereferenceObject(targetProcess);
       return status;
    }
    NTSTATUS DriverUnload(PDRIVER_OBJECT DriverObject)
    {
       UNREFERENCED_PARAMETER(DriverObject);
       return STATUS_SUCCESS;
    }
    NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
    {
       UNREFERENCED_PARAMETER(RegistryPath);
       NTSTATUS status = GetKeServiceDescriptorTableAddr(&gKeServiceDescriptorTable);
       if (status != STATUS_SUCCESS)
       {
          DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed Get KeServiceDescriptorTable.\n");
          return status;
       }
       DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "KeServiceDescriptorTable Address:%p\n", gKeServiceDescriptorTable);
       //return STATUS_ACCESS_DENIED;
       PVOID pPspTerminateProcess = FindPspTerminateProcess();
       if (!pPspTerminateProcess)
       {
          DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "Failed Get PspTerminateProcess.\n");
          return STATUS_NO_MEMORY;
       }
       DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "PspTerminateProcess Address:%p\n", pPspTerminateProcess);
       gPspTerminateProcess = (_PspTerminateProcess)pPspTerminateProcess;
       // 这里要把1234改成你想要结束的进程ID
       status=PspTerminateProcessId((HANDLE)1234);
       DriverObject->DriverUnload = DriverUnload;
       return status;
    }
  2. 最终效果

    js 复制代码
    0: kd> g
    uValue Address:FFFFF802D8AB55D4
    KeServiceDescriptorTable Address:FFFFF802D96018C0
    PspTerminateProcess Address:FFFFF802D8D2FBD0
    EPROCESS Address:FFFF808CBF7F9080
    5: kd> x nt!KeServiceDescriptorTable
    fffff802`d96018c0 nt!KeServiceDescriptorTable = <no type information>
    5: kd> x nt!PspTerminateProcess
    fffff802`d8d2fbd0 nt!PspTerminateProcess (void)
    5: kd> dt nt!_EPROCESS FFFF808CBF7F9080 ExitStatus
       +0x554 ExitStatus : 0n1

    从 WinDbg 的输出结果可以看出:

    • 调试信息的PspTerminateProcess地址正好是x nt!PspTerminateProcess
    • 其中+0x554 ExitStatus : 0n1也正好是gPspTerminateProcess(targetProcess, IoGetCurrentProcess(), 1)中第三个参数的值。

五、总结

通过特征码搜索、SSDT 系统服务表解析、MSR 寄存器读取,成功实现了不同 Windows 版本下两个函数地址的精准获取,并针对性编写了两种内核层强制结束指定 PID 进程的完整代码方案,分别为遍历终止目标进程所有线程、直接调用进程终止函数。经 WinDbg 内核调试验证,所实现的地址获取方法精准有效,进程终止功能可正常执行,退出码参数也按预期生效,最终完成了 Windows 内核层强制结束进程的技术实现与验证。

相关推荐
HAPPY酷2 小时前
C++ 多线程实战三板斧
java·开发语言·c++·技术美术
fpcc2 小时前
并行编程实战——CUDA编程的Tile
c++·cuda
_风华ts4 小时前
C++ 函数封装与绑定
c++·函数指针·函数封装
ShineWinsu4 小时前
对于C++中stack和queue的详细介绍
开发语言·数据结构·c++·面试·stl·queue·stack
L_Aria4 小时前
6421. 【NOIP2019模拟11.11】匹配
c++·算法·动态规划
智者知已应修善业5 小时前
【PAT乙级真题解惑1012数字分类】2025-3-29
c语言·c++·经验分享·笔记·算法
-To be number.wan6 小时前
算法学习日记 | 双指针
c++·学习·算法
wangluoqi6 小时前
c++ 逆元 小总结
开发语言·c++
瓦特what?6 小时前
插 入 排 序
开发语言·c++