实现过程

我们知道,线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。

也就是说,当一个进程中的所有线程都被结束的时候,这个进程也就没有了存在的意义,也随之结束了。这,便是我们本文介绍的这种强制杀进程的实现原理,即把进程中的线程都杀掉,从而让进程消亡,实现间接杀进程的效果。

Windows 提供了一个导出的内核函数 PsTerminateSystemThread 来帮助我们结束线程,所以,类似 360、QQ 等也会对重点监测该函数,防止结束自己的线程。我们通过逆向 PsTerminateSystemThread 函数,可以发现该函数实际上调用了未导出的内核函数 PspTerminateThreadByPointer 来实现的结束线程的操作。所以,我们可以通过查找 PspTerminateThreadByPointer 函数地址,调用直接它来结束线程,就可以绕过绝大部分的进程保护,实现强制杀进程。

PspTerminateThreadByPointer

    NTSTATUS PspTerminateThreadByPointer (PETHREAD pEThread, NTSTATUS ntExitCode, BOOLEAN bDirectTerminate);

但要注意,PspTerminateThreadByPointer 的函数指针的声明的调用约定:

    // 32 位typedef NTSTATUS(*PSPTERMINATETHREADBYPOINTER_X86) (PETHREAD pEThread, NTSTATUS ntExitCode, BOOLEAN bDirectTerminate);// 64 位typedef NTSTATUS(__fastcall *PSPTERMINATETHREADBYPOINTER_X64) (PETHREAD pEThread, NTSTATUS ntExitCode, BOOLEAN bDirectTerminate);

其中,PsTerminateSystemThread 里会调用 PspTerminateThreadByPointer 函数。我们使用 WinDbg 逆向 Win8.1 x64 里的 PsTerminateSystemThread 函数,如下所示:

    nt!PsTerminateSystemThread:fffff800`83904518 8bd1            mov     edx,ecxfffff800`8390451a 65488b0c2588010000 mov   rcx,qword ptr gs:[188h]fffff800`83904523 f7417400080000  test    dword ptr [rcx+74h],800hfffff800`8390452a 7408            je      nt!PsTerminateSystemThread+0x1c (fffff800`83904534)fffff800`8390452c 41b001          mov     r8b,1fffff800`8390452f e978d9fcff      jmp     nt!PspTerminateThreadByPointer (fffff800`838d1eac)fffff800`83904534 b80d0000c0      mov     eax,0C000000Dhfffff800`83904539 c3              ret

由上面代码可以知道,我们可以通过扫描 PsTerminateSystemThread 内核函数中的特征码,从而获取 PspTerminateThreadByPointer 函数的偏移,再根据偏移计算出该函数的地址。其中,不同系统中的特征码也会不同,下面是我使用 WinDbg 逆向各个系统上总结的特征码的情况:

那么,我们强制杀进程的实现原理为:

  • 首先,根据特征码扫描内存,获取 PspTerminateThreadByPointer 函数地址

  • 然后,调用 PsLookupProcessByProcessId 函数,根据将要结束进程 ID 获取对应的进程结构对象 EPROCESS

  • 接着,遍历所有的线程 ID,并调用 PsLookupThreadByThreadId 函数根据线程 ID 获取对应的线程结构 ETHREAD

  • 然后,调用函数 PsGetThreadProcess 获取线程结构 ETHREAD 对应的进程结构 EPROCESS

  • 这时,我们可以通过判断该进程是不是我们指定要结束的进程,若是,则调用 PspTerminateThreadByPointer 函数结束线程;否则,继续遍历下一个线程 ID

  • 重复上述 3、4、5 的操作,直到线程遍历完毕

这样,我们就可以查杀指定进程的所有线程,线程被结束之后,进程也随之结束。注意的是,当调用 PsLookupProcessByProcessId 和 PsLookupThreadByThreadId 等 LookupXXX 系列函数获取对象的时候,都需要调用 ObDereferenceObject 函数释放对象,否则在某些时候会造成蓝屏。

编码实现

强制结束指定进程:

    // 强制结束指定进程NTSTATUS ForceKillProcess(HANDLE hProcessId){PVOID pPspTerminateThreadByPointerAddress = NULL;PEPROCESS pEProcess = NULL;PETHREAD pEThread = NULL;PEPROCESS pThreadEProcess = NULL;NTSTATUS status = STATUS_SUCCESS;ULONG i = 0;#ifdef _WIN64// 64 位typedef NTSTATUS(__fastcall *PSPTERMINATETHREADBYPOINTER) (PETHREAD pEThread, NTSTATUS ntExitCode, BOOLEAN bDirectTerminate);#else// 32 位typedef NTSTATUS(*PSPTERMINATETHREADBYPOINTER) (PETHREAD pEThread, NTSTATUS ntExitCode, BOOLEAN bDirectTerminate);#endif// 获取 PspTerminateThreadByPointer 函数地址pPspTerminateThreadByPointerAddress = GetPspLoadImageNotifyRoutine();if (NULL == pPspTerminateThreadByPointerAddress){ShowError("GetPspLoadImageNotifyRoutine", 0);return FALSE;}// 获取结束进程的进程结构对象EPROCESSstatus = PsLookupProcessByProcessId(hProcessId, &pEProcess);if (!NT_SUCCESS(status)){ShowError("PsLookupProcessByProcessId", status);return status;}// 遍历所有线程, 并结束所有指定进程的线程for (i = 4; i < 0x80000; i = i + 4){status = PsLookupThreadByThreadId((HANDLE)i, &pEThread);if (NT_SUCCESS(status)){// 获取线程对应的进程结构对象pThreadEProcess = PsGetThreadProcess(pEThread);// 结束指定进程的线程if (pEProcess == pThreadEProcess){((PSPTERMINATETHREADBYPOINTER)pPspTerminateThreadByPointerAddress)(pEThread, 0, 1);DbgPrint("PspTerminateThreadByPointer Thread:%d\n", i);}// 凡是Lookup...,必需Dereference,否则在某些时候会造成蓝屏ObDereferenceObject(pEThread);}}// 凡是Lookup...,必需Dereference,否则在某些时候会造成蓝屏ObDereferenceObject(pEProcess);return status;}

