找回密码
 立即注册
搜索

[经验杂志] [驱动开发]通过暴力搜索pid遍历进程并获取进程信息

[复制链接]
发表于 10-21 21:11:28 | 显示全部楼层 |阅读模式
背景

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

本文实现的进程遍历和获取进程信息并不打算使用 ZwQuerySystemInformation 这种方式,而是直接暴力搜索进程的 PID,根据有效的 PID 获取相应进程的信息,从而实现进程的遍历。

使用的函数

[C++] 纯文本查看 复制代码NTSTATUS PsLookupProcessByProcessId(        _In_  HANDLE    ProcessId,                // 指定进程的进程ID。        _Out_ PEPROCESS *Process                // 返回指向ProcessId指定的进程的EPROCESS结构的引用指针。    );// 返回指向ProcessId指定的进程的EPROCESS结构的引用指针。

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

_____________________________________________________________________________

[C++] 纯文本查看 复制代码NTSTATUS IoQueryFileDosDeviceName(        _In_  PFILE_OBJECT             FileObject,                                        // 指向文件的文件对象        _Out_ POBJECT_NAME_INFORMATION *ObjectNameInformation                // 返回指向新分配的OBJECT_NAME_INFORMATION结构的指针。 这个结构用MS-DOS设备名称信息成功返回填写    );    // 成功,则返回STATUS_SUCCESS;否则错误。/*        typedef struct _OBJECT_NAME_INFORMATION {             UNICODE_STRING Name;        } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;*/

实现原理

暴力搜索 PID 这个不难理解,即 PID 从 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 函数来释放对象。

实现

[C++] 纯文本查看 复制代码// 遍历进程    NTSTATUS EnumProcess()    {        NTSTATUS status = STATUS_SUCCESS;        ULONG i = 0;        PEPROCESS pEProcess = NULL;        // 开始遍历        for (i = 4; i < 0x10000; i = i + 4)        {            status = PsLookupProcessByProcessId((HANDLE)i, &pEProcess);            if (NT_SUCCESS(status))            {                // 从进程结构中获取进程信息                GetProcessInfo(pEProcess);                ObDereferenceObject(pEProcess);            }        }        return status;    }

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

[C++] 纯文本查看 复制代码// 从进程结构中获取进程信息    VOID GetProcessInfo(PEPROCESS pEProcess)    {        NTSTATUS status = STATUS_SUCCESS;        HANDLE hParentProcessId = NULL, hProcessId = NULL;        PCHAR pszProcessName = NULL;        PVOID pFilePoint = NULL;        POBJECT_NAME_INFORMATION pObjectNameInfo = NULL;        // 获取父进程 PID        hParentProcessId = PsGetProcessInheritedFromUniqueProcessId(pEProcess);        // 获取进程 PID        hProcessId = PsGetProcessId(pEProcess);        // 获取进程名称        pszProcessName = PsGetProcessImageFileName(pEProcess);        // 获取进程程序路径        status = PsReferenceProcessFilePointer(pEProcess, &pFilePoint);        if (NT_SUCCESS(status))        {            status = IoQueryFileDosDeviceName(pFilePoint, &pObjectNameInfo);            if (NT_SUCCESS(status))            {                // 显示                DbgPrint(&quotEPROCESS=0x%p, PPID=%d, PID=%d, NAME=%s, PATH=%ws\n&quot;,                    pEProcess, hParentProcessId, hProcessId, pszProcessName, pObjectNameInfo->Name.Buffer);            }            ObDereferenceObject(pFilePoint);        }       }
声明
1,本帖收录内容来源于系统采集或网友自主提交,不代表本网站立场!
2,本帖收录内容,仅供参考使用,本站不对其安全性,正确性等作出保证。
3,如您认为本帖收录内容侵犯了您的版权或者违规,请在右下角进行举报,发现直接删帖!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|wcbb导航网-属于年轻人的导航网-网站导航-素材导航论坛! ( 桂ICP备2024029389号-2 )|网站地图

快速回复 返回顶部 返回列表