A forum for reverse engineering, OS internals and malware analysis 

Ask your beginner questions here.
 #1329  by __Genius__
 Fri Jun 25, 2010 8:56 pm
Hi folks .
I have been written a code for enumerating open handles in a system (process handle enumeration) && (of-course it's based on napalm code)
however, napalm code was a C++ code, & I converted it to C .
but there's some problems that is blind to me .
here's the code :


Code: Select all
#define _WIN32_WINNT	0x0501

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <tchar.h>
#include "ex.h"
#include <Shlwapi.h>
#include <Psapi.h>

#define OBJ_CASE_INSENSITIVE 0x00000040L
typedef struct _UUNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UUNICODE_STRING;

typedef VOID *POBJECT;

typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;

#define STATUS_INFO_LENGTH_MISMATCH		((NTSTATUS)0xC0000004L)
#define STATUS_BUFFER_OVERFLOW			((NTSTATUS)0x80000005L)

typedef UUNICODE_STRING OBJECT_NAME_INFORMATION;
typedef UUNICODE_STRING *POBJECT_NAME_INFORMATION;


typedef struct _SYSTEM_HANDLE {
	ULONG		uIdProcess;
	UCHAR		ObjectType;    // OB_TYPE_* (OB_TYPE_TYPE, etc.)
	UCHAR		Flags;         // HANDLE_FLAG_* (HANDLE_FLAG_INHERIT, etc.)
	USHORT		Handle;
	POBJECT		pObject;
	ACCESS_MASK	GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;

typedef struct _SSYSTEM_HANDLE_INFORMATION {
	ULONG			uCount;
	SYSTEM_HANDLE	Handles[1];
} SSYSTEM_HANDLE_INFORMATION, *PSSYSTEM_HANDLE_INFORMATION;

NTSTATUS RtlAdjustPrivilege(ULONG Privilege, BOOLEAN Enable, BOOLEAN Client)
{
	NTSTATUS Status;
	HANDLE Token;
	LUID LuidPrivilege;
	TOKEN_PRIVILEGES NewPrivileges, OldPrivileges;
	ULONG Length;

	if (Client)
		Status = NtOpenThreadToken(NtCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &Token);
	else 
		Status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token);
	if (STATUS_SUCCESS != Status) return Status;
	LuidPrivilege.LowPart = Privilege;
	LuidPrivilege.HighPart = 0;
	NewPrivileges.PrivilegeCount = 1;
	NewPrivileges.Privileges[0].Luid = LuidPrivilege;
	if (Enable) 
		NewPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	else
		NewPrivileges.Privileges[0].Attributes = 0;
	Status = NtAdjustPrivilegesToken(Token, FALSE, &NewPrivileges, sizeof(TOKEN_PRIVILEGES), &OldPrivileges, &Length);
	NtClose(Token);
	if (Status == STATUS_NOT_ALL_ASSIGNED) return STATUS_PRIVILEGE_NOT_HELD;
	return Status;
};


int __cdecl main(int argc, char **argv)
{
	DWORD dwSize = sizeof(SSYSTEM_HANDLE_INFORMATION);
	NTSTATUS NtStatus;
	PSSYSTEM_HANDLE_INFORMATION pHandleInfo = (PSSYSTEM_HANDLE_INFORMATION)malloc(sizeof(dwSize));
	if(RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE)==STATUS_SUCCESS){	
		printf("\nDebug Privilege ok ");
	}
		NtStatus = NtQuerySystemInformation(SystemHandleInformation, &pHandleInfo, dwSize, &dwSize);
		if(NtStatus == STATUS_SUCCESS)
		{
			printf("\nNtQuery is ok ...");
		}
		else if(NtStatus == STATUS_INFO_LENGTH_MISMATCH){
			printf("\nLength mismatch !");
			pHandleInfo=NULL;			
			NtStatus = NtQuerySystemInformation(SystemHandleInformation, pHandleInfo, dwSize, &dwSize);
					if(NtStatus == STATUS_SUCCESS){
							printf(" Found %d Handles.\n\n", pHandleInfo->uCount);
					}
		}

	_getch();
	return 0;
}
I have been cut the most part of the real code for revealing the problem, as I realized the problem is on dwSize & pHandleInfo, the binary could be done for me on the building phase but the code seems not working as well & has few problems.
if anyone could guide at this case, it would be appreciated as always .

