How to impersonate a user from a service correctly? - c++

I'm working a service, which should impersonate the logged on user.
My code so far, with basic error handling:
// get the active console session ID of the logged on user
if ( !WTSQueryUserToken( WTSGetActiveConsoleSessionId(), &hToken ) )
{
ShowErrorText( "WTSQueryUserToken failed.", GetLastError( ), true );
return;
}
HANDLE hDuplicated;
// duplicate the token
if ( !DuplicateToken( hToken, SecurityImpersonation, &hDuplicated ) )
{
ShowErrorText( "DuplicateToken failed.", GetLastError( ), true );
}
else
{
ShowErrorText( "DuplicateToken succeeded.", 0, true );
}
// impersonate the logged on user
if ( !ImpersonateLoggedOnUser( hToken ) )
{
ShowErrorText( "ImpersonateLoggedOnUser failed.", GetLastError(), true );
return;
}
// retrieve the DC name
if ( !GetPrimaryDC( DC ) )
{
ShowErrorText( "GetPrimaryDC failed.", 0, true );
}
PROFILEINFO lpProfileInfo;
ZeroMemory( &lpProfileInfo, sizeof( PROFILEINFO ) );
lpProfileInfo.dwSize = sizeof( PROFILEINFO );
lpProfileInfo.lpUserName = CurrentUser;
// get type of profile. roaming, mandatory or temporary
int ret = GetTypeOfProfile();
if ( ret == 2 )
{
// if roaming profile get the path of it
if ( !GetRoamingProfilePath( DC, CurrentUser, RoamingProfilePath ) )
{
ShowErrorText( "Failed to retrieve roaming profile path.", GetLastError(), true );
}
}
if ( RevertToSelf( ) )
{
ShowErrorText( "Impersonation ended successfully.", 0, true );
}
if ( !LoadUserProfile( hDuplicated, &lpProfileInfo ) )
{
ShowErrorText( "LoadUserProfile failed.", GetLastError(), true );
}
else
{
ShowErrorText( "LoadUserProfile succeeded.", 0, true );
}
//do some stuff
if ( !UnloadUserProfile( hDuplicated, lpProfileInfo.hProfile ) )
{
ShowErrorText( "UnloadUserProfile failed.", GetLastError( ), true );
}
else
{
ShowErrorText( "UnloadUserProfile succeeded.", 0, true );
}
if ( !ImpersonateLoggedOnUser( hToken ) )
{
ShowErrorText( "ImpersonateLoggedOnUser failed.", GetLastError( ), true );
return;
}
According to MSDN:
When a user logs on interactively, the system automatically loads the user's profile. If a service or an application impersonates a user, the system does not load the user's profile. Therefore, the service or application should load the user's profile with LoadUserProfile.
Services and applications that call LoadUserProfile should check to see if the user has a roaming profile. If the user has a roaming profile, specify its path as the lpProfilePath member of PROFILEINFO. To retrieve the user's roaming profile path, you can call the NetUserGetInfo function, specifying information level 3 or 4.
Upon successful return, the hProfile member of PROFILEINFO is a registry key handle opened to the root of the user's hive. It has been opened with full access (KEY_ALL_ACCESS). If a service that is impersonating a user needs to read or write to the user's registry file, use this handle instead of HKEY_CURRENT_USER. Do not close the hProfile handle. Instead, pass it to the UnloadUserProfile function.
If i use my code as it is now, then it works. However is it a little strange, because first i have to impersonate the logged on user, and then end the impersonation, to Load the users profile. If i don't end the impersonation then LoadUserProfile will fail with error 5 ( Access denied ). And after LoadUserProfile succeeded i should impersonate the user again?
So my question is, this meant to be done this way, or i am doing something wrong?
Another question is, that if LoadUserProfile succeeded i could use hProfile as a Handle to the logged on users registry. Question is how? Because to use RegOpenKeyEy and RegSetValueEx i need to pass a HKEY, not a HANDLE. So how can i use this Handle?
Thank!

You don't need to call ImpersonateLoggedOnUser() since you are passing the user's token to LoadUserProfile(). Call ImpersonateLoggedOnUser() only if you need to call APIs that do not allow you to pass a user token to them.
If you read the rest of the LoadUserProfile() documentation, it says:
The calling process must have the SE_RESTORE_NAME and SE_BACKUP_NAME privileges.
By impersonating the user you are trying to load a profile for, you are likely losing those privileges. So don't impersonate the user.
Update: Try something like this:
// get the active console session ID of the logged on user
DWORD dwSessionID = WTSGetActiveConsoleSessionId();
if ( dwSessionID == 0xFFFFFFFF )
{
ShowErrorText( "WTSGetActiveConsoleSessionId failed.", GetLastError( ), true );
return;
}
if ( !WTSQueryUserToken( dwSessionID, &hToken ) )
{
ShowErrorText( "WTSQueryUserToken failed.", GetLastError( ), true );
return;
}
// duplicate the token
HANDLE hDuplicated = NULL;
if ( !DuplicateToken( hToken, SecurityImpersonation, &hDuplicated ) )
{
ShowErrorText( "DuplicateToken failed.", GetLastError( ), true );
CloseHandle( hToken );
return;
}
// retrieve the DC name
if ( !GetPrimaryDC( DC ) )
{
ShowErrorText( "GetPrimaryDC failed.", 0, true );
CloseHandle( hDuplicated );
CloseHandle( hToken );
return;
}
PROFILEINFO lpProfileInfo;
ZeroMemory( &lpProfileInfo, sizeof( PROFILEINFO ) );
lpProfileInfo.dwSize = sizeof( PROFILEINFO );
lpProfileInfo.lpUserName = CurrentUser;
// get type of profile. roaming, mandatory or temporary
USER_INFO_4 *UserInfo = NULL;
int ret = GetTypeOfProfile();
if ( ret == 2 )
{
// if roaming profile get the path of it
if ( NetUserGetInfo( DC, CurrentUser, 4, (LPBYTE*)&UserInfo) != NERR_Success )
{
ShowErrorText( "NetUserGetInfo failed.", 0, true );
CloseHandle( hDuplicated );
CloseHandle( hToken );
return;
}
lpProfileInfo.lpProfilePath = UserInfo->usri3_profile;
}
if ( !LoadUserProfile( hDuplicated, &lpProfileInfo ) )
{
ShowErrorText( "LoadUserProfile failed.", GetLastError(), true );
if ( UserInfo )
NetApiBufferFree(UserInfo);
CloseHandle( hDuplicated );
CloseHandle( hToken );
return;
}
if ( UserInfo )
NetApiBufferFree(UserInfo);
ShowErrorText( "LoadUserProfile succeeded.", 0, true );
//do some stuff
if ( !UnloadUserProfile( hDuplicated, lpProfileInfo.hProfile ) )
{
ShowErrorText( "UnloadUserProfile failed.", GetLastError( ), true );
}
else
{
ShowErrorText( "UnloadUserProfile succeeded.", 0, true );
}
CloseHandle( hDuplicated );
CloseHandle( hToken );
As for the Registry, the hProfile handle is the opened HKEY for the user's HKEY_CURRENT_USER tree. Simpy type-cast it from HANDLE to HKEY when passing it to Registry API functions. It is already opened, so you do not need to call RegOpenKeyEx() to open that same key again, but you can use it as the root key when creating/opening subkeys, or reading/writing values in the root key.

Related

GetProcessMemoryInfo failed with error 6 Handle is invalid

I'm trying to get the list of processes running in the system using C++. I use the functions available in the Windows API (like OpenProcess & CreateToolhelp32Snapshot ) to get it done.
The problem is that the code works fine for most of the processes, but couldn't get the memory info for crucial system processes alone, I have given the seDebugPrivilege also and have run the program as administrator only.
I get the output like
File Name PID Memory Used
winlogon.exe 1248 2432 KB
fontdrvhost.exe 1308
WARNING: GetProcessMemoryInfo failed with error 6 (The handle is invalid)
dwm.exe 1384
WARNING: GetProcessMemoryInfo failed with error 6 (The handle is invalid)
svchost.exe 1448 4744 KB
My code is :
BOOL GetProcessList( )
{
HANDLE hProcessSnap;
HANDLE hProcess;
HANDLE hToken;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass;
PROCESS_MEMORY_COUNTERS pmc;
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
char err[]="CreateToolhelp32Snapshot (of processes)";
printError( err );
return( FALSE );
}
pe32.dwSize = sizeof( PROCESSENTRY32 );
if( !Process32First( hProcessSnap, &pe32 ) )
{
char err[]="Process32First";
printError( err ); // show cause of failure
CloseHandle( hProcessSnap ); // clean the snapshot object
return( FALSE );
}
if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken))
{
if (GetLastError() == ERROR_NO_TOKEN)
{
if (!ImpersonateSelf(SecurityImpersonation))
return FALSE;
if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)){
char err[]="OpenThreadToken";
printError( err );
return FALSE;
}
}
else
return FALSE;
}
SetPrivilege(hToken, SE_DEBUG_NAME, FALSE);
do
{
printf( "%-25s", pe32.szExeFile );
dwPriorityClass = 0;
SIZE_T dwMin, dwMax;
hProcess = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION , FALSE, pe32.th32ProcessID );
printf("%-10d", pe32.th32ProcessID );
if(GetProcessMemoryInfo( hProcess, (PROCESS_MEMORY_COUNTERS *)&pmc, sizeof(pmc)))
{
printf( "%-10d KB", pmc.PagefileUsage/1024);
} else{
char err[]="GetProcessMemoryInfo";
printError( err );
}
printf("\n");
CloseHandle(hProcess);
}while( Process32Next( hProcessSnap, &pe32 ) );
CloseHandle( hProcessSnap );
return( TRUE );
}
To get this code to work, you have to change:
SetPrivilege(hToken, SE_DEBUG_NAME, FALSE)
to:
SetPrivilege(hToken, SE_DEBUG_NAME, TRUE)
As others have commented, to get this code to work properly, you have to:
check for and report all possible error conditions
release all resources when you are done, in this case release hToken (via CloseHandle()) and call revertToSelf() if needs be.
Other than that, it's a decent effort so thumbs up for that.
Link to SetPrivilege(), in case any future visitor needs it:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa446619.aspx
Happy hacking.

How to disable encryption done by Wincrypt API

I want to disable the encryption which is encrypted in Wincrypt API.
Please give me suggestions, how to do that, general sugestions are also welcomed
Below is the Code Samples from EncryptedMessage.cpp :
EncryptedMessage Encrypt( TextMessage& Msg, const KeyBlob& RecipientExchangeKeyBlob )
throw( CCryptoEngine::Exception )
{
CryptProvider CryptProvider = GetCryptoProvider();
CryptKey SessionKey = CreateSessionKey( CryptProvider );
CryptKey RecipientExchangeKey = ImportExchangeKey( CryptProvider,
RecipientExchangeKeyBlob );
KeyBlob SessionKeyBlob = CreateSessionKeyBlob( SessionKey, RecipientExchangeKey );
if( ! CryptEncrypt( SessionKey, 0, TRUE, 0,
Msg.Text(), &Msg.Size(), Msg.Capacity() ) )
throw CCryptoEngine::Exception( ResourceString( IDS_CREN_MSG_ENC_FAILED ) +
GetErrorMessageFromCode( GetLastError() ) );
KeyBlob SignatureBlob; //Empty signature
return EncryptedMessage( SessionKeyBlob, Msg, SignatureBlob );
}
Useful Code Snipped from another class Below:
CCryptoEngine::CryptProvider CCryptoEngine::
GetCryptoProvider()
throw( CCryptoEngine::Exception )
{
if( ! CryptProviderAllocator::IsAllocated( m_RSACryptProvider ) )
{
if( ! CryptAcquireContext( &m_RSACryptProvider, _T("CollabWorx SIM Client"),
MS_ENHANCED_PROV, PROV_RSA_FULL, 0 ) )
if( ! CryptAcquireContext( &m_RSACryptProvider, _T("CollabWorx SIM Client"),
MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET ) )
if( ! CryptAcquireContext( &m_RSACryptProvider, NULL, MS_ENHANCED_PROV,
PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_VERIFYCONTEXT ) )
throw CCryptoEngine::Exception(
"Your system may lack the required security capabilities.\n"
"Please make sure that Microsoft High Encryption Pack (128-bit strength) "
"is installed in your system.\n\nInformation for the support:\n"
+ GetErrorMessageFromCode( GetLastError() ) );
g_RSACryptProvider = m_RSACryptProvider;
}
return m_RSACryptProvider;
}
If you want to decrypt the encrypted message, you should use the CryptDecrypt function.
See MSDN document:
https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(Wincrypt%2FCryptDecrypt);k(CryptDecrypt);k(DevLang-C%2B%2B);k(TargetOS-Windows)&rd=true
Based on your code, you should use the same SessionKey as the one used in the Encrypt method to decrypt the encrypted message.

Firewall exception code just works for outgoing connections

