Loading/Unloading a registry hive programmatically in Delphi 5+

Concepts demonstrated:
Registry Use (See procedure TfrmLoadHive.btnDisplayValueClick(Sender: TObject))
Hives & The Default User hive & .Default (See below)
Executing another program from within a Delphi program (See procedure TfrmLoadHive.btnExecRegEditClick)
Use of Process Token Privileges in Delphi (See below)

RE: Hives
The WinXP registry is divided into many different sections. Each major section is called a hive. Handling complete branches of the registry as separate hives allows Microsoft to perform several neat tricks. First of all, it allows hive to appear in several places in the registry with different names. The most obvious example of this is HKey_Current_User which of course points to the hive of the user that has logged in. A lesser known example is HKEY_CLASSES_ROOT which is simply a reloaded version of KEY_LOCAL_MACHINE\SOFTWARE\Classes. Those familiar with the DOS subst command and Linux symbolic links can draw comparisons there too.

An even lesser known use of windows hives is that Windows does not keep all of its hives active. It has separate hives to use as examples for creating local users, and other for creating user accounts when someone has logged into the machine remotely through a domain. I seem to remember there being a couple more examples but they elude me at the moment. Those hives are stored as DAT files on the hard drive. For instance, in the default XP install, the registry hive stored at ‘c:\\Documents and Settings\\Default User\\NTUSER.DAT’ will be used to set all the default registry entries whenever a new user logs into the machine. Set a value in that hive, and all future users will have that value.

NOTE: Do not confuse this with HKEY_USERS\.DEFAULT. The HKEY_USERS\.DEFAULT hive stores the values used when no one is logged in. “Huh? How could that be useful?” Well, if you think about it, controlling whether or not a computer puts itself to sleep if some one has booted it but not logged in can be very important. It might also be nice to set a screensaver that works when you log out of your computer but leave it turned on. An ultra secure person could set the color scheme to be entirely black on black, then only a person that really knows what they are doing could log into the computer – LOL. In any case, .DEFAULT and the Default User hives are NOT the same thing.

RE: Token Privileges:
Windows XP/NT/2000 and newer operating systems have advanced security methods to restrict what programs can and cannot do. These restrictions also allow the logging of some restricted access functions. So, for example, while it is possible for programs to set the system time, just any old program can’t do it.

The program has to ask for and get permission to update the time, before it can be accomplished. It is a bit like what a bell hop must do to get into someone’s hotel room. If a bell hop needs to get into room 5321 (let’s pretend this hotel uses keys and not plastic cards), the bell hop will tell his manager he’s gonna need to get into a room, look up which key that room needs, ask the manager for that key, unlock the room and do his thing. Then of course he will lock the door as soon as he is done. Note that if the bell hop does a bunch of other things before locking the door, the room could be burglarized. And when a good bell hop has to access the room several times, the room will be locked between times he is accessing it.

The process for Windows is the same:
Tell Windows you will be adjusting privileges by calling: OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, TTokenHd);
Find the local name of the privilege you will be adjusting by calling LookupPrivilegeValue
Grant yourself access by setting TTokenPvg.Privileges[0].Attributes to SE_PRIVILEGE_ENABLED
Lock the door again by setting TTokenPvg.Privileges[0].Attributes to SE_PRIVILEGE_DISABLED

In my program, I have created three helper routines for working with the tokens: SetTokenPrivilege, GrantPrivilege and RevokePrivilege. The latter two only serve to make my calling code clear. Readability is essential for any professional grade program. At some point you will forget the details of every single program you’ve write. So, even if you are only writing a routine for your own use, you should do what you can to make it easier to read. Tasks like this may seem wasted on throw away programs, but the more you do it, the faster you will be and the more likely it will be that your habit of writing good code will pay off in the end.

Here are my Delphi privilege routines:

[Delphi]
{******************************************************************************
SetTokenPrivilege
A helper function that enables or disables specific privileges on the
specified computer. A NIL in SystemName means the privilege will be granted
for the current computer. Any other value must match the name of a computer
on your network.
******************************************************************************}
procedure SetTokenPrivilege(aSystemName: PChar; aPrivilegeName: PChar; aEnabled: Boolean);
var
TTokenHd: THandle;
TTokenPvg: TTokenPrivileges;
cbtpPrevious: DWORD;
rTTokenPvg: TTokenPrivileges;
pcbtpPreviousRequired: DWORD;
TokenOpened, ValueFound: Boolean;
begin // SetPrivilege
// The privilege system is only available on NT and beyond
if (Win32Platform = VER_PLATFORM_WIN32_NT)
then begin
// Retrieve the Token that represents this current application session
TokenOpened := OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,
TTokenHd);

