пятница, 21 июня 2019 г.

Задействуем UAC в приложениях написанных на Delphi 7

UAC – это Контроль Учетных Записей (Wikipedia), используется для повышения привилегий в том случае если вашему приложению это необходимо. Появился в Windows Vista и присутствует Windows 7, 8, 10. Необходимо убедится в том, что UAC включен. В Windows 7 это можно проверить, открыв «Панель управления» - «Учетные записи пользователей» - «Изменение параметров контроля учетных записей» - убедится, что установлен уровень «По умолчанию» (Смотрите рисунок 1).

 Рисунок 1. Включение UAC в Windows 7

Создадим тестовое приложение, которое будет писать в реестр Windows выбираемые из списка значения, правда путь куда мы будем записывать значения требуют повышения привилегий. Откроем Delphi 7 и создадим новый проект. Присвоим ему имя p12.dpr. Сохраним основной модуль под именем p12_unit.pas. Чтобы научить наше приложение работать с UAC, необходимо создать в папке проекта файл манифеста, назовём его Win7UAC.manifest. Содержимое файла следующее:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity type="win32" name="App" version="3.1.0.0" processorArchitecture="*"/>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" publicKeyToken="6595b64144ccf1df" language="*" processorArchitecture="*"/>
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
        </requestedPrivileges>
    </security>
  </trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!--The ID below indicates application support for Windows Vista -->
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
      <!--The ID below indicates application support for Windows 7 -->
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <!--The ID below indicates application support for Windows 8 -->
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> 
      <!--The ID below indicates application support for Windows 8.1 -->
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> 
      <!--The ID below indicates application support for Windows 10 --> 
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
    </application>
  </compatibility></assembly>

Основным, важным моментом в файле манифеста является строчка кода:

 <requestedPrivileges>
        <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
 </requestedPrivileges>

Параметр level со значением requireAdministrator указывает на то, что нашему приложению для работы требуются права администратора.  Следующими строчками кода мы указываем с какими операционными системами наше приложение будет совместимо:

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!--The ID below indicates application support for Windows Vista -->
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
      <!--The ID below indicates application support for Windows 7 -->
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <!--The ID below indicates application support for Windows 8 -->
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> 
      <!--The ID below indicates application support for Windows 8.1 -->
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> 
      <!--The ID below indicates application support for Windows 10 --> 
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
    </application>
 </compatibility>

Далее нам необходимо в каталоге проекта создать файл ресурсов компиляции с именем Win7UAC.rc. Содержимое файла компиляции будет следующее:

1 24 "Win7UAC.manifest"

То есть мы в качестве ресурсов нашего приложения указываем наш файл манифеста.

Файл ресурсов компиляции Win7UAC.rc необходимо скомпилировать при помощи компилятора ресурсов brcc32.exe, этот компилятор ресурсов расположен в каталоге, где расположены бинарные файлы Delphi, у меня это каталог D:\Programs\Delphi7\Files\Delphi7\Bin. Убедитесь, что данный каталог добавлен в переменную окружения Path. Запустите командную строку Windows, перейдите в каталог проекта и выполните команду компиляции ресурсов (Смотрите рисунок 2).

Рисунок 2. Запуск компилятора ресурсов

brcc32.exe Win7UAC.rc

В качестве результата в каталоге проекта вы получите файл ресурсов Win7UAC.RES, который необходимо в файле проекта p12.dpr подключить. Смотрите код ниже:

program p12;

uses
  Forms,
  p12_unit1 in 'p12_unit1.pas' {Form1};

{$R 'Win7UAC.RES'}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

Вынесите на форму с именем Form1 одну кнопку Button1 и один список ComboBox1 (Смотрите рисунок 3).

 Рисунок 3. Создания формы приложения

Добавьте в свойства Items списка ComboBox1 две строки DOMAIN\User1 и DOMAIN\User2 (Смотрите рисунок 4). Эти строки у нас будут выбираться в ComboBox1. Также поменяйте свойства Style для списка ComboBox1 на csOwnerDraw.

Рисунок 4. Формирование списка ComboBox

Переходим к написанию кода. Рассмотрим обработчик показа формы Form1, это следующий код:

procedure TForm1.FormShow(Sender: TObject);
begin
  Combobox1.ItemIndex := Combobox1.Items.IndexOf('DOMAIN\User1');
end;

В данном обработчике мы присваиваем списку ComboBox1 значение по умолчанию значение DOMAIN\User1. 

