驱动开发:内核强制结束进程运行

[复制链接]
发表于 2022-10-29 10:39:46 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
通常使用Windows系统自带的任务管理器可以正常地结束掉一般进程,而某些特殊的进程在应用层很难被结束掉,例如某些系统核心进程其权限是在0环内核态,但有时我们不得不想办法结束掉这些特殊的进程,当然某些正常进程在特殊状态下也会无法被正常结束,此时使用驱动前行在内核态将其结束掉就变得很有用了,驱动结束进程有多种方法。

  • 1.标准方法就是使用ZwOpenProcess打开进程获得句柄,然后使用ZwTerminateProcess这个内核API实现结束进程,最后使用ZwClose关闭句柄。
  • 2.第二种方法,通过动态定位的方式找到PspTerminateThreadByPointer这个内核函数地址,然后调用该函数结束掉进程中所有的线程,当线程为空则进程也就消亡了。
  • 3.第三种方法,我将其称作是内存清零法,其核心原理是通过打开进程,得到进程的基址,通过内存填充的方式将对端内存全部置0实现类似于结束的效果。
首先是第一种方法结束进程,封装实现KillProcess函数,用户传入lyshark.exe进程名,进程内执行PsGetProcessImageFileName判断是否是我们要结束的如果是则,调用ZwOpenProcess打开进程,并发送ZwTerminateProcess终止信号从而正常结束,其核心代码如下所示。
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: [email protected]
  5. #include <ntifs.h>
  6. NTKERNELAPI UCHAR* PsGetProcessImageFileName(IN PEPROCESS Process);
  7. // 根据进程ID返回进程EPROCESS结构体,失败返回NULL
  8. PEPROCESS GetProcessNameByProcessId(HANDLE pid)
  9. {
  10.         PEPROCESS ProcessObj = NULL;
  11.         NTSTATUS Status = STATUS_UNSUCCESSFUL;
  12.         Status = PsLookupProcessByProcessId(pid, &ProcessObj);
  13.         if (NT_SUCCESS(Status))
  14.                 return ProcessObj;
  15.         return NULL;
  16. }
  17. // 根据ProcessName获取到进程的PID号
  18. HANDLE GetPidByProcessName(char *ProcessName)
  19. {
  20.         PEPROCESS pCurrentEprocess = NULL;
  21.         HANDLE pid = 0;
  22.         for (int i = 0; i < 1000000000; i += 4)
  23.         {
  24.                 pCurrentEprocess = GetProcessNameByProcessId((HANDLE)i);
  25.                 if (pCurrentEprocess != NULL)
  26.                 {
  27.                         pid = PsGetProcessId(pCurrentEprocess);
  28.                         if (strstr(PsGetProcessImageFileName(pCurrentEprocess), ProcessName) != NULL)
  29.                         {
  30.                                 ObDereferenceObject(pCurrentEprocess);
  31.                                 return pid;
  32.                         }
  33.                         ObDereferenceObject(pCurrentEprocess);
  34.                 }
  35.         }
  36.         return (HANDLE)-1;
  37. }
  38. // 传入进程名称,终止掉该进程
  39. BOOLEAN KillProcess(PCHAR ProcessName)
  40. {
  41.         PEPROCESS pCurrentEprocess = NULL;
  42.         HANDLE pid = 0;
  43.         HANDLE Handle = NULL;
  44.         OBJECT_ATTRIBUTES obj;
  45.         CLIENT_ID cid = { 0 };
  46.         NTSTATUS Status = STATUS_UNSUCCESSFUL;
  47.         for (int i = 0; i < 10000000; i += 4)
  48.         {
  49.                 pCurrentEprocess = GetProcessNameByProcessId((HANDLE)i);
  50.                 if (pCurrentEprocess != NULL)
  51.                 {
  52.                         pid = PsGetProcessId(pCurrentEprocess);
  53.                         // 判断当前镜像名称是否是需要结束的进程
  54.                         if (strstr(PsGetProcessImageFileName(pCurrentEprocess), ProcessName) != NULL)
  55.                         {
  56.                                 ObDereferenceObject(pCurrentEprocess);
  57.                                 // 找到后开始结束
  58.                                 InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
  59.                                 cid.UniqueProcess = (HANDLE)pid;
  60.                                 cid.UniqueThread = 0;
  61.                                 // 打开进程
  62.                                 Status = ZwOpenProcess(&Handle, GENERIC_ALL, &obj, &cid);
  63.                                 if (NT_SUCCESS(Status))
  64.                                 {
  65.                                         // 发送终止信号
  66.                                         ZwTerminateProcess(Handle, 0);
  67.                                         ZwClose(Handle);
  68.                                 }
  69.                                 ZwClose(Handle);
  70.                                 return TRUE;
  71.                         }
  72.                         ObDereferenceObject(pCurrentEprocess);
  73.                 }
  74.         }
  75.         return FALSE;
  76. }
  77. VOID UnDriver(PDRIVER_OBJECT driver)
  78. {
  79.         DbgPrint("驱动已卸载 \n");
  80. }
  81. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  82. {
  83.         DbgPrint("hello lyshark.com \n");
  84.         BOOLEAN Retn;
  85.         Retn = KillProcess("lyshark.exe");
  86.         DbgPrint("结束状态: %d \n", Retn);
  87.         Driver->DriverUnload = UnDriver;
  88.         return STATUS_SUCCESS;
  89. }
复制代码
我们运行这个驱动,当进程lyshark.exe存在时则可以看到结束效果,当然这种方式只是在内核层面调用了结束进程函数,其本质上还是正常结束,只是这种方式权限要大一些仅此而已。

第二种方法,其原理就是将进程内的线程全部结束掉从而让进程自动结束,由于PspTerminateThreadByPointer没有被导出,所以我们需要动态的这个内存地址,然后动态调用即可,这个寻找方法可以总结为以下步骤。

  • 1.寻找PsTerminateSystemThread函数地址,这个地址可以直接通过MmGetSystemRoutineAddress函数得到。
  • 2.在PsTerminateSystemThread函数地址内向下扫描特征e80cb6f6ff得到call nt!PspTerminateThreadByPointer地址。
根据《驱动开发:内核枚举LoadImage映像回调》中使用的SearchMemory函数实现搜索PspTerminateThreadByPointer内存地址。
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: [email protected]
  5. #include <ntifs.h>
  6. // 得到PspTerminateThreadByPointer内存地址
  7. PVOID PspTerminateThreadByPointer()
  8. {
  9.         UNICODE_STRING ustrFuncName;
  10.         PVOID pAddress = NULL;
  11.         LONG lOffset = 0;
  12.         PVOID pPsTerminateSystemThread = NULL;
  13.         PVOID pPspTerminateThreadByPointer = NULL;
  14.         // 获取 PsTerminateSystemThread 函数地址
  15.         RtlInitUnicodeString(&ustrFuncName, L"PsTerminateSystemThread");
  16.         pPsTerminateSystemThread = MmGetSystemRoutineAddress(&ustrFuncName);
  17.        
  18.         DbgPrint("pPsTerminateSystemThread = 0x%p \n", pPsTerminateSystemThread);
  19.         if (NULL == pPsTerminateSystemThread)
  20.         {
  21.                 return 0;
  22.         }
  23.         // 查找 PspTerminateThreadByPointer 函数地址
  24.         /*
  25.         1: kd> uf PsTerminateSystemThread
  26.                         nt!PsTerminateSystemThread:
  27.                         fffff802`254e6a90 4883ec28        sub     rsp,28h
  28.                         fffff802`254e6a94 8bd1            mov     edx,ecx
  29.                         fffff802`254e6a96 65488b0c2588010000 mov   rcx,qword ptr gs:[188h]
  30.                         fffff802`254e6a9f f7417400040000  test    dword ptr [rcx+74h],400h
  31.                         fffff802`254e6aa6 0f8444081100    je      nt!PsTerminateSystemThread+0x110860 (fffff802`255f72f0)  Branch
  32.                         nt!PsTerminateSystemThread+0x1c:
  33.                         fffff802`254e6aac 41b001          mov     r8b,1
  34.                         fffff802`254e6aaf e80cb6f6ff      call    nt!PspTerminateThreadByPointer (fffff802`254520c0)
  35.                         nt!PsTerminateSystemThread+0x24:
  36.                         fffff802`254e6ab4 4883c428        add     rsp,28h
  37.                         fffff802`254e6ab8 c3              ret
  38.                         nt!PsTerminateSystemThread+0x110860:
  39.                         fffff802`255f72f0 b80d0000c0      mov     eax,0C000000Dh
  40.                         fffff802`255f72f5 e9baf7eeff      jmp     nt!PsTerminateSystemThread+0x24 (fffff802`254e6ab4)  Branch
  41.         */
  42.         UCHAR pSpecialData[50] = { 0 };
  43.         ULONG ulSpecialDataSize = 0;
  44.         // fffff802`254e6aaf e80cb6f6ff      call    nt!PspTerminateThreadByPointer (fffff802`254520c0)
  45.         pSpecialData[0] = 0xE8;
  46.         ulSpecialDataSize = 1;
  47.         // 搜索地址 PsTerminateSystemThread --> PsTerminateSystemThread + 0xff 查找 e80cb6f6ff
  48.         pAddress = SearchMemory(pPsTerminateSystemThread, (PVOID)((PUCHAR)pPsTerminateSystemThread + 0xFF), pSpecialData, ulSpecialDataSize);
  49.         if (NULL == pAddress)
  50.         {
  51.                 return 0;
  52.         }
  53.         // 先获取偏移,再计算地址
  54.         lOffset = *(PLONG)pAddress;
  55.         pPspTerminateThreadByPointer = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset);
  56.         if (NULL == pPspTerminateThreadByPointer)
  57.         {
  58.                 return 0;
  59.         }
  60.         return pPspTerminateThreadByPointer;
  61. }
  62. VOID UnDriver(PDRIVER_OBJECT driver)
  63. {
  64.         DbgPrint("驱动已卸载 \n");
  65. }
  66. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  67. {
  68.         DbgPrint("hello lyshark.com \n");
  69.         PVOID address = PspTerminateThreadByPointer();
  70.         DbgPrint("PspTerminateThreadByPointer = 0x%p \n", address);
  71.         Driver->DriverUnload = UnDriver;
  72.         return STATUS_SUCCESS;
  73. }
