Once you've started an application with Administrator permission, programs executed using ShellExecute
in that application will inherit the Administrator permission. But that isn't what I want: it just has to start regularly without the extra permissions. ShellExecute
accepts the parameter OPEN
(regular) and RUNAS
(Administrator). But if you use OPEN
after you've started the application as Administrator, it still acts like RUNAS
.
The following example demonstrates this: If you start it with regular permissions it says 'Started regular'. Once you press 1 for 'admin' it will start as administrator. If you press 2 in the newly created prompt it will not starts a 'regular' prompt, but again a 'Administrator' prompt.
I've found something about some parameters in RUNAS (https://superuser.com/a/374866), but they cannot be passed in ShellExecute
. Any ideas?
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.
I used to solve this puzzle when creating an installer, here's one of the possible solutions.
The idea is to create a background process that runs with user privileges, your main application communicates with it and lets it know what program to start - the started process will have user privileges.
It should work like this: Background process is launched as usual, with User privileges. When launched, it starts your main program as Admin. The background process thn stays hidden and awaits the command from the main process.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With