Рассмотрим обработчик нажатия кнопки Button1, это следующий код:

procedure TForm1.Button1Click(Sender: TObject);
var
  R: TRegistry;
  openResult: Boolean;
const
  SubKey : String = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI';

begin
  strSetRegValue := ComboBox1.Text;
  if (strSetRegValue <> '') then
  begin
    R := TRegistry.Create(KEY_READ);
    R.RootKey := HKEY_LOCAL_MACHINE;
    if (R.KeyExists(SubKey)) then
    begin
      With R do
      begin
        Access := KEY_WRITE OR $0100;
        openResult := OpenKey(SubKey, False);
        if (not openResult = True) Then
        begin
          MessageDlg('Unable to create key! Exiting.', mtError, mbOKCancel, 0);
        end;
        WriteString('LastLoggedOnSAMUser', strSetRegValue);
        WriteString('LastLoggedOnUser', strSetRegValue);

        CloseKey();
        Free;
      end;
    end;
    ShowMessage('Done! Recorded in the registry.');
    strSetRegValue := '';
  end;
end;

В данном обработчике мы указываем путь в реестре Windows куда будем писать значения, это переменная типа String c именем SubKey. Смотрите код:

SubKey : String = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI';

Далее берем выбранное значение ComboBox1 и присваиваем его переменной strSetRegValue. Смотрите код:

strSetRegValue := ComboBox1.Text;

Если переменная strSetRegValue не пуста, то начинаем писать в реестр Windows. Работать будем в корневом разделе HKEY_LOCAL_MACHINE. Смотрите код:

  if (strSetRegValue <> '') then
  begin
    R := TRegistry.Create(KEY_READ);
    R.RootKey := HKEY_LOCAL_MACHINE;


Далее проверяем существует ли путь в реестре SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI. Также открываем подраздел реестра на запись для Windows 7 32 bit и 64 bit, следующая строчка: 

Access := KEY_WRITE OR $0100;


Смотрите следующий код:

if (R.KeyExists(SubKey)) then
    begin
      With R do
      begin
        Access := KEY_WRITE OR $0100;
        openResult := OpenKey(SubKey, False);
        if (not openResult = True) Then
        begin
          MessageDlg('Unable to create key! Exiting.', mtError, mbOKCancel, 0);
        end;


Далее пишем в реестр параметры LastLoggedOnSAMUser, LastLoggedOnUser и закрываем ветку реестра и освобождаем память. Следующие строчки:

        WriteString('LastLoggedOnSAMUser', strSetRegValue);
        WriteString('LastLoggedOnUser', strSetRegValue);

        CloseKey();
        Free;


Ниже показан снимок рабочей программы (Смотрите рисунок 5) и код полностью. При запуске приложения, оно спросит повышения привилегий, если вы имеете права админа (Смотрите рисунок 6) или повышения привилегий путем ввода логина и пароля администратора (Смотрите рисунок 7).

Рисунок 5. Запущенная программа

Рисунок 6. Окно разрешения запуска вашей программы, если вы имеете права администратора

Рисунок 7. Запрос прав администратора, если они у вас отсутствуют

unit p12_unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Registry;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ComboBox1: TComboBox;
    procedure Button1Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  strSetRegValue: String;

procedure TForm1.Button1Click(Sender: TObject);
var
  R: TRegistry;
  openResult: Boolean;
const
  SubKey : String = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI';

begin
  strSetRegValue := ComboBox1.Text;
  if (strSetRegValue <> '') then
  begin
    R := TRegistry.Create(KEY_READ);
    R.RootKey := HKEY_LOCAL_MACHINE;
    if (R.KeyExists(SubKey)) then
    begin
      With R do
      begin
        Access := KEY_WRITE OR $0100;
        openResult := OpenKey(SubKey, False);
        if (not openResult = True) Then
        begin
          MessageDlg('Unable to create key! Exiting.', mtError, mbOKCancel, 0);
        end;
        WriteString('LastLoggedOnSAMUser', strSetRegValue);
        WriteString('LastLoggedOnUser', strSetRegValue);

        CloseKey();
        Free;
      end;
    end;
    ShowMessage('Done! Recorded in the registry.');
    strSetRegValue := '';
  end;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  Combobox1.ItemIndex := Combobox1.Items.IndexOf('DOMAIN\User1');
end;

end.

Комментариев нет:

Отправить комментарий