// Check for failure
if (not TokenOpened)
then raise Exception.Create(‘The current user does not have the access required to run this program.’)
else begin
// Get the name of the privilege (since Windows is multi-lingual, this must be done)
ValueFound := LookupPrivilegeValue(aSystemName, aPrivilegeName, TTokenPvg.Privileges[0].Luid) ;
TTokenPvg.PrivilegeCount := 1;

// Enable or disable the flag according to the bool passed
if (aEnabled)
then TTokenPvg.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
else TTokenPvg.Privileges[0].Attributes := SE_PRIVILEGE_DISABLED; // See note on local constant declaration
cbtpPrevious := SizeOf(rTTokenPvg) ;
pcbtpPreviousRequired := 0;
if (not ValueFound)
then raise Exception.Create(‘This program is incompatible with the operating system installed on this computer.’)
else begin
try
// Adjust the permissions as required.
Windows.AdjustTokenPrivileges(TTokenHd, False, TTokenPvg, cbtpPrevious,
rTTokenPvg, pcbtpPreviousRequired);
except
raise Exception.Create(‘The current user does not have the required access to load a registry hive.’)
end;
end;
end
end;
end; // SetPrivilege
{******************************************************************************
GrantPrivilege
This routine grants the privilege(s) needed to access the hidden system hive
and load it into memory.
******************************************************************************}
procedure TfrmLoadHive.GrantPrivilege(aPrivilegeName: String);
begin // GrantPrivilege
SetTokenPrivilege(NIL, PChar(aPrivilegeName), TRUE);
end; // GrantPrivilege

{******************************************************************************
RevokePrivilege
This routine revokes privilege(s) given in GrantPrivilege
******************************************************************************}
procedure TfrmLoadHive.RevokePrivilege(aPrivilegeName: String);
begin // RevokePrivilege
SetTokenPrivilege(NIL, PChar(aPrivilegeName), FALSE);
end; // RevokePrivilege
[/Delphi]

In my case, I am using the SeRestorePrivilege token. This is actually one of the most powerful and lethal tokens. With it you are telling Windows that you are a Hard Drive backup program and you want to have access to all sorts of files that most programs are not allowed access to. Presumably you are doing this for good and not evil. Other tokens are:
SeCreateTokenPrivilege, SeAssignPrimaryTokenPrivilege, SeLockMemoryPrivilege, SeIncreaseQuotaPrivilege, SeUnsolicitedInputPrivilege, SeMachineAccountPrivilege, SeTcbPrivilege, SeSecurityPrivilege, SeTakeOwnershipPrivilege, SeLoadDriverPrivilege, SeSystemProfilePrivilege, SeSystemtimePrivilege, SeProfileSingleProcessPrivilege, SeIncreaseBasePriorityPrivilege, SeCreatePagefilePrivilege, SeCreatePermanentPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeShutdownPrivilege, SeDebugPrivilege, SeAuditPrivilege, SeSystemEnvironmentPrivilege, SeChangeNotifyPrivilege, SeRemoteShutdownPrivilege, SeUndockPrivilege, SeSyncAgentPrivilege, SeEnableDelegationPrivilege, SeManageVolumePrivilege
So, that’s the basics. Take a look a the comments in the rest of the source code and you’ll soon see what happens and why.

Also try some different things. Run RegEdit and load the hive manually through File>Load Hive. Did you notice that you HAVE to be at a point within one of the preloaded hives before that option is enabled? What happens when you press the load hive button but you haven’t granted yourself privileges? What happens when you grant your self privileges and don’t revoke them b4 closing the program. Can you then load the hive when you rerun the program? What happens if you Grant 4 time but only unload once?

Experiment. But remember, you are playing with the registry and thar be monsters there. This app works fine on my system, I’ve used similar routine regularly for a couple years now, but I haven’t tested it with all versions of Windows and I have no idea how it will handle out-of-the-ordinary circumstances, like bad sectors in a dat file on your HD. Additionally, a Windows Service pack could totally change what this program does. So, in short, don’t come to me when you need to reinstall Windows. I’ll simply say it was a bad coincidence and anyway your system is beyond my control, you never should have run this program on it. I’m not responsible for your financial and emotional loss. You are responsible for making sure that source code you run on your computer does not have deliberate or accidental malicious behaviors.

http://www.TheCodeCave.com/downloads/delphi/LoadHiveDemo.exe
http://www.TheCodeCave.com/downloads/delphi/LoadHiveDemo.dpr
http://www.TheCodeCave.com/downloads/delphi/U_LoadHive.dfm
http://www.TheCodeCave.com/downloads/delphi/U_LoadHive.pas

4 Comments

Add a Comment

Your email address will not be published. Required fields are marked *