Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Запуск программы от имени администратора в Delphi без запроса пароля: обход UAC и методы повышения привилегий.

Delphi , ОС и Железо , Windows

 

Введение

В разработке приложений на Delphi часто возникает необходимость выполнить определенные действия с правами администратора, даже если пользователь вошел в систему с обычными правами. В этой статье мы рассмотрим различные методы повышения привилeгий приложения в Windows, фокусируясь на решении проблемы, когда программа знает учетные данные администратора, но не должна запрашивать их у пользователя.

Проблема и основные подходы

Как видно из обсуждения, существует несколько способов решения этой задачи:

  1. Использование ShellExecuteEx с флагом runas
  2. Применение CreateProcessWithLogonW
  3. Использование CreateProcessAsUser
  4. Метод с ImpersonateUser

Каждый из этих методов имеет свои особенности и ограничения, которые мы рассмотрим подробнее.

Метод 1: ShellExecuteEx с флагом runas

function RunAsAdmin(const Path, Params: string): Boolean;
var
  sei: TShellExecuteInfo;
begin
  try
    FillChar(sei, SizeOf(sei), 0);
    sei.cbSize := SizeOf(sei);
    sei.fMask := SEE_MASK_FLAG_DDE_USE_AGENT or SEE_MASK_FLAG_NO_UI;
    sei.lpVerb := 'runas';
    sei.lpFile := PChar(Path);
    sei.lpParameters := PChar(Params);
    sei.nShow := SW_SHOWNORMAL;
    Result := ShellExecuteEx(@sei);
  except
    Result := False;
  end;
end;

Недостатки: Этот метод все равно запрашивает подтверждение UAC, что не соответствует требованиям задачи.

Метод 2: CreateProcessWithLogonW

function RunAsAdminWithPassword(UserName, Password, Domain, AppPath: string): Integer;
var
  SI: TStartupInfoW;
  PI: TProcessInformation;
begin
  Result := 0;
  ZeroMemory(@SI, SizeOf(SI));
  SI.cb := SizeOf(SI);
  if CreateProcessWithLogonW(
        PWideChar(UserName),
        PWideChar(Domain),
        PWideChar(Password),
        LOGON_WITH_PROFILE,
        nil,
        PWideChar(AppPath),
        CREATE_NEW_CONSOLE,
        nil,
        nil,
        SI,
        PI) then
  begin
    CloseHandle(PI.hThread);
    CloseHandle(PI.hProcess);
  end
  else
    Result := GetLastError;
end;

Особенности: Этот метод не требует прав администратора для вызова, но приложение должно находиться в общем каталоге (например, C:\Users\Public).

Метод 3: Имперсонализация пользователя

type
  TImpersonateUser = class
  private
    FUserToken: THandle;
    FErrorCode: DWORD;
  public
    constructor Create;
    destructor Destroy; override;
    function Logon(const UserName, Domain, Password: string): Boolean;
    procedure Logoff;
    property ErrorCode: DWORD read FErrorCode;
  end;

constructor TImpersonateUser.Create;
begin
  inherited;
  FUserToken := 0;
  FErrorCode := 0;
end;

destructor TImpersonateUser.Destroy;
begin
  Logoff;
  inherited;
end;

function TImpersonateUser.Logon(const UserName, Domain, Password: string): Boolean;
var
  LoggedOn: Boolean;
begin
  Result := False;
  Logoff;

  if UserName = '' then
  begin
    FErrorCode := ERROR_BAD_ARGUMENTS;
    Exit;
  end;

  if Domain <> '' then
    LoggedOn := LogonUser(PChar(UserName), PChar(Domain), PChar(Password),
      LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, FUserToken)
  else
    LoggedOn := LogonUser(PChar(UserName), PChar(Domain), PChar(Password),
      LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50, FUserToken);

  if not LoggedOn then
  begin
    FErrorCode := GetLastError;
    Exit;
  end;

  if not ImpersonateLoggedOnUser(FUserToken) then
  begin
    FErrorCode := GetLastError;
    Exit;
  end;

  FErrorCode := ERROR_SUCCESS;
  Result := True;
