Running Process in system context - c++

Is it possible to launch process in system context from a parent process thats running under administrator account with elevation(say a command prompt). The problem is similar to what psexec does but more of how it actually implements this.
I was thinking opening the crss.exe/winlogon.exe process duplicating the token and launching a new process using that process token. But I fail to even open the process handle (Getlasterror return 5). Can someone let me know if this is the right approach or the process should be launched differently ?
HANDLE hWinLogonProcess;
for(const auto& ps : running_processes)
{
if(ps.id == GetCurrentProcessId() ||
0 != ps.short_name.CompareNoCase(L"winlogon.exe"))
{
continue;
}
DWORD dwWinLogonSessionId(0);
if(FALSE == ProcessIdToSessionId(GetCurrentProcessId(), &dwWinLogonSessionId))
{
std::wcerr<<"Could not get Winlogon process session id"<<std::endl;
continue;
}
if(dwWinLogonSessionId != dwCurSessionId)
{
continue;
}
hWinLogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ps.id);
if(FALSE == hWinLogonProcess)
{
std::wcerr<<"Failed to get winlogon process handle"<<std::endl;
return;
}
else
{
std::wcout<<"Able to open process "<<ps.short_name.GetString()<<" handle"<<std::endl;
break;
}
}
I am sure its possible as there is a working tool (psexec) but I couldnt find any reference online to do this.
Also this is similar to question, but posting separately as there was details on how it had to be achieved.

Yes, this is possible (without any service help).
But I fail to even open the process handle
Does your process have the SE_DEBUG_PRIVILEGE privilege enabled?
With this privilege, you can open a system process with all access if it is not protected (smss.exe, csrss.exe, services.exe), and use that handle in CreateProcessAsUser(), or with UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS) if you also have SE_ASSIGNPRIMARYTOKEN_PRIVILEGE and SE_TCB_PRIVILEGE privileges enabled (for setting the token's SessionId to 0), which you can get in 2 ways:
open a thread from an unprotected system process and impersonate it, then open your own thread token and adjust privileges on it.
open a token from any system process (this works even for protected processes), duplicate the token, adjust privileges on it, and then impersonate with this token.
To "launch a process in the system context", if you want to run the process:
with the LocalSystem token.
in the System terminal session (0)
Both, as I say, are possible. And all you need is SE_DEBUG_PRIVILEGE.
more simply - open some system process with PROCESS_CREATE_PROCESS access right. Use this handle with UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS). As a result, your started process inherits a token from the system process. This will be not work on XP, but there it is possible to hook NtCreateProcess/Ex() to replace HANDLE ParentProcess with your opened handle.
Another way is to use CreateProcessAsUser(). Before creating the process, you will be need SE_ASSIGNPRIMARYTOKEN_PRIVILEGE and SE_TCB_PRIVILEGE privileges to set the token's TokenSessionId (if you want to run in session 0).

