通过暴力搜索PID遍历进程并获取进程信息

大葱

发布日期: 2019-03-05 22:59:35 浏览量: 1770
评分:
star star star star star star star_border star_border star_border star_border
*转载请注明来自write-bug.com

背景

通常我们在内核中使用 ZwQuerySystemInformation 函数来遍历进程模块并获取进程信息,这种是通过正常的进程遍历方式,所以,有很多 Rootkit 程序会 HOOK 这个 ZwQuerySystemInformation 函数,过滤指定进程,从而实现进程的隐藏。

本文实现的进程遍历和获取进程信息并不打算使用 ZwQuerySystemInformation 这种方式,而是直接暴力搜索进程的 PID,根据有效的 PID 获取相应进程的信息,从而实现进程的遍历。现在,我就来讲解具体的实现过程和原理,这个程序支持 32 位和 64 位 Win 7 至 Win10 全平台。

函数介绍

PsLookupProcessByProcessId 函数

PsLookupProcessByProcessId例程接受进程的进程ID,并返回引用的指向EPROCESS结构的进程。

函数声明

  1. NTSTATUS PsLookupProcessByProcessId(
  2. _In_ HANDLE ProcessId,
  3. _Out_ PEPROCESS *Process
  4. );

参数

  • ProcessId [in]
    指定进程的进程ID。
  • Process[out]
    返回指向ProcessId指定的进程的EPROCESS结构的引用指针。

返回值

  • PsLookupProcessByProcessId在成功时返回STATUS_SUCCESS或适当的NTSTATUS值,例如:STATUS_INVALID_PARAMETER,表示进程 ID 无效。

备注

  • 如果对 PsLookupProcessByProcessId 的调用成功,PsLookupProcessByProcessId 会增加Process参数中返回的对象的引用计数。因此,当驱动程序完成使用 Process 参数时,驱动程序必须调用 ObDereferenceObject 来取消引用从 PsLookupProcessByProcessId 例程接收的Process参数。

IoQueryFileDosDeviceName 函数

获取文件的 Dos 设备名称。

  1. NTSTATUS IoQueryFileDosDeviceName(
  2. _In_ PFILE_OBJECT FileObject,
  3. _Out_ POBJECT_NAME_INFORMATION *ObjectNameInformation
  4. );

参数

  • FileObject [in]
    指向文件的文件对象。
  • ObjectNameInformation [out]
    返回指向新分配的OBJECT_NAME_INFORMATION结构的指针。 这个结构用MS-DOS设备名称信息成功返回填写。 结构定义如下:
    1. typedef struct _OBJECT_NAME_INFORMATION {
    2. UNICODE_STRING Name;
    3. } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
    4. // 注意:最终通过调用 ExFreePool 来释放此结构。

返回值

  • 成功,则返回STATUS_SUCCESS;否则错误。

实现原理

暴力搜索 PID 这个不难理解,即 PID 从 4 开始,步长为 4,一直遍历到 0x1000,因为进程的 PID 总是为 4 的倍数,所以,我们设置遍历的步长为 4。

然后,我们根据 PID,调用 PsLookupProcessByProcessId 函数获取 EPROCESS 进程结构体,因为 EPROCESS 这个结构体里存储着进程所有的信息,我们可以从这个 EPROCESS 结构体中获取我们想要的信息,例如进程的父进程、进程名、路径、进程双链表链等等。调用完 PsLookupProcessByProcessId 获取 EPROCESS 之后,记得调用 ObDereferenceObject 来释放对象。

在不同的系统版本中,EPROCESS 这个结构体定义也不相同,所以不建议使用固定的偏移地址来获取进程信息,而应该使用提供的 API 函数从 EPROCESS 结构体中获取。例如:

  • 获取进程 PID,可以使用 PsGetProcessId 函数。

  • 获取进程的父进程 PID,可以使用PsGetProcessInheritedFromUniqueProcessId 函数。

  • 获取进程名称,可以使用 PsGetProcessImageFileName 函数。

  • 获取进程路径,可以先试用 PsReferenceProcessFilePointer 函数获取文件指针对象,然后再调用 IoQueryFileDosDeviceName 获取 Dos 路径,最后还要记得使用 ObDereferenceObject 函数来释放对象。

编码实现

进程遍历

  1. // 遍历进程
  2. NTSTATUS EnumProcess()
  3. {
  4. NTSTATUS status = STATUS_SUCCESS;
  5. ULONG i = 0;
  6. PEPROCESS pEProcess = NULL;
  7. // 开始遍历
  8. for (i = 4; i < 0x10000; i = i + 4)
  9. {
  10. status = PsLookupProcessByProcessId((HANDLE)i, &pEProcess);
  11. if (NT_SUCCESS(status))
  12. {
  13. // 从进程结构中获取进程信息
  14. GetProcessInfo(pEProcess);
  15. ObDereferenceObject(pEProcess);
  16. }
  17. }
  18. return status;
  19. }

从进程结构中获取进程信息

  1. // 从进程结构中获取进程信息
  2. VOID GetProcessInfo(PEPROCESS pEProcess)
  3. {
  4. NTSTATUS status = STATUS_SUCCESS;
  5. HANDLE hParentProcessId = NULL, hProcessId = NULL;
  6. PCHAR pszProcessName = NULL;
  7. PVOID pFilePoint = NULL;
  8. POBJECT_NAME_INFORMATION pObjectNameInfo = NULL;
  9. // 获取父进程 PID
  10. hParentProcessId = PsGetProcessInheritedFromUniqueProcessId(pEProcess);
  11. // 获取进程 PID
  12. hProcessId = PsGetProcessId(pEProcess);
  13. // 获取进程名称
  14. pszProcessName = PsGetProcessImageFileName(pEProcess);
  15. // 获取进程程序路径
  16. status = PsReferenceProcessFilePointer(pEProcess, &pFilePoint);
  17. if (NT_SUCCESS(status))
  18. {
  19. status = IoQueryFileDosDeviceName(pFilePoint, &pObjectNameInfo);
  20. if (NT_SUCCESS(status))
  21. {
  22. // 显示
  23. DbgPrint("PEPROCESS=0x%p, PPID=%d, PID=%d, NAME=%s, PATH=%ws\n",
  24. pEProcess, hParentProcessId, hProcessId, pszProcessName, pObjectNameInfo->Name.Buffer);
  25. }
  26. ObDereferenceObject(pFilePoint);
  27. }
  28. }

程序测试

在 Win7 32 位下,驱动程序正常运行:

在 Win10 64 位下,驱动程序正常运行:

总结

这个程序不难理解,关键是要注意 EPROCESS 这个函数包含了几乎进程所有的信息,本文只用到了它其中的一小部分。建议大家私下可以使用 WinDbg 查看下系统中 EPROCESS 的定义,同时观察它具体有哪些信息,不同平台系统之间的区别,以此来加深对 EPROCESS 的印象。

参考

参考自《Windows黑客编程技术详解》一书

上传的附件 cloud_download EnumProcess_Test.7z ( 8.42kb, 21次下载 )

keyboard_arrow_left上一篇 : 通过暴力搜索PID遍历进程并获取进程信息 编程实现U盘插入自动复制U盘内容到本地 : 下一篇keyboard_arrow_right



大葱
2019-03-05 22:59:23
通过暴力搜索PID遍历进程并获取进程信息
sjtx
2020-10-17 00:21:30
请问一下该文章参考了《Windows黑客编程技术详解》一书的哪些章节的内容呢,大概翻了翻没见有这样暴力枚举进程的内容

发送私信

这一切都不是我的,但总有一天,会是我的

77
文章数
68
评论数
最近文章
eject