» Как узнать, запущена программа с правами администратора или нет Borland Delphi. . . Блог программистов


Блог программистов






20105 Мар

Как узнать, запущена программа с правами администратора или нет

Иногда возникает задача узнать, запущена ли программа под администраторской учеткой или же обычного пользователя. Для чего это нужно? Ну, например мы написали крутую софтину, выполняющую некие действия с системой (например свой собственный редактор реестра). Для редактирования некоторых веток (например HKEY_LOCAL_MACHINE), требуются права админа. А вдруг программа запущена без соответствующих привилегий, то тогда мы ничего не сможем сделать — это раз, система нам будет показывать непонятные на первый взгляд ошибки — это два. Одна из самых частых в такой ситуации — ошибка с кодом 5 (ERROR_ACCESS_DENIED). С проверкой на «вшивость» можно говорить пользователю, что нужно запустить программу с правами администратора и смело закрываться.

Погуглив, не нашел ничего подходящего. Может просто плохо искал?
Обратившись к крутой справочной системе, входящей в состав Delphi 7, был обнаружен кусок кода, который как раз за это отвечает. Но… Он на Си. Ну ничего, попыхтев немного мне всетаки удалось переписать его на Delphi.

Отступление:
исходник функции на Си можно найти в Help -> Windows SDK -> Поиск.
Если запускаете поиск первый раз, то нужно выбрать пункт «Обеспечить максимальные возможности поиска».
Если запускаете не первый раз, то нужно нажать на кнопку «Перестроить…» и выбрать пункт «Обеспечить максимальные возможности поиска».
После этого в поле поиска (1 поле) ввести «admin», а в результатах поиска (2 поле) выбрать первый пункт «admin». И в третьем поле, там где нас просят выбрать нужный раздел, выбираем раздел «Determining Whether the User is an Administrator». Жмем «Показать» и копипастим код:)

Код на Delphi:

function isAdmin: Boolean;
{ Объявление констант, которых в delphi я не нашел }
const
  SECURITY_BUILTIN_DOMAIN_RID = $00000020;
  DOMAIN_ALIAS_RID_ADMINS = $00000220;

var
  hProcess, hAccessToken: Cardinal;
  InfoBuffer: array [0..1023] of Char;
  ptgGroups: PTokenGroups;
  dwInfoBufferSize: DWORD;
  psidAdmins: PSID;
  siaNtAuthority: TSidIdentifierAuthority;
  x: UINT;
begin
  { Получаем Token нашего приложения }
  hProcess := GetCurrentProcess();
  {
    Обнуляем память и заносим в последний элемент 5.
    Это нужно для того что бы "формат" данных выглядел так [0, 0, 0, 0, 0, 5]
    тупым присваиванием не прокатило.
    Откуда я это знаю? Подсмотрел в VC, как и те две константы, что объявлены
    в начале:)
  }
  ZeroMemory(@siaNtAuthority.Value, sizeof(Char)*6);
  siaNtAuthority.Value[5] := 5;
  { даем указатель ptgGroups на InfoBuffer }
  ptgGroups := PTokenGroups(@InfoBuffer);

  { Попытка открыть процесс и получить инфу о нем }
  if not OpenProcessToken(hProcess, TOKEN_READ, hAccessToken) then
  begin
    Result := false;
    Exit;
  end;

  { Пытаемся получить информаци о првах доступа, одновременно заполная все что
    нужно }
  if not (getTokenInformation(hAccessToken, TokenGroups, @InfoBuffer,
    High(InfoBuffer) + 1, dwInfoBufferSize)) then
  begin
    Result := false;
    Exit;
  end;

  { Распределяем и инициализируем идентификатор безопасности (SID) с восьмью
    полномочиями }
  AllocateAndInitializeSid(siaNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
    DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, psidAdmins);

  { Тут вроде происходит собственно проверка на то, является ли процесс запущенный
    с правами админа }
  for x := 0 to ptgGroups.GroupCount - 1 do
    if EqualSid(psidAdmins, ptgGroups.Groups[x].Sid) then
    begin
      FreeSid(psidAdmins);
      Result := true;
      Exit;
    end;

  FreeSid(psidAdmins);
  Result := false;
end;

