Windows NtQueryInformationProcess()

跟風遠走 提交于 2019-12-04 14:17:39

 

{

  https://www.orcode.com/article/Processes_20126324.html

}

{



{A}
{S0}简介
本文将展示一种方法来读取一个过程的下列项目,主要是使用{A2}进程ID父ID关联掩码退出代码状态命令行过程过程映像文件的路径终端服务会话ID标志,如果目前正在调试过程地址进程环境块(PEB)
这个信息是一个变量声明为一个结构,smPROCESSINFO返回。这种结构是在NtProcessInfo.h定义:
typedef struct _smPROCESSINFO

{

    DWORD   dwPID;

    DWORD   dwParentPID;

    DWORD   dwSessionID;

    DWORD   dwPEBBaseAddress;

    DWORD   dwAffinityMask;

    LONG    dwBasePriority;

    LONG    dwExitStatus;

    BYTE    cBeingDebugged;

    TCHAR   szImgPath[MAX_UNICODE_PATH];

    TCHAR   szCmdLine[MAX_UNICODE_PATH];

} smPROCESSINFO;

虽然有Windows API的检索上述值,本文将展示如何获得这些值,而让那些不通过Windows API的。注:此方法使用核心NTDLL.DLL中,这可能在未来的版本中改变结构和功能。 Microsoft建议使用Windows API的"; safelyquot";从系统获得的信息。
的核心职能,以获取上述信息提供NtProcessInfo.h和NtProcessInfo.cpp。只包含到您的项目H / CPP文件中,引用的职能,并编译。如果这些文件包括在您的项目/解决方案列表,不要忘了排除他们从构建。 sm_GetNtProcessInfo(),主要功能,需要一个过程ID和一个变量声明为smPROCESSINFO。我建议调用的顺序如下(可以被交换的步骤5和6)的功能: sm_EnableTokenPrivilege或您自定义令牌的特权功能,使SE_DEBUG_NAME。sm_LoadNTDLLFunctions。保持免费库后的变量返回的HMODULE。获得进程ID。一个手动指定,或使用EnumProcesses,GetCurrentProcessId,CreateToolhelp32Snapshot等。sm_GetNtProcessInfo进程ID和smPROCESSINFO变量。您的smPROCESSINFO变量/数组的内容输出到您所需的介质。从sm_LoadNTDLLFunctions返回的HMODULE变量sm_FreeNTDLLFunctions。
本文的演示应用程序是一个基本的Win32,一个ListView共同控制子窗口,以清单的编制过程内容。也可用于在MFC应用程序没有问题的代码。代码是在Visual Studio。NET 2003 SP1的,是Win2K或以后的打算。启用调试特权
在当前用户读取大多数进程的详细信息,我们必须使调试特权。用户令牌或用户所属的组令牌必须已经调试特权分配。要确定哪些特权令牌,使用{A3}{C}枚举进程ID
为了得到一个正在运行的进程列表,我们将使用{A4}
DWORD EnumProcesses2Array(smPROCESSINFO lpi[MAX_PI])

{

    DWORD dwPIDs[MAX_PI] = {0};

    DWORD dwArraySize    = MAX_PI * sizeof(DWORD);

    DWORD dwSizeNeeded   = 0;

    DWORD dwPIDCount     = 0;



    //== only to have better chance to read processes =====



    if(!sm_EnableTokenPrivilege(SE_DEBUG_NAME))

        return 0;



    // Get a list of Process IDs of current running processes



    if(EnumProcesses((DWORD*)&dwPIDs, dwArraySize, &dwSizeNeeded))

    {

        HMODULE hNtDll = sm_LoadNTDLLFunctions();



        if(hNtDll)

        {

            // Get detail info on each process



            dwPIDCount = dwSizeNeeded / sizeof(DWORD);

            for(DWORD p = 0; p < MAX_PI && p < dwPIDCount; p++)

            {

                if(sm_GetNtProcessInfo(dwPIDs[p], &lpi[p]))

                {

                      // Do something else upon success



                }

            }

            sm_FreeNTDLLFunctions(hNtDll);

        }

    }



    // Return either PID count or MAX_PI whichever is smaller



    return (DWORD)(dwPIDCount > MAX_PI) ? MAX_PI : dwPIDCount;

}
访问NT​​DLL的功能
NtQueryInformationProcess()函数不导入库,所以我们必须使用{A5}
typedef NTSTATUS (NTAPI *pfnNtQueryInformationProcess)(

    IN  HANDLE ProcessHandle,

    IN  PROCESSINFOCLASS ProcessInformationClass,

    OUT PVOID ProcessInformation,

    IN  ULONG ProcessInformationLength,

    OUT PULONG ReturnLength    OPTIONAL

    );



pfnNtQueryInformationProcess gNtQueryInformationProcess;





HMODULE sm_LoadNTDLLFunctions()

{

    // Load NTDLL Library and get entry address



    // for NtQueryInformationProcess



    HMODULE hNtDll = LoadLibrary(_T("ntdll.dll"));



    if(hNtDll == NULL) return NULL;



    gNtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(hNtDll,

                                                        "NtQueryInformationProcess");

    if(gNtQueryInformationProcess == NULL) {

        FreeLibrary(hNtDll);

        return NULL;

    }

    return hNtDll;

}
获取进程的基本信息
我们{A6} PROCESS_QUERY_INFORMATION访问权利得到基本的信息,因为我们将使用ReadProcessMemory()函数来读取在PEB过程,这个过程还必须打开PROCESS_VM_READ访问权。
// Attempt to access process



HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | 

                              PROCESS_VM_READ, FALSE, dwPID);

