-
-
[分享]使用为导出函数PspTerminateProcess关闭进程
-
发表于: 6天前 225
-
环境:winXP
`PspTerminateProcess`是为导出函数,所以无法直接通过dll进行调用,**函数只是没有导出,而不是不存在**,对于未导出的函数,我们有两种解决办法,1.特征码匹配,2.解析内核PDB文件,我打算采取特征码匹配的方式得到为导出的函数地址。
思路
1. 确定`PspTerminateProcess`所在的模块
通过`Driver_OBJECT`的成员`DriverSection
`指向的`LDR_DATA_TABLE_ENTRY`结构,得到内核空间中的各个模块,确定模块之后,即可查找的基地址
2. 在windbg中查看函数`PspTerminateProcess`,选取特征码
特征码需要避开硬编码地址(全局变量、间接Call(FF)),硬编码地址可能会因为系统重启而导致模块装载位置变化,从而影响硬编码地址,避开公共代码部分,选择该函数特有的部分
关于特征码我使用的如下区域

3. 从基地址开始进行特征码匹配,如果匹配成功会得到我们获取特征码的位置,根据特征码相当于函数开始处的偏移,即可得到该函数的地址
4. 定义函数指针
在定义函数指针之前,我们需要搞清楚`PspTerminateProcess`的参数,在10-10-12分页下IDA去分页一下函数`PspTerminateProcess`,使用交叉引用就可以知道有谁调用了这个函数,最终我们确定了函数`PsTerminateProcess`


我们去查阅关于`PsTerminateProcess`的资料,会发现该函数是个导出函数
NTSTATUS NTAPI PsTerminateProcess(IN PEPROCESS Process,
IN NTSTATUS ExitStatus)
{
/* Call the internal API */
return PspTerminateProcess(Process, ExitStatus);
}所以我们就可以确定`PspTerminateProcess`的函数指针
typedef NTSTATUS(*funcPspTerminateProcess)(PEPROCESS process, NTSTATUS ExitStatus); funcPspTerminateProcess PspTerminateProcess;
代码示例
#include <ntifs.h>
NTSTATUS UnloadDriver(PDRIVER_OBJECT DriverObject)
{
DbgPrint("Driver Uninstall!!\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
DbgPrint("Driver Loading!!\n");
DriverObject->DriverUnload = UnloadDriver;
//1.获取PspTerminateProcess所在模块的基址
PDRIVER_OBJECT Driver = DriverObject;
LIST_ENTRY* pListHead = Driver->DriverSection;
LIST_ENTRY* pCurrent = pListHead->Flink;
UINT32 DllBase = 0;
UINT32 SizeOfImage = 0;
UNICODE_STRING targetName;
RtlInitUnicodeString(&targetName, L"ntoskrnl.exe");
while (pCurrent != pListHead)
{
PUNICODE_STRING pDllName = (PUNICODE_STRING)((UINT32)pCurrent + 0x2c);
DbgPrint("DllName: %wZ", pDllName);
UINT32 BaseAddr = *(UINT32*)((UINT32)pCurrent + 0x18);
if (!RtlCompareUnicodeString(pDllName, &targetName, FALSE))
{
DllBase = BaseAddr;
SizeOfImage = *(UINT32*)((UINT32)pCurrent + 0x20);
DbgPrint("ntoskrnl GET! Base: %X, Size: %X\n", DllBase, SizeOfImage);
break;
}
pCurrent = pCurrent->Flink;
}
//2.获取特征码,进行特征码匹配
UCHAR Buffer1[12] = { 0xf6, 0x47, 0x01, 0x20, 0x74, 0x12, 0x8d, 0x86, 0x74, 0x01, 0x00, 0x00 };
PUCHAR pBase = (PUCHAR)DllBase;
//特征码匹配
UINT32 signature_offset; //特征码相对于函数开始处的偏移
for (UINT32 i = 0; i < SizeOfImage - sizeof(Buffer1); i++)
{
__try
{
if (RtlCompareMemory(Buffer1, pBase + i, sizeof(Buffer1)) == sizeof(Buffer1))
{
DbgPrint("PspTerminateProcess GET!!!!!\n");
DbgPrint("PspTerminateProcess signature found at offset: 0x%X\n", i);
signature_offset = i;
break;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
continue;
}
}
//3.定义PspTerminateProcess的函数指针
typedef NTSTATUS(*funcPspTerminateProcess)(PEPROCESS process, NTSTATUS ExitStatus);
funcPspTerminateProcess PspTerminateProcess;
//4.获取PspTerminateProcess函数地址
PspTerminateProcess = (funcPspTerminateProcess)((UINT32)pBase + signature_offset - 0x22);//特征码相对于函数开始处的偏移,计算出PspTerminateProcess函数地址
DbgPrint("PspTerminateProcess: %x\n", PspTerminateProcess);
//5.定义PspTerminateProcess函数的参数
PEPROCESS pEProc;//每个进程都有一个 EPROCESS 结构,里面保存着进程的各种信息,和相关结构的指针。
HANDLE pid = 1796;//输入要结束的进程PID
NTSTATUS status = PsLookupProcessByProcessId(pid, &pEProc);//PsLookupProcessByProcessId 函数用于根据进程ID查找对应的EPROCESS结构指针。
//6.调用PspTerminateProcess的函数指针 杀死指定pid的进程
__try
{
PspTerminateProcess(pEProc, 0);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
return STATUS_SUCCESS;
}测试
使用PspTerminateProcess函数杀死`notepad.exe`

此处的`pid = 1664`,修改驱动程序中定义的`pid`,生成驱动程序
HANDLE pid = 1664;//要结束的进程PID
注册并运行驱动

成功杀死了`notepad.exe`
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。