Воть. За коменты сильно не бейте, писал от себя, так, как я это понимаю +переводы SDK, весьма скудными знаниями английского((
Надеюсь статейка будет полезна. (на форуме где то видел похожую тему).

Комментарии

  1. 1 апреля, 2010 | 14:11

    спасибо за информацию! очень полезная.. :mrgreen: :mrgreen: :mrgreen:

  2. 5 апреля, 2010 | 05:05

    Есть еще один очень тупой, но очень простой метод, который позволяет узнать это на много быстрее. Нужно попробовать создать файл в любой защищенной области в файловой системе или в реестре. Если ошибка, то отваливаем. Метод в заметке лучше и позволяет узнать более точно, под кем работает, но в большинстве случаев, достаточно ответа да/нет.

  3. 8 апреля, 2010 | 15:02

    Статья ваша действительно оказалась полезной

  4. psycho-coder
    10 апреля, 2010 | 15:09

    2Михаил
    Если у пользователя стоят права «Опытный пользователь», то создать файл в защищенной области можно, но изменять нельзя. Тем более, может возникнуть ситуация когда файл с таким именем существует и не будет доступа создать файл.
    Некоторые антивирусы и фаеры, «следят» за реестром. Он (защитное ПО) спросит «Разрешить создать ключ или нет?», кто-то может ответить что нет, вывалится ошибка о не достаточном доступе и прога скажет, что нужно запускаться от админа, а она может уже запущена от админа!

    Так что я думаю этот способ не подойдет:)

  5. psycho-coder
    14 апреля, 2010 | 11:34

    Чуть попозже, все таки почитаю конкретно про функции которые были использованы и подправлю коменты.

  6. yugovoo
    15 апреля, 2010 | 09:14

    под вин7 почемуто всегда выдает, что нет прав админа 😕 ❗

  7. psycho-coder
    18 апреля, 2010 | 16:38

    2yugovoo
    Опиши процесс, как ты запускаешь прогу.
    К сожалению, не могу проверить под вин7(

  8. 20 апреля, 2010 | 20:27

    Большое спасибо, как раз это и искал, а то никак не мог хост изменить…

  9. Prigs
    7 мая, 2010 | 13:26

    const
    SECURITY_NT_AUTHORITY: TSIDIdentifierAuthority =
    (Value: (0, 0, 0, 0, 0, 5));
    SECURITY_BUILTIN_DOMAIN_RID = $00000020;
    DOMAIN_ALIAS_RID_ADMINS = $00000220;
    .
    .
    .
    function TRegistration.IsAdmin: Boolean;
    var
    hAccessToken: THandle;
    ptgGroups: PTokenGroups;
    dwInfoBufferSize: DWORD;
    psidAdministrators: PSID;
    x: Integer;
    bSuccess: BOOL;
    begin
    Result := False;
    bSuccess := OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True,
    hAccessToken);
    if not bSuccess then
    begin
    if GetLastError = ERROR_NO_TOKEN then
    bSuccess := OpenProcessToken(GetCurrentProcess, TOKEN_QUERY,
    hAccessToken);
    end;
    if bSuccess then
    begin
    GetMem(ptgGroups, 1024);
    bSuccess := GetTokenInformation(hAccessToken, TokenGroups,
    ptgGroups, 1024, dwInfoBufferSize);
    CloseHandle(hAccessToken);
    if bSuccess then
    begin
    AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
    SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
    0, 0, 0, 0, 0, 0, psidAdministrators);
    {$R-}
    for x := 0 to ptgGroups.GroupCount — 1 do
    if EqualSid(psidAdministrators, ptgGroups.Groups[x].Sid) then
    begin
    Result := True;
    Break;
    end;
    {$R+}
    FreeSid(psidAdministrators);
    end;
    FreeMem(ptgGroups);
    end;
    end;
    Точно работает по Win7 и под все семейство NT

  10. Alla
    14 февраля, 2011 | 13:06

    Недавно Станислав Подгорный(технический директор), в сотрудничестве с Александром Вербовским(PHP разработчик) разработали уникальное приложение под названием “My Market Value” , позволяющее проследить за процессами на рынке труда и соизмерить свои силы с ожиданиями по зароботной плате.
    Даное приложение являеться новинкой в мире IT и не имеет аналогов в Украине и за рубежом. Благодаря уникальной разработке двух ярких индивидуальностей и истинных профессионалов своего дела, разработчики нашей страны получили возможность реально оценивать свои силы в сфере IT.
    Оцените свои возможности, проследите за стремительно изменяющимися технологиями, освойте новые направления и творчески подходите к своим возможностям.
    Теперь, оценить свои знания и навыки легко – несколько кликов – и вы в мире IT, в мире несоизмеримых возможностей и перспектив.

    http://apps.facebook.com/mymarketvalue

    Сделайте шаг навстречу своей мечте, получите работу, на которую вы заслуживаете и оцените свои таланты по достоинству!

  11. 24 февраля, 2012 | 21:11

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

  12. 23423
    27 марта, 2012 | 09:27

    23432432432
    2343242343243

  13. ВЛад
    12 мая, 2012 | 19:04

    проголосуйте на стене
    широков или измайлов?
    http://vk.com/id17072313

  14. Андрей Гром
    7 февраля, 2015 | 17:26

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