if(hProcess == INVALID_HANDLE_VALUE)

{

     return FALSE;

}

现在,我们为我们的PROCESS_BASIC_INFORMATION结构变量分配内存。
// Try to allocate buffer 



hHeap = GetProcessHeap();



dwSize = sizeof(smPROCESS_BASIC_INFORMATION);



pbi = (smPPROCESS_BASIC_INFORMATION)HeapAlloc(hHeap,

                                              HEAP_ZERO_MEMORY,

                                              dwSize);

// Did we successfully allocate memory



if(!pbi) {

    CloseHandle(hProcess);

    return FALSE;

}

这个结构定义在winternl.h和ntddk.h。下面的定义是从WIN2003 {A7} ntddk.h,因为我winternl.h在Visual Studio 2003和微软MSDN之一不包含尽可能多的细节。我还发现,winternl.h和ntddk.h在编译过程中的相互冲突,所以我决定复制一个新的名字在我的头文件NtProcessInfo.h(包括下载)(作为前缀添加SM)的最新定义。
typedef struct _smPROCESS_BASIC_INFORMATION {

    LONG ExitStatus;

    smPPEB PebBaseAddress;

    ULONG_PTR AffinityMask;

    LONG BasePriority;

    ULONG_PTR UniqueProcessId;

    ULONG_PTR InheritedFromUniqueProcessId;

} smPROCESS_BASIC_INFORMATION, *smPPROCESS_BASIC_INFORMATION;

然后,我们通过NtQueryInformationProcess()函数得到一个进程的基本信息。
// Attempt to get basic info on process



NTSTATUS dwStatus = gNtQueryInformationProcess(hProcess,

                                               ProcessBasicInformation,

                                               pbi,

                                               dwSize,

                                               &dwSizeNeeded);

// Did we successfully get basic info on process



if(dwStatus >= 0)

{

    // Basic Info



    spi.dwPID            = (DWORD)pbi->UniqueProcessId;

    spi.dwParentPID      = (DWORD)pbi->InheritedFromUniqueProcessId;

    spi.dwBasePriority   = (LONG)pbi->BasePriority;

    spi.dwExitStatus     = (NTSTATUS)pbi->ExitStatus;

    spi.dwPEBBaseAddress = (DWORD)pbi->PebBaseAddress;

    spi.dwAffinityMask   = (DWORD)pbi->AffinityMask;
读在PEB
从基本的信息,我们已经得到PebBaseAddress指针变量PEB的基地址,如果有的话,。如果地址是不等于零,我们刚刚通过的ReadProcessMemory()函数的地址。如果成功的话,它应该在我们的{A8}结构变量,其中还包含BeingDebugged和SessionID变量返回的信息的过程。
// Read Process Environment Block (PEB)



if(pbi->PebBaseAddress)

{

    if(ReadProcessMemory(hProcess, pbi->PebBaseAddress, &peb, sizeof(peb), &dwBytesRead))

    {

        spi.dwSessionID    = (DWORD)peb.SessionId;

        spi.cBeingDebugged = (BYTE)peb.BeingDebugged;

在PEB结构的定义为:
typedef struct _smPEB {

    BYTE Reserved1[2];

    BYTE BeingDebugged;

    BYTE Reserved2[1];

    PVOID Reserved3[2];

    smPPEB_LDR_DATA Ldr;

    smPRTL_USER_PROCESS_PARAMETERS ProcessParameters;

    BYTE Reserved4[104];

    PVOID Reserved5[52];

    smPPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;

    BYTE Reserved6[128];

    PVOID Reserved7[1];

    ULONG SessionId;

} smPEB, *smPPEB;

从这一点来说,我们也有内存地址LDR,这是我们本文中未使用。基本上,{A9}
// We got Process Parameters, is CommandLine filled in



if(peb_upp.CommandLine.Length > 0) {

    // Yes, try to read CommandLine



    pwszBuffer = (WCHAR *)HeapAlloc(hHeap,

                                    HEAP_ZERO_MEMORY,

                                    peb_upp.CommandLine.Length);

    // If memory was allocated, continue



    if(pwszBuffer)

    {

       if(ReadProcessMemory(hProcess,

                            peb_upp.CommandLine.Buffer,

                            pwszBuffer,

                            peb_upp.CommandLine.Length,

                            &dwBytesRead))

       {

            // if commandline is larger than our variable, truncate



            if(peb_upp.CommandLine.Length >= sizeof(spi.szCmdLine)) 

                dwBufferSize = sizeof(spi.szCmdLine) - sizeof(TCHAR);

            else

                dwBufferSize = peb_upp.CommandLine.Length;

                            

            // Copy CommandLine to our structure variable



#if defined(UNICODE) || (_UNICODE)

            // Since core NT functions operate in Unicode



            // there is no conversion if application is



            // compiled for Unicode



            StringCbCopyN(spi.szCmdLine, sizeof(spi.szCmdLine),

                          pwszBuffer, dwBufferSize);

#else

            // Since core NT functions operate in Unicode



            // we must convert to Ansi since our application



            // is not compiled for Unicode



            WideCharToMultiByte(CP_ACP, 0, pwszBuffer,

                                (int)(dwBufferSize / sizeof(WCHAR)),

                                spi.szCmdLine, sizeof(spi.szCmdLine),

                                NULL, NULL);

#endif

        }

        if(!HeapFree(hHeap, 0, pwszBuffer)) {

            // failed to free memory



            bReturnStatus = FALSE;

            goto gnpiFreeMemFailed;

        }

    }

}    // Read CommandLine in Process Parameters

... ... ImagePathName变量{A10}
// We got Process Parameters, is ImagePathName filled in



if(peb_upp.ImagePathName.Length > 0) {

    // Yes, try to read Image Path



    pwszBuffer = (WCHAR *)HeapAlloc(hHeap,

                                    HEAP_ZERO_MEMORY,

                                    peb_upp.ImagePathName.Length);

    // If memory was allocated, continue



    if(pwszBuffer)

    {

       if(ReadProcessMemory(hProcess,

                            peb_upp.ImagePathName.Buffer,

                            pwszBuffer,

                            peb_upp.ImagePathName.Length,

                            &dwBytesRead))

       {

            // if image path is larger than our variable, truncate



            if(peb_upp.ImagePathName.Length >= sizeof(spi.szImgPath)) 

                dwBufferSize = sizeof(spi.szImgPath) - sizeof(TCHAR);

            else

                dwBufferSize = peb_upp.ImagePathName.Length;

                            

            // Copy ImagePathName to our structure variable



#if defined(UNICODE) || (_UNICODE)

            // Since core NT functions operate in Unicode



            // there is no conversion if application is



            // compiled for Unicode



            StringCbCopyN(spi.szImgPath, sizeof(spi.szImgPath),

                          pwszBuffer, dwBufferSize);

#else

            // Since core NT functions operate in Unicode



            // we must convert to Ansi since our application



            // is not compiled for Unicode



            WideCharToMultiByte(CP_ACP, 0, pwszBuffer,

                                (int)(dwBufferSize / sizeof(WCHAR)),

                                spi.szImgPath, sizeof(spi.szImgPath),

                                NULL, NULL);

#endif

        }

        if(!HeapFree(hHeap, 0, pwszBuffer)) {

            // failed to free memory



            bReturnStatus = FALSE;

            goto gnpiFreeMemFailed;

        }

    }

}    // Read ImagePathName in Process Parameters

(PID = 4在XP上WIN2K后,8,并在NT 4 2)对于系统的过程中,我们手动指定进程的路径,因为我们知道它是%SystemRoot%\ SYSTEM32 \ NTOSKRNL.EXE但不是由API返回。 NTOSKRNL.EXE也可以被NTKRNLMP.EXE {A11}
// System process for WinXP and later is PID 4 and we cannot access

// PEB, but we know it is aka ntoskrnl.exe so we will manually define it



if(spi.dwPID == 4)

{

    ExpandEnvironmentStrings(_T("%SystemRoot%\\System32\\ntoskrnl.exe"),

                             spi.szImgPath, sizeof(spi.szImgPath));

}

上述与PROCESS_BASIC_INFORMATION结构,{A12}
typedef struct _smRTL_USER_PROCESS_PARAMETERS {

    BYTE Reserved1[16];

    PVOID Reserved2[10];

    UNICODE_STRING ImagePathName;

    UNICODE_STRING CommandLine;

} smRTL_USER_PROCESS_PARAMETERS, *smPRTL_USER_PROCESS_PARAMETERS;
净化
在这里,我们免费NTDLL.DLL中我们前面加载。这就是它!
void sm_FreeNTDLLFunctions(HMODULE hNtDll)

{

    if(hNtDll)

       FreeLibrary(hNtDll);

    gNtQueryInformationProcess = NULL;

}
兴趣点
我写这篇文章分享我学到的方法,而试图得到我自己的经验,而无需使用简单的{A13}一个基本的过程中浏览器的进程信息。
一些quot; safequot; Windows API函数来获得另一个进程的信息是:ProcessIdToSessionIdCheckRemoteDebuggerPresentGetExitCodeProcessGetProcessAffinityMaskGetProcessImageFileNameCreateRemoteThread的其他{A14}
注:我没有在演示应用程序的调试过程中收到以下消息,但出现之前发生,以WinMain的,似乎是因为第二次机会没有抛出异常处理:
"First-chance exception at 0x7c918fea in GetNtProcessInfo.exe: 

              0xC0000005: Access violation writing location 0x00000010."

我没有得到与现实世界实现NtProcessInfo.h和NtProcessInfo.cpp此异常。历史最初的版本。

回答

 
评论会员:jlkdaslkfjd 时间:2011/12/14
谢谢你张贴,GetProcessimagefilename现在已经一个星期的痛苦
但我只是想知道,如果有什么办法可以在Vb.net?

'All the code I could scrape together

'Some of these functions are VB6, I tried converting Strptr,varptr etc..

Imports Microsoft.VisualBasic

Imports System.Runtime.InteropServices

Public Class getimagefilename

    Private Const ProcessImageFileName = 27

    Private Const STATUS_INFO_LENGTH_MISMATCH = &HC0000004

    Private Const PROCESS_QUERY_INFORMATION = &H400&

    Private Const PROCESS_VM_READ = &H10&

    Private Const HEAP_ZERO_MEMORY = &H8&

    Private Const MAX_PATH = 260

    Private Structure UNICODE_STRING

        Dim Length As Integer

        Dim MaximumLength As Integer

        Dim Buffer As Long

    End Structure

    Private Declare Function GetProcessHeap Lib "kernel32.dll" () As Long

    Private Declare Function HeapAlloc Lib "kernel32.dll" (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal dwBytes As Long) As Long

    Private Declare Function HeapFree Lib "kernel32.dll" (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal lpMem As Long) As Long

    Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessid As Long) As Long

    Private Declare Function NtQueryInformationProcess Lib "ntdll.dll" (ByVal ProcessHandle As Long, ByVal ProcessInformationClass As Long, ByVal ProcessInformation As Long, ByVal ProcessInformationLength As Long, ByRef ReturnLength As Long) As Long

    Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long

    Private Declare Sub RtlMoveMemory Lib "kernel32.dll" (ByVal lpDest As Long, ByVal lpSource _ 

As Long, ByVal cbCopy As Long)

 

    Public Function VarPtr(ByVal e As Object) As Integer

        Dim GC As GCHandle = GCHandle.Alloc(e, GCHandleType.Pinned)

        Dim GC2 As Integer = GC.AddrOfPinnedObject.ToInt32

        GC.Free()

        Return GC2

    End Function

    Public Function strptr(ByVal source As String, ByVal dest As String) As String

        Return dest = dest.Insert(0, source)

    End Function

 

    Public Function GetProcessNameByPid(ByVal pid As Long) As String

        Dim uni As UNICODE_STRING

        Dim Buffer As Long

        Dim hProcess As Long

        Dim FileName As String

        Dim cbNeeded As Long

        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, 0, pid)

        If hProcess = 0 Then

        Else

            ' Get the buffer size needed for the call.

            If NtQueryInformationProcess(hProcess, ProcessImageFileName, VarPtr(uni), 8, cbNeeded) = STATUS_INFO_LENGTH_MISMATCH Then

                ' Allocate the required buffer from the heap.

                Buffer = HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, cbNeeded)

                If NtQueryInformationProcess(hProcess, ProcessImageFileName, Buffer, cbNeeded, cbNeeded) = 0 Then

                    ' UNICODE_STRING

                    RtlMoveMemory(VarPtr(uni), Buffer&, Len(uni))

                    FileName = Strings.Left(uni.Length / 2, vbNullChar)

                    RtlMoveMemory(strptr(FileName, FileName), uni.Buffer, uni.Length)

                    Return FileName

                End If

                HeapFree(GetProcessHeap, 0, Buffer)

            End If

        End If

      

        CloseHandle(hProcess)

    End Function

 

End Class

 
评论会员:zinodream 时间:2011/12/14
我编译成功

感谢
修改上,3月29日(星期一),2010 0:25
 
评论会员:baron43 时间:2011/12/14
。通缉致以谢意缺少魔法酱,制作精良的代码

我有一个过程的阅读器应用程序(,因为每个人),但我是越来越少的进程在任务管理器,然后在"Iarsn TaskInfo"计划上市。一个非常关键的一块,使DEGUG privaledges令牌。
你是唯一的编程细节这非常关键的一点,我所看到的许多代码和程序样本。
谢谢你们,让您的旅途好运!

荃湾
 
评论会员:。Chury 时间:2011/12/14
BOOL sm_EnableTokenPrivilege(​​LPCTSTR pszPrivilege)
{处理hToken = 0;TOKEN_PRIVILEGES TKP = {0}

/ /获取了这一进程的令牌。
如果(OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES |
TOKEN_QUERY,放大器; hToken))
{
返回FALSE;
}

/ /获取特权的LUID。
(LookupPrivilegeValue(NULL,pszPrivilege,
安培。tkp.Privileges [0] LUID))
{
& #160; tkp.PrivilegeCount = 1; / /一个权限设置
tkp.Privileges [0]属性= SE_PRIVILEGE_ENABLED;

/ /设置为这一进程的特权。
AdjustTokenPrivileges(hToken,FALSE,则放大器; TKP,0,
(PTOKEN_PRIVILEGES)NULL,0);

如果(GetLastError函数()!= ERROR_SUCCESS)
返回FALSE;
返回TRUE;}

