2016-11-04 1 views
5

После того, как вы запустили приложение с правами администратора, программы, выполненные с использованием ShellExecute в этом приложении, наследуют разрешение администратора. Но это не то, что я хочу: он просто должен запускаться регулярно без дополнительных разрешений. ShellExecute принимает параметр OPEN (обычный) и RUNAS (Администратор). Но если вы используете OPEN после того, как вы запустили приложение в качестве администратора, оно все равно действует как RUNAS.Запуск приложения без прав администратора

Следующий пример демонстрирует это: если вы запустите его с помощью обычных разрешений, то он говорит: «Начал обычный». Как только вы нажмете 1 для «admin», он начнется с администратора. Если вы нажмете 2 во вновь созданном приглашении, он не запустит приглашение «регулярное», но снова появится приглашение «Администратор».

Я нашел что-то о некоторых параметрах в RUNAS (https://superuser.com/a/374866), но они не могут быть переданы в ShellExecute. Есть идеи?

program WindowsPrivilegeTest; 
{$APPTYPE CONSOLE} 
{$R *.res} 

uses 
    System.SysUtils, 
    Winapi.Windows, 
    Winapi.ShellAPI; 

function CheckTokenMembership(TokenHandle: THANDLE; SidToCheck: Pointer; var 
    IsMember: BOOL): BOOL; stdcall; external advapi32 name 'CheckTokenMembership'; 

// Source: http://stackoverflow.com/a/28572886/1870208 
function IsAdministrator: Boolean; 
var 
    psidAdmin: Pointer; 
    B: BOOL; 
const 
    SECURITY_NT_AUTHORITY: TSidIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5)); 
    SECURITY_BUILTIN_DOMAIN_RID = $00000020; 
    DOMAIN_ALIAS_RID_ADMINS  = $00000220; 
    SE_GROUP_USE_FOR_DENY_ONLY = $00000010; 
begin 
    psidAdmin := nil; 
    try 
    Win32Check(AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2, 
     SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, 
     psidAdmin)); 

    if CheckTokenMembership(0, psidAdmin, B) then 
     Result := B 
    else 
     Result := False; 
    finally 
    if psidAdmin <> nil then 
     FreeSid(psidAdmin); 
    end; 
end; 

var 
    lLine : String; 
    lOperation : PChar; 
begin 
    try 
    if IsAdministrator then 
    begin 
     Writeln('Started as administrator'); 
    end 
    else 
    begin 
     Writeln('Started regular'); 
    end; 

    while True do 
    begin 
     Writeln(''); 
     Writeln('How to start? 1 = admin, 2 = regular user. Type number and press enter'); 
     ReadLn(lLine); 
     lOperation := ''; 

     if lLine = '1' then 
     begin 
     lOperation := 'RUNAS'; 
     end 
     else 
     if lLine = '2' then 
     begin 
     lOperation := 'OPEN'; 
     end; 

     if lOperation <> '' then 
     begin 
     ShellExecute(0, lOperation, PChar(ParamStr(0)), nil, nil, SW_SHOWNORMAL); 
     Break; 
     end; 
    end; 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
end. 
+0

Проголосовало за повторное открытие, поскольку ответ в вопросе, на который ссылается, является неправильным способом, правильным способом было бы получить токен процесса, вызов 'GetTokenInformation' с параметром« TokenLinkedToken », чтобы получить неэлавированный токен. Используйте этот токен для запуска нового процесса. Очевидно, также проверить, действительно ли UAC включен (http://www.remkoweijnen.nl/blog/2011/08/11/gettokeninformation-with-tokenlinkedtoken-returns-error-1312/). – Remko

ответ

3

Я использовал эту головоломку при создании установщика, вот одно из возможных решений.

Идея состоит в том, чтобы создать фоновый процесс, который запускается с пользовательскими привилегиями, ваше основное приложение общается с ним и позволяет узнать, для чего начать программу - запущенный процесс будет иметь пользовательские привилегии.

Он должен работать следующим образом: Фоновый процесс запускается, как обычно, с привилегиями пользователя. При запуске он запускает вашу основную программу в качестве администратора. Фоновый процесс остается скрытым и ждет команды из основного процесса.

+0

Это, безусловно, самый простой способ, если единственным требованием является запуск процессов * в качестве пользователя текущего входа в систему *. В противном случае единственным способом получить токен для входа в систему, не зная или сохраняя свой пароль, является [через вызовы API в качестве пользователя локальной системы] (https://msdn.microsoft.com/en-us/library /aa383840(v=vs.85).aspx) (т. е. вам нужно написать системную услугу, чтобы вызвать это, а затем следить за «ShellExecuteEx», передавая токен пользователя). –

+0

@J ... Не совсем, см. Обман –

+0

@DavidHeffernan Удивляет, что это возможно с учетом предостережений относительно использования 'WTSQueryUserToken' (и рисков утечки токена) даже из системного контекста, которому это запрещено. +1 для этого, в любом случае. –

 Смежные вопросы

  • Нет связанных вопросов^_^