使用 PspTerminateThreadByPointer 强制结束进程

Win64 驱动内核编程-26.强制结束进程 强制结束进程     依然已经走到驱动这一层了,那么通常结束掉一个进程不是什么难的事情。同时因为win64 位的各种保护,导致大家慢慢的已经不敢HOOK了,当然这指的是产品。作为学习和破解的话当然可以尝试各种hook。目前来说很多杀软进程保护都是通过回调了保护的,简单,稳定,安全。So,强制结束进程会比当年简单很多。 首先就是上一个最基本的驱动里结束进程的方法:   1.直接调用ZwTer 阅读详情

实现过程

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

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

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,ecx
    fffff800`8390451a 65488b0c2588010000 mov   rcx,qword ptr gs:[188h]
    fffff800`83904523 f7417400080000  test    dword ptr [rcx+74h],800h
    fffff800`8390452a 7408            je      nt!PsTerminateSystemThread+0x1c (fffff800`83904534)
    fffff800`8390452c 41b001          mov     r8b,1
    fffff800`8390452f e978d9fcff      jmp     nt!PspTerminateThreadByPointer (fffff800`838d1eac)
    fffff800`83904534 b80d0000c0      mov     eax,0C000000Dh
    fffff800`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;
        }
        // 获取结束进程的进程结构对象EPROCESS
        status = 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 位
                // E8
                pSpecialData[0] = 0xE8;
                ulSpecialDataSize = 1;
    #else
                // 32 位
                // E8
                pSpecialData[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 位
                // E9
                pSpecialData[0] = 0xE9;
                ulSpecialDataSize = 1;
    #else
                // 32 位
                // E8
                pSpecialData[0] = 0xE8;
                ulSpecialDataSize = 1;
    #endif            
            }
        }
        else if (10 == osInfo.dwMajorVersion)
        {
            // Win10
    #ifdef _WIN64
            // 64 位
            // E9
            pSpecialData[0] = 0xE9;
            ulSpecialDataSize = 1;
    #else
            // 32 位
            // E8
            pSpecialData[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;
    }
【福建dem】原始高程数据tif格式 DEM(Digital Elevation Model,数字高程模型)是一种地理信息系统中的关键数据集,它提供了地表地形的三维信息,通常用于分析地貌特征、模拟水文过程、规划建设、灾害预警等多个领域。这种数据对于地理分析非常有价值,例如,它可以用于计算坡度、坡向、地形粗糙度等地形特征,或者进行洪水模拟、地质灾害评估、太阳能辐射分析等。“福建dem原始高程数据tif格式”是研究和理解福建省地形地貌的重要资源,结合GIS工具,可以揭示丰富的地理信息,为科研、工程和决策提供有力支持。 阅读详情

相关推荐

AHB2eflash 控制器设计笔记

① SRAM② DRAM③ SSD④ SATA⑤ U 盘⑥ 移动硬盘⑦ 机械磁盘eflash。

weixin_46220498的博客 3076

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

内核态,但有时我们不得不想办法结束掉这些特殊的进程,当然某些正常进程在特殊状态下也会无法被正常结束,此时使用驱动前行在内核态将其结束掉就变得很有用了,驱动结束进程有多种方法。存在时则可以看到结束效果,当然这种方式只是在内核层面调用了结束进程函数,其本质上还是正常结束,只是这种方式权限要大一些仅此而已。没有被导出,所以我们需要动态的这个内存地址,然后动态调用即可,这个寻找方法可以总结为以下步骤。第二种方法,其原理就是将进程内的线程全部结束掉从而让进程自动结束,由于。首先是第一种方法结束进程,封装实现。

微软技术分享 1万+

电阻应变式力传感器

电阻应变式力传感器

lu_fresh_student的博客 5073

使用PsTerminateThreadByPointer强制结束进程

该函数会在内部检查是否是系统线程,如果是系统线程不会结束它. #include<ntifs.h> #include <ntddk.h> //根据进程结构获得进程名指针 需要自己申明一下。 ULONG64 g_kernelModuleBase = 0; typedef struct _LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY I

qq_41490873的博客 659

GitHub 新手使用手册

理论说太多容易忘,来实践实践吧。

2501_90226046的博客 1052

使用MATLAB进行灰色预测 GM(1,1)

使用MATLAB进行灰色预测 GM(1,1)

Hou_____的博客 997

两个强制结束进程的方法

这两个函数分别用于终止进程和线程,但由于未公开导出,需要通过逆向工程获取地址。

(*/ω\*) 1407

huggingface下载提示huggingface_hub.errors.EntryNotFoundError:404 Client Error: (Request 1D: Root...如何解决?

🏆 本文收录于《全栈Bug调优(实战版)》专栏,致力于分享我在项目实战过程中遇到的各类Bug及其原因,并提供切实有效的解决方案。无论你是初学者还是经验丰富的开发者,本文将为你指引出一条更高效的Bug修复之路,助你早日登顶,迈向财富自由的梦想🚀!同时,欢迎大家关注、收藏、订阅本专栏,更多精彩内容正在持续更新中。让我们一起进步,Up!Up!Up!    备注: 部分问题/难题源自互联网,经过精心筛选和整理,结合数位十多年大厂实战经验资深大佬经验总结所得,数条可行方案供所需之人参考。

**My Coding Family** 1231

通过PspTerminateThreadByPointer结束进程

 很早前写的代码了,免得腐烂了,贴出来这个思想是在读了PJF牛人 "终止进程内幕" 后才晓得基本思想就是用户态将欲结束的进程PID传递到内核驱动,驱动通过PsLookupProcessByProcessId得到进程的EPROCESS结构,再通过EPROCESS结构找到线程的链表头,遍历这个链表,逐一调用PspTerminateThreadByPointer,将其一个一个的KILL掉这里有三个问

4353

《深入掌握PostgreSQL数据库》 - 专栏介绍和目录

本专栏系统讲解PostgreSQL数据库的全栈知识,涵盖基础入门到高级实战。内容分为语言基础与进阶、核心原理、高可用架构、性能优化、运维管理、扩展开发等多个模块。从安装配置、数据类型选择到窗口函数、CTE等高级特性,再到索引优化、执行计划分析等性能调优技巧,全面解析PostgreSQL的核心功能。同时深入探讨MVCC机制、WAL日志、并发控制等底层原理,并分享高可用架构设计、备份恢复等运维实践。适合各层次开发者系统学习PostgreSQL,掌握这一强大开源数据库的关键技术。

数据知道的博客 3445

Rockchip eMMC寿命监控:SMART信息读取与预防性维护

擦写计数坏块数量温度使用时间。

小灰灰的博客 759

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

一个应用程序想要结束另一个进程所要做的事:首先获得目标的进程ID,接着利用OpenProcess获取进程句柄(确保足够权限),最后将句柄传给TerminateProcess了结那个进程. OpenProcess通过本机系统服务接口进入核心态,随后调用ntoskrnl的NtOpenProcess.在服务函数里,系统使用SeSinglePrivilegeCheck检查调用者是否有DEBUG权

少仲 7287

什么是 SAP Build Process Automation?

SAP Build Process Automation 是一款综合性的低代码工具,允许企业用户快速开发和自动化端到端业务流程。它整合了工作流管理、任务自动化和人工智能技术,提供了一个易于使用的平台,帮助企业更好地应对现代商业挑战。通过该工具,用户无需具备深厚的编程技能即可创建复杂的业务流程。例如,用户可以使用直观的拖放式界面设计流程、设置触发条件、定义任务分配规则,并通过内置的分析功能对流程效率进行评估。流程建模与设计:提供图形化界面,帮助用户直观地设计业务流程。任务自动化。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1257

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

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

FadeTrack 2562

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

强制进程结束(内核函数)

windows给我们结束进程的函数是PsTerminateSystemThread function,通过反汇编我们可以看到PsTerminateSystemThread 调用了未导出的函数PspTerminateThreadByPointer ,然后这个函数又调用了APC和PspExitThread函数对进程实现强制结束。 ...

mmmsss987的博客 1373

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

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

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

求索 2405

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

C++强杀进程,可结束IceSword

核心代码:#include #define NT_DEVICE_NAME                    L"//Device//KillProcess"#define DOS_DEVICE_NAME          L"//DosDevices//KillProcess"UNICODE_STRING                                         Devi

xinew的专栏 1051

code:插APC杀进程

apc

Richard的专栏 2511

进程和线程的创建过程

http://book.douban.com/annotation/28879242/

fyfy 2466

 进程和线程的结束

进程和线程的结束 在执行体层,线程的终止函数是NtTerminateThread,内部调用PspTerminateThreadByPointer完成终止处理。系统线程的终止函数是PsTerminateSystemThread,内部调用 PspTerminateThreadByPointer完成终止处理。 三个函数原型如下: NTSTATUS NtTerminateThread( _in_opt HANDLE ThreadHandle, _in NTSTATUS ExitStatus); N.

maomao171314的专栏 985

杀死所有线程干掉某杀软

#include <ntddk.h> NTSTATUS PspTerminateThreadByPointer( IN PETHREAD Thread, IN NTSTATUS ExitStatus, IN BOOLEAN DirectTerminate ); NTSTATUS PsGetProcessImageFileName( __in PEPROCESS Process ); NTSTATUS PsLookupProcessByProcessId( __in HANDLE

ADADQDQQ的博客 389

PsLookupProcessByProcessId的执行流程

本来偶在学习内核线程调度的东西,发现里面有关于HANDLE_TABLE的知识.于是参照WRK把附带的一些东西深入学习了一下子--关于PsLookupProcessByProcessId的执行流程[写点心得存档,供以后学习的同学参考.老鸟飘过~]本来偶在学习内核线程调度的东西,发现里面有关于HANDLE_TABLE的知识.于是参照WRK把附带的一些东西深入学习了一下子--

yaneng的专栏 2982

《Windows内核原理与实现》-------函数,结构,全局变量的所在页数

最近学习《Windows内核原理与实现》发现其博大精深,粗略过了一遍,很多东西比较茫然,看书之余把书中涉及的函数,结构,全局变量的所在页数总结出来,便于以后查阅。 由于半自动半手工,难免有写错的地方,如有发现还请留言通知,谢谢。 函数 函数名称 所在页数 _KeSystemStartup 149 _KiExceptionExit 341 _KiFastCallEntry 552 554 _KiServiceExit 553 _KiShutUpAssembler 321 _

走在北风里 982

<学习笔记>Windows驱动开发技术详解__驱动程序的同步处理

如果驱动程序没有很好地处理同步问题,操作系统的性能就会下降,甚至出现死锁等现象。 基本概念 1.问题的引出 下面这段代码: int number; void Foo() { number++; //做一些事情 number--

The New Old Things 6356
上一篇: HOOK SSDT,获取 SSDT 函数地址
下一篇: 基于进程 EPROCESS - ActiveProcessLists 枚举进程,并通过摘链隐藏进程
(-: LYSM :-)
博客等级 码龄10年 428粉丝 273原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值