Skip to content

Instantly share code, notes, and snippets.

@im-infamou5
Last active November 7, 2023 10:15
Show Gist options
  • Save im-infamou5/89322f146a0ada65a39a to your computer and use it in GitHub Desktop.
Save im-infamou5/89322f146a0ada65a39a to your computer and use it in GitHub Desktop.
This tool allows to view handles of all process including system ones. Generally, fork of bit.ly/1kyJU8J with system processes supported.
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <time.h>
#define DEBUG 1
#define BUFSIZE MAX_PATH
#define RTN_OK 0
#define RTN_USAGE 1
#define RTN_ERROR 13
#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;
typedef struct _FILE_NAME_INFORMATION {
ULONG FileNameLength;
WCHAR FileName[MAX_PATH];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
typedef DWORD (WINAPI *PNtQueryInformationFile)(HANDLE, PVOID, PVOID, DWORD, DWORD );
#define QUERYOBJECT_TIME_MAX_MS 5000//60000
#define QUERYOBJECT_TIME_DELTA_MS 100
BOOL g_bNameThreadEnd = FALSE;
BOOL g_bNameRecieved = FALSE;
wchar_t g_wcsHName[MAX_PATH] = L"";
PVOID GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName)
{
return GetProcAddress(GetModuleHandleA(LibraryName), ProcName);
}
DWORD WINAPI NewThreadFunc(LPVOID param)
{
_NtQueryObject NtQueryObject = GetLibraryProcAddress("ntdll.dll", "NtQueryObject");
PNtQueryInformationFile NTQIF = (PNtQueryInformationFile)GetLibraryProcAddress("ntdll.dll", "NtQueryInformationFile");
HANDLE h = (HANDLE)param;
BOOL bRes = FALSE;
FILE_NAME_INFORMATION NmInfo;
DWORD iob[2];
g_wcsHName[0] = 0;
if(NT_SUCCESS(NTQIF(h, &iob, &NmInfo, sizeof(NmInfo), /*FileNameInformation*/9)))
{
if( NmInfo.FileNameLength > 0 && NmInfo.FileNameLength <= MAX_PATH)
{
wcsncpy_s(g_wcsHName, _countof(g_wcsHName), NmInfo.FileName, NmInfo.FileNameLength / 2);
g_wcsHName[NmInfo.FileNameLength / 2] = 0;
g_bNameRecieved = TRUE;
}
if(wcsstr(g_wcsHName, L"NtControlPipe") == 0)
{
PVOID objectNameInfo = malloc(0x1000);//!!! Если поток завершится аварийно, то ресурсы не освободятся
ULONG returnLength = 0;
if (NT_SUCCESS(NtQueryObject( h, ObjectNameInformation, objectNameInfo, 0x1000, &returnLength )))
{
bRes = TRUE;
}
else
{
if(returnLength > 0x1000)
{
objectNameInfo = realloc(objectNameInfo, returnLength);
if (NT_SUCCESS(NtQueryObject( h, ObjectNameInformation, objectNameInfo, returnLength, NULL )))
{
bRes = TRUE;
}
}
}
if(bRes)
{
UNICODE_STRING objectName = *(PUNICODE_STRING)objectNameInfo;
wcscpy_s(g_wcsHName, _countof(g_wcsHName), objectName.Buffer);
g_bNameRecieved = TRUE;
}
free(objectNameInfo);//!!! Если поток завершится аварийно, то ресурсы не освободятся
}
}
g_bNameThreadEnd = TRUE;
return 0;
}
BOOL GetHandleName(HANDLE Handle, wchar_t *pwcsHandleName)
{
BOOL bRes = FALSE;
if(Handle != 0 && pwcsHandleName != 0)
{
DWORD thID;
HANDLE hThread = NULL;
DWORD dwWorkTime = 0;
g_bNameThreadEnd = FALSE;
g_bNameRecieved = FALSE;
g_wcsHName[0] = 0;
hThread = CreateThread(0, 0, NewThreadFunc, (LPVOID)Handle, 0, &thID);
while(dwWorkTime < QUERYOBJECT_TIME_MAX_MS && !g_bNameThreadEnd)//Поток завершён или истекло время ожидания
{
Sleep(QUERYOBJECT_TIME_DELTA_MS);
dwWorkTime += QUERYOBJECT_TIME_DELTA_MS;
continue;
}
if(!g_bNameThreadEnd)//Поток не был завершён, необходимо завершать аварийно
{
TerminateThread(hThread, -1);
}
CloseHandle(hThread);
if(g_bNameRecieved)//Имя найдено
{
wcscpy(pwcsHandleName, g_wcsHName);
bRes = TRUE;
}
}
return bRes;
}
BOOL SetPrivilege(
HANDLE hToken, // token handle
LPCTSTR Privilege, // Privilege to enable/disable
BOOL bEnablePrivilege // TRUE to enable. FALSE to disable
)
{
TOKEN_PRIVILEGES tp = { 0 };
// Initialize everything to zero
LUID luid;
DWORD cb=sizeof(TOKEN_PRIVILEGES);
if(!LookupPrivilegeValue( NULL, Privilege, &luid ))
return FALSE;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if(bEnablePrivilege) {
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
} else {
tp.Privileges[0].Attributes = 0;
}
AdjustTokenPrivileges( hToken, FALSE, &tp, cb, NULL, NULL );
if (GetLastError() != ERROR_SUCCESS)
return FALSE;
if(DEBUG)
printf("[DEBUGDATA]: SetPrivilege()\n");
return TRUE;
}
void DisplayError(
LPTSTR szAPI // pointer to failed API name
)
{
LPTSTR MessageBuffer;
DWORD dwBufferLength;
fprintf(stderr,"%s() error!\n", szAPI);
if(dwBufferLength=FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
GetSystemDefaultLangID(),
(LPTSTR) &MessageBuffer,
0,
NULL
))
{
DWORD dwBytesWritten;
WriteFile(
GetStdHandle(STD_ERROR_HANDLE),
MessageBuffer,
dwBufferLength,
&dwBytesWritten,
NULL
);
if(DEBUG)
printf("[DEBUGDATA]: DisplayError()\n");
LocalFree(MessageBuffer);
}
}
BOOL LookupLogFile(wchar_t* filename)
{
DWORD osversion = LOWORD(GetVersion());
DWORD dwMajorVersion = (DWORD)(LOBYTE(osversion));
DWORD dwMinorVersion = (DWORD)(HIBYTE(osversion));
if(filename == NULL)
return FALSE;
if(wcslen(filename) != 0)
{
const wchar_t str[MAX_PATH] = L"";
if((int)dwMajorVersion == 5 && (int)dwMinorVersion == 1)
{
wcscpy_s(str, _countof(str), L"SysEvent.Evt");
}
else
{
wcscpy_s(str, _countof(str), L"System.evtx");
}
if( wcsstr(filename, str))
{
return TRUE;
}
else
{
return FALSE;
}
}
else return FALSE;
}
BOOL DosPathName2NtPathName( wchar_t *pszDosPathName, wchar_t *pszNtPathName )
{
wchar_t szDosDriveName[MAX_PATH + 1] = {0},
szDrive[10] = {0};
int i;
DWORD dwDrivesMask;
wcsncpy_s( pszNtPathName,MAX_PATH, pszDosPathName, MAX_PATH );
CharLower( pszNtPathName );
dwDrivesMask = GetLogicalDrives();
if( dwDrivesMask )
{
for( i = 0; i < 26; ++i )
{
if( dwDrivesMask & (1 << i) )
{
wsprintf( szDrive, L"%c:", 'A' + i );
if( QueryDosDevice( szDrive, szDosDriveName, MAX_PATH ) != 0 )
{
CharLower( szDosDriveName );
if( wcsstr( pszNtPathName, szDosDriveName ) )
{
wsprintf( pszNtPathName, L"%s%s", szDrive, &pszDosPathName[ wcslen( szDosDriveName ) ] );
return TRUE;
}
}
}
}
}
return FALSE;
}
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;
HANDLE hToken;
ULONG i;
clock_t begin, end;
wchar_t ntpath[MAX_PATH + 1] = {0};
if(DEBUG)
{
printf("[DEBUGDATA]: main()\n");
fflush(stdout);
}
if (argc < 2)
{
printf("Usage: info [pid]\n");
return 1;
}
pid = _wtoi(argv[1]);
if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken))
{
if (GetLastError() == ERROR_NO_TOKEN)
{
if (!ImpersonateSelf(SecurityImpersonation))
return RTN_ERROR;
if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)){
DisplayError((LPTSTR)"OpenThreadToken");
return RTN_ERROR;
}
}
else
return RTN_ERROR;
}
if(!SetPrivilege(hToken, SE_DEBUG_NAME, TRUE))
{
DisplayError((LPTSTR)"SetPrivilege");
CloseHandle(hToken);
return RTN_ERROR;
}
if (!(processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid)))
{
printf("Could not open PID %d! \n", pid);
return 1;
}
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))
{
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;
BOOL bFileNameRecieved = FALSE;
wchar_t wcsHandleName[MAX_PATH] = L"";
begin = clock();
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(DEBUG)
{
fflush(stdout);
}
if(objectTypeInfo == NULL)
continue;
if(objectTypeInfo->Name.Buffer == NULL)
continue;
if(wcscmp(objectTypeInfo->Name.Buffer, L"File") != 0)
continue;
if(GetHandleName(dupHandle, wcsHandleName))
{
printf(
"[%#x] %.*S: %S\n",
handle.Handle,
objectTypeInfo->Name.Length / 2,
objectTypeInfo->Name.Buffer,
wcsHandleName
);
fflush(stdout);
if(LookupLogFile(wcsHandleName))
{
if(DEBUG) printf("File lookup succedeed\n");
fflush(stdout);
if(DuplicateHandle(processHandle, (HANDLE)handle.Handle, NULL, NULL, 0, FALSE, 0x1))
{
CloseHandle(dupHandle);
dupHandle = NULL;
printf("Handle deletion succedeed\n");
fflush(stdout);
DosPathName2NtPathName((wchar_t*)objectName.Buffer, ntpath);
if(DeleteFile(ntpath))
{
printf("Deletion file %s succeeded\n", ntpath);
fflush(stdout);
}
else printf("File deletion error with code %d\n", GetLastError());
fflush(stdout);
}
else printf("Unable to close handle %d\n", handle.Handle);
fflush(stdout);
}
}
else
{
printf(
"[%#x] %.*S: (unnamed)\n",
handle.Handle,
objectTypeInfo->Name.Length / 2,
objectTypeInfo->Name.Buffer
);
}
free(objectTypeInfo);
if(dupHandle)
CloseHandle(dupHandle);
end = clock();
//printf("Elapsed: %f seconds\n", (double)(begin - end) / CLOCKS_PER_SEC);
fflush(stdout);
}
free(handleInfo);
CloseHandle(processHandle);
CloseHandle(hToken);
printf("<Press any key...>");
getchar();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment