32bit Application run 64bit registry (with WOW6432Node) - c++

I have a 32bit application that must call C:\Windows\System32\regedit.exe, but instead it runs C:\Windows\SysWOW64\regedit.exe. How can I call the regedit in System32?
void CSecureShellView::OnCommandsRegistry64bit()
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
CString szExe;
szExe = "regedit.exe";
if (CreateProcess("C:\\Windows\\Sysnative\\cmd.exe", szExe.GetBuffer(100), 0, 0, FALSE, CREATE_NO_WINDOW, 0, 0, &si, &pi))
{
WaitForSingleObject(pi.hProcess, IGNORE);// optionally wait for process to finish
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
The Condition returns True but regedit does not run.
Instead of SysNative, I put System32, but it does not work. In szExe, I put the string "C:\Windows\regedit", but it does not work. And so on ...

You are trying to run regedit.exe via cmd.exe, why? Any result you get will be for cmd.exe, regardless of what commands it executes.
Just run the Registry Editor instead of cmd.exe. However, there is a wrinkle.
The 64bit C:\Windows\System32 folder does not have a regedit.exe executable. The 64bit regedit.exe is located in C:\Windows instead. If a 32bit process tries to run that executable directly, the 32bit C:\Windows\SysWOW64\regedit.exe will be run, which you don't want.
In order for a 32bit process to run the 64bit regedit.exe, it needs to run C:\Windows\Sysnative\Regedt32.exe instead, which is a stub that will run the 64bit C:\Windows\regedit.exe:
void CSecureShellView::OnCommandsRegistry64bit()
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
CString szExe = "C:\\Windows\\Sysnative\\Regedt32.exe";
if (CreateProcess(NULL, szExe.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
WaitForSingleObject(pi.hProcess, INFINITE); // optionally wait for process to finish
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
If CreateProcess() fails with ERROR_ELEVATION_REQUIRED, and you don't want to run your 32bit process elevated, then try using ShellExecute/Ex() with the runas" verb to launch Regedt32.exe elevated.
That being said, you should not hard-code the path to the Windows installation folder. Ask Windows where it is actually installed, such as via GetWindowsDirectory(), SHGetFolderPath(CSIDL_WINDOWS), SHGetKnownFolderPath(FOLDERID_Windows), etc. And then you can append Sysnative\\Regedt32.exe to the end of that path.

To solve this problem I use ShellExecuteEx() and SHELLEXECUTEINFO.
HRESULT result = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
SHELLEXECUTEINFO Sei;
ZeroMemory(&Sei,sizeof(SHELLEXECUTEINFO));
Sei.cbSize = sizeof(SHELLEXECUTEINFO);
Sei.lpFile = "C:\\windows\\regedit.exe";
Sei.nShow = SW_SHOW;
Sei.fMask = SEE_MASK_INVOKEIDLIST;
Sei.lpVerb = "open";
ShellExecuteEx(&Sei);
if (result == S_OK || result == S_FALSE)
CoUninitialize();
For reference: Launching Applications

Related

trying to run commend on cmd throw c++ using createprocces (API)?

bool execute()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
bool flag = true;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
string f = "dir desktop"
if (CmdLine.parameter != "")
{
LPSTR l1 = const_cast<char *>(f.c_str());
CreateProcess(NULL, l1, NULL, NULL, false, 0, NULL, NULL, &si, &pi);
flag = true;
// WaitForSingleObject(pi.hProcess, INFINITE);
// // Close process and thread handles.
// CloseHandle(pi.hProcess);
// CloseHandle(pi.hThread);
//}
}
return flag;
}
I'm trying to run cmd command by visual studio.
I'm using createprocces (API) in order to run this thing
but I can't understand why it doesn't run anything.
dir is a command understood by cmd.exe, it's not a program you can execute.
You can try the command cmd /k "dir desktop", properly expressed as a C++ string.
E.g.,
auto execute()
-> bool
{
STARTUPINFO si = { sizeof( si ) };
PROCESS_INFORMATION pi = {};
string f = "cmd /k \"dir desktop\"\0";
bool const ok = !!CreateProcess( 0, &f[0], 0, 0, false, 0, 0, 0, &si, &pi );
if( !ok ) { return false; }
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return true;
}
Note how the calls to ZeroMemory have been replaced with C++ initialization.
Just by letting the compiler do its job you get shorter, more clear code that is more likely correct, and just as efficient (possibly more). Win win win.
Disclaimer: code not reviewed by compiler.
If the intent is to list the contents of the user's desktop folder, then note that dir desktop doesn't do that. As an interactive command in the command interpreter you could use dir %userprofile%\desktop, and that also works via the Windows Run-dialog. Depending on the command interpreter's behavior for command line arguments it may work directly via CreateProcess, or not.
Generally, when using Windows API level functions it's preferable to use the wchar_t-based text based functions, i.e. define UNICODE before including <windows.h> (or use the ...W functions explicitly).
If you call CreateProcess() with the first parameter set to NULL, then you have to make sure that l1 starts with the module name to call.
As dir is an internal command of the command processor and not an executable, you have to use cmd as module name and give the rest of the parameter as cmd expects them.
So try the following:
string f = "cmd /c=dir desktop";

CreateProcessAsUser fails with ERROR_ELEVATION_REQUIRED for a process with UIAccess="true"

I'm trying to use the following code to run a user-mode process from my service application (running as a local system.)
The requirement for the user-mode process is to run without elevatation, but to have UIAccess="true" in its manifest to be able to display top-most windows correctly under Windows 8.
So I do this (from my service) to run my user-mode process:
//NOTE: Error checking is omitted for readability
//'dwSessionID' = user session ID to run user-mode process in
//'pUserProcPath' = L"C:\\Program Files (x86)\\Company\\Software\\user_process.exe"
HANDLE hToken = NULL;
WTSQueryUserToken(dwSessionID, &hToken);
HANDLE hToken2;
DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hToken2);
LPVOID pEnvBlock = NULL;
CreateEnvironmentBlock(&pEnvBlock, hToken2, FALSE);
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = L"winsta0\\default";
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
//ImpersonateLoggedOnUser(hToken2); //Not necessary as suggested below
PVOID OldRedir;
Wow64DisableWow64FsRedirection(&OldRedir);
BOOL bSuccess = CreateProcessAsUser(
hToken2, // client's access token
pUserProcPath, // file to execute
NULL, // command line
NULL, // pointer to process SECURITY_ATTRIBUTES
NULL, // pointer to thread SECURITY_ATTRIBUTES
FALSE, // handles are not inheritable
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, // creation flags
pEnvBlock, // pointer to new environment block
NULL, // name of current directory
&si, // pointer to STARTUPINFO structure
&pi // receives information about new process
);
int nOSError = ::GetLastError();
Wow64RevertWow64FsRedirection(OldRedir);
//RevertToSelf(); //Not necessary as suggested below
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
DestroyEnvironmentBlock(pEnvBlock);
CloseHandle(hToken2);
CloseHandle(hToken);
This runs fine, if UIAccess="false" in the manifest for the user_process.exe.
But if I do the following:
Enable UIAccess="true" for the user_process.exe:
Sign it with my code-signing certificate and
Place it in the "C:\Program Files (x86)\Company\Software" folder.
What I get is that CreateProcessAsUser fails with the error ERROR_ELEVATION_REQUIRED.
Can someone suggest how to make it work?
PS. I tried adjusting my service's privileges to enable SE_DEBUG_NAME and SE_TCB_NAME, but neither helped.
PS2. If I simply double-click my user_process.exe process compiled with UIAccess="true", code-signed, and placed in the C:\Program Files (x86)\Company\Software folder, it starts & runs just fine (not elevated.).
I found the answer. Here it is for whoever runs into it as well:
Add this after DuplicateTokenEx call:
HANDLE hToken2;
DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hToken2);
//ONLY if requiring UIAccess!
DWORD dwUIAccess = 1;
::SetTokenInformation(hToken2, TokenUIAccess, &dwUIAccess, sizeof(dwUIAccess));