Thanks pals .

Genius
 #1330  by nullptr
 Fri Jun 25, 2010 11:55 pm
Code: Select all
 else if(NtStatus == STATUS_INFO_LENGTH_MISMATCH){
         printf("\nLength mismatch !");
         pHandleInfo=NULL;         
         NtStatus = NtQuerySystemInformation(SystemHandleInformation, pHandleInfo, dwSize, &dwSize);
               if(NtStatus == STATUS_SUCCESS){
                     printf(" Found %d Handles.\n\n", pHandleInfo->uCount);
STATUS_INFO_LENGTH_MISMATCH means the buffer (pHandleInfo) is not large enough. The dwSize variable from the previous call to NtQuerySystemInformation(...) now holds the size of the memory that you need to allocate. That's the problem, you never allocate dwSize amount of memory for pHandleInfo.
 #1331  by EP_X0FF
 Sat Jun 26, 2010 3:02 am
Hi,

[syntax="c"]if(NtStatus == STATUS_SUCCESS)[/syntax]

Why not use

[syntax="c"]if (NT_SUCCESS(NtStatus))[/syntax]

?

Regards.
 #1337  by Eric_71
 Sat Jun 26, 2010 9:59 am
Hi __Genius__ ,

C code example (based on existing codes with some modifications) :

Handle.h

[syntax="c"]
#ifndef __HANDLE__
#define __HANDLE__

#define WINVER 0x0501
#define _WIN32_WINNT 0x0501
#define _WIN32_IE 0x0500

#define UNICODE
#define _UNICODE

#include <windows.h>

#define NT_SUCCESS(x) ((x) >= 0)
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)


#define SystemHandleInformation 16
#define ObjectBasicInformation 0
#define ObjectNameInformation 1
#define ObjectTypeInformation 2

DWORD
WINAPI
GetModuleBaseNameW(
HANDLE hProcess,
HMODULE hModule,
LPWSTR lpBaseName,
DWORD nSize
);

typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef LONG NTSTATUS;

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 _IO_STATUS_BLOCK
{
union
{
NTSTATUS Status;
PVOID Pointer;
};

ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

typedef VOID (WINAPI * PIO_APC_ROUTINE)(
PVOID,
PIO_STATUS_BLOCK,
DWORD
);

typedef VOID *POBJECT;

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);
}

#endif

[/syntax]

Handle.c (For example, just with explorer.exe)

[syntax="c"]
#include "Handle.h"


WCHAR *stristrW(WCHAR *Str, WCHAR *Pat)
{
WCHAR *pptr, *sptr, *start;

for (start = (WCHAR *)Str; *start != '\0'; start++)
{
for ( ; ((*start!='\0') && (toupper(*start) != toupper(*Pat))); start++);
if ('\0' == *start) return NULL;
pptr = (WCHAR *)Pat;
sptr = (WCHAR *)start;
while (toupper(*sptr) == toupper(*pptr))
{
sptr++;
pptr++;
if ('\0' == *pptr) return (start);
}
}
return NULL;
}

//==============================================================================

VOID HandleList(DWORD pid)
{
NTSTATUS status;
PSYSTEM_HANDLE_INFORMATION handleInfo;
ULONG handleInfoSize = 0x10000;
HANDLE processHandle;
ULONG i;

_NtQuerySystemInformation NtQuerySystemInformation = GetLibraryProcAddress("ntdll.dll", "NtQuerySystemInformation");
_NtDuplicateObject NtDuplicateObject = GetLibraryProcAddress("ntdll.dll", "NtDuplicateObject");
_NtQueryObject NtQueryObject = GetLibraryProcAddress("ntdll.dll", "NtQueryObject");

if(!(processHandle = OpenProcess(PROCESS_DUP_HANDLE|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,pid))) return;

handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize);

