HOWTO: Load a User's Hive Programmatically
ID: Q168877
|
The information in this article applies to:
-
Microsoft Win32 Application Programming Interface (API), used with:
-
Microsoft Windows NT, versions 3.51, 4.0
SUMMARY
By default, a user's hive is loaded for only the interactive user and
services running from a user account (Windows NT 4.0 only). A user's hive
contains specific registry information pertaining to the user's application
settings, desktop, environment, network connections, and printers. The hive
is loaded under the HKEY_USERS key. The name of the hive is based on the
SECURITY IDENTIFIER (SID) of the user. A process refers to its hive via the
HKEY_CURRENT_USER key. This key is a mapping to the user's hive under
HKEY_USERS based upon the user's SID. If the user's hive is not loaded, the
system maps references pertaining to HKEY_CURRENT_USER to
HKEY_USER\.default. In addition, a process running in the LocalSystem
security context references to HKEY_CURRENT_USER are also mapped to
HKEY_USER\.default.
MORE INFORMATION
For a process that did not originate from either the interactive
logged-on user or from a service (Windows NT 4.0 only) to have access to
its hive, the hive must be loaded programmatically. For example, the
CreateProcessAsUser API does not automatically load the user's hive, so by
default any references to HKEY_CURRENT_USER from the process would map to
HKEY_USERS\.default instead of HKEY_USERS\<user's sid> if the hive is not
already loaded.
Sample Code
The following sample code requires a user, password, and an executable. This
sample assumes that the specified user has an existing hive. This means the
user must have interactively logged on to the machine at least once. Based
on the above information, the sample code loads the user's hive and then
launches the .exe given to it by the user. To load a user's hive, the user
running the sample code needs to be granted the "Restore files and
directories" (SE_RESTORE_NAME) privilege. Once the executable has exited,
the sample code unloads the user's hive. You can verify that the user's
hive is loaded by using Regedt32.exe. Note that the sample code does not
handle modifying the security on the interactive Windowstation and
Desktop. You should specify a user account that belongs to the
Administrator group to avoid the User32.dll initialization error.
For additional information about granting a user access to the interactive Windowstation and
Desktop, please click the article number below
to view the article in the Microsoft Knowledge Base:
Q165194 INFO: CreateProcessAsUser, Windowstations, and Desktops
Note that the information contained in the ProfileImagePath registry key
has changed between Windows NT 3.51 and Windows NT 4.0. On Windows NT 3.51,
this key value contained both the path and name of the hive for a user. On
Windows NT 4.0, it only contains the path of the hive. Hives on Windows NT
4.0 are always named Ntuser.dat. These differences are handled in the
sample code.
Libraries required: USER32.LIB
ADVAPI32.LIB
#define RTN_OK 0
#define RTN_ERROR 13
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
BOOL ConvertSid(PSID pSid, LPTSTR pszSidText, LPDWORD dwBufferLen)
{
PSID_IDENTIFIER_AUTHORITY psia;
DWORD dwSubAuthorities;
DWORD dwSidRev=SID_REVISION;
DWORD dwCounter;
DWORD dwSidSize;
//
// test if SID passed in is valid
//
if(!IsValidSid(pSid)) return FALSE;
// obtain SidIdentifierAuthority
psia=GetSidIdentifierAuthority(pSid);
// obtain sidsubauthority count
dwSubAuthorities=*GetSidSubAuthorityCount(pSid);
//
// compute buffer length
// S-SID_REVISION- + identifierauthority- + subauthorities- + NULL
//
dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
//
// check provided buffer length.
// If not large enough, indicate proper size and setlasterror
//
if (*dwBufferLen < dwSidSize){
*dwBufferLen = dwSidSize;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
//
// prepare S-SID_REVISION-
//
dwSidSize=wsprintf(pszSidText, TEXT("S-%lu-"), dwSidRev );
//
// prepare SidIdentifierAuthority
//
if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) ){
dwSidSize+=wsprintf(pszSidText + lstrlen(pszSidText),
TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
(USHORT)psia->Value[0],
(USHORT)psia->Value[1],
(USHORT)psia->Value[2],
(USHORT)psia->Value[3],
(USHORT)psia->Value[4],
(USHORT)psia->Value[5]);
}
else{
dwSidSize+=wsprintf(pszSidText + lstrlen(pszSidText),
TEXT("%lu"),
(ULONG)(psia->Value[5] ) +
(ULONG)(psia->Value[4] << 8) +
(ULONG)(psia->Value[3] << 16) +
(ULONG)(psia->Value[2] << 24) );
}
//
// loop through SidSubAuthorities
//
for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++){
dwSidSize+=wsprintf(pszSidText + dwSidSize, TEXT("-%lu"),
*GetSidSubAuthority(pSid, dwCounter) );
}
return TRUE;
}
BOOL ObtainProfilePath(LPTSTR pszSid, LPTSTR pszProfilePath,
DWORD dwPathSize)
{
TCHAR szRegKey[1024] = TEXT("SOFTWARE\\Microsoft\\");
TCHAR szTemp[256] = TEXT("");
DWORD dwSizeProfilePath = dwPathSize;
DWORD dwType;
HKEY hKey;
LONG lErrorCode;
//
// concat sid
//
lstrcat(szRegKey, TEXT("Windows NT\\CurrentVersion\\ProfileList\\"));
lstrcat(szRegKey, pszSid);
//
// find the hive in the registry
//
lErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegKey, 0,
KEY_READ, &hKey);
if (lErrorCode != ERROR_SUCCESS)
return FALSE;
//
// query the value
//
lErrorCode = RegQueryValueEx(hKey, TEXT("ProfileImagePath"), NULL,
&dwType, (LPBYTE)pszProfilePath, &dwSizeProfilePath);
if (lErrorCode != ERROR_SUCCESS)
return FALSE;
//
// fix profile path by replacing "%SystemRoot%" with the actual path
//
lstrcpy(szTemp, pszProfilePath);
ZeroMemory(pszProfilePath, dwPathSize);
if (!ExpandEnvironmentStrings(szTemp, pszProfilePath,dwPathSize))
return FALSE;
//
// determine if it is a file or directory, WinNT 4.0 it is a
// directory
// WinNT 3.51 it is a file
//
if ((GetFileAttributes(pszProfilePath) & FILE_ATTRIBUTE_DIRECTORY) ==
FILE_ATTRIBUTE_DIRECTORY)
lstrcat(pszProfilePath, TEXT("\\ntuser.dat"));
//
// close the key
//
lErrorCode = RegCloseKey(hKey);
if (lErrorCode != ERROR_SUCCESS)
return FALSE;
return TRUE;
}
BOOL Privilege(LPTSTR pszPrivilege, BOOL bEnable)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
//
// obtain the processes token
//
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return FALSE;
//
// get the luid
//
if (!LookupPrivilegeValue(NULL, pszPrivilege,
&tp.Privileges[0].Luid))
return FALSE;
tp.PrivilegeCount = 1;
if (bEnable)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
//
// enable or disable the privilege
//
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0,
(PTOKEN_PRIVILEGES)NULL, 0))
return FALSE;
if (!CloseHandle(hToken))
return FALSE;
return TRUE;
}
BOOL Hive(LPTSTR pszSid, LPTSTR pszProfilePath, BOOL bLoad)
{
LONG lErrorCode;
if (bLoad){
lErrorCode = RegLoadKey(HKEY_USERS, pszSid, pszProfilePath);
if (lErrorCode != ERROR_SUCCESS)
return FALSE;
}
else{
lErrorCode = RegUnLoadKey(HKEY_USERS, pszSid);
if (lErrorCode != ERROR_SUCCESS)
return FALSE;
}
return TRUE;
}
BOOL ObtainSid(HANDLE hToken, LPTSTR pszSid, LPDWORD pdwBufferLen)
{
DWORD dwReturnLength = 0;
DWORD dwTokenUserLength = 0;
TOKEN_INFORMATION_CLASS tic = TokenUser;
TOKEN_USER *ptu = NULL;
//
// query info in the token
//
if (!GetTokenInformation(hToken, tic, (LPVOID)ptu, dwTokenUserLength,
&dwReturnLength)){
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){
ptu = (TOKEN_USER *)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwReturnLength);
if (ptu == NULL)
return FALSE;
dwTokenUserLength = dwReturnLength;
dwReturnLength = 0;
if (!GetTokenInformation(hToken, tic, (LPVOID)ptu,
dwTokenUserLength, &dwReturnLength))
return FALSE;
}
else
return FALSE;
}
//
// convert the sid to textural form
//
if (!ConvertSid((ptu->User).Sid, pszSid, pdwBufferLen))
return FALSE;;
if (!HeapFree(GetProcessHeap(), 0, (LPVOID)ptu))
return FALSE;
return TRUE;
}
int _tmain(int argc, TCHAR *argv[])
{
TCHAR szComputerName[256];
TCHAR szProfilePath[256];
TCHAR szSid[256];
DWORD dwBufferLen;
DWORD dwComputerLen;
HANDLE hToken = NULL;
int iSuccess = RTN_ERROR;
PROCESS_INFORMATION pi;
STARTUPINFO si;
__try
{
if (argc != 4){
_tprintf(TEXT("Usage: [account name] [password] [exe]\n"));
return RTN_ERROR;
}
dwComputerLen = sizeof(szComputerName)/sizeof(TCHAR);
if (!GetComputerName(szComputerName, &dwComputerLen))
__leave;
if (!LogonUser(argv[1], szComputerName, argv[2],
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, &hToken))
__leave;
//
// initialize buffers
//
ZeroMemory(szSid, (sizeof(szSid)/sizeof(TCHAR)));
ZeroMemory(szProfilePath, (sizeof(szProfilePath)/sizeof(TCHAR)));
dwBufferLen = (sizeof(szSid)/sizeof(TCHAR));
//
// obtain the sid
//
if (!ObtainSid(hToken, szSid, &dwBufferLen))
__leave;
//
// obtain profile path
//
if (!ObtainProfilePath(szSid, szProfilePath,
(sizeof(szProfilePath)/sizeof(TCHAR))))
__leave;
//
// enable privilege
//
if (!Privilege(SE_RESTORE_NAME, TRUE))
__leave;
//
// load the hive
//
if (!Hive(szSid, szProfilePath, TRUE))
__leave;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = TEXT("winsta0\\default");
if (!CreateProcessAsUser(hToken, NULL, argv[3], NULL, NULL,
FALSE, CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS, NULL,
NULL, &si, &pi))
__leave;
if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED)
__leave;
//
// unload the hive
//
if (!Hive(szSid, szProfilePath, FALSE))
__leave;
//
// disable the privilege
//
if (!Privilege(SE_RESTORE_NAME, FALSE))
__leave;
iSuccess = RTN_OK;
}
__finally
{
if (hToken != NULL)
CloseHandle(hToken);
if (pi.hProcess != NULL)
CloseHandle(pi.hProcess);
if (pi.hThread != NULL)
CloseHandle(pi.hThread);
}
return iSuccess;
}
REFERENCES
For more information on registry hives, please refer to the Microsoft Windows
NT Resource Kit, Vol 1.
Additional query words:
Keywords : kbcode kbprg kbKernBase kbRegistry kbDSupport kbGrpKernBase
Version : winnt:3.51,4.0
Platform : winnt
Issue type : kbhowto