返回FALSE;
}

这种方法是发生句柄泄漏...

所以..下面的

BOOL sm_EnableTokenPrivilege(​​LPCTSTR pszPrivilege)
{处理hToken = 0;TOKEN_PRIVILEGES TKP = {0}
BOOL bResult = FALSE;
/ /获取这个过程中的信物。
如果(OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES |
TOKEN_QUERY,放大器; hToken))
{
&# 160;返回FALSE;
}

/ /获取特权的LUID。
(LookupPrivilegeValue(NULL,pszPrivilege,
安培。tkp.Privileges [0] LUID))
{
tkp.PrivilegeCount = 1; / /一个权限设置
tkp.Privileges [0]属性= SE_PRIVILEGE_ENABLED;

/ /设置为这一进程的特权。
AdjustTokenPrivileges(hToken,FALSE,则放大器; TKP,0,
(PTOKEN_PRIVILEGES)NULL,0);

如果(GetLastError函数()== ERROR_SUCCESS)
bResult = TRUE;
}


CloseHandle(hToken);返回bResult;
}

THX ...

11
 
评论会员:gabrielmaldi 时间:2011/12/14
您好,

我下载的,这与VC 6工程的最后一个平台SDK(二月
2003年):http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm

然而IM得到一个奇怪的错误,当我编译。我做的是
以下内容:

- 从开始菜单运行这个快捷方式来设置变量:设置Windows
XP的32位编译环境(零售)。LNK

- 打开VC 6,创建一个新的Win32简单的应用程序

- 包括winternl.h

这是代码:

#包括"stdafx.h中"


INT APIENTRY的WinMain(HINSTANCE HINSTANCE,HINSTANCE hPrevInstance,
INT LPSTR lpCmdLine,nCmdShow){
0;PROCESS_BASIC_INFORMATION P;

返回0;
}

编译时,我得到这些错误:

错误C2065:'PROCESS_BASIC_INFORMATION":未声明的标识符
错误C2146:语法错误:缺少";"前标识符'P'
错误C2065:"P":未声明的标识符

包括是正确的,但仍认为(任何)成员从
头不被认可。
如果我使用其他头(只试过一对夫妇)一切正常。

任何想法?
 
评论会员:open_mind_core 时间:2011/12/14
它是一个无论是暂停或无NTDLL,suspendthread / ResumeThread线程的状态可以查询?
 
评论会员:OrionScorpion 时间:2011/12/14
在2006年1月MSDN库,它说:"NtQueryInformationProcess是在Windows 2000和Windows XP中使用,它可能会改变或在后续版本中不可用的应用程序应该使用列在候补功能。这个话题。"

但在目前的DVD的MSDN库,这是使先进的我可以不甚至管理的"帮助"菜单中的版本的邮票的,它只是说"[NtQueryInformationProcess可能被改变或在未来的Windows版本中不可用的应用程序应该使用的第二功能本主题中列出。]",和在线的MSDN说同样的事情。

我没有实际测试,诱惑来推断,他们留在Vista的功能,但谁知道什么政策将在下一个版本中,HMM的呢?

PG - AZ

}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!