Recently I came across a Windows API called GetAppContainerNamedObjectPath. But I have no idea on how I can use it.
I found a msdn page for this api (https://learn.microsoft.com/en-us/windows/win32/api/securityappcontainer/nf-securityappcontainer-getappcontainernamedobjectpath). But it does not have a right example and remarks, parameters are written poorly.
I am getting ERROR_INVALID_PARAMETER(87) error at the end, which tells me something's wrong with the parameters that I put. Here's what I've tried.
#define TokenIsAppContainer 29
#define TokenAppContainerSid 31
#define TokenAppContainerNumber 32
typedef struct _TOKEN_APPCONTAINER_INFORMATION {
PSID TokenAppContainer;
} TOKEN_APPCONTAINER_INFORMATION, *PTOKEN_APPCONTAINER_INFORMATION;
void GetAppContainerProcessInfo(CString & procName)
{
DWORD dwSize = 0;
DWORD dwResult;
HANDLE hToken;
PTOKEN_APPCONTAINER_INFORMATION pAppCoInfo;
WCHAR wcsDebug[1024] = {0,};
WCHAR * pwSID = NULL;
typedef BOOL (WINAPI *_LPGETAPPCONTAINERNAMEOBJECTPATH)(HANDLE, PSID, ULONG, LPWSTR, PULONG);
static _LPGETAPPCONTAINERNAMEOBJECTPATH lpGetAppContainerNamedObjectPath = NULL;
if (0 == lpGetAppContainerNamedObjectPath)
{
HMODULE hKernel32 = LoadLibraryExW(L"kernel32.dll", NULL, 0);
if (hKernel32)
{
lpGetAppContainerNamedObjectPath = reinterpret_cast<_LPGETAPPCONTAINERNAMEOBJECTPATH>(GetProcAddress(hKernel32, "GetAppContainerNamedObjectPath"));
}
}
if (lpGetAppContainerNamedObjectPath)
{
DWORD processId = (DWORD)_ttoi((LPCTSTR)procName);
//HANDLE hProcess = GetProcessHandleByProcessName(procName);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
if(!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
{
dwResult = GetLastError();
swprintf_s( wcsDebug, _countof(wcsDebug), L"OpenProcessToken Error(%u) PID(%d)\n", dwResult, processId );
AfxMessageBox(wcsDebug);
return;
}
if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) TokenAppContainerSid, NULL, dwSize, &dwSize))
{
dwResult = GetLastError();
if( dwResult != ERROR_INSUFFICIENT_BUFFER )
{
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetTokenInformation Error %u\n", dwResult );
AfxMessageBox(wcsDebug);
return;
}
}
pAppCoInfo = (PTOKEN_APPCONTAINER_INFORMATION) GlobalAlloc( GPTR, dwSize );
if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) TokenAppContainerSid, pAppCoInfo, dwSize, &dwSize))
{
dwResult = GetLastError();
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetTokenInformation Error %u\n", dwResult );
AfxMessageBox(wcsDebug);
return;
}
WCHAR wcsNamedObjectPath[MAX_PATH];
ULONG ulRetlen = 0;
BOOL bRet = lpGetAppContainerNamedObjectPath(hToken, pAppCoInfo->TokenAppContainer, _countof(wcsNamedObjectPath), wcsNamedObjectPath, &ulRetlen );
if (bRet)
{
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetAppContainerNamedObjectPath Path(%s)\n", wcsNamedObjectPath );
AfxMessageBox(wcsDebug);
}
else
{
dwResult = GetLastError();
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetAppContainerNamedObjectPath Error %u\n", dwResult );
AfxMessageBox(wcsDebug);
}
if (pwSID)
LocalFree(pwSID);
CloseHandle(hToken)
CloseHandle(hProcess);
}
}
As a side-note, I have tried using wchar_t * and dynamically allocate the memory buffer by calling GetAppContainerNamedObjectPath twice. But still had no chance. Return length does not return a meaningful value.
if you call RtlGetLastNtStatus(); instead GetLastError(); after GetAppContainerNamedObjectPath you will got
STATUS_INVALID_PARAMETER_MIX - An invalid combination of parameters was specified.
this give you more info compare simply invalid parameter.
then look for function signature
BOOL
WINAPI
GetAppContainerNamedObjectPath(
_In_opt_ HANDLE Token,
_In_opt_ PSID AppContainerSid,
_In_ ULONG ObjectPathLength,
_Out_writes_opt_(ObjectPathLength) LPWSTR ObjectPath,
_Out_ PULONG ReturnLength
);
the Token and AppContainerSid declared with In_opt -- this mean that this parameters is optional, and you can pass 0 in place one of it. then ask your self - for what you query token for TokenAppContainerSid ? are system can not do this for you if you pass this token to api ? obvious can. so you not need do this yourself. really you need pass Token to api and in this case AppContainerSid must be 0. or you can pass AppContainerSid to api and in this case Token must be 0. when both AppContainerSid and Token not zero - you and got STATUS_INVALID_PARAMETER_MIX
also as side note - you not need open process with PROCESS_ALL_ACCESS if you need get it token. the PROCESS_QUERY_LIMITED_INFORMATION is enough
really api not do big magic. it return to you
AppContainerNamedObjects\<Sid>
path, where string form of app container sid.(some like S-1-15-2-...)
Related
LPCSTR lpszUsername = "admin user";
LPCSTR lpszDomain = "DESKTOP-H60GO83";
LPCSTR lpszPassword = "password";
DWORD dwLogonType = LOGON32_LOGON_INTERACTIVE;
DWORD dwLogonProvider = LOGON32_PROVIDER_WINNT40;
PHANDLE hToken;
LogonUserA(
lpszUsername,
lpszDomain,
lpszPassword,
dwLogonType,
dwLogonProvider,
hToken);
memset(&sui, 0, sizeof(sui));
sui.cb = sizeof(sui);
LPTSTR lpApplicationName = "C:\\Windows\\System32\\cmd.exe ";
CreateProcessAsUserA(
hToken,
lpApplicationName,
NULL,
NULL,
NULL,
TRUE,
NULL,
NULL,
NULL,
&sui,
&pi
);
That's my code. What am I doing wrong? Process exits immediately when the console loads.
I need this to add to my reverse shell.
I used CreateProcess() and it worked. I'm using CreateProcessAsUserA() to give my shell admin privileges.
You are not using the hToken variable correctly.
You have declared an uninitialized pointer to a HANDLE, but are not pointing it at a valid HANDLE. You are then passing that bad pointer to LogonUserA(), which is undefined behavior. And then you are passing that bad pointer to CreateProcessAsUserA(), which doesn't even want a pointer to a HANDLE to begin with, it wants the actual HANDLE instead.
You are also not checking for errors from the API calls.
Try this instead:
LPCSTR lpszUsername = "admin user";
LPCSTR lpszDomain = "DESKTOP-H60GO83";
LPCSTR lpszPassword = "password";
DWORD dwLogonType = LOGON32_LOGON_INTERACTIVE;
DWORD dwLogonProvider = LOGON32_PROVIDER_WINNT40;
HANDLE hToken = NULL; // <-- no P !
if (!LogonUserA(
lpszUsername,
lpszDomain,
lpszPassword,
dwLogonType,
dwLogonProvider,
&hToken)) // <-- add & !
{
// error handling...
}
STARTUPINFO sui;
memset(&sui, 0, sizeof(sui));
sui.cb = sizeof(sui);
PROCESS_INFORMATION pi;
LPTSTR lpApplicationName = "C:\\Windows\\System32\\cmd.exe";
if (!CreateProcessAsUserA(
hToken,
lpApplicationName,
NULL,
NULL,
NULL,
TRUE,
NULL,
NULL,
NULL,
&sui,
&pi
))
{
// error handling ...
}
...
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
/*
author: #......MARSHA4CODING
*/
#include <iostream>
#include <windows.h>
using namespace std;
STARTUPINFO sui;
PROCESS_INFORMATION pi;
int main(){
LPCSTR lpszUsername = "ADMIN";
LPCSTR lpszDomain = " DESKTOP-
H60GO73";
LPCSTR lpszPassword = "PASSWORD" ;
DWORD dwLogonType =
LOGON32_LOGON_INTERACTIVE;
DWORD dwLogonProvider =
LOGON32_PROVIDER_DEFAULT ;
HANDLE hToken = NULL; // <-- no P !
if (!LogonUserA(
lpszUsername,
lpszDomain,
lpszPassword,
dwLogonType,
dwLogonProvider,
&hToken)) // <-- add & !
{
DWORD rx2 = GetLastError();
return rx2;
}
STARTUPINFO sui;
memset(&sui, 0, sizeof(sui));
sui.cb = sizeof(sui);
PROCESS_INFORMATION pi;
LPTSTR lpApplicationName =
"C:\\Windows\\System32\\cmd.exe";
HANDLE phNewToken; // stores either the
Primary or Impersonation token gotten
from DuplicateTokenEx
//LPSECURITY_ATTRIBUTES
lpTokenAttributes
//SECURITY_IMPERSONATION_LEVEL
ImpersonationLevel
if(!DuplicateTokenEx(hToken,
0,lpTokenAttributes,
ImpersonationLevel,1,phNewToken)){
cout<<"Duplication Error";
}
if (!CreateProcessAsUserA(
hToken,
lpApplicationName,
NULL,
NULL,
NULL,
TRUE,
NULL,
NULL,
NULL,
&sui,
&pi
))
{
DWORD rx2 = GetLastError();
return rx2;
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
}
I think the issue is with the
DuplicateTokenEx();
function because the token I'm supposed to get from the
LogonUserA();
Will be used to generate either a Primary or Impersonation Token with
DuplicateTokenEx(); function
So my challenge right now is with the
TokenAttributes and Impersonationlevel when using
DuplicateTokenEx(): function I don't know what to write there, Pardon my silly Questions.
There is a launcher - a program in C++, which you need to run as administrator. The launcher launches another process as well on behalf of the administrator and because of this, third-party programs (AutoHotkey) running with the rights of a normal user can not access it. The second process does not require administrator rights, so I would like to implement the launch with the rights of a normal user. How to do it?
At the moment I'm running the process using boost::process::system.
Raymond Chen has a blog article on this very topic:
How can I launch an unelevated process from my elevated process and vice versa?
Going from an unelevated process to an elevated process is easy. You can run a process with elevation by passing the runas verb to ShellExecute or ShellExecuteEx.
Going the other way is trickier. For one thing, it's really hard to munge your token to remove the elevation nature properly. And for another thing, even if you could do it, it's not the right thing to do, because the unelevated user may be different from the elevated user.
...
The solution here is to go back to Explorer and ask Explorer to launch the program for you. Since Explorer is running as the original unelevated user, the program ... will run as [the user].
His article provides the following code to launch an unelevated process, and a detailed explanation of what the code is actually doing (the FindDesktopFolderView function mentioned below is defined in his Manipulating the positions of desktop icons blog article):
#define STRICT
#include <windows.h>
#include <shldisp.h>
#include <shlobj.h>
#include <exdisp.h>
#include <atlbase.h>
#include <stdlib.h>
// FindDesktopFolderView incorporated by reference
void GetDesktopAutomationObject(REFIID riid, void **ppv)
{
CComPtr<IShellView> spsv;
FindDesktopFolderView(IID_PPV_ARGS(&spsv));
CComPtr<IDispatch> spdispView;
spsv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&spdispView));
spdispView->QueryInterface(riid, ppv);
}
void ShellExecuteFromExplorer(
PCWSTR pszFile,
PCWSTR pszParameters = nullptr,
PCWSTR pszDirectory = nullptr,
PCWSTR pszOperation = nullptr,
int nShowCmd = SW_SHOWNORMAL)
{
CComPtr<IShellFolderViewDual> spFolderView;
GetDesktopAutomationObject(IID_PPV_ARGS(&spFolderView));
CComPtr<IDispatch> spdispShell;
spFolderView->get_Application(&spdispShell);
CComQIPtr<IShellDispatch2>(spdispShell)
->ShellExecute(CComBSTR(pszFile),
CComVariant(pszParameters ? pszParameters : L""),
CComVariant(pszDirectory ? pszDirectory : L""),
CComVariant(pszOperation ? pszOperation : L""),
CComVariant(nShowCmd));
}
int __cdecl wmain(int argc, wchar_t **argv)
{
if (argc < 2) return 0;
CCoInitialize init;
ShellExecuteFromExplorer(
argv[1],
argc >= 3 ? argv[2] : L"",
argc >= 4 ? argv[3] : L"",
argc >= 5 ? argv[4] : L"",
argc >= 6 ? _wtoi(argv[5]) : SW_SHOWNORMAL);
return 0;
}
if we run as admin (more concrete have S-1-5-32-544 'Administrators' group enabled in token) we can open local system process token (it grant all needed to as access for 'Administrators').
so we can do next:
get self terminal session id
enable debug privileges in token, for be able open any process with
PROCESS_QUERY_LIMITED_INFORMATION
enumerate running processes in system
open process with PROCESS_QUERY_LIMITED_INFORMATION
open process token with TOKEN_QUERY|TOKEN_DUPLICATE
query token privileges - are it have
SE_ASSIGNPRIMARYTOKEN_PRIVILEGE and SE_INCREASE_QUOTA_PRIVILEGE -
it need for call CreateProcessAsUser and SE_TCB_PRIVILEGE it
require for WTSQueryUserToken
if token have all this privileges (LocalSystem token have) -
duplicate this token to TokenImpersonation type.
if need enable some of this 3 privileges in token
impersonate with this token
and now we can
call WTSQueryUserToken with self session id - for get not elevated
user token
and finally CreateProcessAsUser with this token
reset impersonation
code:
static volatile UCHAR guz;
ULONG RunNonElevated(_In_ ULONG SessionId,
_In_ HANDLE hToken,
_In_opt_ LPCWSTR lpApplicationName,
_Inout_opt_ LPWSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCWSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOW lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation)
{
ULONG err;
PVOID stack = alloca(guz);
ULONG cb = 0, rcb = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[SE_MAX_WELL_KNOWN_PRIVILEGE]);
union {
PVOID buf;
::PTOKEN_PRIVILEGES ptp;
};
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (GetTokenInformation(hToken, ::TokenPrivileges, buf, cb, &rcb))
{
if (ULONG PrivilegeCount = ptp->PrivilegeCount)
{
int n = 3;
BOOL fAdjust = FALSE;
::PLUID_AND_ATTRIBUTES Privileges = ptp->Privileges;
do
{
switch (Privileges->Luid.LowPart)
{
case SE_ASSIGNPRIMARYTOKEN_PRIVILEGE:
case SE_INCREASE_QUOTA_PRIVILEGE:
case SE_TCB_PRIVILEGE:
if (!(Privileges->Attributes & SE_PRIVILEGE_ENABLED))
{
Privileges->Attributes |= SE_PRIVILEGE_ENABLED;
fAdjust = TRUE;
}
if (!--n)
{
err = NOERROR;
if (DuplicateTokenEx(hToken,
TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE,
0, ::SecurityImpersonation, ::TokenImpersonation,
&hToken))
{
if (fAdjust)
{
AdjustTokenPrivileges(hToken, FALSE, ptp, rcb, NULL, NULL);
err = GetLastError();
}
if (err == NOERROR)
{
if (SetThreadToken(0, hToken))
{
HANDLE hUserToken;
if (WTSQueryUserToken(SessionId, &hUserToken))
{
if (!CreateProcessAsUserW(hUserToken,
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation))
{
err = GetLastError();
}
CloseHandle(hUserToken);
}
else
{
err = GetLastError();
}
SetThreadToken(0, 0);
}
else
{
err = GetLastError();
}
}
CloseHandle(hToken);
}
else
{
err = GetLastError();
}
return err;
}
}
} while (Privileges++, --PrivilegeCount);
}
return ERROR_NOT_FOUND;
}
} while ((err = GetLastError()) == ERROR_INSUFFICIENT_BUFFER);
return err;
}
ULONG RunNonElevated(_In_opt_ LPCWSTR lpApplicationName,
_Inout_opt_ LPWSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LPVOID lpEnvironment,
_In_opt_ LPCWSTR lpCurrentDirectory,
_In_ LPSTARTUPINFOW lpStartupInfo,
_Out_ LPPROCESS_INFORMATION lpProcessInformation
)
{
ULONG SessionId;
if (!ProcessIdToSessionId(GetCurrentProcessId(), &SessionId))
{
return GetLastError();
}
BOOLEAN b;
RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, b);
ULONG err = NOERROR;
// much more effective of course use NtQuerySystemInformation(SystemProcessesAndThreadsInformation) here
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0), hToken;
if (hSnapshot != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32W pe = { sizeof(pe) };
if (Process32FirstW(hSnapshot, &pe))
{
err = ERROR_NOT_FOUND;
do
{
if (pe.th32ProcessID && pe.th32ParentProcessID)
{
if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID))
{
if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE, &hToken))
{
err = RunNonElevated(
SessionId,
hToken,
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
CloseHandle(hToken);
}
else
{
err = GetLastError();
}
CloseHandle(hProcess);
}
else
{
err = GetLastError();
}
}
} while (err && Process32NextW(hSnapshot, &pe));
}
else
{
err = GetLastError();
}
CloseHandle(hSnapshot);
}
return err;
}
and test:
void test()
{
STARTUPINFO si = { sizeof(si)};
PROCESS_INFORMATION pi;
WCHAR ApplicationName[MAX_PATH];
if (GetEnvironmentVariableW(L"ComSpec", ApplicationName, RTL_NUMBER_OF(ApplicationName)))
{
if (!RunNonElevated(ApplicationName, L"cmd /k whoami.exe /priv /groups",0,0,0,0,0,0,&si, &pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
}
with this we can not only run not elevated process, but ,if need, start it with duplicated handles
Xcvdata() for deleting port.
BOOL DeletePortCus( TCHAR* PortName )
{
HANDLE hPrinter;
PRINTER_DEFAULTS PrinterDefaults;
memset(&PrinterDefaults, 0, sizeof(PrinterDefaults));
PrinterDefaults.pDatatype = NULL;
PrinterDefaults.pDevMode = NULL;
PrinterDefaults.DesiredAccess = SERVER_ACCESS_ADMINISTER;
DWORD needed = 0;
DWORD rslt = 0;
//Port data
PORT_DATA_1 pOutputData ;
DWORD error = 0;
if (!OpenPrinter(L",XcvMonitor Standard TCP/IP Port", &hPrinter, &PrinterDefaults))
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), NULL,(LPTSTR) &lpMsgBuf, 0, NULL );
_tprintf( TEXT("Error in OpenPrinter. Error msg : %s"),lpMsgBuf);
LocalFree( lpMsgBuf );
return FALSE;
}
DWORD xcvresult= 0;
if (
!XcvData(
hPrinter,
TEXT("DeletePort"),
(PBYTE)PortName,
(lstrlen(PortName) +1) * sizeof(TCHAR), //the 1 is for the trailing NULL
( byte * ) &pOutputData,
sizeof(PORT_DATA_1),
&needed,
&xcvresult)
)
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), NULL,(LPTSTR) &lpMsgBuf, 0, NULL );
_tprintf( TEXT("Error in XcvData. Error msg : %s; XcvDataPort status val = %d"), lpMsgBuf, xcvresult);
LocalFree( lpMsgBuf );
return FALSE;
}
ClosePrinter(hPrinter);
return TRUE;
}
The highlight is both the functions (openprinter and xcvdata) succeed. But the port is not getting removed. I am completely at a loss here as I dont have any error to lookup.
Instead of ,XcvMonitor Standard TCP/IP Port I also tried with ,XcvPort <portname>. Still same.
As Samer suggested below, I tried with OpenPrinter2 with no cache option.
PS: I know there's this simple alternative DeletePort(), but it invokes a UI dialog box if it fails, so I don't want to use it.
It seems the issue might be related to specific version of OS which caches printer handles. To get around this you use an alternate call OpenPrinter2 with the PRINTER_OPTION_NO_CACHE. Below is the modified code with the flag set.
HANDLE hPrinter;
PRINTER_DEFAULTS PrinterDefaults;
memset(&PrinterDefaults, 0, sizeof(PrinterDefaults));
PrinterDefaults.pDatatype = NULL;
PrinterDefaults.pDevMode = NULL;
PrinterDefaults.DesiredAccess = SERVER_ACCESS_ADMINISTER;
PRINTER_OPTIONS PrinterOptions;
PrinterOptions.cbSize = sizeof(PrinterOptions);
PrinterOptions.dwFlags = PRINTER_OPTION_NO_CACHE;
DWORD needed = 0;
DWORD rslt = 0;
//Port data
PORT_DATA_1 pOutputData ;
DWORD error = 0;
if (!OpenPrinter2(L",XcvMonitor Standard TCP/IP Port", &hPrinter, &PrinterDefaults, &PrinterOptions))
{
LPVOID lpMsgBuf;
I'm trying to adjust my monitor brightness programmatically. After little bit of research, I came up with this link, and wrote the following code (mostly copy paste from other links that one lead me).
#include "Windows.h"
#include "WinUser.h"
#include "PhysicalMonitorEnumerationAPI.h"
#include "HighLevelMonitorConfigurationAPI.h"
#include <strsafe.h>
void ShowError(LPTSTR lpszFunction);
int main()
{
HMONITOR hMonitor = NULL;
DWORD cPhysicalMonitors;
LPPHYSICAL_MONITOR pPhysicalMonitors = NULL;
HWND hWnd = GetDesktopWindow();
// Get the monitor handle.
hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY);
// Get the number of physical monitors.
BOOL bSuccess = GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, &cPhysicalMonitors);
if (bSuccess)
{
// Allocate the array of PHYSICAL_MONITOR structures.
pPhysicalMonitors = (LPPHYSICAL_MONITOR)malloc(cPhysicalMonitors* sizeof(PHYSICAL_MONITOR));
if (pPhysicalMonitors != NULL)
{
// Get the array.
bSuccess = GetPhysicalMonitorsFromHMONITOR( hMonitor, cPhysicalMonitors, pPhysicalMonitors);
// Get physical monitor handle.
HANDLE hPhysicalMonitor = pPhysicalMonitors[0].hPhysicalMonitor;
LPDWORD pdwMinimumBrightness = NULL;
LPDWORD pdwCurrentBrightness = NULL;
LPDWORD pdwMaximumBrightness = NULL;
bSuccess = GetMonitorBrightness(hPhysicalMonitor, pdwMinimumBrightness, pdwCurrentBrightness, pdwMaximumBrightness);
if (bSuccess == FALSE)
{
ShowError(TEXT("GetMonitorBrightness"));
}
// Close the monitor handles.
bSuccess = DestroyPhysicalMonitors(cPhysicalMonitors, pPhysicalMonitors);
// Free the array.
free(pPhysicalMonitors);
}
}
return 0;
}
void ShowError(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}
This code crashes when executing this line:
bSuccess = GetMonitorBrightness(hPhysicalMonitor, pdwMinimumBrightness, pdwCurrentBrightness, pdwMaximumBrightness);
According to documentation, that function might not be supported.
If this function is supported, the GetMonitorCapabilities function
returns the MC_CAPS_BRIGHTNESS flag.
So, in order to check that, I add the following block to my code, just before calling GetMonitorBrightness.
LPDWORD pdwMonitorCapabilities = NULL;
LPDWORD pdwSupportedColorTemperatures = NULL;
bSuccess = GetMonitorCapabilities(hPhysicalMonitor, pdwMonitorCapabilities, pdwSupportedColorTemperatures);
if (bSuccess == FALSE)
{
ShowError(TEXT("GetMonitorCapabilities"));
}
Unfortunately after I added that block, I received the following error:
Again, according to documentation, GetMonitorCapabilities function fails if the monitor does not support DDC/CI.
Then I checked if my monitor is supporting DDC/CI, and found out that it is. Moreover, when I manually disable DDC/CI support from monitor settings, previous error message switches to following one, so now I'm pretty sure my monitor has DDC/CI support.
I feel like I'm doing everything correct but apparently I'm not. In short, GetMonitorCapabilities function fails with an error message that I can't give any meaning, and GetMonitorBrightness function gets crashed.
Notes:
My monitor is Dell U2713H.
I'm on 64 bit Windows 7.
I'm using Microsoft Visual C++ Compiler 12.0 (x86)
Your calls to GetMonitorBrightness() and GetMonitorCapabilities() are wrong. You are passing NULL pointers, but they expect pointers to actual DWORD variables instead:
DWORD dwMinimumBrightness = 0;
DWORD dwCurrentBrightness = 0;
DWORD dwMaximumBrightness = 0;
bSuccess = GetMonitorBrightness(hPhysicalMonitor, &dwMinimumBrightness, &dwCurrentBrightness, &dwMaximumBrightness);
DWORD dwMonitorCapabilities = 0;
DWORD dwSupportedColorTemperatures = 0;
bSuccess = GetMonitorCapabilities(hPhysicalMonitor, &dwMonitorCapabilities, &dwSupportedColorTemperatures);
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 {};
}