获取 PspTerminateThreadByPointer 函数地址:

    // 获取 PspTerminateThreadByPointer 函数地址PVOID GetPspLoadImageNotifyRoutine(){PVOID pPspTerminateThreadByPointerAddress = NULL;RTL_OSVERSIONINFOW osInfo = { 0 };UCHAR pSpecialData[50] = { 0 };ULONG ulSpecialDataSize = 0;// 获取系统版本信息, 判断系统版本RtlGetVersion(&osInfo);if (6 == osInfo.dwMajorVersion){if (1 == osInfo.dwMinorVersion){// Win7#ifdef _WIN64// 64 位// E8pSpecialData[0] = 0xE8;ulSpecialDataSize = 1;#else// 32 位// E8pSpecialData[0] = 0xE8;ulSpecialDataSize = 1;#endif    }else if (2 == osInfo.dwMinorVersion){// Win8#ifdef _WIN64// 64 位#else// 32 位#endif}else if (3 == osInfo.dwMinorVersion){// Win8.1#ifdef _WIN64// 64 位// E9pSpecialData[0] = 0xE9;ulSpecialDataSize = 1;#else// 32 位// E8pSpecialData[0] = 0xE8;ulSpecialDataSize = 1;#endif            }}else if (10 == osInfo.dwMajorVersion){// Win10#ifdef _WIN64// 64 位// E9pSpecialData[0] = 0xE9;ulSpecialDataSize = 1;#else// 32 位// E8pSpecialData[0] = 0xE8;ulSpecialDataSize = 1;#endif}// 根据特征码获取地址pPspTerminateThreadByPointerAddress = SearchPspTerminateThreadByPointer(pSpecialData, ulSpecialDataSize);return pPspTerminateThreadByPointerAddress;}

根据特征码获取 PspTerminateThreadByPointer 数组地址:

    // 根据特征码获取 PspTerminateThreadByPointer 数组地址PVOID SearchPspTerminateThreadByPointer(PUCHAR pSpecialData, ULONG ulSpecialDataSize){UNICODE_STRING ustrFuncName;PVOID pAddress = NULL;LONG lOffset = 0;PVOID pPsTerminateSystemThread = NULL;PVOID pPspTerminateThreadByPointer = NULL;// 先获取 PsTerminateSystemThread 函数地址RtlInitUnicodeString(&ustrFuncName, L"PsTerminateSystemThread");pPsTerminateSystemThread = MmGetSystemRoutineAddress(&ustrFuncName);if (NULL == pPsTerminateSystemThread){ShowError("MmGetSystemRoutineAddress", 0);return pPspTerminateThreadByPointer;}// 然后, 查找 PspTerminateThreadByPointer 函数地址pAddress = SearchMemory(pPsTerminateSystemThread,(PVOID)((PUCHAR)pPsTerminateSystemThread + 0xFF),pSpecialData, ulSpecialDataSize);if (NULL == pAddress){ShowError("SearchMemory", 0);return pPspTerminateThreadByPointer;}// 先获取偏移, 再计算地址lOffset = *(PLONG)pAddress;pPspTerminateThreadByPointer = (PVOID)((PUCHAR)pAddress + sizeof(LONG) + lOffset);return pPspTerminateThreadByPointer;}

指定内存区域的特征码扫描:

    // 指定内存区域的特征码扫描PVOID SearchMemory(PVOID pStartAddress, PVOID pEndAddress, PUCHAR pMemoryData, ULONG ulMemoryDataSize){PVOID pAddress = NULL;PUCHAR i = NULL;ULONG m = 0;// 扫描内存for (i = (PUCHAR)pStartAddress; i < (PUCHAR)pEndAddress; i++){// 判断特征码for (m = 0; m < ulMemoryDataSize; m++){if (*(PUCHAR)(i + m) != pMemoryData[m]){break;}}// 判断是否找到符合特征码的地址if (m >= ulMemoryDataSize){// 找到特征码位置, 获取紧接着特征码的下一地址pAddress = (PVOID)(i + ulMemoryDataSize);break;}}return pAddress;}

