-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathTakeOwnershipJob.pas
More file actions
135 lines (115 loc) · 3.88 KB
/
TakeOwnershipJob.pas
File metadata and controls
135 lines (115 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
unit TakeOwnershipJob;
interface
uses Windows, Registry, AccCtrl, CBSEnum_JobProcessor;
{$IFDEF DEBUG}
//{$DEFINE DEBUG_HELPER}
{$ENDIF}
type
TTakeOwnershipJob = class(TProcessingThread)
protected
{$IFDEF DEBUG_HELPER}
procedure AclHelpersLog(const AMsg: string);
{$ENDIF}
procedure TakeRegistryOwnership();
procedure TakeRegistryOwnershipOfKey(AReg: TRegistry; const AKey: string; ANewOwner: PSID);
public
procedure Execute; override;
end;
implementation
uses SysUtils, Classes, AclHelpers, CBSEnum_Main;
{$IFDEF DEBUG_HELPER}
procedure TTakeOwnershipJob.AclHelpersLog(const AMsg: string);
begin
Self.Log(AMsg);
end;
{$ENDIF}
procedure TTakeOwnershipJob.Execute;
begin
{$IFDEF DEBUG_HELPER}
AclHelpers.OnLog := Self.AclHelpersLog;
{$ENDIF}
TakeRegistryOwnership();
{$IFDEF DEBUG_HELPER}
AclHelpers.OnLog := nil;
{$ENDIF}
end;
procedure TTakeOwnershipJob.TakeRegistryOwnership();
var hProcToken: THandle;
pSidAdmin: PSID;
reg: TRegistry;
begin
pSidAdmin := nil;
//Before we take ownership, we need to claim that privilege
Log('Opening process token');
if not OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hProcToken) then
RaiseLastOsError();
Log('Setting SE_TAKE_OWNERSHIP_NAME');
if not SetPrivilege(hProcToken, SE_TAKE_OWNERSHIP_NAME, true) then
RaiseLastOsError();
//Clear and release the handles later
try
Log('Getting BUILTIN\Administrators reference');
//We're going to give ownership to BUILTIN\Administrators, this is comparatively safe + fits our needs
pSidAdmin := AllocateSidBuiltinAdministrators();
reg := TRegistry.Create;
try
reg.RootKey := hkCbsRoot;
reg.Access := KEY_READ;
TakeRegistryOwnershipOfKey(reg, '\'+sCbsKey, pSidAdmin);
finally
FreeAndNil(reg);
end;
finally
if pSIDAdmin <> nil then
FreeSid(pSIDAdmin);
Log('Clearing SE_TAKE_OWNERSHIP_NAME');
SetPrivilege(hProcToken, SE_TAKE_OWNERSHIP_NAME, false);
CloseHandle(hProcToken);
end;
Log('Done.');
end;
//Called for every child key, recursively. Sets its owner to ANewOwner and gives the previous owner full rights.
//Key must start with /
procedure TTakeOwnershipJob.TakeRegistryOwnershipOfKey(AReg: TRegistry; const AKey: string; ANewOwner: PSID);
var subkeys: TStringList;
subkey: string;
err: cardinal;
pSidPreviousOwner: PSID;
pPreviousOwnerDescriptor: PSECURITY_DESCRIPTOR;
begin
Log('Processing key '+AKey);
//There's no way to "go one level upper" with TRegistry so we're stuck with non-efficient "open each key from the root"
if not AReg.OpenKey(AKey, false) then
RaiseLastOsError();
err := SwitchOwnership(sCbsRootSec+AKey, SE_REGISTRY_KEY, ANewOwner, pSIDPreviousOwner,
pPreviousOwnerDescriptor);
if err <> ERROR_SUCCESS then RaiseLastOsError(err);
if pSidPreviousOwner <> nil then try
Log('...ownership taken, granting permissions to previous owner');
//Give explicit full permissions to the previous owner
err := AddExplicitPermissions(sCbsRootSec+AKey, SE_REGISTRY_KEY, pSidPreviousOwner, KEY_ALL_ACCESS);
if err <> ERROR_SUCCESS then
RaiseLastOsError(err);
finally
LocalFree(NativeUInt(pPreviousOwnerDescriptor));
pPreviousOwnerDescriptor := nil;
pSidPreviousOwner := nil;
end else
Log('...already owned.');
//Give new owner full access (if they don't have it)
err := AddExplicitPermissions(sCbsRootSec+AKey, SE_REGISTRY_KEY, ANewOwner, KEY_ALL_ACCESS);
if err <> ERROR_SUCCESS then
RaiseLastOsError(err);
//Process subkeys
subkeys := TStringList.Create;
try
AReg.GetKeyNames(subkeys);
for subkey in subkeys do begin
TakeRegistryOwnershipOfKey(AReg, AKey+'\'+subkey, ANewOwner);
if Terminated then break;
end;
finally
FreeAndNil(subkeys);
end;
end;
end.