Thanks to RbMm answer I figured a way to accomplish this task.
For any of you who did not succeed, I leave below something that might help:
//First we need to add debug privilege to this process
HANDLE hToken;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken))
{
std::cout << "OpenProcessToken failed: " << GetLastError();
return 0;
}
TOKEN_PRIVILEGES tk;
tk.PrivilegeCount = 1;
tk.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tk.Privileges[0].Luid))
{
std::cout << "LookupPrivilegeValue failed: " << GetLastError();
return 0;
}
AdjustTokenPrivileges(hToken, FALSE, &tk, 0, NULL, 0);
if((DWORD res = GetLastError()) != ERROR_SUCCESS)
{
std::cout << "AdjustTokenPrivileges failed: " << res;
}
CloseHandle(hToken);
//Now we need a handle to a process that already runs as SYSTEM.
//You can choose any process that is not protected (if OpenProcess fails try with other process)
//pid of chosen process (you can get this by opening task manager and go to
//Details tab or by enumerating all processes and extract that one you need)
DWORD pid;
HANDLE hProcess = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, pid);
if (!hProcess)
{
std::cout << "OpenProcess with pid " << pid << "failed: " << GetLastError();
return 0
}
//We need to initialize a list that contains PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
//to specify that parent process of the process we are going to start is the
//process we opened earlier (this will make the child process inherit the system context).
//This list will be specified in a STARTUPINFOEX object that CreateProcess will get
STARTUPINFOEX siex = { sizeof(STARTUPINFOEX) };
siex.StartupInfo.cb = sizeof(STARTUPINFOEXW);
//We need to initialize our list. To do this we call InitializeProcThreadAttributeList
//with a NULL list to get how big our list needs to be to store all attributes
//we want to specify, then we allocate our list with the size we got from first call
//and we call again the function to initialize the list.
SIZE_T cbAttributeListSize = 0;
if(!InitializeProcThreadAttributeList(NULL, 1, 0, &cbAttributeListSize))
{
std::cout << "InitializeProcThreadAttributeList failed: " << GetLastError();
return 0
}
siex.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(HeapAlloc(GetProcessHeap(), 0, cbAttributeListSize));
if(!InitializeProcThreadAttributeList(siex.lpAttributeList, 1, 0, &cbAttributeListSize))
{
std::cout << "InitializeProcThreadAttributeList failed: " << GetLastError();
return 0
}
if(!UpdateProcThreadAttribute(siex.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hProcess, sizeof(hProcess), NULL, NULL))
{
std::cout << "UpdateProcThreadAttribute failed: " << GetLastError();
return 0
}
//path to program we want to run in system context
LPWSTR szCmdline = _wcsdup(TEXT("C:\\Windows\\System32\\notepad.exe"));
PROCESS_INFORMATION pi = { 0 };
if(!CreateProcess(NULL, szCmdline, nullptr, nullptr, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, reinterpret_cast<LPSTARTUPINFOW>(&siex), &pi))
{
std::cout << "CreateProcess failed: " << GetLastError();
return 0
}

Related

Windows C++: Whats the fastest way to write a large file on a remote machine?

In our application we have to write large files (100 MBytes up to some GBytes) on remote machines (in the same LAN segement) frequently. This is the bottleneck of our application. Remote machines may be native Windows but also Linux machines using SMB.
We found that creating files first locally and then copying them using the Windows API function CopyFile is MUCH faster than using CreateFile directly with a UNC Path (or drive letter) targeting the remote machine. But still we have to do 2 writes which seems far from optimum.
Inspired by the first comments on this question i implemented the usage of FILE_FLAG_OVERLAPPED for CreateFile as discussed here and here:
HANDLE hToken;
auto openResult = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
if (!openResult)
{
gConsoleAndLog << "OpenProcessToken failed with err " << GetLastError() << std::endl;
}
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 3;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[2].Attributes = SE_PRIVILEGE_ENABLED;
if(! LookupPrivilegeValue(NULL, SE_MANAGE_VOLUME_NAME, &tp.Privileges[0].Luid))
gConsoleAndLog << "LookupPrivilegeValue SE_MANAGE_VOLUME_NAME failed with err " << GetLastError() << std::endl;
if (! LookupPrivilegeValue(NULL, SE_INCREASE_QUOTA_NAME, &tp.Privileges[1].Luid))
gConsoleAndLog << "LookupPrivilegeValue SE_INCREASE_QUOTA_NAME failed with err " << GetLastError() << std::endl;
if (! LookupPrivilegeValue(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &tp.Privileges[2].Luid))
gConsoleAndLog << "LookupPrivilegeValue SE_ASSIGNPRIMARYTOKEN_NAME failed with err " << GetLastError() << std::endl;
auto adjustResult = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
if (!adjustResult || GetLastError() != ERROR_SUCCESS)
{
gConsoleAndLog << "AdjustTokenPrivileges failed with err " << GetLastError() << std::endl;
}
else gConsoleAndLog << "AdjustTokenPrivileges SUCCESS" << std::endl;
In difference to the second post i can not set the privilege "SE_ASSIGNPRIMARYTOKEN_NAME" even when starting as administrator. I dont know if that makes a difference.
After opening the file with FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, the calculated size is pre allocated:
auto setFileErr = SetFilePointerEx(hFile, endPosition, NULL, FILE_BEGIN);
if (setFileErr == INVALID_SET_FILE_POINTER)
{
CPrintWithOSError(NULL, 0, "SetFilePointerEx FAILED");
return 1;
}
if (!SetEndOfFile(hFile))
{
CPrintWithOSError(NULL, 0, "SetEndOfFile FAILED");
return 1;
}
if (!SetFileValidData(hFile, endPosition.QuadPart))
{
CPrintWithOSError(NULL, 0, "SetFileValidData FAILED");
return 1;
}
That works for local drives but SetFileValidData fails on remote drives.
The call fails with windows error
1314 a required privilege is not held by the client
How can this be fixed?
What are other ways to do this?
Is there a
way to increase file buffering for appending writes using the WinAPI?
If you have access to the tifflib source code, you should be able to solve this by buffering data to be written to the output file until the buffer is full or the file is closed. A simple FILE * will do this, using setvbuf to set the buffer size to 1MB or so.

