Конференция "WinAPI" » Как правильней получить список процессов? [D7, WinXP]
 
  • WanderBuild (23.01.09 13:10) [0]
    Нашел в сети несколько примеров, остановился на двух, оба они делают одно и то же (возвращают список процессов), но разными методами.
    Какой на ВАШ профессиональный взгляд метод, более правильно использовать?
    Код первого примера:

    SnapProcHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    Result := (SnapProcHandle <> INVALID_HANDLE_VALUE);
    if Result then
      try
        ProcEntry.dwSize := SizeOf(ProcEntry);
        NextProc := Process32First(SnapProcHandle, ProcEntry);
        while NextProc do
        begin
           FileName := ProcessFileNameByPID(ProcEntry.th32ProcessID, True);
           if FileName = '' then FileName := ProcEntry.szExeFile;
          Form1.ListBox1.Items.AddObject(FileName, Pointer(ProcEntry.th32ProcessID));
          NextProc := Process32Next(SnapProcHandle, ProcEntry);
        end;
      finally
        CloseHandle(SnapProcHandle);
      end;



    Код второго примера:

    EnumProcesses(@PIDArray, SizeOf(PIDArray), cb);
     ProcCount := cb div SizeOf(DWORD);
     for I := 0 to ProcCount - 1 do
     begin
       hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PIDArray[I]);
       if not (hProcess=0) then
       begin
         EnumProcessModules(hProcess, @hMod, SizeOf(hMod), cb);
         GetModuleFilenameEx(hProcess, hMod, ModuleName, SizeOf(ModuleName));
         Form1.ListBox1.Items.Add(ModuleName);
         CloseHandle(hProcess);
       end;
     end;



    И второй вопрос: как определить пользователя, под которым работает тот или иной процесс?
  • multiflex (23.01.09 13:59) [1]
  • Сергей М. © (23.01.09 14:00) [2]
  • WanderBuild (23.01.09 14:45) [3]
    Спасибо, мужики, за реально лаконичные ответы :)
    насколько я увидел в обоих примерах используется код, аналогичный моему второму примеру.
    Просто интересно узнать, имеет ли право на жизнь первый мой пример, поскольку результатом его выполнения является список, аналогичный второму примеру, т.е. они оба работают.

    Да, еще интересный момент:
    процессы с именем csrss.exe и winlogon.exe оба примера возвращают вот в таком загадочном виде (остальные нормально)
    \??\С:\Windows\System32\csrss.exe
    \??\С:\Windows\System32\winlogon.exe
    вот то, что выделил жирным, никто не знает что это за муть?
  • Сергей М. © (23.01.09 15:56) [4]

    > они оба работают


    2-й не будет работать под Win9x/Me
  • WanderBuild (23.01.09 16:15) [5]
    >>2-й не будет работать под Win9x/Me
    ну этих мамонтов я думаю уже не встречу в этой жизни, так что не критично. Просто интересно, там же список добывается совершенно иным способом (CreateToolhelp32Snapshot).

    И по поводу артифактов \??\ ни у кого мыслей нет?
  • clickmaker © (23.01.09 16:39) [6]
    > И по поводу артифактов \??\

    насколько я помню, это эквивалент \Device\Harddrive0
  • clickmaker © (23.01.09 16:43) [7]
    вернее даже \Device\Harddrive0\Partition1
  • Игорь Шевченко © (23.01.09 17:11) [8]

    > И по поводу артифактов \??\ ни у кого мыслей нет?


    пишется артефакт

    мысль есть - ?? это корень пространства имен DOS-устройств диспетчера объектов Windows

    Легче стало ?
  • Игорь Шевченко © (23.01.09 17:12) [9]

    > вернее даже \Device\Harddrive0\Partition1


    неа
  • Eraser © (23.01.09 17:35) [10]
    > [0] WanderBuild   (23.01.09 13:10)


    > И второй вопрос: как определить пользователя, под которым
    > работает тот или иной процесс?

    способов получения списка процессов еще, как минимум 2, это доступных из user-mode, возможно и еще есть.
    в вашем случае полезнее способ с использованием WTSEnumerateProcesses.
  • clickmaker © (23.01.09 17:35) [11]
    > Игорь Шевченко ©   (23.01.09 17:12)

    ну хоть первое слово угадал - Device -)
  • clickmaker © (23.01.09 17:36) [12]
    > способов получения списка процессов еще, как минимум 2,
    > это доступных из user-mode

    ага, еще через WMI можно
  • WanderBuild (23.01.09 18:05) [13]
    Всем спасибо за быстрый отклик и ответы, считаю вопрос исчерпанным.

    Специально для Игорь Шевченко:
    Тем не менее тоже спасибо, хоть и слышу в вашем ответе нескрытое презрение. Простите, что обидел Вас неправильным написанием слова, если вам станет от этого хоть чуточку легче, то оговорюсь, что ошибку заметил сразу после того как запостил сообщение, но изменить его я уже не мог.
  • Игорь Шевченко © (23.01.09 18:44) [14]
    Имена, начинающиеся с \??\ (или с \Device\..) называются ядерными именами, потому как внутре ядро работает именно с такими именами и ни с какими другими.

    Тем не менее, почему именно у этих двух процессов такие имена исполняемых файлов - потому что первый (csrss.exe) запускается процессом smss.exe, а второй (winlogon.exe) запускается процессом csrss.exe.
    Отличительная особенность этих процессов состоит в том, что они не используют подсистему Win32 для запуска процессов - в случае smss.exe ее еще не существует, а в случае csrss.exe - он мало того, что ее инициализирует, так еще является и серверной ее частью (в частности, отрабатывает CreateProcess).

    Поэтому в этих процессах используются только вызовы функций Native API, которые отличаются тем, что не понимают в качестве имен файлов строки, начинающиеся на C:\, D:\ и так далее. Зато они понимают имена, которые содержатся в пространстве имен диспетчера объектов Windows (он к тому времени уже проинициализирован, ядерные имена для пути к разделам диска прописаны, драйверы для дисков установлены, в общем, есть все данные, чтобы по ядерному имени добраться до файла).

    Собственно, такое имя можно получить и из привычного имени файла, вызвав RtlPathNameToNtPathName, и, соответственно, наоборот, из ядерного имени файла можно получить (не всегда) привычное.
  • WanderBuild (26.01.09 09:16) [15]
    >>Игорь Шевченко - а теперь огромное спасибо за крайне интересную и весьма редкую информацию. И ещё раз извините.
  • имя (15.09.09 15:02) [16]
    Удалено модератором
  • Игорь © (15.09.09 16:15) [17]

    > WanderBuild   (23.01.09 13:10)  
    >
    > И второй вопрос: как определить пользователя, под которым
    > работает тот или иной процесс?


    type
     TWinStationGetProcessSid = function(hServer: Cardinal;
       ProcessId: Cardinal;
       ProcessStartTime: _FILETIME;
       pProcessUserSid: PByte;
       var dwSidSize: Cardinal): Boolean; stdcall;

    var
     _WinStationGetProcessSid: TWinStationGetProcessSid;

    function _GetOSVersion: Cardinal;
    var
     OSVersionInfo: TOSVersionInfo;
    begin
     Result:= 0;
     FillChar(OSVersionInfo, Sizeof(OSVersionInfo), 0);
     OSVersionInfo.dwOSVersionInfoSize:= SizeOf(OSVersionInfo);
     if GetVersionEx(OSVersionInfo) then
     begin
       if OSVersionInfo.dwPlatformId = VER_PLATFORM_WIN32_NT then
       begin
         if OSVersionInfo.dwMajorVersion = 5 then
         begin
           if OSVersionInfo.dwMinorVersion = 0 then
             Result:= 50
           else if OSVersionInfo.dwMinorVersion = 2 then
             Result:= 52
           else if OSVersionInfo.dwMinorVersion = 1 then
             Result:= 51
         end;
         if OSVersionInfo.dwMajorVersion = 6 then
         begin
           if OSVersionInfo.dwMinorVersion = 0 then
             Result:= 60
           else if OSVersionInfo.dwMinorVersion = 1 then
             Result:= 61;
         end;
       end;
     end;
    end;

    function _EnablePrivilege(Privilege: string): Boolean;
    var
     TokenHandle: THandle;
     TokenPrivileges: TTokenPrivileges;
     ReturnLength: Cardinal;
    begin
     Result:= False;
     if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, TokenHandle) then
     begin
       LookupPrivilegeValue(nil, PChar(Privilege), TokenPrivileges.Privileges[0].Luid);
       TokenPrivileges.PrivilegeCount:= 1;
       TokenPrivileges.Privileges[0].Attributes:= SE_PRIVILEGE_ENABLED;
       if AdjustTokenPrivileges(TokenHandle, False, TokenPrivileges, 0, nil, ReturnLength) then
         Result:= True;
     end;
    end;

    function _GetProcessUserAndDomainName_1(PID: DWORD; var UserName: string; var DomainName: string): Boolean;
    type
     TOKEN_USER = record
       User: TSidAndAttributes;
     end;
     PTOKEN_USER = ^TOKEN_USER;
     TTOKEN_USER = TOKEN_USER;
    var
     hToken: THandle;
     cbBuf: Cardinal;
     ptiUser: PTOKEN_USER;
     snu: SID_NAME_USE;
     Domain, User: array[0..1024] of Char;
     chUser: DWORD;
     chDomain: DWORD;
     hProcess: THandle;
    begin
     Result:= False;
     UserName:= '';
     DomainName:= '';
     chDomain:= 1024;
     chUser:= 1024;
     hProcess:= OpenProcess(MAXIMUM_ALLOWED, False, PID);
     if hProcess <> 0 then
     begin
       if OpenProcessToken(hProcess, MAXIMUM_ALLOWED, hToken) then
       begin
         try
           GetTokenInformation(hToken, TokenUser, nil, 0, cbBuf);
           GetMem(ptiUser, cbBuf);
           if GetTokenInformation(hToken, TokenUser, ptiUser, cbBuf, cbBuf) then
           begin
             if LookupAccountSid(nil, ptiUser.User.Sid, User, chUser, Domain, chDomain, snu) then
             begin
               UserName:= User;
               DomainName:= Domain;
             end;
           end;
           FreeMem(ptiUser);
         finally
           CloseHandle(hToken);
         end;
       end;
     end;
    end;

    function _GetProcessUserAndDomainName_2(PID: DWORD; var UserName: string; var DomainName: string): Boolean;
    var
     hProcess: THandle;
     lpCreationTime, lpExitTime, lpKernelTime, lpUserTime: _FILETIME;
     pProcessUserSid: Pointer;
     User, Domain: PChar;
     cbUser, cbDomain: Cardinal;
     dwSidSize: Cardinal;
     CreateTime: TSystemTime;
    begin
     Result:= False;
     UserName:= '';
     DomainName:= '';
     if _GetOSVersion >= 60 then
       hProcess:= OpenProcess($1000, False, PID)
     else
       hProcess:= OpenProcess(MAXIMUM_ALLOWED, False, PID);
     if hProcess <> 0 then
     begin
       try
         dwSidSize:= 0;
         GetProcessTimes(hProcess, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime);
         FileTimeToSystemTime(lpCreationTime, CreateTime);
         _WinStationGetProcessSid(0, PID, lpCreationTime, nil, dwSidSize);
         GetMem(pProcessUserSid, dwSidSize);
         if _WinStationGetProcessSid(0, PID, lpCreationTime, pProcessUserSid, dwSidSize) then
         begin
           cbUser:= 0;
           cbDomain:= 0;
           LookupAccountSid(nil, pProcessUserSid, nil, cbUser, nil, cbDomain, dwSidSize);
           GetMem(User, cbUser);
           GetMem(Domain, cbDomain);
           Result:= LookupAccountSid(nil, pProcessUserSid, User, cbUser, Domain, cbDomain, dwSidSize);
           SetLength(UserName, cbUser);
           SetLength(DomainName, cbDomain);
           lstrcpy(PChar(UserName), User);
           lstrcpy(PChar(DomainName), Domain);
           FreeMem(User);
           FreeMem(Domain);
         end;
         FreeMem(pProcessUserSid);
       finally
         CloseHandle(hProcess);
       end;
     end;
    end;

    function _GetProcessUserAndDomainName(PID: DWORD; var UserName: string; var DomainName: string): Boolean;
    begin
     if _GetOSVersion > 50 then
       Result:= _GetProcessUserAndDomainName_2(PID, UserName, DomainName)
     else
       Result:= _GetProcessUserAndDomainName_1(PID, UserName, DomainName); //Windows 20000
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
     _EnablePrivilege('SeDebugPrivilege');
     if _GetOSVersion > 50 then
       @_WinStationGetProcessSid:= GetProcAddress(LoadLibrary('winsta.dll'), 'WinStationGetProcessSid');
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    var
     User, Domain: String;
    begin
     _GetProcessUserAndDomainName(1156, User, Domain);
     ShowMessage(Domain + '\' + User);
    end;

  • brother © (16.09.09 04:24) [18]
    > а теперь огромное спасибо за крайне интересную и весьма
    > редкую информацию.

    вот те еще бонусом:)
    http://www.lookinfo.org/2007/08/05/jetapy_zagruzki_windows_xp.html
  • AntiZOG (17.09.09 18:09) [19]

    > SnapProcHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,
    >  0);


    Работает в WOW64, показывает как 64-битные процессы, так и 32-битные.

    Второй в WOW64 показывает только 32-х битные.
 
Конференция "WinAPI" » Как правильней получить список процессов? [D7, WinXP]
Есть новые Нет новых   [134433   +24][b:0][p:0.004]