转载:https://blez.wordpress.com/2012/09/17/enumerating-opened-handles-from-a-process/
因为NtQueryInformation确实缺少文档或示例,因此我会在一两年前杀死这段消息。
以下代码显示特定进程的所有已打开句柄。结合DuplicateHandle技巧,您也可以打开其文件(或其他句柄)。
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
#define NT_SUCCESS(x) ((x) >= 0)
#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
#define SystemHandleInformation 16
#define ObjectBasicInformation 0
#define ObjectNameInformation 1
#define ObjectTypeInformation 2
typedef
NTSTATUS (NTAPI *_NtQuerySystemInformation)(
ULONG
SystemInformationClass,
PVOID
SystemInformation,
ULONG
SystemInformationLength,
PULONG
ReturnLength
);
typedef
NTSTATUS (NTAPI *_NtDuplicateObject)(
HANDLE
SourceProcessHandle,
HANDLE
SourceHandle,
HANDLE
TargetProcessHandle,
PHANDLE
TargetHandle,
ACCESS_MASK DesiredAccess,
ULONG
Attributes,
ULONG
Options
);
typedef
NTSTATUS (NTAPI *_NtQueryObject)(
HANDLE
ObjectHandle,
ULONG
ObjectInformationClass,
PVOID
ObjectInformation,
ULONG
ObjectInformationLength,
PULONG
ReturnLength
);
typedef
struct
_UNICODE_STRING {
USHORT
Length;
USHORT
MaximumLength;
PWSTR
Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef
struct
_SYSTEM_HANDLE {
ULONG
ProcessId;
BYTE
ObjectTypeNumber;
BYTE
Flags;
USHORT
Handle;
PVOID
Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;
typedef
struct
_SYSTEM_HANDLE_INFORMATION {
ULONG
HandleCount;
SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
typedef
enum
_POOL_TYPE {
NonPagedPool,
PagedPool,
NonPagedPoolMustSucceed,
DontUseThisType,
NonPagedPoolCacheAligned,
PagedPoolCacheAligned,
NonPagedPoolCacheAlignedMustS
} POOL_TYPE, *PPOOL_TYPE;
typedef
struct
_OBJECT_TYPE_INFORMATION {
UNICODE_STRING Name;
ULONG
TotalNumberOfObjects;
ULONG
TotalNumberOfHandles;
ULONG
TotalPagedPoolUsage;
ULONG
TotalNonPagedPoolUsage;
ULONG
TotalNamePoolUsage;
ULONG
TotalHandleTableUsage;
ULONG
HighWaterNumberOfObjects;
ULONG
HighWaterNumberOfHandles;
ULONG
HighWaterPagedPoolUsage;
ULONG
HighWaterNonPagedPoolUsage;
ULONG
HighWaterNamePoolUsage;
ULONG
HighWaterHandleTableUsage;
ULONG
InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG
ValidAccess;
BOOLEAN
SecurityRequired;
BOOLEAN
MaintainHandleCount;
USHORT
MaintainTypeList;
POOL_TYPE PoolType;
ULONG
PagedPoolUsage;
ULONG
NonPagedPoolUsage;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
PVOID
GetLibraryProcAddress(
PSTR
LibraryName,
PSTR
ProcName) {
return
GetProcAddress(GetModuleHandleA(LibraryName), ProcName);
}
void
ErrorExit(
LPTSTR
lpszFunction) {
// Retrieve the system error message for the last-error code
LPVOID
lpMsgBuf;
LPVOID
lpDisplayBuf;
DWORD
dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(
LPTSTR
) &lpMsgBuf,
0, NULL );
printf
((
LPTSTR
) lpMsgBuf);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(dw);
}
void
ShowErr() {
CHAR
errormsg[100];
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, errormsg,
sizeof
(errormsg), NULL);
printf
(
"ERROR: %s"
, errormsg);
}
int
wmain(
int
argc,
WCHAR
*argv[]) {
_NtQuerySystemInformation NtQuerySystemInformation = GetLibraryProcAddress(
"ntdll.dll"
,
"NtQuerySystemInformation"
);
_NtDuplicateObject NtDuplicateObject = GetLibraryProcAddress(
"ntdll.dll"
,
"NtDuplicateObject"
);
_NtQueryObject NtQueryObject = GetLibraryProcAddress(
"ntdll.dll"
,
"NtQueryObject"
);
NTSTATUS status;
PSYSTEM_HANDLE_INFORMATION handleInfo;
ULONG
handleInfoSize = 0x10000;
ULONG
pid;
HANDLE
processHandle;
ULONG
i;
if
(argc < 2) {
printf
(
"Usage: handles [pid]\n"
);
return
1;
}
pid = _wtoi(argv[1]);
if
(!(processHandle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid))) {
printf
(
"Could not open PID %d! (Don't try to open a system process.)\n"
, pid);
return
1;
}
handleInfo = (PSYSTEM_HANDLE_INFORMATION)
malloc
(handleInfoSize);
// NtQuerySystemInformation won't give us the correct buffer size,
// so we guess by doubling the buffer size.
while
((status = NtQuerySystemInformation(
SystemHandleInformation,
handleInfo,
handleInfoSize,
NULL
)) == STATUS_INFO_LENGTH_MISMATCH)
handleInfo = (PSYSTEM_HANDLE_INFORMATION)
realloc
(handleInfo, handleInfoSize *= 2);
// NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH.
if
(!NT_SUCCESS(status)) {
printf
(
"NtQuerySystemInformation failed!\n"
);
return
1;
}
for
(i = 0; i < handleInfo->HandleCount; i++) {
SYSTEM_HANDLE handle = handleInfo->Handles[i];
HANDLE
dupHandle = NULL;
POBJECT_TYPE_INFORMATION objectTypeInfo;
PVOID
objectNameInfo;
UNICODE_STRING objectName;
ULONG
returnLength;
// Check if this handle belongs to the PID the user specified.
if
(handle.ProcessId != pid)
continue
;
// Duplicate the handle so we can query it.
if
(!NT_SUCCESS(NtDuplicateObject(
processHandle,
(
void
*) handle.Handle,
GetCurrentProcess(),
&dupHandle,
0,
0,
0
))) {
printf
(
"[%#x] Error!\n"
, handle.Handle);
continue
;
}
// Query the object type.
objectTypeInfo = (POBJECT_TYPE_INFORMATION)
malloc
(0x1000);
if
(!NT_SUCCESS(NtQueryObject(
dupHandle,
ObjectTypeInformation,
objectTypeInfo,
0x1000,
NULL
))) {
printf
(
"[%#x] Error!\n"
, handle.Handle);
CloseHandle(dupHandle);
continue
;
}
// Query the object name (unless it has an access of
// 0x0012019f, on which NtQueryObject could hang.
if
(handle.GrantedAccess == 0x0012019f) {
// We have the type, so display that.
printf
(
"[%#x] %.*S: (did not get name)\n"
,
handle.Handle,
objectTypeInfo->Name.Length / 2,
objectTypeInfo->Name.Buffer
);
free
(objectTypeInfo);
CloseHandle(dupHandle);
continue
;
}
objectNameInfo =
malloc
(0x1000);
if
(!NT_SUCCESS(NtQueryObject(
dupHandle,
ObjectNameInformation,
objectNameInfo,
0x1000,
&returnLength
))) {
// Reallocate the buffer and try again.
objectNameInfo =
realloc
(objectNameInfo, returnLength);
if
(!NT_SUCCESS(NtQueryObject(
dupHandle,
ObjectNameInformation,
objectNameInfo,
returnLength,
NULL
))) {
// We have the type name, so just display that.
printf
(
"[%#x] %.*S: (could not get name)\n"
,
handle.Handle,
objectTypeInfo->Name.Length / 2,
objectTypeInfo->Name.Buffer
);
free
(objectTypeInfo);
free
(objectNameInfo);
CloseHandle(dupHandle);
continue
;
}
}
// Cast our buffer into an UNICODE_STRING.
objectName = *(PUNICODE_STRING)objectNameInfo;
// Print the information!
if
(objectName.Length)
{
// The object has a name.
printf
(
"[%#x] %.*S: %.*S\n"
,
handle.Handle,
objectTypeInfo->Name.Length / 2,
objectTypeInfo->Name.Buffer,
objectName.Length / 2,
objectName.Buffer
);
}
else
{
// Print something else.
printf
(
"[%#x] %.*S: (unnamed)\n"
,
handle.Handle,
objectTypeInfo->Name.Length / 2,
objectTypeInfo->Name.Buffer
);
}
free
(objectTypeInfo);
free
(objectNameInfo);
CloseHandle(dupHandle);
}
free
(handleInfo);
CloseHandle(processHandle);
return
0;
}
|