Last active
November 7, 2023 10:15
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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