end;

procedure TImpersonateUser.Logoff;
begin
  if FUserToken <> 0 then
  begin
    RevertToSelf;
    CloseHandle(FUserToken);
    FUserToken := 0;
  end;
end;

Применение:

var
  Impersonator: TImpersonateUser;
begin
  Impersonator := TImpersonateUser.Create;
  try
    if Impersonator.Logon('AdminUser', 'Domain', 'Password') then
    begin
      try
        // Выполняем действия с правами администратора
      finally
        Impersonator.Logoff;
      end;
    end
    else
      ShowMessage('Ошибка входа: ' + IntToStr(Impersonator.ErrorCode));
  finally
    Impersonator.Free;
  end;
end;

Метод 4: Использование CreateProcessAsUser

function CreateProcessAsAdmin(const CommandLine: string): Boolean;
var
  Token: THandle;
  StartInfo: TStartupInfo;
  ProcInfo: TProcessInformation;
begin
  Result := False;
  if not OpenProcessToken(GetCurrentProcess, TOKEN_ALL_ACCESS, Token) then Exit;

  try
    ZeroMemory(@StartInfo, SizeOf(StartInfo));
    StartInfo.cb := SizeOf(StartInfo);
    StartInfo.lpDesktop := 'winsta0\default';
    StartInfo.dwFlags := STARTF_USESHOWWINDOW;
    StartInfo.wShowWindow := SW_SHOW;

    if CreateProcessAsUser(Token, nil, PChar(CommandLine), nil, nil, False,
      CREATE_NEW_CONSOLE, nil, nil, StartInfo, ProcInfo) then
    begin
      CloseHandle(ProcInfo.hThread);
      CloseHandle(ProcInfo.hProcess);
      Result := True;
    end;
  finally
    CloseHandle(Token);
  end;
end;

Решение с учетом всех требований

Наиболее подходящим решением, учитывающим все требования (не запрашивать пароль, не требовать дополнительных файлов, работать без установки), является комбинация методов:

  1. Использование CreateProcessWithLogonW для запуска процесса с правами администратора
  2. Предварительное копирование исполняемого файла в общий каталог
procedure CopyFileToPublic(const SourceFile: string);
var
  PublicPath: string;
begin
  PublicPath := GetEnvironmentVariable('PUBLIC') + '\' + ExtractFileName(SourceFile);
  if not FileExists(PublicPath) or (FileAge(SourceFile) <> FileAge(PublicPath)) then
    CopyFile(PChar(SourceFile), PChar(PublicPath), False);
end;

function RunAsAdminSilently(const UserName, Password, Domain, AppPath: string): Boolean;
var
  PublicAppPath: string;
begin
  PublicAppPath := GetEnvironmentVariable('PUBLIC') + '\' + ExtractFileName(AppPath);
  CopyFileToPublic(AppPath);

  Result := RunAsAdminWithPassword(UserName, Password, Domain, PublicAppPath) = 0;
end;

Альтернативные решения

  1. Использование планировщика задач: Создание задачи с правами администратора и запуск ее программно.
  2. Сервис Windows: Создание сервиса с правами SYSTEM, который будет выполнять необходимые действия.
  3. Использование API NtCreateToken: Более сложный метод, требующий глубоких знаний Windows API.

Заключение

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

При реализации таких механизмов следует также учитывать политики безопасности организации и требования к защите информации. В некоторых случаях запрос учетных данных

Создано по материалам из источника по ссылке.

В статье рассматриваются методы запуска программы от имени администратора в Delphi без запроса пароля, включая обход UAC и повышение привилегий с использованием различных API-функций Windows.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Windows ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-06-13 19:45:13/0.0065350532531738/0