SSDT HOOK实现进程保护
阅读原文时间:2021年04月20日阅读:1

转自灰狐

http://nokyo.blogbus.com/logs/35320995.html

SSDT HOOK已经是很老的技术了,但对新手来说还是有一些嚼头的。根据常规的做法,我们应该挂钩 ZwTerminateProcess函数,不过这个函数仅有两个参数,其中一个是进程句柄,它指定了需要被结束的进程。

由于我们不能直接从进程句柄获取有关进程的一些信息,这就使得一些“懒惰”的家伙尝试找一些捷径。由 于要想获得句柄通常都需要首先调用ZwOpenProcess,而ZwOpenProcess需要传递PID作为标识,于是有些人就不管 ZwTerminateProcess函数了,改为挂钩ZwOpenProcess,这样你无法打开我们关注的进程,也就无法获得句柄,自然也就没办法结 束我们的进程。

乍一看,这还是真是一种思路巧妙的做法。不过,点心毕竟是不能当正餐吃的,这样的做法作为临时救火也 没什么,要是一直抱着它不愿放弃就大错特错了。

实际上,这种做法是有副作用的,比如通常在ring3使用PSAPI枚举进程时,我们经常使用下面的 代码来获取进程完整路径:

HANDLE hProcess = OpenProcess(

PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,

FALSE,

ProcessId[i]);

if(hProcess)

{

EnumProcessModules(hProcess,&hModule,sizeof(hModule),&cbNeeded);

GetModuleFileNameEx(hProcess,hModule,szPath,sizeof(szPath));

// 输出到列表框

}

CloseHandle(hProcess);

如果我们挂钩了ZwOpenProcess,那么使用这种方法枚举进程的程序就可能无法获得我们的保 护进程信息。有人会说这样还不好?不要忘了,我们的目的不是隐藏,而是保护。自我保护是任何人都无可非议的做法,但尝试隐藏自身却会让人怀疑你的目的。

其实说穿了,我们挂钩ZwOpenProcess的根本原因是不会使用句柄得到进程信息。好吧,我们 现在就介绍如何通过进程句柄获取信息。

在炉子的《API HOOK实现ring3的进程保护》一文中给出了一种解决方法,即使用NTDLL 导出的 Zw(Nt)QueryInformationProcess 函数。

下面我们看看这个函数的声明:

NTSYSAPI

NTSTATUS

NTAPI

NtQueryInformationProcess(

IN HANDLE        ProcessHandle,

IN PROCESSINFOCLASS  ProcessInformationClass,

OUT PVOID          ProcessInformation,

IN ULONG         ProcessInformationLength,

OUT PULONG        ReturnLength );

这个函数的关键是第二个参数,它决定了第三个参数输出什么结构。现在我们可以将其填写为 ProcessBasicInformation,这样我们会获得一个PROCESS_BASIC_INFORMATION结构的信息输出。而 PROCESS_BASIC_INFORMATION结构的UniqueProcessId子域即是该句柄代表的进程ID。

下面是通过句柄获得PID的代码:

ULONG lRet;

PVOID pBuffer;

PROCESS_BASIC_INFORMATION  *pbi;

pBuffer = ExAllocatePool(PagedPool, sizeof(PROCESS_BASIC_INFORMATION));

ZwQueryInformationProcess(ProcessHandle,

ProcessBasicInformation,

pBuffer,

sizeof(PROCESS_BASIC_INFORMATION),

&lRet);

pbi = (struct _PROCESS_BASIC_INFORMATION *)pBuffer;

KdPrint(("ProcessHandle代表进程%d!", pbi.UniqueProcessId));

有了PID剩下的就好办了,我们可以使用函数PsLookupProcessByProcessId 来获取该进程的EPROCESS结构,这个结构中就有进程名的信息。

与之类似,文件句柄可以通过Zw(Nt)QueryInformationFile函数,注册表句柄 可以通过Zw(Nt)QueryKey函数来获取有关信息。

另外还有一种较为通用的方法,即使用ObReferenceObjectByHandle函数和 ObQueryNameString函数配合使用。它可以通过进程句柄、文件句柄、注册表句柄获取完整的路径信息。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章