【问题标题】:Start application without administrator rights [duplicate]在没有管理员权限的情况下启动应用程序[重复]
【发布时间】:2017-03-18 07:51:28
【问题描述】:

一旦您以管理员权限启动应用程序,在该应用程序中使用ShellExecute 执行的程序将继承管理员权限。但这不是我想要的:它只需要在没有额外权限的情况下定期启动。 ShellExecute 接受参数OPEN(常规)和RUNAS(管理员)。但是如果您在以管理员身份启动应用程序后使用OPEN,它的行为仍然类似于RUNAS。

以下示例演示了这一点:如果您使用常规权限启动它,它会显示“常规启动”。一旦按 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.

【问题讨论】:

  • 投票重新打开,因为所提到的问题中的答案不是正确的方法,正确的方法是获取进程令牌,调用GetTokenInformation 和@987654332 @ 参数以获取未提升的令牌。使用该令牌启动新进程。显然还要检查是否真的启用了 UAC (remkoweijnen.nl/blog/2011/08/11/…)。

标签: delphi delphi-xe7


【解决方案1】:

我以前在创建安装程序时解决了这个难题,这是可能的解决方案之一。

这个想法是创建一个以用户权限运行的后台进程,您的主应用程序与其通信并让它知道要启动什么程序 - 启动的进程将具有用户权限。

它应该像这样工作: 后台进程照常启动,具有用户权限。启动时,它会以管理员身份启动您的主程序。后台进程保持隐藏状态并等待来自主进程的命令。

【讨论】:

  • 如果唯一的要求是作为当前登录会话的用户启动进程,这当然是最简单的方法。否则,在不知道或存储其密码的情况下,为登录用户获取令牌的唯一方法是via API calls as the local system user(即:您需要编写一个系统服务来调用它,然后跟进ShellExecuteEx,通过在用户的令牌中)。
  • @J... 不完全是,看骗子
  • @DavidHeffernan 令人惊讶的是,考虑到使用 WTSQueryUserToken 的注意事项(以及泄露令牌的风险),即使从它被限制的系统上下文来看,这也是可能的。在任何情况下都为此 +1。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多