while((status = NtQuerySystemInformation(SystemHandleInformation,handleInfo,handleInfoSize,NULL)) == STATUS_INFO_LENGTH_MISMATCH)
handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2);

if(!NT_SUCCESS(status)) return;

for(i = 0; i < handleInfo->HandleCount; i++)
{
SYSTEM_HANDLE handle = handleInfo->Handles;
HANDLE dupHandle = NULL;
POBJECT_TYPE_INFORMATION objectTypeInfo;
PVOID objectNameInfo;
UNICODE_STRING objectName;
ULONG returnLength;

if(handle.ProcessId != pid) continue;
if(!NT_SUCCESS(NtDuplicateObject(processHandle,(HANDLE)handle.Handle,GetCurrentProcess(),&dupHandle,0,0,0))) continue;
objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000);

if(!NT_SUCCESS(NtQueryObject(dupHandle,ObjectTypeInformation,objectTypeInfo,0x1000,NULL)))
{
CloseHandle(dupHandle);
continue;
}

if((handle.GrantedAccess != 0x0012019f)
&& (handle.GrantedAccess != 0x001a019f)
&& (handle.GrantedAccess != 0x00120189)
&& (handle.GrantedAccess != 0x00100000))
{
wprintf(L"%s - 0x%X - ",objectTypeInfo->Name.Buffer, handle.Handle);
//wprintf(L"0x%X",handle.GrantedAccess);

objectNameInfo = malloc(0x1000);
if(!NT_SUCCESS(NtQueryObject(dupHandle,ObjectNameInformation,objectNameInfo,0x1000,&returnLength)))
{
objectNameInfo = realloc(objectNameInfo, returnLength);
if(!NT_SUCCESS(NtQueryObject(dupHandle,ObjectNameInformation,objectNameInfo,returnLength,NULL)))
{
free(objectTypeInfo);
free(objectNameInfo);
CloseHandle(dupHandle);
continue;
}
}
objectName = *(PUNICODE_STRING)objectNameInfo;

if(objectName.Length) wprintf(L"%s",objectName.Buffer);
else wprintf(L"\0");

wprintf(L"\n");
}
free(objectTypeInfo);
free(objectNameInfo);
CloseHandle(dupHandle);
}
free(handleInfo);
CloseHandle(processHandle);
return;
}

//==============================================================================

int main()
{
DWORD PID;
WCHAR PN[MAX_PATH]={0};

for(PID = 0;PID < 0xFFFF; PID +=4)
{
HANDLE hP = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, PID);
if(hP)
{
GetModuleBaseNameW(hP, NULL, PN, sizeof(PN));
if(stristrW(PN, L"explorer.exe")) HandleList(PID);
}
CloseHandle(hP);
}
}
[/syntax]

This works but it can be improved :

Image

Regards,

Eric
Attachments
Console example + source code
(5.63 KiB) Downloaded 45 times
 #1342  by __Genius__
 Sat Jun 26, 2010 4:55 pm
Hi Eric, thank you, your code is running fine . Thnx for your kindness :) ;)

@ EP_X0FF :
& what's the benefit with NT_SUCCESS rather NtStatus checking?

kind regards,

- Genius
 #1343  by EP_X0FF
 Sat Jun 26, 2010 5:03 pm
NT_SUCCESS(Value) macro tests Value to be success (values from 0 − 0x7FFFFFFF). Actually it tests value to be >= 0. Some functions may return STATUS_SUCCESS as a successful result and other value that also will indicate successful result, but not equal to STATUS_SUCCESS or incomplete success (wait). This is maybe unimportant for user mode NativeAPI programming but for kernel mode drivers you should carefully lead available documentation. For more info look here (MSDN article).