how to start a program using a windows service?

I created a windows service in c++ using visual studios and now I want the service to run an exe file. The service is set to start every time the computer starts
i know i need to use code to locate the path of the exe like C:\MyDirectory\MyFile.exe but how to I actually run the file from the service?
i read about the process start method here but i am not sure how to use it
You can use createprocess function in your service to run an exe.
TCHAR* path = L"C:\\MyDirectory\\MyFile.exe";
STARTUPINFO info;
PROCESS_INFORMATION processInfo;
ZeroMemory( &info, sizeof(info) );
info.cb = sizeof(info);
ZeroMemory( &processInfo, sizeof(processInfo) );
if (CreateProcess(path, NULL, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
{
::WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}

CreateProcess can start a process, but QProcess cannot... why?

I am writing a windows QT app that needs to launch other apps. If I use the following windows calls everything works fine:
QString qsExePath = "C:\\Program Files (x86)\\Some Company\\SomeApp.exe";
QString qsCommandLine = "";
DWORD dwLastError = 0;
STARTUPINFO startupInfo;
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
startupInfo.wShowWindow = (WORD)1;
PROCESS_INFORMATION processInfo;
ZeroMemory(&processInfo, sizeof(processInfo));
if (CreateProcess((TCHAR*)(qsExePath.utf16()), (TCHAR*)(qsCommandLine.utf16()),
NULL, NULL, FALSE, 0, NULL, NULL,
&startupInfo, &processInfo))
{
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
else
{
dwLastError = GetLastError();
}
However, if I use the following QT calls it does not work and fails with QProcess::Unknown Error.
QProcess process;
bool bStarted = process.startDetached(qsExePath);
qDebug() << process.error();
I can get QProcess to work if copy SomeApp.exe to my %TMP% directory and change the qsExePath accordingly, so it is obviously some kind of permissions error. I don't understand why though... if it were really permissions, shouldn't my CreateProcess windows call fail?
Your path has spaces in it. You are calling the overloaded version of QProcess.startDetached() that takes a single parameter, so it interprets that as the complete command line to execute. As such, try wrapping the path in quotes, otherwise it will think that "C:\Program" is the program to execute and everything else are arguments, which would be wrong:
QString qsExePath = "\"C:\\Program Files (x86)\\Some Company\\SomeApp.exe\"";
bool bStarted = process.startDetached(qsExePath);
Alternatively, call one of the other overloaded versions of startDetached() and let it work out the necessary quoting internally for you:
QString qsExePath = "C:\\Program Files (x86)\\Some Company\\SomeApp.exe";
bool bStarted = process.startDetached(qsExePath, QStringList());

Got error code(5) access denied when use TerminateProcess to terminate the "mstsc.exe" process

I use the CreateProcess() function to launch the rdp client app using "mstsc.exe". After that, I want to terminate it so I use TerminateProcess() function, but it fails with error code of 5. If I replace the "mstsc.exe" with "notepad.exe", the terminate function works. The code are as follows:
TCHAR szCommandLine[] = TEXT("mstsc.exe");
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;
BOOL bResult = CreateProcess(NULL, szCommandLine, NULL, NULL,
FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
::Sleep(3000);
if (TerminateProcess(pi.hProcess, 0) == 0) {
printf("failed: %d", GetLastError());
}
Can anyone help explain it and solve it?
What I observed is that the pid of the pi returned is different from the id of the process "mstsc.exe" observed in taksmanager or "Process Explorer".
Is your host process 32-bit and you are running on 64-bit windows?
If so, you are invoking the 32-bit mstsc and it is spawning a 64-bit version, hence the different PID. Check out this thread
You must gain the privilege before terminating another process.
Try this:
void UpdatePrivilege(void)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hToken))
{
LookupPrivilegeValue(NULL,SE_DEBUG_NAME, &luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
}
}
Call this function before calling TerminateProcess.