After ImpersonateLoggedOnUser(), why failed to call Windows API SetDisplayConfig()?

This is a System service. After ImpersonateLoggedOnUser(), I can call CreateProcessAsUser() successfully. But it fails to call one Windows API SetDisplayConfig(). The error is 5 (ERROR_ACCESS_DENIED). Please see the code below.
// This function is called in a System service.
void SetDisplayToExtendMode()
{
DWORD dwSessionId = WTSGetActiveConsoleSessionId();
if (dwSessionId == 0xFFFFFFFF)
{
qCritical() << "Failed to get active console session Id when setting extend mode for display!";
}
HANDLE hUserToken = NULL;
if (WTSQueryUserToken(dwSessionId, &hUserToken) == FALSE)
{
qCritical() << "Failed to query user token when setting extend mode for display!";
}
HANDLE hTheToken = NULL;
if (DuplicateTokenEx(hUserToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &hTheToken) == TRUE)
{
if (ImpersonateLoggedOnUser(hTheToken) == TRUE)
{
DWORD dwCreationFlags = HIGH_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
LPVOID pEnv = NULL;
if (CreateEnvironmentBlock(&pEnv, hTheToken, TRUE) == TRUE)
{
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
}
// Way 1: Call Windows API directly.
// Fail. Error code is ERROR_ACCESS_DENIED
LONG errCode = SetDisplayConfig(0, NULL, 0, NULL, SDC_TOPOLOGY_EXTEND | SDC_APPLY);
if (errCode != ERROR_SUCCESS)
{
qCritical() << "Failed to set Windows Display to Extended mode! Error is " << errCode;
if (errCode == ERROR_ACCESS_DENIED)
{
qCritical() << "ACCESS denied!";
}
}
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES Security1 = { sizeof(Security1) };
SECURITY_ATTRIBUTES Security2 = { sizeof(Security2) };
std::wstring command = L"C:\\Users\\SomeUser\\Desktop\\QT_Projects\\build\\release\\TestSetDisplay.exe";
TCHAR commandLine[MAX_PATH];
_tcscpy_s(commandLine, MAX_PATH, command.c_str());
// Way 2: This way can be successful.
BOOL bResult = CreateProcessAsUser(
hTheToken,
NULL, // (LPWSTR)(path),
(LPWSTR)(commandLine),
&Security1,
&Security2,
FALSE,
dwCreationFlags,
pEnv,
NULL,
&si,
&pi
);
if (!bResult)
{
qCritical() << "Failed to CreateProcessAsUser()";
}
RevertToSelf();
if (pEnv)
{
DestroyEnvironmentBlock(pEnv);
}
}
CloseHandle(hTheToken);
}
CloseHandle(hUserToken);
}
So, after ImpersonateLoggedOnUser(), how to call Windows API SetDisplayConfig() successfully?
Alternatively, in one System service, how to call one Windows API as a user? (For this case, the purpose of calling SetDisplayConfig() is to set the display mode to Extend mode. This display mode is set per user. So, as a system service, it may need to impersonateLoggedOnUser() first.)
from SetDisplayConfig documentation
ERROR_ACCESS_DENIED The caller does not have access to the console
session. This error occurs if the calling process does not have access
to the current desktop or is running on a remote session.
and you wrote
This is a System service.
but System service have no access to interactive desktop. so you need call it from interactive session

Write/Read a memory-protected process's memory