I took this code from the web to add a firewall exception for my application:
STDAPI AddApplicationToExceptionListW( const WCHAR* strGameExeFullPath, const WCHAR* strFriendlyAppName )
{
HRESULT hr = E_FAIL;
bool bCleanupCOM = false;
BSTR bstrFriendlyAppName = NULL;
BSTR bstrGameExeFullPath = NULL;
INetFwAuthorizedApplication* pFwApp = NULL;
INetFwAuthorizedApplications* pFwApps = NULL;
INetFwProfile* pFwProfile = NULL;
#ifdef SHOW_DEBUG_MSGBOXES
WCHAR sz[1024];
StringCchPrintf( sz, 1024, L"strFriendlyAppName='%s' strGameExeFullPath='%s'", strFriendlyAppName, strGameExeFullPath );
MessageBox( NULL, sz, L"AddApplicationToExceptionListW", MB_OK );
#endif
if( strGameExeFullPath == NULL || strFriendlyAppName == NULL )
{
assert( false );
return E_INVALIDARG;
}
bstrGameExeFullPath = SysAllocString( strGameExeFullPath );
bstrFriendlyAppName = SysAllocString( strFriendlyAppName );
if( bstrGameExeFullPath == NULL || bstrFriendlyAppName == NULL )
{
hr = E_OUTOFMEMORY;
goto LCleanup;
}
hr = CoInitialize( 0 );
bCleanupCOM = SUCCEEDED( hr );
pFwProfile = GetFirewallProfile();
if( pFwProfile == NULL )
{
hr = E_FAIL;
goto LCleanup;
}
hr = pFwProfile->get_AuthorizedApplications( &pFwApps );
if( FAILED( hr ) )
goto LCleanup;
// Create an instance of an authorized application.
hr = CoCreateInstance( __uuidof( NetFwAuthorizedApplication ), NULL,
CLSCTX_INPROC_SERVER, __uuidof( INetFwAuthorizedApplication ), ( void** )&pFwApp );
if( FAILED( hr ) )
goto LCleanup;
// Set the process image file name.
hr = pFwApp->put_ProcessImageFileName( bstrGameExeFullPath );
if( FAILED( hr ) )
goto LCleanup;
// Set the application friendly name.
hr = pFwApp->put_Name( bstrFriendlyAppName );
if( FAILED( hr ) )
goto LCleanup;
// Add the application to the collection.
hr = pFwApps->Add( pFwApp );
LCleanup:
if( bstrFriendlyAppName ) SysFreeString( bstrFriendlyAppName );
if( bstrGameExeFullPath ) SysFreeString( bstrGameExeFullPath );
if( pFwApp ) pFwApp->Release();
if( pFwApps ) pFwApps->Release();
if( pFwProfile ) pFwProfile->Release();
if( bCleanupCOM ) CoUninitialize();
return hr;
}
Everything works great when I try to send data through the Windows firewall, but incoming connections are still blocked. So I have to disable my firewall to recieve data. I thought, that exception would allow all connections (outgoing and incoming)...
Does somebody know what I should add to this code so I can recieve incoming data?
It is not enough to just add the application by itself. The firewall has no way of discovering which port(s) the application is listening on for inbound connections. You have to tell the firewall which port(s) the application is using. You do that via the INetFwProfile::GloballyOpenPorts collection, eg:
INetFwOpenPorts *pFwPorts = NULL;
INetFwOpenPort *pFWPort = NULL;
...
hr = pFwProfile->get_GloballyOpenPorts( &pFwPorts );
if( FAILED( hr ) )
goto LCleanup;
// Create an instance of an open port.
hr = CoCreateInstance( __uuidof( NetFwOpenPort ), NULL, CLSCTX_INPROC_SERVER, __uuidof( INetFwOpenPort ), ( void** )&pFwPort );
if( FAILED( hr ) )
goto LCleanup;
// Set the port number.
hr = pFWPort->put_Port( ... );
if( FAILED( hr ) )
goto LCleanup;
// Add the port to the collection.
hr = pFwPorts->Add( pFwPort );
...
if( pFwPort ) pFwPort->Release();
if( pFwPorts ) pFwPorts->Release();
In my case the solution was deleting the firewall rules that blocked my application. I don't know where these rules came from, but now it finally works.

How to determinate if my application is running under SYSTEM account or not?

