1

I'm trying to open a process running on another user account, when I run my application as Administrator (right click > run as admin), I successfully get it, but I need the app to self-elevate the privilege, this is what I have so far:

procedure ChangePrivilege;
var
  NewState: TTokenPrivileges;
  luid: TLargeInteger;
  hToken: THandle;
  ReturnLength: DWord;
begin
  if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hToken) then
  begin
   if LookupPrivilegeValue(nil, PChar('SeDebugPrivilege'), luid) then
   begin
    NewState.PrivilegeCount:= 1;
    NewState.Privileges[0].Luid := luid;
    NewState.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
    if AdjustTokenPrivileges(hToken, False, NewState, 0, nil, ReturnLength) then
      WriteLn('Privileged');
   end;
    CloseHandle(hToken);
  end;
end;

This function executes nicely and I get the "Privileged" output, but on my OpenProcess, I don't see the process name running on the other account:

procedure ProcEnum;
var
  Snapshot, ProcessPID: THandle;
  pe: TProcessEntry32;
begin
  Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
  try
    pe.dwSize := SizeOf(pe);
    if Process32First(Snapshot, pe) then
      while Process32Next(Snapshot, pe) do
      begin
        try
          ProcessPID:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_OPERATION or
                                        PROCESS_VM_READ, false, pe.th32ProcessID);

          if (ProcessPID <> 0) then
            WriteLn(pe.szExeFile);
        finally
          ProcessPID:= 0;
          CloseHandle(ProcessPID);
        end;
      end;
  finally
    CloseHandle(Snapshot);
  end;
end;

Is there something that I'm missing? I just tried this same code on Windows 2008 Server, and it worked. But while working on Windows 10, the problem persists.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
LessStress
  • 187
  • 2
  • 17
  • 1
    After Process32First you already have first record to process, but you skip it and call Process32Next. And try to output szExeFile for every record, you do it only if OpenProcess is succesfull. – Andrei Galatyn Dec 29 '15 at 13:27
  • Yes... My idea is to write the szExeFile only if the OpenProcess is succesfull... And I don't see the processes running on other user accounts. Only if right click > run as admin – LessStress Dec 29 '15 at 13:33
  • That seems to work. Looks like there's a difference between your actual code and what you've posted here. – Ondrej Kelle Dec 29 '15 at 13:40
  • No, the code is identical. I'm just running the ProcEnum inside a timer, but I dont know if this makes any difference... I'm in a Windows 10 machine. – LessStress Dec 29 '15 at 13:42
  • Trying on Windows 7, I get exe names of processes running under other accounts. I get the symptoms you describe (`OpenProcess` returning `0`, therefore no exe name for processes running under other accounts) only if I *don't* enable `SeDebugPrivilege`. – Ondrej Kelle Dec 29 '15 at 13:48
  • Looks perfect for you so... Strange, not sure if MS changed something for Win10... – LessStress Dec 29 '15 at 13:56
  • Tested in a Win Server 2008 and is working... – LessStress Dec 29 '15 at 14:12
  • 1
    Have you tried to call GetLastError to see if the error is actually ERROR_SUCCESS ? Because it could be ERROR_NOT_ALL_ASSIGNED – EProgrammerNotFound Dec 29 '15 at 15:04
  • You will need to run as administrator even the task manager does. The taskManager kills itself and restart in an elevated mode – EProgrammerNotFound Jan 01 '16 at 20:12
  • Either restart your program with runAs verb using shellExecute case your app needs this for a specific functionality or add a [manifest](http://stackoverflow.com/a/2818776/2087187) – EProgrammerNotFound Jan 01 '16 at 20:25

2 Answers2

1

1. Try to take a look on Enabling and Disabling Privileges in C++. From this it seems you must change the ChangePrivilege to specify the size of the TTokenPrivileges in AdjustTokenPrivileges. Right now its 0. To catch this type of problem, I think this is why they suggest to double check that GetLastError <> ERROR_NOT_ALL_ASSIGNED. Hopefully these modifications will help:

procedure ChangePrivilegeModified;
var
  NewState: TTokenPrivileges;
  luid: TLargeInteger;
  hToken: THandle;
  ReturnLength: DWord;
begin
  if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hToken) then
  begin
   if LookupPrivilegeValue(nil, PChar('SeDebugPrivilege'), luid) then
   begin
    NewState.PrivilegeCount:= 1;
    NewState.Privileges[0].Luid := luid;
    NewState.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
    if AdjustTokenPrivileges(hToken, False, NewState, SizeOf(TTokenPrivileges), nil, ReturnLength) then
    begin
      if GetLastError = ERROR_NOT_ALL_ASSIGNED then
        WriteLn('Change privilege failed: Not all assigned')
      else
        WriteLn('Privileged');
    end;
   end;
    CloseHandle(hToken);
  end;
end;

2. If the OpenProcess still fails, then from documentation OpenProcess function, there is access rights considerations, which are elaborated in Process Security and Access Rights. To troubleshoot the OpenProcess, try to narrow down the number of permissions to PROCESS_QUERY_LIMITED_INFORMATION = $1000:

ProcessPID:= OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, false, pe.th32ProcessID );

Does this succeed?

  • Yeah, I did what you said, and now I'm getting the failed message... What can be done here? Nothing? Considering that I'm running this on an Administrator account, but not right click > run as admin... – LessStress Dec 30 '15 at 13:37
  • @LessStress I found this post talking about Its a privilege that must be set (see answer two for manual way) : https://social.msdn.microsoft.com/Forums/en-US/0f394922-4d3d-4c00-8bc1-88aeeeedd843/how-to-add-a-user-to-debug-users-group?forum=netfxbcl – Christian Holm Jørgensen Dec 30 '15 at 18:48
0

When Process32First returns, it contains the information about the first process in the snapshot. You ignore that process by calling Process32Next. Perhaps that first process, the one you fail to process, is the one you are looking for.

You have other problems in the code:

  1. You don't check return values for errors in in consistent way.
  2. You mis-name a process handle as a PID.
  3. You leak the process handles because you do not close them. Instead you call CloseHandle(0) repeatedly.

And there are probably more errors that I've not spotted.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I fixed the leak process handles and the first process ignore... And I answered the answer from Christian with more details, check if you can help from there too. Thank you. – LessStress Dec 30 '15 at 13:38