I'll try to explain my problem the best I can.
I'm trying to access to a memory-protected process memory (Minesweeper).
I'll put my code first and then I'll explain what's the thing I want to archieve. (If you read everything and know another way to do this, please post it).
First, the getProcessHandle, a function that returns a open handle to the process with name procName.
It works perfectly, and I can list all the processes.
HANDLE getProcessHandle(const wchar_t *procName){
HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 procEnt;
procEnt.dwSize = sizeof(PROCESSENTRY32);
Process32First(snap, &procEnt);
printf("--Listando procesos...\n");
do{
printf("Process name: %S \n", procEnt.szExeFile);
if (!wcscmp(procName, procEnt.szExeFile)){
printf("Encontrado %S.\n\n", procName);
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, procEnt.th32ProcessID);
}
} while (Process32Next(snap, &procEnt));
printf("No se ha encontrado el proceso.");
CloseHandle(snap);
return NULL;
Second, the getModule function. Its work should be finding and enumerating all the modules in the process passed as a HANDLE.
HMODULE getHModule(HANDLE procHandle, const wchar_t *procName){
HMODULE moduleHandle[1024];
DWORD bytesNeeded;
unsigned int i = 0;
if (EnumProcessModulesEx(procHandle, moduleHandle, sizeof(moduleHandle), &bytesNeeded, LIST_MODULES_ALL)){
printf("--Modulos del proceso:\n");
for (i = 0; i < (bytesNeeded / sizeof(HMODULE)); i++){
TCHAR pathModule[1024];
GetModuleBaseName(procHandle, moduleHandle[i], pathModule, sizeof(pathModule) / sizeof(TCHAR));
if (!wcscmp(procName, pathModule)){
printf("Encontrado modulo %S.", procName);
return moduleHandle[i];
}
printf("Module %d: %S \n", i + 1, pathModule);
}
printf("No se ha encontrado el modulo.");
return NULL;
}
else {
printf("Error en EnumProcessModulesEx n: %ls", GetLastError());
}
return NULL;
And the problem comes here. When I try to enumerate all the modules in the process, if the process is a normal process, I mean, a not-memory-protected process, it works perfectly.
The problem is when the process is memory-protected.
At this point, I decided to search, and I discovered the Privilege Tokens. It's said that if I get the SE_DEBUG_NAME token activated, my process could surpass the protection, so, I've done that function:
int privileges(){
HANDLE token;
TOKEN_PRIVILEGES tp;
DWORD siz = sizeof(TOKEN_PRIVILEGES);
if (OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &token) != 0){
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(token, 0, &tp, siz, NULL ,NULL) != 0){
cout << "--Conseguido acceso debug.\n";
return TRUE;
}
else {
cout << "fail adjust\n";
return FALSE;
}
}
else {
cout << "fail if: " << GetLastError() << endl;
cin.get();
return FALSE;
}
And the "main" function:
int _tmain(int argc, _TCHAR* argv[])
{
privileges();
wchar_t *processName = _T("calc.exe");
HANDLE hProc = getProcessHandle(processName);
if (hProc){
HMODULE hMod = getHModule(hProc, processName);
cout << hMod;
}
cin.get();
return 0;
}
The problem I have right now is, when I execute this function, privileges(), it returns the ERROR_NO_TOKEN code number.
Someone here said me to change the OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &token) for an OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token), and that causes no problem, neither result, with that fix, I have the same problem as if privileges() is not executed.
Thanks for reading all the text, and, if is there another way to do this, please tell me, I'm trying to learn.
The documentation for EnumProcessModulesEx says:
This function is intended primarily for 64-bit applications. If the function is called by a 32-bit application running under WOW64, the dwFilterFlag option is ignored and the function provides the same results as the EnumProcessModules function.
Going to the documentation for EnumProcessModules, we find:
If this function is called from a 32-bit application running on WOW64, it can only enumerate the modules of a 32-bit process.
So to work on a 64-bit process, your code will have to be 64-bit itself.
The documentation continues:
If the process is a 64-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299).
It seems that this may be incorrect, since you were receiving a access violation exception instead.
Write ImpersonateSelf(SecurityImpersonation); like here:
ImpersonateSelf(SecurityImpersonation);
OpenThreadToken
(
GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
&token
);
The ImpersonateSelf makes function obtains an access token that impersonates the security context of the calling process. The token is assigned to the calling thread.
To see all the SECURITY_IMPERSONATION_LEVELs click here

How to kill Processes running under different users using c++ code

The following code works fine in displaying the process id of all the processes (eg: notepad.exe) running under different users. But process under current user is alone getting killed. I need to kill all the processes running under different users.
#define SAMPLEAPP "notepad.exe"
void main()
{
KillProcessByName(SAMPLEAPP);
system("pause");
}
void KillProcessByName(const char *filename)
{
// Taking snapshot of all processes
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
//structure to capture each entry in snapshot
PROCESSENTRY32 pEntry;
pEntry.dwSize = sizeof (pEntry);
//capture the first process in the list
BOOL hRes = Process32First(hSnapShot, &pEntry);
while (hRes)
{
char tempProcess[PROCESS_SIZE];// = pEntry.szExeFile;
wcstombs(tempProcess, pEntry.szExeFile, PROCESS_SIZE);
//if process name is equal to the process passed as argument to be killed
if (strcmp(tempProcess, filename) == 0)
{
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0,
(DWORD) pEntry.th32ProcessID);
std::cout << "Process ID of the Process " << tempProcess << " is : " << pEntry.th32ProcessID;
if (hProcess != NULL)
{
// Kill the process
TerminateProcess(hProcess, 9);
CloseHandle(hProcess);
}
}
//Capture the next process in process snapshot
hRes = Process32Next(hSnapShot, &pEntry);
}
CloseHandle(hSnapShot);
}
How can I kill a process, even if it belongs to another user?
Right-click your program, and then select "Run as administrator".

Locking files using C++ on Windows

I have a program writing/reading from a file, and I want to lock the file for other instances of my application. How can I do it (in c++ visual studio 2003)?
I tried using the _locking() but then also I myself cannot reach the file when trying to read/write (in the same instance).
I know there's an option of LockFile() but have no idea how to set it properly.
Please help me.
You can simply use the Win32 API CreateFile and then specify no sharing rights. This will ensure that no other processes can access the file.
The dwShareMode DWORD specifies the type of sharing you would like, for example GENERIC_READ. If you specify 0 then that means no sharing rights should be granted.
Example:
HANDLE hFile = CreateFile(_T("c:\\file.txt"), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
If you want to only lock a certain part of the file you can use LockFile or LockFileEx.
Example:
//Lock the first 1024 bytes
BOOL bLocked = LockFile(hFile, 0, 0, 1024, 0);
For locking on other platforms please see my post here.
You want LockFileEx() (exclusive file locking). Have a look at this discussion from Secure Programming Cookbook for C and C++.
After searching online for a while, I didn't find any good examples.
Here are two calls to CreateFile with the intent of locking the file for the life of a process... I use this along side the CLimitSingleInstance that uses CreateMutex for a global named mutex.
The first call to CreateFile attempts to open it, the second one creates it if necessary.
I have a little bit more thorough implementation. I implemented it in Qt, hence the qCritical() instead of std::cout and the QDir::tempPath() instead of getting that some other way.
class SingleInstance
{
protected:
DWORD m_dwLastError;
HANDLE m_hFile;
public:
SingleInstance(const char *strMutexName) { }
bool attemptToLockTempFile()
{
QString lockFile = QDir::tempPath() + "/My.exe.lock";
m_hFile = CreateFileA(lockFile.toLocal8Bit().data(), GENERIC_READ, 0,
NULL, OPEN_EXISTING, 0, NULL);
DWORD dwLastError = GetLastError();
if(m_hFile != NULL && m_hFile != INVALID_HANDLE_VALUE)
{
return true;
}
else
{
if(dwLastError == ERROR_FILE_NOT_FOUND )
{
m_hFile = CreateFileA(lockFile.toLocal8Bit().data(), GENERIC_READ,
0, NULL, CREATE_NEW, 0, NULL);
dwLastError = GetLastError();
if(m_hFile != NULL && m_hFile != INVALID_HANDLE_VALUE)
{
return true;
}
else if(dwLastError == ERROR_SHARING_VIOLATION)
{
qCritical() << "Sharing Violation on My.exe.lock";
}
else
{
qCritical() << "Error reading" << "My.exe.lock" << "-" << dwLastError;
}
}
else if(dwLastError == ERROR_SHARING_VIOLATION)
{
qCritical() << "Sharing Violation on My.exe.lock";
}
else
{
qCritical() << "Unable to obtain file lock -" << dwLastError;
}
return false;
}
}
~SingleInstance()
{
if ( m_hFile != NULL && m_hFile != INVALID_HANDLE_VALUE)
{
::CloseHandle(m_hFile); //Do as late as possible.
m_hFile = NULL;
}
}
}
Here is what you would have at the top of your main function:
SingleInstance g_SingleInstanceObj(globalId_QA);
// Makes sure that the program doesn't run if there is another
// instance already running
if (g_SingleInstanceObj.IsAnotherInstanceRunning())
{
return 0;
}