2016-11-04 7 views
5

管理者権限でアプリケーションを起動すると、そのアプリケーションでShellExecuteを使用して実行されたプログラムは管理者権限を継承します。しかし、それは私が望むものではありません。余分なパーミッションなしで定期的に開始するだけです。 ShellExecuteは、パラメータOPEN(通常)とRUNAS(管理者)を受け入れます。しかし、管理者としてアプリケーションを起動した後にOPENを使用すると、それでもRUNASのように動作します。管理者権限のないアプリケーションの起動

次の例はこれを示しています。正規のアクセス権で起動すると、「Started regular」と表示されます。 「管理者」のために1を押すと、管理者として開始されます。新しく作成したプロンプトで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

返される投票には、正しい方法ではないという質問の答えとして、正しい方法はプロセストークンを取得することです。トークンを取得するためには 'TokenLinkedToken'パラメータで' GetTokenInformation'を呼び出します非溶けたトークン。そのトークンを使用して新しいプロセスを起動します。明らかに、UACが実際に有効になっているかどうかもチェックしてください(http://www.remkoweijnen.nl/blog/2011/08/11/gettokeninformation-with-tokenlinkedtoken-returns-error-1312/)。 – Remko

答えて

3

インストーラを作成するときにこのパズルを解決するために使用しましたが、これは可能な解決策の1つです。

ユーザー権限で動作するバックグラウンドプロセスを作成し、メインアプリケーションと通信し、開始するプログラムを知ることができます。開始プロセスにはユーザー権限が与えられます。

これは次のように動作します。 バックグラウンドプロセスは、通常どおりユーザー権限で起動されます。起動すると、Adminとしてメインプログラムが起動します。バックグラウンドプロセスは隠されており、メインプロセスからのコマンドを待っています。

+0

これは、現在ログインしているセッションのユーザー*としてプロセス*を起動することが唯一の要件であれば、最も簡単な方法です。そうしないと、ログインしているユーザーのパスワードを知らないで保存するための唯一の方法は[ローカルシステムユーザーとしてのAPI呼び出しを介して]です(https://msdn.microsoft.com/en-us/library) /aa383840(v=vs.85).aspx)(つまり、これを呼び出すためのシステムサービスを作成し、 'ShellExecuteEx'をフォローして、ユーザーのトークンを渡す必要があります)。 –

+0

@J ...そうではありません。 –

+0

@DavidHeffernan 'WTSQueryUserToken'(およびトークンを漏らすリスク)を使用する際の注意点として、これが可能なのは驚くべきことです。いずれにしても+1。 –

関連する問題