Идентификация SID в Delphi: обход PsGetSid без использования SysInternals
Введение
SID (Security Identifier) - это уникальный идентификатор, используемый в Windows для идентификации пользователей, групп и компьютеров. Для разработчиков, работающих с Delphi, может возникнуть необходимость извлечения SID компьютера для различных целей, например, для управления доступом или аутентификации.
Проблема
Пользователь ищет способ извлечения SID компьютера с помощью кода на Delphi. Существует утилита PsGetSid от SysInternals, которая выполняет эту задачу, но использование сторонних инструментов может быть нежелательно или невозможно в некоторых приложениях.
Решение
Для решения задачи можно использовать функцию LookupAccountName из WinAPI или WMI класс Win32_Account для извлечения SID. Ниже приведены примеры кода на Object Pascal, которые демонстрируют оба подхода.
Использование WinAPI LookupAccountName
program GetLocalComputerSID;
{$APPTYPE CONSOLE}
uses
Windows,
SysUtils;
function ConvertSidToStringSid(Sid: PSID; out StringSid: PChar): BOOL; stdcall; external 'ADVAPI32.DLL' name {$IFDEF UNICODE} 'ConvertSidToStringSidW'{$ELSE} 'ConvertSidToStringSidA'{$ENDIF};
function SIDToString(ASID: PSID): string;
var
StringSid: PChar;
begin
if not ConvertSidToStringSid(ASID, StringSid) then
RaiseLastWin32Error;
Result := string(StringSid);
LocalFree(HLocal(StringSid));
end;
function GetLocalComputerName: string;
var
nSize: DWORD;
begin
nSize := MAX_COMPUTERNAME_LENGTH + 1;
SetLength(Result, nSize);
if not GetComputerName(PChar(Result), {var}nSize) then
begin
Result := '';
Exit;
end;
SetLength(Result, nSize);
SetLength(Result, Length(Result) - 1); // Убираем лишний символ в конце строки
end;
function GetComputerSID: string;
var
Sid: PSID;
cbSid: DWORD;
cbReferencedDomainName: DWORD;
ReferencedDomainName: string;
peUse: SID_NAME_USE;
Success: BOOL;
lpSystemName, lpAccountName: string;
begin
Sid := nil;
try
lpSystemName := '';
lpAccountName := GetLocalComputerName;
cbSid := 0;
cbReferencedDomainName := 0;
// Первый вызов к LookupAccountName для получения размеров буфера.
Success := LookupAccountName(PChar(lpSystemName), PChar(lpAccountName), nil, cbSid, nil, cbReferencedDomainName, peUse);
if (not Success) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
begin
SetLength(ReferencedDomainName, cbReferencedDomainName);
Sid := AllocMem(cbSid);
// Второй вызов к LookupAccountName для получения SID.
Success := LookupAccountName(PChar(lpSystemName), PChar(lpAccountName), Sid, cbSid, PChar(ReferencedDomainName), cbReferencedDomainName, peUse);
if not Success then
begin
FreeMem(Sid);
Sid := nil;
RaiseLastOSError;
end
else
Result := SIDToString(Sid);
end
else
RaiseLastOSError;
finally
if Assigned(Sid) then
FreeMem(Sid);
end;
end;
begin
try
Writeln(GetComputerSID);
except
on E: Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Нажмите Enter, чтобы выйти');
Readln;
end.
Использование WMI класса Win32_Account
program GetWMI_Info;
{$APPTYPE CONSOLE}
uses
SysUtils,
ActiveX,
ComObj,
Variants;
function GetComputerSID: string;
const
WbemUser := '';
WbemPassword := '';
WbemComputer := 'localhost';
wbemFlagForwardOnly = $00000020;
var
FSWbemLocator: OLEVariant;
FWMIService: OLEVariant;
FWbemObjectSet: OLEVariant;
FWbemObject: OLEVariant;
oEnum: IEnumvariant;
iValue: LongWord;
begin
FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
FWMIService := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword);
FWbemObjectSet := FWMIService.ExecQuery('SELECT SID FROM Win32_Account Where SIDType=1', 'WQL', wbemFlagForwardOnly);
oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
if oEnum.Next(1, FWbemObject, iValue) = 0 then
begin
Result := FWbemObject.SID;
Result := Copy(Result, 1, LastDelimiter('-', Result) - 1);
FWbemObject := Unassigned;
end;
end;
begin
try
CoInitialize(nil);
try
Writeln(GetComputerSID);
finally
CoUninitialize;
end;
except
on E: EOleException do
Writeln(Format('EOleException %s %x', [E.Message, E.ErrorCode]));
on E: Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Нажмите Enter, чтобы выйти');
Readln;
end.
Заключение
В данной статье были рассмотрены два способа извлечения SID компьютера в Delphi: с использованием WinAPI функции LookupAccountName и с использованием WMI класса Win32_Account. Оба подхода позволяют обойти необходимость использования стороннего инструмента PsGetSid от SysInternals. Выбор метода зависит от конкретных требований и предпочтений разработчика.
Пользователь ищет способ идентификации SID в Delphi, избегая использования стороннего инструмента PsGetSid, и рассматривает два метода: использование функции WinAPI `LookupAccountName` и WMI класс `Win32_Account`.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.