How could I decide if my application is running under LocalSystem Account or not? Is there an easy way to do that?
Thanks!
Thanks for your help, but I might have found a way. Not the best, I know, but it works.
BOOL CheckIfRunningAsSYSTEM( VOID )
{
DWORD i, dwSize = 0, dwResult = 0;
HANDLE hToken;
PTOKEN_USER Ptoken_User;
// Open a handle to the access token for the calling process.
if ( !OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken ) )
{
printf( "OpenProcessToken Error %u\n", GetLastError() );
return FALSE;
}
// Call GetTokenInformation to get the buffer size.
if ( !GetTokenInformation( hToken, TokenUser, NULL, dwSize, &dwSize ) )
{
dwResult = GetLastError();
if ( dwResult != ERROR_INSUFFICIENT_BUFFER )
{
printf( "GetTokenInformation Error %u\n", dwResult );
return FALSE;
}
}
// Allocate the buffer.
Ptoken_User = ( PTOKEN_USER )GlobalAlloc( GPTR, dwSize );
// Call GetTokenInformation again to get the group information.
if ( !GetTokenInformation( hToken, TokenUser, Ptoken_User, dwSize, &dwSize ) )
{
printf( "GetTokenInformation Error %u\n", GetLastError() );
return FALSE;
}
LPWSTR SID = NULL;
if ( !ConvertSidToStringSidW( Ptoken_User->User.Sid, &SID ) )
{
printf( "\nConvertSidToStringSidW failed. Error = %d", GetLastError() );
return FALSE;
}
else printf( "\nConvertSidToStringSidW succeeded." );
if ( _wcsicmp( L"S-1-5-18", SID ) == 0 ) printf( "\nRunning under SYSTEM" );
else printf( "\nNOT running under SYSTEM" );
if ( Ptoken_User ) GlobalFree( Ptoken_User );
return TRUE;
}//CheckIfRunningAsSYSTEM

Filter System processes from user processes

I need to know how can I filter current user files/processes from operating system processes ?
I have listed all the current running files through the attached code in C++ .
now, i need to know how can i show only user files from this list?
Is there any demarcation parameter for this!!
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
// Forward declarations:
BOOL GetProcessList( );
BOOL ListProcessModules( DWORD dwPID );
void printError( TCHAR* msg );
int main( void )
{
GetProcessList( );
return 0;
}
BOOL GetProcessList( )
{
HANDLE hProcessSnap;
HANDLE hProcess;
PROCESSENTRY32 pe32;
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
printError( TEXT("CreateToolhelp32Snapshot (of processes)") );
return( FALSE );
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof( PROCESSENTRY32 );
// Retrieve information about the first process,
// and exit if unsuccessful
if( !Process32First( hProcessSnap, &pe32 ) )
{
printError( TEXT("Process32First") ); // show cause of failure
CloseHandle( hProcessSnap ); // clean the snapshot object
return( FALSE );
}
// Now walk the snapshot of processes, and
// display information about each process in turn
do
{
_tprintf( TEXT("\n\n=====================================================" ));
_tprintf( TEXT("\nPROCESS NAME: %s"), pe32.szExeFile );
// List the modules and threads associated with this process
ListProcessModules( pe32.th32ProcessID );
} while( Process32Next( hProcessSnap, &pe32 ) );
CloseHandle( hProcessSnap );
return( TRUE );
}
BOOL ListProcessModules( DWORD dwPID )
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
printError( TEXT("CreateToolhelp32Snapshot (of modules)") );
return( FALSE );
}
// Set the size of the structure before using it.
me32.dwSize = sizeof( MODULEENTRY32 );
// Retrieve information about the first module,
// and exit if unsuccessful
if( !Module32First( hModuleSnap, &me32 ) )
{
printError( TEXT("Module32First") ); // show cause of failure
CloseHandle( hModuleSnap ); // clean the snapshot object
return( FALSE );
}
// Now walk the module list of the process,
// and display information about each module
do
{
_tprintf( TEXT("\n\n MODULE NAME: %s"), me32.szModule );
_tprintf( TEXT("\n Executable = %s"), me32.szExePath );
} while( Module32Next( hModuleSnap, &me32 ) );
CloseHandle( hModuleSnap );
return( TRUE );
}
void printError( TCHAR* msg )
{
DWORD eNum;
TCHAR sysMsg[256];
TCHAR* p;
eNum = GetLastError( );
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
sysMsg, 256, NULL );
// Trim the end of the line and terminate it with a null
p = sysMsg;
while( ( *p > 31 ) || ( *p == 9 ) )
++p;
do { *p-- = 0; } while( ( p >= sysMsg ) &&
( ( *p == '.' ) || ( *p < 33 ) ) );
// Display the message
_tprintf( TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg );
}