Advertisement
Guest User

Handles

a guest
Nov 26th, 2012
556
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 16.34 KB | None | 0 0
  1.                                                                      
  2.                                                                      
  3.                                                                      
  4.                                              
  5. #include <windows.h>
  6. #include <stdio.h>
  7. #include <shlwapi.h>
  8. #include <tchar.h>
  9. #include <stdio.h>
  10.  
  11. #pragma comment ( lib, "shlwapi.lib" )
  12.  
  13. #define NT_SUCCESS(x) ((x) >= 0)
  14. //#define STATUS_INFO_LENGTH_MISMATCH 0xc0000004
  15.  
  16. #define SystemHandleInformation 16
  17. #define ObjectBasicInformation 0
  18. #define ObjectNameInformation 1
  19. #define ObjectTypeInformation 2
  20. #define STATUS_SUCCESS               ((NTSTATUS)0x00000000L) //getprocid
  21. #define STATUS_INFO_LENGTH_MISMATCH  ((NTSTATUS)0xC0000004L) //getprocid
  22.  
  23. typedef NTSTATUS ( NTAPI *_NtQuerySystemInformation )
  24.     (
  25.         ULONG SystemInformationClass,
  26.         PVOID SystemInformation,
  27.         ULONG SystemInformationLength,
  28.         PULONG ReturnLength
  29.     );
  30. typedef NTSTATUS ( NTAPI *_NtDuplicateObject )
  31.     (
  32.         HANDLE SourceProcessHandle,
  33.         HANDLE SourceHandle,
  34.         HANDLE TargetProcessHandle,
  35.         PHANDLE TargetHandle,
  36.         ACCESS_MASK DesiredAccess,
  37.         ULONG Attributes,
  38.         ULONG Options
  39.     );
  40. typedef NTSTATUS ( NTAPI *_NtQueryObject )
  41.     (
  42.         HANDLE ObjectHandle,
  43.         ULONG ObjectInformationClass,
  44.         PVOID ObjectInformation,
  45.         ULONG ObjectInformationLength,
  46.         PULONG ReturnLength
  47.     );
  48.  
  49. typedef struct _UNICODE_STRING
  50. {
  51.     USHORT Length;
  52.     USHORT MaximumLength;
  53.     PWSTR Buffer;
  54. } UNICODE_STRING, *PUNICODE_STRING;
  55.  
  56. typedef struct _SYSTEM_HANDLE
  57. {
  58.     ULONG ProcessId;
  59.     BYTE ObjectTypeNumber;
  60.     BYTE Flags;
  61.     USHORT Handle;
  62.     PVOID Object;
  63.     ACCESS_MASK GrantedAccess;
  64. } SYSTEM_HANDLE, *PSYSTEM_HANDLE;
  65.  
  66. typedef struct _SYSTEM_HANDLE_INFORMATION
  67. {
  68.     ULONG HandleCount;
  69.     SYSTEM_HANDLE Handles[ 1 ];
  70. } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
  71.  
  72. typedef enum _POOL_TYPE
  73. {
  74.     NonPagedPool,
  75.     PagedPool,
  76.     NonPagedPoolMustSucceed,
  77.     DontUseThisType,
  78.     NonPagedPoolCacheAligned,
  79.     PagedPoolCacheAligned,
  80.     NonPagedPoolCacheAlignedMustS
  81. } POOL_TYPE, *PPOOL_TYPE;
  82.  
  83. typedef struct _OBJECT_TYPE_INFORMATION
  84. {
  85.     UNICODE_STRING Name;
  86.     ULONG TotalNumberOfObjects;
  87.     ULONG TotalNumberOfHandles;
  88.     ULONG TotalPagedPoolUsage;
  89.     ULONG TotalNonPagedPoolUsage;
  90.     ULONG TotalNamePoolUsage;
  91.     ULONG TotalHandleTableUsage;
  92.     ULONG HighWaterNumberOfObjects;
  93.     ULONG HighWaterNumberOfHandles;
  94.     ULONG HighWaterPagedPoolUsage;
  95.     ULONG HighWaterNonPagedPoolUsage;
  96.     ULONG HighWaterNamePoolUsage;
  97.     ULONG HighWaterHandleTableUsage;
  98.     ULONG InvalidAttributes;
  99.     GENERIC_MAPPING GenericMapping;
  100.     ULONG ValidAccess;
  101.     BOOLEAN SecurityRequired;
  102.     BOOLEAN MaintainHandleCount;
  103.     USHORT MaintainTypeList;
  104.     POOL_TYPE PoolType;
  105.     ULONG PagedPoolUsage;
  106.     ULONG NonPagedPoolUsage;
  107. } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
  108.  
  109. //getprocid
  110. typedef enum _SYSTEM_INFORMATION_CLASS
  111. {
  112.     SystemProcessInformation = 5
  113. } SYSTEM_INFORMATION_CLASS;
  114.  
  115. typedef LONG KPRIORITY; // Thread priority
  116.  
  117. typedef struct _SYSTEM_PROCESS_INFORMATION_DETAILD
  118. {
  119.     ULONG NextEntryOffset;
  120.     ULONG NumberOfThreads;
  121.     LARGE_INTEGER SpareLi1;
  122.     LARGE_INTEGER SpareLi2;
  123.     LARGE_INTEGER SpareLi3;
  124.     LARGE_INTEGER CreateTime;
  125.     LARGE_INTEGER UserTime;
  126.     LARGE_INTEGER KernelTime;
  127.     UNICODE_STRING ImageName;
  128.     KPRIORITY BasePriority;
  129.     HANDLE UniqueProcessId;
  130.     ULONG InheritedFromUniqueProcessId;
  131.     ULONG HandleCount;
  132.     BYTE Reserved4[4];
  133.     PVOID Reserved5[11];
  134.     SIZE_T PeakPagefileUsage;
  135.     SIZE_T PrivatePageCount;
  136.     LARGE_INTEGER Reserved6[6];
  137. } SYSTEM_PROCESS_INFORMATION_DETAILD, *PSYSTEM_PROCESS_INFORMATION_DETAILD;
  138.  
  139. typedef NTSTATUS( WINAPI *PFN_NT_QUERY_SYSTEM_INFORMATION )
  140. (
  141.   IN       SYSTEM_INFORMATION_CLASS SystemInformationClass,
  142.   IN OUT   PVOID SystemInformation,
  143.   IN       ULONG SystemInformationLength,
  144.   OUT OPTIONAL  PULONG ReturnLength
  145. );
  146.  
  147. typedef struct {
  148.     HANDLE handle;
  149.     PVOID  NameInfo;
  150.     ULONG retVal;
  151. } SFileNameInfo;
  152.  
  153. int Counter = 0;
  154.  
  155. PVOID GetLibraryProcAddress( PSTR LibraryName, PSTR ProcName );
  156. int GetHandle( ULONG pid );
  157.  
  158. static _NtQuerySystemInformation NtQuerySystemInformation;
  159. static _NtDuplicateObject   NtDuplicateObject;
  160. static _NtQueryObject            NtQueryObject;
  161.  
  162.  
  163. int test( HANDLE handli );
  164. void EnableDebugPriv( void );
  165. int GetProcessList();
  166.  
  167. static bool InitNTDLL()
  168. {
  169.      NtQuerySystemInformation = ( _NtQuerySystemInformation ) GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "NtQuerySystemInformation" );
  170.      NtDuplicateObject = ( _NtDuplicateObject ) GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "NtDuplicateObject" );
  171.      NtQueryObject =( _NtQueryObject ) GetProcAddress(GetModuleHandleA( "ntdll.dll" ), "NtQueryObject" );
  172.  
  173.     return NtQuerySystemInformation != NULL &&
  174.            NtDuplicateObject   != NULL &&
  175.            NtQueryObject            != NULL;
  176. }
  177.  
  178. NTSTATUS status;
  179. PSYSTEM_HANDLE_INFORMATION handleInfo;
  180. ULONG handleInfoSize = 0x10000;
  181.  
  182. int __cdecl wmain( int argc, PWSTR argv[] )
  183. {
  184.     if ( !InitNTDLL() )
  185.     {
  186.         printf( "\nFailed to bind to ntdll.dll!" );
  187.         return 1;
  188.     }
  189.  
  190.     handleInfo = ( PSYSTEM_HANDLE_INFORMATION )malloc( handleInfoSize );
  191.  
  192.     while ( ( status = NtQuerySystemInformation( SystemHandleInformation, handleInfo, handleInfoSize, NULL ) ) == STATUS_INFO_LENGTH_MISMATCH )
  193.         handleInfo = ( PSYSTEM_HANDLE_INFORMATION )realloc( handleInfo, handleInfoSize *= 2 );
  194.  
  195.     EnableDebugPriv();
  196.     GetProcessList();
  197.    
  198.     free( handleInfo );
  199.  
  200.     NtQueryObject = NULL;
  201.     NtDuplicateObject = NULL;
  202.     NtQuerySystemInformation = NULL;
  203. }
  204.  
  205. int test( HANDLE HandleToTest )
  206. {
  207.     HANDLE Job( CreateJobObject( NULL, NULL ) );
  208.     if( !Job )
  209.     {
  210.         wprintf( L"Could not create job object, error %d\n", GetLastError() );
  211.         return 0;
  212.     }
  213.  
  214.     HANDLE IOPort( CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 1 ) );
  215.     if( !IOPort )
  216.     {
  217.         wprintf( L"Could not create IO completion port, error %d\n", GetLastError() );
  218.         return 0;
  219.     }
  220.  
  221.     JOBOBJECT_ASSOCIATE_COMPLETION_PORT Port;
  222.     Port.CompletionKey = HandleToTest;
  223.     Port.CompletionPort = IOPort;
  224.  
  225.     if( !SetInformationJobObject( HandleToTest, JobObjectAssociateCompletionPortInformation, &Port, sizeof( Port ) ) )
  226.     {
  227.         wprintf( L"Could not associate job with IO completion port, error %d\n", GetLastError() );
  228.         return 0;
  229.     }
  230.    
  231.     PROCESS_INFORMATION ProcessInformation;
  232.     STARTUPINFO StartupInfo = { sizeof(StartupInfo) };
  233.     PWSTR CommandLine = PathGetArgs(GetCommandLine());
  234.    
  235.     if( !CreateProcess( NULL, CommandLine, NULL, NULL, FALSE, CREATE_NEW_CONSOLE | CREATE_SUSPENDED, NULL, NULL, &StartupInfo, &ProcessInformation ) )
  236.     {
  237.         wprintf( L"Could not run process, error %d\n", GetLastError() );
  238.         return 0;
  239.     }
  240.  
  241.     if( !AssignProcessToJobObject( HandleToTest, ProcessInformation.hProcess ) )
  242.     {
  243.         wprintf( L"Could not assign process to job, error %d\n", GetLastError() );
  244.         return 0;
  245.     }
  246.     printf( "\nHandle : [%#x]", HandleToTest );
  247.     system( "pause" );
  248.    
  249.     ResumeThread( ProcessInformation.hThread );
  250.     CloseHandle( ProcessInformation.hThread );
  251.     CloseHandle( ProcessInformation.hProcess );
  252.  
  253.     DWORD CompletionCode;
  254.     ULONG_PTR CompletionKey;
  255.     LPOVERLAPPED Overlapped;
  256.  
  257.     int ProcessCount = 0;
  258.  
  259.     while ( GetQueuedCompletionStatus( IOPort, &CompletionCode, &CompletionKey, &Overlapped, INFINITE ) && CompletionCode != JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO )
  260.     {
  261.         if ( CompletionCode == JOB_OBJECT_MSG_NEW_PROCESS ) ProcessCount++;
  262.         if ( ( CompletionCode == JOB_OBJECT_MSG_EXIT_PROCESS ) || ( CompletionCode == JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS) ) ProcessCount--;
  263.        
  264.         wprintf( L"Waiting for %d processes to finish...\n", ProcessCount );
  265.     }
  266.  
  267.     wprintf( L"All done\n" );
  268.    
  269.     return 0;
  270. }
  271.  
  272. void EnableDebugPriv( void )
  273. {
  274.     HANDLE hToken;
  275.     LUID sedebugnameValue;
  276.     TOKEN_PRIVILEGES tkp;
  277.  
  278.     // enable the SeDebugPrivilege
  279.     if ( ! OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
  280.     {
  281.         _tprintf( _T( "OpenProcessToken() failed, Error = %d SeDebugPrivilege is not available.\n" ) , GetLastError() );
  282.         return;
  283.     }
  284.  
  285.     if ( ! LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &sedebugnameValue ) )
  286.     {
  287.         _tprintf( _T( "LookupPrivilegeValue() failed, Error = %d SeDebugPrivilege is not available.\n" ), GetLastError() );
  288.         CloseHandle( hToken );
  289.         return;
  290.     }
  291.  
  292.     tkp.PrivilegeCount = 1;
  293.     tkp.Privileges[ 0 ].Luid = sedebugnameValue;
  294.     tkp.Privileges[ 0 ].Attributes = SE_PRIVILEGE_ENABLED;
  295.  
  296.     if ( ! AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp, NULL, NULL ) )
  297.         _tprintf( _T( "AdjustTokenPrivileges() failed, Error = %d SeDebugPrivilege is not available.\n" ), GetLastError() );
  298.        
  299.     CloseHandle( hToken );
  300. }//EnableDebugPriv
  301.  
  302. PVOID GetLibraryProcAddress( PSTR LibraryName, PSTR ProcName )
  303. {
  304.     return GetProcAddress( GetModuleHandleA( LibraryName ), ProcName );
  305. }
  306.  
  307. int GetHandle( ULONG pid )
  308. {
  309.     HANDLE processHandle;
  310.     ULONG i;
  311.     wchar_t tmp[ 64 ] = { 0 };
  312.     HANDLE duplicated;
  313.  
  314.     if ( !( processHandle = OpenProcess( PROCESS_DUP_HANDLE, FALSE, pid ) ) )
  315.     {
  316.         printf( "\n\tCould not open PID %d! (Don't try to open a system process.)\n", pid );
  317.         return 1;
  318.     }
  319.  
  320.     /* NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH. */
  321.     if ( !NT_SUCCESS( status ) )
  322.     {
  323.         printf( "NtQuerySystemInformation failed!\n" );
  324.         return NULL;
  325.     }
  326.    
  327.     int Count = 0;
  328.  
  329.     for ( i = 0; i < handleInfo->HandleCount; i++ )
  330.     {
  331.         SYSTEM_HANDLE handle = handleInfo->Handles[ i ];
  332.         HANDLE dupHandle = NULL;
  333.         POBJECT_TYPE_INFORMATION objectTypeInfo;
  334.         PVOID objectNameInfo;
  335.         UNICODE_STRING objectName;
  336.         ULONG returnLength;
  337.  
  338.         /* Check if this handle belongs to the PID the user specified. */
  339.         if ( handle.ProcessId != pid ) continue;
  340.  
  341.         //--------------------------------------------------------------
  342.         Count++;
  343.         //--------------------------------------------------------------
  344.  
  345.         /* Duplicate the handle so we can query it. */
  346.         if ( !NT_SUCCESS( NtDuplicateObject( processHandle, ( HANDLE )handle.Handle, GetCurrentProcess(), &dupHandle, 0, 0, 0 ) ) )
  347.         {
  348.             //  printf( "%3d - [%#x] Error!\n", Count, handle.Handle );
  349.             continue;
  350.         }
  351.  
  352.         /* Query the object type. */
  353.         objectTypeInfo = ( POBJECT_TYPE_INFORMATION )malloc( 0x1000 );
  354.         if ( !NT_SUCCESS( NtQueryObject( dupHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, NULL ) ) )
  355.         {
  356.             printf( "%3d - [%#x] Error!\n", Count, handle.Handle );
  357.             CloseHandle( dupHandle );
  358.             continue;
  359.         }
  360.  
  361.         /* Query the object name (unless it has an access of
  362.            0x0012019f, on which NtQueryObject could hang. */
  363.         if ( handle.GrantedAccess == 0x0012019f )
  364.         {
  365.             /* We have the type, so display that. */
  366.             if ( wcscmp( tmp , L"Job" ) != 0 ) ;//do nothing
  367.             else
  368.             {
  369.                 printf( "%3d - [%#x] %.*S: (did not get name)\n", Count, handle.Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer );
  370.            
  371.                 if ( !DuplicateHandle( OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid ), ( HANDLE )handle.Handle, GetCurrentProcess(), &duplicated, 0, FALSE, DUPLICATE_SAME_ACCESS ) )
  372.                     printf( "\nDuplicateHandle Failed!" );
  373.                 else
  374.                 {
  375.                     BOOL res;
  376.                     IsProcessInJob( duplicated, NULL, &res );
  377.                     printf( "IsProcessInJob: %s\n", res ? "True" : "False" );
  378.                     if ( res ) test( duplicated );
  379.                 }
  380.             }
  381.             free( objectTypeInfo );
  382.             CloseHandle( dupHandle );
  383.             continue;
  384.         }
  385.  
  386.         objectNameInfo = malloc( 0x1000 );
  387.         if ( !NT_SUCCESS( NtQueryObject( dupHandle, ObjectNameInformation, objectNameInfo, 0x1000, &returnLength ) ) )
  388.         {
  389.             /* Reallocate the buffer and try again. */
  390.             objectNameInfo = realloc( objectNameInfo, returnLength );
  391.             if ( !NT_SUCCESS( NtQueryObject( dupHandle, ObjectNameInformation, objectNameInfo, returnLength, NULL ) ) )
  392.             {
  393.                 /* We have the type name, so just display that. */
  394.                 if ( wcscmp( tmp , L"Job" ) != 0 ) ;//do nothing
  395.                 else
  396.                 {
  397.                     printf( "\n\t%3d - [%#x] %.*S: (could not get name)\n", Count, handle.Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer );
  398.                
  399.                     if ( !DuplicateHandle( OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid ), ( HANDLE )handle.Handle, GetCurrentProcess(), &duplicated, 0, FALSE, DUPLICATE_SAME_ACCESS ) )
  400.                         printf( "\nDuplicateHandle Failed!" );
  401.                     else
  402.                     {
  403.                         BOOL res;
  404.                         IsProcessInJob( duplicated, NULL, &res );
  405.                         printf( "IsProcessInJob: %s\n", res ? "True" : "False" );
  406.                         if ( res ) test( duplicated );
  407.                     }
  408.                 }
  409.                 free( objectTypeInfo );
  410.                 free( objectNameInfo );
  411.                 CloseHandle( dupHandle );
  412.                 continue;
  413.             }
  414.         }
  415.  
  416.         /* Cast our buffer into an UNICODE_STRING. */
  417.         objectName = *( PUNICODE_STRING )objectNameInfo;
  418.  
  419.        
  420.         /* Print the information! */
  421.         if ( objectName.Length )
  422.         {
  423.             /* The object has a name. */
  424.            
  425.             wsprintf( tmp, L"%ls", objectTypeInfo->Name.Buffer );
  426.            
  427.             if ( wcscmp( tmp , L"Job" ) != 0 ) ;//do nothing
  428.             else
  429.             {
  430.                 //printf( "\n\t%3d - [%#x] %.*S: %.*S\n", Count, handle.Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer,   objectName.Length / 2, objectName.Buffer );
  431.                 printf( "\n\t%3d - [%#x] \t%d - %ls \t\n", Count, handle.Handle, handle.ObjectTypeNumber, objectName.Buffer );
  432.                
  433.                 if ( !DuplicateHandle( OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid ), ( HANDLE )handle.Handle, GetCurrentProcess(), &duplicated, 0, FALSE, DUPLICATE_SAME_ACCESS ) )
  434.                     printf( "\nDuplicateHandle Failed!" );
  435.                 else
  436.                 {
  437.                     BOOL res;
  438.                     IsProcessInJob( duplicated, NULL, &res );
  439.                     printf( "IsProcessInJob: %s\n", res ? "True" : "False" );
  440.                     if ( res ) test( duplicated );
  441.                 }
  442.             }
  443.         }
  444.         else
  445.         {
  446.             /* Print something else. */
  447.             wsprintf( tmp, L"%ls", objectTypeInfo->Name.Buffer );
  448.        
  449.             if ( wcscmp( tmp , L"Job" ) != 0 ) ;//do nothing
  450.             else
  451.             {
  452.                 //printf( "\n\t%3d - [%#x] %.*S: (unnamed)\n", Count,   handle.Handle, objectTypeInfo->Name.Length / 2, objectTypeInfo->Name.Buffer );
  453.                 printf( "\n\t%3d - [%#x] \t%d - %ls \t\n", Count, handle.Handle, handle.ObjectTypeNumber, objectName.Buffer );
  454.  
  455.                 if ( !DuplicateHandle( OpenProcess( PROCESS_ALL_ACCESS, FALSE, pid ), ( HANDLE )handle.Handle, GetCurrentProcess(), &duplicated, 0, FALSE, DUPLICATE_SAME_ACCESS ) )
  456.                     printf( "\nDuplicateHandle Failed!" );
  457.                 else
  458.                 {
  459.                     BOOL res;
  460.                     IsProcessInJob( duplicated, NULL, &res );
  461.                     printf( "IsProcessInJob: %s\n", res ? "True" : "False" );
  462.                     if ( res ) test( duplicated );
  463.                 }
  464.             }
  465.         }
  466.  
  467.         free( objectTypeInfo );
  468.         free( objectNameInfo );
  469.         CloseHandle( dupHandle );
  470.     }
  471.  
  472.     CloseHandle( processHandle );
  473.  
  474.     return 0;
  475. }
  476.  
  477. int GetProcessList()
  478. {
  479.     size_t bufferSize = 102400;
  480.     PSYSTEM_PROCESS_INFORMATION_DETAILD pspid = ( PSYSTEM_PROCESS_INFORMATION_DETAILD )malloc( bufferSize );
  481.     ULONG ReturnLength;
  482.     PFN_NT_QUERY_SYSTEM_INFORMATION pfnNtQuerySystemInformation = ( PFN_NT_QUERY_SYSTEM_INFORMATION )
  483.     GetProcAddress( GetModuleHandle( TEXT( "ntdll.dll" ) ), "NtQuerySystemInformation" );
  484.     NTSTATUS status;
  485.  
  486.     while( TRUE )
  487.     {
  488.         status = pfnNtQuerySystemInformation( SystemProcessInformation, ( PVOID )pspid, bufferSize, &ReturnLength );
  489.         if ( status == STATUS_SUCCESS )
  490.             break;
  491.         else if ( status != STATUS_INFO_LENGTH_MISMATCH )
  492.         { // 0xC0000004L
  493.             _tprintf( TEXT( "ERROR 0x%X\n" ), status );
  494.             return 1;   // error
  495.         }
  496.  
  497.         bufferSize *= 2;
  498.         pspid = ( PSYSTEM_PROCESS_INFORMATION_DETAILD )realloc( ( PVOID )pspid, bufferSize );
  499.     }
  500.  
  501.     int Counter = 1;
  502.  
  503.     for ( ; ; pspid = ( PSYSTEM_PROCESS_INFORMATION_DETAILD )( pspid->NextEntryOffset + ( PBYTE )pspid ) )
  504.     {
  505.         _tprintf( TEXT( "%4d.\tPID: %d, \tProcess: %ls\n" ), Counter++, pspid->UniqueProcessId,
  506.             ( pspid->ImageName.Length && pspid->ImageName.Buffer ) ? pspid->ImageName.Buffer: L"" );
  507.        
  508.         wchar_t test[64] = {0};
  509.         wsprintf( test, L"%ls",pspid->ImageName.Buffer );
  510.        
  511.         GetHandle( ( DWORD )pspid->UniqueProcessId );
  512.        
  513.         if ( pspid->NextEntryOffset == 0 ) break;
  514.     }
  515.  
  516.     return 0;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement