Delete key and subkey from registry:Code throw unhandled exception - c++

I want to delete the Registry key and the all subkey.I am using the code from here.
Code compile fine but when debug the code
"Unhandled exception at 0x00416d14 in deletedemo.exe: 0xC0000005: Access violation writing location 0x0041ff01."
exception occur at the line
// Check for an ending slash and add one if it is missing.
lpEnd = lpSubKey + lstrlen(lpSubKey);
if (*(lpEnd - 1) != TEXT('\\'))
{
*lpEnd = TEXT('\\'); //Here exception occur.
lpEnd++;
*lpEnd = TEXT('\0');
}

I have written a code to delete the Registry Key and its Subkeys recursively some time ago. The code goes like this::
static BOOL RcrsvRegDel( HKEY hKey, LPTSTR lpszSub, DWORD dwOpenFlags )
{
BOOL bRet = TRUE ;
LONG lRet ;
DWORD dwSize = MAX_PATH ;
TCHAR szName[MAX_PATH] ;
HKEY hKeySub = NULL ;
HRESULT hr = NULL ;
HANDLE hProcess = NULL ;
HANDLE hToken = NULL ;
do{
lRet = RegOpenKeyEx( hKey, lpszSub, 0, dwOpenFlags, &hKeySub ) ;
if( lRet != ERROR_SUCCESS )
{
bRet = FALSE ;
break ;
}
while( ERROR_NO_MORE_ITEMS != (lRet = RegEnumKeyEx(hKeySub, 0, szName, &dwSize, NULL,
NULL, NULL, NULL)) )
if( !RcrsvRegDel(hKeySub, szName, dwOpenFlags) )
{
bRet = FALSE ;
break ;
}
lRet = RegDeleteKey( hKey, lpszSub ) ;
printf("RegDelKey:: %S :: lRet = %ld\n", lpszSub, lRet) ;
if( lRet != ERROR_SUCCESS )
{
bRet = FALSE ;
break ;
}
if( hKeySub != NULL )
{
RegCloseKey(hKeySub) ;
hKeySub = NULL ;
}
}while(0) ;
return bRet ;
}
dwOpenFlags = Flags to be passed to RegOpenKeyEx or RegDeleteKey.
EDIT:: If you do not want to delete the whole tree yourself recursively, MSDN have two functions to do this. You can always use them, namely, RegDeleteTree and SHDeleteKey.

Related

How to get the SID and User Name of the user utilising my service in C++

I am attempting to create a service that will essentially act as a local web server. In theory users will use a REST API by visiting URIs through localhost in a browser i.e. http://localhost:2017/path/to/function/call will connect to the service and execute a function.
My question is how do I get the SID and User Name of the account that called the service?
I have implemented a couple of solutions but they return the SID and User Name of the service and not the user using it.
OJSon* UnifiedStreamingService::getUserDetails()
{
OJSon* result = OJSon::create();
if(result)
{
/*
HANDLE hToken = NULL;
ULONG id = WTSGetActiveConsoleSessionId();
BOOL bRet = WTSQueryUserToken(id, &hToken);
if (bRet == false)
{
DWORD error = GetLastError();
printf("ERROR: %d", error);
}
*/
HANDLE hToken = NULL;
if ( ! OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken ) )
{
//_tprintf( _T("OpenProcessToken failed. GetLastError returned: %d\n"), GetLastError());
return NULL;
}
// Get the size of the memory buffer needed for the SID
DWORD dwBufferSize = 0;
if ( ! GetTokenInformation( hToken, TokenUser, NULL, 0, &dwBufferSize ) && ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) )
{
//_tprintf( _T("GetTokenInformation failed. GetLastError returned: %d\n"), GetLastError());
// Cleanup
CloseHandle( hToken );
hToken = NULL;
return NULL;
}
// Allocate buffer for user token data
std::vector<BYTE> buffer;
buffer.resize( dwBufferSize );
PTOKEN_USER pTokenUser = reinterpret_cast<PTOKEN_USER>( &buffer[0] );
// Retrieve the token information in a TOKEN_USER structure
if ( ! GetTokenInformation(
hToken,
TokenUser,
pTokenUser,
dwBufferSize,
&dwBufferSize))
{
//_tprintf( _T("2 GetTokenInformation failed. GetLastError returned: %d\n"), GetLastError());
// Cleanup
CloseHandle( hToken );
hToken = NULL;
return NULL;
}
// Check if SID is valid
if ( ! IsValidSid( pTokenUser->User.Sid ) )
{
//_tprintf( _T("The owner SID is invalid.\n") );
// Cleanup
CloseHandle(hToken);
hToken = NULL;
return NULL;
}
// add the name
OString* name = lookupAccountSid(pTokenUser->User.Sid);
if(name)
{
result->setKey(&OString("name"), name);
SAFEDELETE(name);
}
// add the SID
OString* sid = convertSidToString(pTokenUser->User.Sid);
if(sid)
{
result->setKey(&OString("SID"), sid);
SAFEDELETE(sid);
}
// Cleanup
CloseHandle(hToken);
hToken = NULL;
}
return result;
}
OString* UnifiedStreamingService::convertSidToString(PSID pSID)
{
OString* result = NULL;
if(pSID)
{
// Get string corresponding to SID
LPTSTR pszSID = NULL;
if ( ! ConvertSidToStringSid( pSID, &pszSID ) )
{
return NULL;
}
result = new OString(pszSID);
// Release buffer allocated by ConvertSidToStringSid API
LocalFree( pszSID );
pszSID = NULL;
}
return result;
}
OString* UnifiedStreamingService::lookupAccountSid(PSID pSID)
{
DWORD dwSize = 256;
DWORD dwResult = 0;
SID_NAME_USE SidType;
LPTSTR lpName = new TCHAR[dwSize];
LPWSTR lpDomain = new TCHAR[dwSize];
OString* result = NULL;
if( !LookupAccountSid( NULL, pSID, lpName, &dwSize, lpDomain, &dwSize, &SidType ) )
{
dwResult = GetLastError();
return NULL;
}
OString* pDomain = new OString(lpDomain);
OString* pName = new OString(lpName);
if(pDomain && pName)
{
result = OString::createByFormat(&OString("%s\\%s"), pDomain, pName);
SAFEDELETE(pDomain);
SAFEDELETE(pName);
}
delete[] lpDomain;
delete[] lpName;
return result;
}
The task can be accomplished by using WTSGetActiveConsoleSessionId and WTSQueryUserToken to get user token and then getting SID with GetTokenInformation.
The additional requirement is the service is running under Local System account which grants SE_TCB_NAME privelege (== SeTcbPrivilege). SE_TCB_NAME required by WTSQueryUserToken. Note that the other accounts usually have no SE_TCB_NAME privelege!

WinHttpReceiveResponse function return an error

Can someone tell me what is wrong in the code below?
void Mess(LPCWSTR Str)
{
MessageBox(0, Str, L"Hi", 0);
}
int main()
{
// HttpOpen
HINTERNET hHttp = NULL;
LPCWSTR lpcwAgent = L"UserAgent";
DWORD dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
LPCWSTR lpcwProxyName = WINHTTP_NO_PROXY_NAME;
LPCWSTR lpcwProxyByPass = WINHTTP_NO_PROXY_BYPASS;
DWORD dwFlag = 0;
// HttpConnect
HINTERNET hConnect = NULL;
LPCWSTR lpcwServerName = L"localhost";
INTERNET_PORT Port = INTERNET_DEFAULT_HTTP_PORT;
DWORD dwReserved = 0; //must be 0
// HttpOpenRequest
HINTERNET hRequest = NULL;
LPCWSTR lpcwVerb = L"GET"; // or POST, PUT
LPCWSTR lpcwObjectName = L"/index.php";
LPCWSTR lpcwVersion = NULL; //NULL == HTTP/1.1
LPCWSTR lpcwReferrer = WINHTTP_NO_REFERER; // It mean there's no referrer
LPCWSTR* plpcwAccept = WINHTTP_DEFAULT_ACCEPT_TYPES; // For more information: Media types (http://www.iana.org/assi gnments/medi a-types)
DWORD dwRequestFlag = 0;
// HttpSendRequest
bool bSendRequest = false;
LPCWSTR lpcwHeaders = WINHTTP_NO_ADDITIONAL_HEADERS; // Additional headers to append to the request
DWORD dwHeaderLength = 0;
LPVOID lpvOptional = WINHTTP_NO_REQUEST_DATA; //The data which is used for POST or PUT
DWORD dwOptionalLength = 0;
DWORD dwTotalLength = 0;
DWORD_PTR pdwContext = NULL;
// HttpReceiveResponse
bool bReceiveResponse = false;
HINTERNET _hRequest = NULL; // Will be set again after HttpOpenRequest are completed
LPVOID lpvReserved = NULL;
hHttp = WinHttpOpen(lpcwAgent, dwAccessType, lpcwProxyName, lpcwProxyByPass, dwFlag);
if ( hHttp == NULL )
{
Mess(L"Unable to open a connection");
}
else
{
hConnect = WinHttpConnect(hHttp, lpcwServerName, Port, dwReserved);
if ( hConnect == NULL )
{
Mess(L"Unable to Connecting");
}
else
{
hRequest = WinHttpOpenRequest(hConnect, lpcwVerb, lpcwObjectName, lpcwVersion, lpcwReferrer, plpcwAccept, dwRequestFlag);
if ( hRequest == NULL )
{
Mess(L"Unable to open the request");
}
else
{
bSendRequest = WinHttpSendRequest(hRequest, lpcwHeaders, dwHeaderLength, lpvOptional, dwOptionalLength, dwTotalLength, pdwContext);
if ( !bSendRequest )
{
Mess(L"Failed to send the request");
}
else
{
bReceiveResponse = WinHttpReceiveResponse(_hRequest, lpvReserved);
if ( !bReceiveResponse )
{
Mess(L"Unable to receive the response");
}
else
{
Mess(L"Ok");
}
}
}
}
}
if ( hRequest != NULL )
WinHttpCloseHandle(hRequest);
if ( hConnect != NULL )
WinHttpCloseHandle(hConnect);
if ( hHttp != NULL )
WinHttpCloseHandle(hHttp);
return 0;
}
I don't understand WINHTTP much but I'm trying.
When I excute the program, I get
Unable to receive the response
then, I use GetLastError() to get the code of the error that always is 6. I can't find anything about code 6?
Error code 6 is ERROR_INVALID_HANDLE "The handle is invalid."
The problem is that you use wrong variable for the request handle: _hRequest whereas you were to use hRequest instead.
WinHttpReceiveResponse(_hRequest, ...

Denied access trying to open process

Description: I've gotten myself into a problem, I'm trying to open a process and read the memory of that process. It works all fine while debugging in my VS 2013 IDE however, if I build it and run the standalone executable as administrator (or lower credentials) the process cannot be opened properly, I am recieving error code 5, which is access denied.
The thing that confuses me is the fact it's working fine in the IDE but not with the standalone executable. I don't see why VS 2013 would have higher credentials than running a program as administrator.
A link to the code is here:
https://floobits.com/Simple2012/Simple_Bot
The important section is memoryReading.cpp line 30-35
A summary of the problem follows:
1. Everything works fine in visual Studio 2013.
2. The standalone executable is denied access when trying to open "the" process.
3. The executable is run as with full rights as administrator, so is the IDE.
I want to understand this a bit more detailed so I have two key questions, if anyone is in a good mood, I would love to have a very detailed explanation.
Question 1: How can I open the process with my standalone executable?
Question 2: Why does this problem occur the way it do?
If there's any information you're missing, don't hesitate to ask for it and I'll add it in as fast as possible. I also tried highlighing some parts to make it more comfortable to read and get a quick and brief idea of the problem.
I'm trying to open a process and read the memory of that process. It works all fine while debugging
This is because you user account has SE_DEBUG_NAME (SeDebugPrivilege). Its common for developers to develop with SE_DEBUG_NAME, but its not advised.
You should develop as a regular user account to ensure you don't get these kind of unexpected dependencies.
The thing that confuses me is the fact it's working fine in the IDE but not with the standalone executable...
Now that the issue cleared up...
Question 1: How can I open the process with my standalone executable?
Question 2: Why does this problem occur the way it do?
There are a few ways to fix it.
First, you can "compile" the privilege in by setting /MANIFESTUAC:level=requireAdministrator in the manifest options. "Compiling the privilege in" is a bit misleading because you will still be prompted by UAC. See /MANIFESTUAC on MSDN.
Second, you can set "Run as Administrator" on the program's properties. Right click the executable, then select the Compatibility tab. See Configure Applications to Always Run as an Administrator on Technet. You will be prompted by UAC.
Third, you can right click your executable, and then select "Run as Administrator". You will need to do this for each invocation of your program. You will be prompted by UAC.
Its not enough to "Run as Administrator". You will now need to enable a privilege or two. That's because Windows does not start your process with all privileges enabled (unlike Linux/Unix and su or sudo). Of the privileges listed at Privilege Constants, these are the three or four interesting ones:
SE_ASSIGNPRIMARYTOKEN_NAME
SE_DEBUG_NAME
SE_TCB_NAME
SE_INCREASE_QUOTA_NAME
Here's the code I use to enable privileges, like "SeDebugPrivilege":
BOOL CUserPrivilege::EnablePrivilege( LPCTSTR pszPrivilege, BOOL bEnabled ){
// Returned to caller
BOOL bResult = FALSE;
// Thread or Process token
HANDLE hToken = NULL;
__try {
bResult = OpenThreadToken( GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, TRUE, &hToken );
if( !bResult )
{
bResult = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken );
assert( TRUE == bResult );
if( FALSE == bResult ) { __leave; }
}
bResult = EnablePrivilege( hToken, pszPrivilege, bEnabled );
DWORD dwError = GetLastError();
assert( TRUE == bResult || ( ERROR_SUCCESS == GetLastError() || ERROR_NOT_ALL_ASSIGNED == dwError ) );
// We're only enabling one privilege. If we get back
// ERROR_NOT_ALL_ASSIGNED, then we failed.
if( ERROR_NOT_ALL_ASSIGNED == dwError ) { bResult = FALSE; }
}
__finally {
if( NULL != hToken ) {
CloseHandle( hToken ); hToken = NULL;
}
}
return bResult;
}
BOOL CUserPrivilege::EnablePrivilege( HANDLE hToken, LPCTSTR pszPrivilege, BOOL bEnabled )
{
BOOL bResult = FALSE;
__try {
LUID luid;
TOKEN_PRIVILEGES priv;
bResult = LookupPrivilegeValue( NULL, pszPrivilege, &luid );
assert( TRUE == bResult );
if( FALSE == bResult ) { __leave; }
priv.PrivilegeCount = 1;
priv.Privileges[0].Luid = luid;
priv.Privileges[0].Attributes =
(bEnabled ? SE_PRIVILEGE_ENABLED : FALSE );
bResult = AdjustTokenPrivileges( hToken, FALSE, &priv, sizeof(priv), NULL, NULL );
// We're only enabling one privilege. If we get back
// ERROR_NOT_ALL_ASSIGNED, we failed.
if( ERROR_NOT_ALL_ASSIGNED == GetLastError() ) { bResult = FALSE; }
if( FALSE == bResult ) { __leave; }
bResult = TRUE;
}
__finally { ; }
return bResult;
}
You can check what privileges you have with code similar to below:
CUserPrivilege::Status CUserPrivilege::HasPrivilege( LPCTSTR pszPrivilege )
{
// Returned to caller
Status status = Error;
// Thread or Process token
HANDLE hToken = NULL;
// Scratch
BOOL bResult = FALSE;
__try {
bResult = OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken );
if( !bResult )
{
bResult = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken );
assert( TRUE == bResult );
if( FALSE == bResult ) { __leave; }
}
status = HasPrivilege( hToken, pszPrivilege );
}
__finally {
if( NULL != hToken ) {
CloseHandle( hToken ); hToken = NULL;
}
}
return status;
}
CUserPrivilege::Status CUserPrivilege::HasPrivilege( HANDLE hToken, LPCTSTR pszPrivilege )
{
// Returned to caller
Status status = Error;
// Scratch
BOOL bResult = FALSE;
PBYTE pBuffer = NULL;
TOKEN_PRIVILEGES* pTokenInfo = NULL;
__try
{
LUID uid = { 0, 0 };
bResult = LookupPrivilegeValue( NULL, pszPrivilege, &uid );
assert( TRUE == bResult );
if( FALSE == bResult ) { __leave; }
DWORD dwRequired = 0;
bResult = GetTokenInformation( hToken, TokenPrivileges, NULL, 0, &dwRequired );
assert( FALSE == bResult );
if( TRUE == bResult || 0 == dwRequired ) { __leave; }
pBuffer = new BYTE[dwRequired];
assert( NULL != pBuffer );
if( NULL == pBuffer ) { __leave; }
DWORD dwSize = dwRequired;
bResult = GetTokenInformation( hToken, TokenPrivileges, pBuffer, dwSize, &dwRequired );
assert( TRUE == bResult );
if( FALSE == bResult || dwSize != dwRequired ) { __leave; }
pTokenInfo = (TOKEN_PRIVILEGES*)pBuffer;
DWORD count = pTokenInfo->PrivilegeCount;
// Status changed...
status = Missing;
for( DWORD i = 0; i<count; i++ )
{
if( pTokenInfo->Privileges[i].Luid.HighPart == uid.HighPart &&
pTokenInfo->Privileges[i].Luid.LowPart == uid.LowPart )
{
DWORD attrib = pTokenInfo->Privileges[i].Attributes;
if( (attrib & SE_PRIVILEGE_ENABLED) ||
(attrib & SE_PRIVILEGE_ENABLED_BY_DEFAULT) )
{
status = Enabled;
}
else if( (attrib & SE_PRIVILEGE_REMOVED) )
{
status = Disabled;
}
break;
}
}
}
__finally
{
if( NULL != pBuffer ) {
delete[] pBuffer; pBuffer = NULL;
}
}
return status;
}
And here's the Status enumeration mentioned in the code:
enum Status { Missing = -1, Error = 0, Disabled = 1, Enabled = 2 };

Reading Registry in Windows 7 behaving strangely

I am trying to read registry's "(Default)" values in Windows 7 in c++, and following is the code I am using:
string GetSZValueUnique( HKEY openKey, const char* regkey, const char* keyName )
{
HKEY hKey = 0;
BYTE data[512] ;
DWORD szsize = 512 ;
string value ;
LONG retValue = RegOpenKeyEx( openKey, regkey, 0, KEY_READ, &hKey ) ;
if ( retValue == ERROR_SUCCESS )
{
LONG retV = RegQueryValueEx( hKey, keyName, 0, 0, data, &szsize ) ;
if ( retV == ERROR_SUCCESS )
{
char* _value = reinterpret_cast<char*>(data) ;
value = _value ;
RegCloseKey (hKey) ;
return value ;
}
else
{
char msg[512] ;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,(DWORD)retV,0,&msg[0],512,0) ;
error_string = &msg[0];
MessageBox( 0, error_string.c_str(), "Query : GetSZValueUnique", 0 );
}
}
else
{
char msg[512] ;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,(DWORD)retV,0,&msg[0],512,0) ;
error_string = &msg[0];
MessageBox( 0, error_string.c_str(), "Open : GetSZValueUnique", 0 );
}
RegCloseKey (hKey) ;
return "" ;
}
And this is how I am calling the above function :
string ts3 = GetSZValueUnique( HKEY_LOCAL_MACHINE, "SOFTWARE\\TeamSpeak 3 Client\\", "" );
if ( !ts3.empty() )
MessageBox( 0, ts3.c_str(), "GetSZValueUnique", 0 );
For some Keys it works for some it doesn't : For example, it works for "Adobe", "TrendMicro", "CheckPoint", "RegisteredApplications" but not for "7-Zip", "RTLSetup", "Sonic", "TeamSpeak 3 Client"
I am out of ideas now, can somebody point out what's wrong ?
EDIT: I have checked the code with "(Default)" values and other values as well, for keys its not working it never goes past the *"if ( retValue == ERROR_SUCCESS )"* check and I always get "Specified file not found" error. For keys its working, it gets past the "*if ( retValue == ERROR_SUCCESS )*" check and returns the value if its present, if its not present it simply displays the error message "Specified file not found".
EDIT 2: I Checked again : and it seems the keys it works for have their corresponding clone in "Wow6432Node" subkey under SOFTWARE... hmmm... so how do I get it working ?
You can specify the flag::
"KEY_WOW64_32KEY" in "samDesired" parameter of the RegOpenKeyEx if you want to access Wow6432Node Keys i.e., 32-bit keys from your app.
"KEY_WOW64_64KEY" in "samDesired" parameter of the RegOpenKeyEx if you want to access normal Keys i.e., 64-bit keys from your app.
Note:: Your doubt has already been cleared by #WhozCraig in comments with the suitable links. If he answers, do accept his answer over mine.

C++ Get Username From Process

I have a process handle with
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, THE_PROCESS_ID);
How can I get the username of the user that is running the process?
I am using unmanaged code (no .NET).
Use OpenProcessToken to get the token (obviously), then GetTokenInformation with the TokenOwner flag to get the SID of the owner. Then you can use LookupAccountSid to get the username.
if WMI is not an option, then use GetUserFromProcess below that takes the process ID as an input parameter and returns the user name and domain:
#include <comdef.h>
#define MAX_NAME 256
BOOL GetLogonFromToken (HANDLE hToken, _bstr_t& strUser, _bstr_t& strdomain)
{
DWORD dwSize = MAX_NAME;
BOOL bSuccess = FALSE;
DWORD dwLength = 0;
strUser = "";
strdomain = "";
PTOKEN_USER ptu = NULL;
//Verify the parameter passed in is not NULL.
if (NULL == hToken)
goto Cleanup;
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID) ptu, // pointer to PTOKEN_USER buffer
0, // size of buffer
&dwLength // receives required buffer size
))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto Cleanup;
ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
if (ptu == NULL)
goto Cleanup;
}
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID) ptu, // pointer to PTOKEN_USER buffer
dwLength, // size of buffer
&dwLength // receives required buffer size
))
{
goto Cleanup;
}
SID_NAME_USE SidType;
char lpName[MAX_NAME];
char lpDomain[MAX_NAME];
if( !LookupAccountSid( NULL , ptu->User.Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType ) )
{
DWORD dwResult = GetLastError();
if( dwResult == ERROR_NONE_MAPPED )
strcpy (lpName, "NONE_MAPPED" );
else
{
printf("LookupAccountSid Error %u\n", GetLastError());
}
}
else
{
printf( "Current user is %s\\%s\n",
lpDomain, lpName );
strUser = lpName;
strdomain = lpDomain;
bSuccess = TRUE;
}
Cleanup:
if (ptu != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
return bSuccess;
}
HRESULT GetUserFromProcess(const DWORD procId, _bstr_t& strUser, _bstr_t& strdomain)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,procId);
if(hProcess == NULL)
return E_FAIL;
HANDLE hToken = NULL;
if( !OpenProcessToken( hProcess, TOKEN_QUERY, &hToken ) )
{
CloseHandle( hProcess );
return E_FAIL;
}
BOOL bres = GetLogonFromToken (hToken, strUser, strdomain);
CloseHandle( hToken );
CloseHandle( hProcess );
return bres?S_OK:E_FAIL;
}
WMI is probably the path of least resistance. You should also be able to get the token using OpenProcessToken, then GetTokenInformation to get the SID of the owner. You can then turn the SID into a user name.
WMI should be able to tell you that information. Otherwise you need to rely on undocumented fun in ntdll.dll. It appears others have found solutions that don't use ntdll.dll -- use them rather than undocumented stuff.
Here a solution knowing the process id.
std::optional<std::wstring> GetUserNameFromProcess(DWORD id)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id); // 1- OpenProcess
std::wstring endUser = L"";
std::wstring endDomain = L"";
if (hProcess != NULL)
{
HANDLE hToken = NULL;
if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) // 2- OpenProcessToken
{
DWORD tokenSize = 0;
GetTokenInformation(hToken, TokenUser, NULL, 0, &tokenSize);
if (tokenSize > 0)
{
BYTE* data = new BYTE[tokenSize];
GetTokenInformation(hToken, TokenUser, data, tokenSize, &tokenSize); // 3- GetTokenInformation
TOKEN_USER* pUser = (TOKEN_USER*)data;
PSID pSID = pUser->User.Sid;
DWORD userSize = 0;
DWORD domainSize = 0;
SID_NAME_USE sidName;
LookupAccountSid(NULL, pSID, NULL, &userSize, NULL, &domainSize, &sidName);
wchar_t* user = new wchar_t[userSize + 1];
wchar_t* domain = new wchar_t[domainSize + 1];
LookupAccountSid(NULL, pSID, user, &userSize, domain, &domainSize, &sidName); // 4- LookupAccountSid
user[userSize] = L'\0';
domain[domainSize] = L'\0';
endUser = user;
endDomain = domain;
delete[] domain;
delete[] user;
delete[] data;
}
CloseHandle(hToken);
}
CloseHandle(hProcess);
if (endUser != L"")
return endUser;
}
return {};
}