使用 PspTerminateThreadByPointer 强制结束进程相关推荐

  1. Win64 驱动内核编程-26.强制结束进程

    强制结束进程 依然已经走到驱动这一层了,那么通常结束掉一个进程不是什么难的事情.同时因为win64 位的各种保护,导致大家慢慢的已经不敢HOOK了,当然这指的是产品.作为学习和破解的话当然可以尝试各种 ...

  2. 浅谈驱动中强制结束进程的3种方法

    一个应用程序想要结束另一个进程所要做的事:首先获得目标的进程ID,接着利用OpenProcess获取进程句柄(确保足够权限),最后将句柄传给TerminateProcess了结那个进程. OpenPr ...

  3. 驱动 -- 强制结束进程 -- 整理

    有一阵子没 写博客,正好这几天 写了个 内核级强制结束进程 的小例子.写这个例子之前都没去查什么资料,主要是想试试自己能不能写出来吧.写完后才发现 看雪论坛 曾经发表过一篇很相似的文章,实现的细节可能 ...

  4. 强制结束进程的命令和软件

    有时,我们在进程中发现可疑进程时,用Windows的任务管理器并不一定能结束它,这时,我们需要更多更强大的强制结束进程的命令或软件来对付它,下面介绍两个Windows强制结束进程的命令和一个我常用的进 ...

  5. win10taskkill强行结束进程_Win10程序卡死怎么办? Win10强制结束进程的两种方法

    Windows 10系统中,经常遇到某一进程卡死.停止运行的现象,处理此问题的方法可以有:注销一次系统:结束此系统进程. 结束系统进程的方法可以在任务管理器中进行,也可以在管理员命令提示符窗口中使用T ...

  6. linux kill强制结束进程参数,Linux结束进程之kill、killall、pkill命令

    1. 前言 我们经常在Linux里使用kill命令来结束某后台进程.但kill命令实际上是向进程发送信号,并且有多种信号.终止运行一个程序只是其中一个信号而已.kill是根据进程号发送信号的,而另一个 ...

  7. win10taskkill强行结束进程_技术员细说win10系统强制结束进程命令的教程

    win10系统是很多电脑用户首选的装机系统,然而有不少用户在使用过程中可能会碰到win10系统强制结束进程命令的情况.大部分用户电脑技术都是菜鸟水平,面对win10系统强制结束进程命令的问题,无法自行 ...

  8. mysql强行结束程_如何强制结束进程?

    展开全部 1.ntsd强制结束命令 其实只需32313133353236313431303231363533e4b893e5b19e31333337616633要通过两个命令来强制性的结束这些进程,第 ...

  9. 【LInux】后台执行命令 nohup 以及强制结束进程命令 kill

    通过终端远程操作服务器时,难免要使特定进程处于持续运行状态,例如深度学习训练网络参数,但又不可能长时间不间断操作终端,我们希望将进程保持后台持续运行,这里提供两个思路:(1)docker 内运行,退出 ...

最新文章

  1. v$open_cursor与session_cached_cursor
  2. 使用HttpWebRequest提交ASP.NET表单并保持Session和Cookie
  3. 有跳板机时,如何使用sshfs挂载远程服务器文件夹
  4. 如何判断两个jq对象是同一个对象
  5. java中ajax由哪些组成,java中ajax
  6. 问题 J: 十进制整数转二进制
  7. 我一直以为做知识付费的老师是非常赚钱的
  8. 回顾云计算项目的得与失
  9. FISCO BCOS 区块链 零知识证明 可监管
  10. Docker 部署启动 Spring boot 项目
  11. 黑苹果 efi如何替换_看了这篇文章,再也不用花钱请人装黑苹果了
  12. 翁恺c语言程序设计入门作业,程序设计入门——C语言
  13. 捷联惯导系统学习4.3(静基座误差)
  14. PDFObject无法加载远程url和不支持IE浏览器解决方案
  15. 打开本地计算机策略,win7本地组策略打开方法介绍
  16. 产品经理需要了解的宏观趋势(共享经济专题)1/7
  17. 手机上测试东南西北方向软件,指南针怎么看东南西北(手机指南针怎么看图解)...
  18. 如何将文字转换为二维码 python_用python将二维码转换成字符直接输出控制台
  19. 阿里云高主频通用型hfg7云服务器磁盘I/O性能表详解
  20. 看最强大脑中英PK小记

热门文章

  1. C语言教辅书答案,《C语言程序设计上机指导与习题解答》任正云 主编;李素若_孔网...
  2. 关于海外服务器时间和网站时差问题解决方案
  3. 梯度、散度和旋度及在图像处理中的应用(图像融合)
  4. cscope、ctags和vim简明使用流程
  5. PC端 微信扫码登录
  6. 基于STM32L431设计的云端绿化管理系统(ESP8266+阿里云物联网平台)
  7. 秋叶老师的《如何成为PPT高手》介绍
  8. Teamcenter许可不可用(TC许可不可用)怎么办
  9. hadoop教程网站
  10. ArcGIS:区域分析工具概述