{
https://www.orcode.com/article/Processes_20126324.html
}
{
与NtQueryInformationProcess获取进程信息
{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;
}
访问NTDLL的功能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线程的状态可以查询? }