复制代码
运行驱动程序,首先得到PspTerminateThreadByPointer的内存地址,效果如下。

得到内存地址以后直接将地址typedef转为指针函数,调用并批量结束进程内的线程即可。
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: [email protected]
  5. #include <ntifs.h>
  6. typedef NTSTATUS(__fastcall *PSPTERMINATETHREADBYPOINTER) (PETHREAD pEThread, NTSTATUS ntExitCode, BOOLEAN bDirectTerminate);
  7. VOID UnDriver(PDRIVER_OBJECT driver)
  8. {
  9.         DbgPrint("驱动已卸载 \n");
  10. }
  11. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  12. {
  13.         DbgPrint("hello lyshark.com \n");
  14.         PVOID pPspTerminateThreadByPointerAddress = 0xFFFFF802254520C0;
  15.         HANDLE hProcessId = 6956;
  16.         PEPROCESS pEProcess = NULL;
  17.         PETHREAD pEThread = NULL;
  18.         PEPROCESS pThreadEProcess = NULL;
  19.         NTSTATUS status = STATUS_SUCCESS;
  20.         ULONG i = 0;
  21.         // 获取结束进程的进程结构对象EPROCESS
  22.         status = PsLookupProcessByProcessId(hProcessId, &pEProcess);
  23.         if (!NT_SUCCESS(status))
  24.         {
  25.                 return status;
  26.         }
  27.         // 遍历所有线程, 并结束所有指定进程的线程
  28.         for (i = 4; i < 0x80000; i = i + 4)
  29.         {
  30.                 status = PsLookupThreadByThreadId((HANDLE)i, &pEThread);
  31.                 if (NT_SUCCESS(status))
  32.                 {
  33.                         // 获取线程对应的进程结构对象
  34.                         pThreadEProcess = PsGetThreadProcess(pEThread);
  35.                         // 结束进程中的线程
  36.                         if (pEProcess == pThreadEProcess)
  37.                         {
  38.                                 ((PSPTERMINATETHREADBYPOINTER)pPspTerminateThreadByPointerAddress)(pEThread, 0, 1);
  39.                                 DbgPrint("结束线程: %d \n", i);
  40.                         }
  41.                         ObDereferenceObject(pEThread);
  42.                 }
  43.         }
  44.         ObDereferenceObject(pEProcess);
  45.         Driver->DriverUnload = UnDriver;
  46.         return STATUS_SUCCESS;
  47. }
复制代码
循环结束进程6956内的所有线程信息,效果如下;

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表