3

I'm trying to get PIDs of processes which belongs to the current user but I don't know how to check the process owner.

This is my code (the user's checking condition is missing):

uses
  TlHelp32, ...;

type
  TCardinalArray = array of Cardinal;

function GetCurrentUserPIDs(const AProcessName : string) : TCardinalArray;
var
  ContinueLoop: boolean;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  SetLength(Result, 0);
  FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
  ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
  while(ContinueLoop) do
  begin
    if(SameText(FProcessEntry32.szExeFile, AProcessName)) then
    begin
      if((* is this my process? *)) then
      begin
        SetLength(Result, Length(Result) + 1);
        Result[Length(Result) - 1] := FProcessEntry32.th32ProcessID;
      end;
    end;
    ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;
Fabrizio
  • 7,603
  • 6
  • 44
  • 104
  • http://stackoverflow.com/questions/559356/how-do-i-get-the-sid-session-of-an-arbitrary-process/14845528 – Sertac Akyuz Nov 18 '16 at 12:32
  • @SertacAkyuz: Thank you, if I clearly understood, I should use `OpenProcess`. if possible, I'll avoid using that function for avoiding access denied problems seen [here](http://stackoverflow.com/questions/40630528/is-possible-to-get-full-file-name-of-a-process-for-which-i-have-no-permissions). Are there other ways? Task manager shows the user who the process belongs – Fabrizio Nov 18 '16 at 16:53
  • 2
    I think you can use OpenProcessToken with GetTokenInformation to verify a process belongs to the same user that's running the application. Task manager only reports user name when it's running elevated. Otherwise processes that aren't owned by the current user are shown blank for user name. Anyway, you can't avoid access_denied for which your process does not have access. – Sertac Akyuz Nov 18 '16 at 17:02

1 Answers1

4

I found a GetUserAndDomainFromPID function which allows to easily accomplish the task.

As Sertac Akyuz suggested, the function uses OpenProcessToken and GetTokenInformation. It also uses LookupAccountSid:

uses
  TlHelp32;

type
  PTOKEN_USER = ^TOKEN_USER;
  _TOKEN_USER = record
    User: TSidAndAttributes;
  end;
  TOKEN_USER = _TOKEN_USER;

function GetUserAndDomainFromPID(ProcessId: DWORD;
  var User, Domain: string): Boolean;
var
  hToken: THandle;
  cbBuf: Cardinal;
  ptiUser: PTOKEN_USER;
  snu: SID_NAME_USE;
  ProcessHandle: THandle;
  UserSize, DomainSize: DWORD;
  bSuccess: Boolean;
begin
  Result := False;
  ProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION, False, ProcessId);
  if ProcessHandle <> 0 then
  begin
  //  EnableProcessPrivilege(ProcessHandle, 'SeSecurityPrivilege', True);
    if OpenProcessToken(ProcessHandle, TOKEN_QUERY, hToken) then
    begin
      bSuccess := GetTokenInformation(hToken, TokenUser, nil, 0, cbBuf);
      ptiUser  := nil;
      while (not bSuccess) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) do
      begin
        ReallocMem(ptiUser, cbBuf);
        bSuccess := GetTokenInformation(hToken, TokenUser, ptiUser, cbBuf, cbBuf);
      end;
      CloseHandle(hToken);

      if not bSuccess then
      begin
        Exit;
      end;

      UserSize := 0;
      DomainSize := 0;
      LookupAccountSid(nil, ptiUser.User.Sid, nil, UserSize, nil, DomainSize, snu);
      if (UserSize <> 0) and (DomainSize <> 0) then
      begin
        SetLength(User, UserSize);
        SetLength(Domain, DomainSize);
        if LookupAccountSid(nil, ptiUser.User.Sid, PChar(User), UserSize,
          PChar(Domain), DomainSize, snu) then
        begin
          Result := True;
          User := StrPas(PChar(User));
          Domain := StrPas(PChar(Domain));
        end;
      end;

      if bSuccess then
      begin
        FreeMem(ptiUser);
      end;
    end;
    CloseHandle(ProcessHandle);
  end;
end;

Then I've written a function for getting the current windows username (It uses GetUserName):

const
  UNLEN = 256; // Maximum user name length

function GetWindowsUsername: string;
var
  UserName : string;
  UserNameLen : Dword;
begin
  UserNameLen := UNLEN;
  SetLength(UserName, UserNameLen) ;
  if GetUserName(PChar(UserName), UserNameLen)
  then Result := Copy(UserName, 1, UserNameLen - 1)
  else Result := '';
end;

The following function returns an array composed by all ids of processes who belongs to the current user (Note that processes are filtered by process name):

uses
  TlHelp32;

type
  TCardinalArray = array of Cardinal;

function GetCurrentUserPIDs(const AProcessName : string) : TCardinalArray;
var
  ContinueLoop: boolean;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
  UserName : string;
  DomainName : string;
  CurrentUser : string;
begin
  CurrentUser := GetWindowsUsername();

  SetLength(Result, 0);
  FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
  ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
  while(ContinueLoop) do
  begin
    if(SameText(FProcessEntry32.szExeFile, AProcessName)) then
    begin
      if(GetUserAndDomainFromPID(FProcessEntry32.th32ProcessID, UserName, DomainName)) then
      begin
        if(UserName = CurrentUser) then
        begin
          SetLength(Result, Length(Result) + 1);
          Result[Length(Result) - 1] := FProcessEntry32.th32ProcessID;
        end;
      end;
    end;
    ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;
Fabrizio
  • 7,603
  • 6
  • 44
  • 104