Permission denied while taking a snapshot of running process using CreateToolhelp32Snapshot() - c++

Today I was requested to turn my console app(eg:App.exe) into a service, just googled and found nssm then used its effective commands to turn my APP.exe to a service,My next job is to monitor the running process(APP.exe) and if its size exceeds >30MB restart it that's all.What I've learned previously from nssm is when I kill the APP.exe nssm automatically restart it, So now I only need to code for only monitoring and killing the APP.exe when it exceeds 30MB,finally I've created an app that does monitoring There comes the problem, In the monitoring app I have been using CreateToolhelp32Snapshot() to take a snapshot of all running processes and try to find my APP.exe by its name then get it's size by pmc.WorkingSetSize, Yet When I ran my monitoring app it can't find the APP.EXE though i see it exist in the task manager I even ran it as an administrator yet it remains the same can any one helpme rid of this issue.
The error I am getting while taking a snapshot is permission denied.
please see my code below:
int main()
{
LOG mon;
PROCESSENTRY32 pe32 = {0};
HANDLE hSnap;
HANDLE hprocess;
PROCESS_MEMORY_COUNTERS pmc;
int iDone;
int iTime = 60;
bool bProcessFound;
while(true) // go forever
{
cout<<"adjfhaljkehdfhwoefjiej";
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
pe32.dwSize = sizeof(PROCESSENTRY32);
Process32First(hSnap,&pe32); // Can throw away, never an actual app
bProcessFound = false; //init values
iDone = 1;
while(iDone) // go until out of Processes
{
iDone = Process32Next(hSnap,&pe32);
if (strcmp(pe32.szExeFile,"APP.exe") == 0) // Did we find our process?
{
DWORD processID = pe32.th32ProcessID;
hprocess= OpenProcess( PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
FALSE, processID );
if (GetProcessMemoryInfo( hprocess, &pmc, sizeof(pmc)))
{
size_t procsize=pmc.WorkingSetSize;
cout<<procsize;
if(procsize>30MB)--mylogic
{
hprocess=OpenProcess(PROCESS_TERMINATE,0, processID);
TerminateProcess (hprocess, 0);
mon.RestartLog("Server Closed due to large size");
}
}
bProcessFound = true;
iDone = 0;
}
}
if(!bProcessFound) .
{
mon.RestartLog("Server Down ");
}
Sleep(iTime*50); // delay x amount of seconds.
}
return 0;
}

Run the above said monitor app as a system process. i.e, make it as a service.

Related

Logoff remote system using c++

I am looking for an API to logoff current user on remote computer. Two
functions ExitWindows and InitiateSystemShutdown seem not exactly what I
want. The first one doesn't accept computer name, the second one doesn't
have logoff option.is it possible to logoff current user
on remote computer ?. Can someone tell me how to achieve this in a
C++ program?
I knew that you want to shutdown system by using exitwindows function.
However, if you want to shut down the remote system in your own process, you need to use the exitwindowsEX function and write a program that specifies the process ID.
The relevant function references are as follows:
https://learn.microsoft.com/zh-cn/windows/win32/shutdown/how-to-shut-down-the-system
The following are specific codes:
#pragma region
#include<windows.h>
#pragma warning(disable:4996)
BOOL ReSetWindows(DWORD dwFlags, BOOL bForce)
{
if (dwFlags != EWX_LOGOFF && dwFlags != EWX_REBOOT && dwFlags != EWX_SHUTDOWN)
return FALSE;
OSVERSIONINFO osvi = { 0 };
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx(&osvi))
{
return FALSE;
}
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
//EnableShutDownPriv();
}
dwFlags |= (bForce != FALSE) ? EWX_FORCE : EWX_FORCEIFHUNG;
return ExitWindowsEx(dwFlags, 0);
}
int main()
{
ReSetWindows(EWX_LOGOFF, false);//logoff
//ReSetWindows(EWX_REBOOT, true);//restart
//ReSetWindows(EWX_SHUTDOWN, true);//shutdown
}
=======================
Caution!!!Please save your important file before running or running in the virtual machine
WTSLogoffSession? but the concept of a current user on a remote machine does not really exist, you would have to inspect the sessions with WTSEnumerateSessions+WTSQuerySessionInformation if you want to find a specific user. This only makes sense in a environment where there is a NT domain so you can match against a domain SID. Without a domain, all you can do is match against the username which might be enough for you.
This is the program specifies the process ID:
DWORD GetProcessIDByName(LPCTSTR szProcessName)
{
STARTUPINFO st;
PROCESS_INFORMATION pi;
PROCESSENTRY32 ps;
HANDLE hSnapshot;
DWORD dwPID = 0;
ZeroMemory(&st, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
st.cb = sizeof(STARTUPINFO);
ZeroMemory(&ps, sizeof(PROCESSENTRY32));
ps.dwSize = sizeof(PROCESSENTRY32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE)//
{
return dwPID;
}
if (!Process32First(hSnapshot, &ps))
{
return dwPID;
}
do
{
if (lstrcmpi(ps.szExeFile, szProcessName) == 0)
{
dwPID = ps.th32ProcessID;
}
} while (Process32Next(hSnapshot, &ps));
CloseHandle(hSnapshot);
return dwPID;//
}
You need this line of code in your main function:
DWORD pId = GetProcessIDByName("\\\.exe");
Closing remote system by local machine is easy. Closing local machine by remote machine sounds like a virus. No offense, it is difficult to implement. Maybe you can try using socket to communicate local machine with virtual machine.

How to restart explorer without taskkill

Is there a way to restart explorer without taskkill?
I write a program, in it I make some changes in registry, and to apply these changes it needs to restart explorer.exe, but I don't want to use taskkill, is there any other way to restart explorer.exe?
You can use the Restart Manager API:
The Restart Manager stops applications in the following order, and
after the applications have been updated, restarts applications that
have been registered for restart in the reverse order.
GUI applications
Console applications
Windows services Windows
explorer
Sheng Jiang's blog (from Microsoft) has a nice article explaining how to restart Explorer gracefully using the Restart Manager API:
//returns the process id and create time for the oldest explorer.exe
RM_UNIQUE_PROCESS GetExplorerApplication()
{
RM_UNIQUE_PROCESS result={0};
DWORD bytesReturned=0;
DWORD processIdSize=4096;
std::vector<DWORD> processIds;
processIds.resize(1024);
EnumProcesses(processIds.data(),processIdSize,&bytesReturned);
while(bytesReturned==processIdSize)
{
processIdSize+=processIdSize;
processIds.resize(processIdSize/4);
EnumProcesses(processIds.data(),processIdSize,&bytesReturned);
} std::for_each(processIds.begin(), processIds.end(), [&result] (DWORD processId) {
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
FALSE, processId);
if (hProcess) {
std::wstring imageName;
imageName.resize(4096);
if(GetProcessImageFileName (hProcess,(LPWSTR)imageName.data(),4096)>0)
{
if(wcscmp(L"explorer.exe",PathFindFileName(imageName.data()))==0)
{
//this is assmuing the user is not running elevated and won't see explorer processes in other sessions
FILETIME ftCreate, ftExit, ftKernel, ftUser;
if (GetProcessTimes(hProcess, &ftCreate, &ftExit,&ftKernel, &ftUser))
{
if(result.dwProcessId==0)
{
result.dwProcessId=processId;
result.ProcessStartTime=ftCreate;
}
else if(CompareFileTime(&result.ProcessStartTime,&ftCreate)>0)
{
result.dwProcessId=processId;
result.ProcessStartTime=ftCreate;
}
}
}
}
CloseHandle(hProcess);
}
});
return result;
}
//taskbar position calculating code omitted
DWORD dwSession=0;
WCHAR szSessionKey[CCH_RM_SESSION_KEY+1] = { 0 };
DWORD dwError = RmStartSession(&dwSession, 0, szSessionKey);
if (dwError == ERROR_SUCCESS) {
RM_UNIQUE_PROCESS rgApplications[1]={GetExplorerApplication()};
dwError=RmRegisterResources(
dwSession,0,NULL,1,rgApplications,0,NULL);
DWORD dwReason;
UINT nProcInfoNeeded;
UINT nProcInfo = 10;
RM_PROCESS_INFO rgpi[10];
dwError = RmGetList(dwSession, &nProcInfoNeeded,
&nProcInfo, rgpi, &dwReason);
if(dwReason==RmRebootReasonNone)//now free to restart explorer
{
RmShutdown(dwSession,RmForceShutdown,NULL);//important, if we change the registry before shutting down explorer will override our change
//using undocumented setting structure, could break any time
//edge setting is stored at HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StuckRects2!Settings
HKEY hKey={0};
DWORD result=0;
result=::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StuckRects2"),
0, KEY_READ|KEY_WRITE, &hKey) ;
if (result== ERROR_SUCCESS)
{
std::vector<BYTE> data;
data.resize(256);
TCHAR settingValue[]= _T("Settings");
DWORD dwKeyDataType=0;
DWORD dwDataBufSize=data.size();
result=::RegQueryValueEx(hKey,settingValue, NULL, &dwKeyDataType,
(LPBYTE) data.data(), &dwDataBufSize);
while(ERROR_MORE_DATA==result)
{
data.resize(256+data.size());
dwDataBufSize=data.size();
result=::RegQueryValueEx(hKey,settingValue, NULL, &dwKeyDataType,
(LPBYTE) data.data(), &dwDataBufSize);
}
data.resize(dwDataBufSize);
if(result==ERROR_SUCCESS)
{
switch ( dwKeyDataType )
{
case REG_BINARY:
if(data.size()==40)
{
BYTE taskbarPosition=data[12];
taskbarPosition=edge;
data[12]=taskbarPosition;
RECT* taskbarRect=(RECT*)&data[24];
CopyRect (taskbarRect,&abd.rc);
result=::RegSetValueEx(hKey,settingValue,0,REG_BINARY,(LPBYTE) data.data(), dwDataBufSize);
}
break;
}
}
::RegCloseKey( hKey );
}
RmRestart (dwSession,0,NULL);
}
}
RmEndSession(dwSession);
It could be not necessary to restart explorer at all.
There may be some Windows message that does the trick of updating necessary stuff.
For example notification area icons are recreated on RegiserWindowsMessage("TaskbarCreated") and some of settings apply on WM_SETTINGCHANGE.
Or maybe the setting in question is accessible via API that does refresh in addition to registry write.
Consider "softer" approaches before resorting to restart.

TerminateProcess not suceeding on Windows 10

Our C++ app launches a separate .exe ( which may start its own sub-processes) using CreateProcess as below.
BOOL started = ::CreateProcess(NULL, // application
p, // parameters
NULL, // process security
NULL, // thread security
TRUE, // inherit handles flag
0, // flags
NULL, // inherit environment
dirLP, // inherit directory
&startup, // STARTUPINFO
&procinfo); // PROCESS_INFORMATIO
In case we need cancel the "job" we use CreateToolhelp32Snapshot to iterate through the process list to find any child processes of the one we launched.
static BOOL TerminateProcessTree (HANDLE parentProcess,UINT exitCode)
{
BOOL result=TRUE;
HANDLE hProcessSnap = NULL;
PROCESSENTRY32 pe32 = {0};
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
return (FALSE);
pe32.dwSize = sizeof(PROCESSENTRY32);
// Walk the snapshot of the processes
DWORD parentID=GetProcessId(parentProcess);
if(parentID==0){
PrintLastError("GetProcessId");
return FALSE;
}
if (Process32First(hProcessSnap, &pe32)) {
do{
if(pe32.th32ParentProcessID==parentID){
HANDLE hProcess = OpenProcess (PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID);
if(hProcess!=NULL){
BOOL terminateChildren=TerminateProcessTree(hProcess,exitCode);
BOOL terminatedChild = TerminateProcess(hProcess, exitCode);
if (!terminatedChild){
PrintLastError("TerminateProcess");
}
CloseHandle(hProcess);
if(!terminatedChild || !terminateChildren){
result=FALSE;
break;
}
} else{
PrintLastError("OpenProcess");
}
}
}while (Process32Next(hProcessSnap, &pe32));
}
CloseHandle (hProcessSnap);
DWORD checkCode=0;
BOOL terminated;
if(GetExitCodeProcess(parentProcess,&checkCode) && checkCode==STILL_ACTIVE){
terminated=TerminateProcess(parentProcess,exitCode);
if (!terminated){
PrintLastError("TerminateProcess");
result= FALSE;
}
}
return result;
}
As noted, this works fine on Windows 7. Windows 10 fails with "Access Denied" on the first call "TerminateProcess". Clearly something has changed in the Windows security model when it comes to processes.
The robust way to deal with controlling a process tree of objects is to use Job objects as noted in the comment threads.
The one thing to keep in mind is that a process can only belong to a single job, and by default any EXE that the OS determines needs appcompat help is put into a job object automatically managed by the "Program Compatibility Assistant". This makes using a Job object to manage arbitrary 3rd party EXEs a little bit more complicated (i.e. AssignProcessToJobObject fails for these processes).
If you are using CreateProcess you can make use of the flag CREATE_BREAKAWAY_FROM_JOB. See this blog post. This works fine as long as the target EXE has the same rights as the calling object.
For a Standard User EXE to run an EXE that might need Administrator rights (i.e. they contain a manifest which marks it as requireAdministrator), you have to use ShellExecute or ShellExecuteEx as calling CreateProcess in this case will fail. If your target EXEs are all using the proper manifest elements then it won't be put into a PCA Job object.. You can use the trick of passing SEE_MASK_FLAG_NO_UI which will have the side-effect of avoiding the PCA job behavior. If you are launching arbitrary 3rd party EXEs, you should use ShellExecuteEx and not CreateProcess.
bool SpawnProcess( const WCHAR* szExePath, const WCHAR* szExeArgs )
{
if( !szExePath )
return false;
// NOTE: szExeArgs can be nullptr.
// Get working directory from executable path.
WCHAR szDirectory[MAX_PATH] = {0};
wcscpy_s( szDirectory, szExePath );
PathRemoveFileSpec( szDirectory );
// ShellExecute or ShellExecuteEx must be used instead of CreateProcess
// to permit the shell to display a UAC prompt asking for consent to
// elevate when the target executable's manifest specifies a run level
// of "requireAdministrator".
//
// You can only use CreateProcess if you know that the application you
// are spawning will be at the same run level as the current process.
// Otherwise, you will receive ERROR_ACCESS_DENIED if the elevation
// consent could not be obtained.
SHELLEXECUTEINFO info = {};
info.cbSize = sizeof( info );
info.lpVerb = L"open";
info.fMask = SEE_MASK_FLAG_NO_UI;
info.lpFile = szExePath;
info.lpParameters = szExeArgs;
info.lpDirectory = szDirectory;
info.nShow = SW_SHOW;
if( !ShellExecuteEx( &info ) )
return false;
return true;
}
Note that if you want to wait until this process exits, you can use:
bool SpawnProcessAndWait( const WCHAR *szExePath, const WCHAR *szExeArgs, DWORD *pdwExitCode )
{
if( !szExePath )
return false;
// NOTE: szExeArgs and pExitCode can be nullptr.
// Get working directory from executable path.
WCHAR szDirectory[MAX_PATH] = {0};
wcscpy_s( szDirectory, szExePath );
PathRemoveFileSpec( szDirectory );
// See SpawnProcess for information why ShellExecute or ShellExecuteEx
// must be used instead of CreateProcess.
SHELLEXECUTEINFO info = {};
info.cbSize = sizeof( info );
info.lpVerb = L"open";
info.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS;
info.lpFile = szExePath;
info.lpParameters = szExeArgs;
info.lpDirectory = szDirectory;
info.nShow = SW_SHOW;
if( !ShellExecuteEx( &info ) )
return false;
// Wait for process to finish.
WaitForSingleObject( info.hProcess, INFINITE );
// Return exit code from process, if requested by caller.
if( pdwExitCode )
GetExitCodeProcess( info.hProcess, pdwExitCode );
CloseHandle( info.hProcess );
return true;
}
You haven't noted if your "master" application here is using administrator or Standard User rights. Ideally it is using Standard User rights per the User Account Control guidelines dating back to Windows Vista. If your app is running as Standard User, then it's likely that your code no longer works due to security improvements to keep non-Administrator malware from doing this kind of thing to other processes.
For general appcompat questions about Windows 10, be sure to read the Windows and Windows Server compatibility cookbook and look back at the Windows 8.0 and Windows 8.1 material if you are jumping directly from Windows 7 to Windows 10.

Windows Event Viewer holds a lock on my EXE file

I'm curious about something. I'm developing a Windows service and log all the diagnostic events into the Windows Event Log. So when the service is running I open the Event Viewer (from Administrative tools) to view the results of my service's operation.
This works great except for the moment when I need to uninstall my program (again, for the testing purposes.) For some weird reason the Event Viewer holds a lock on the .exe image file for my service so the uninstaller fails to delete it with the error code ERROR_SHARING_VIOLATION:
The process cannot access the file because it is being used by another process.
This happens only on Vista and later OS and seems not to be an issue on XP.
Any idea how to make Event Viewer release the file lock? (I'm asking about programmatic approach. I can obviously close it manually, but that's not what I'm after.)
I released the lock this way:
Start -> Services
Locate Windows Event Log
Right click -> Restart
There's a less known feature introduced in Vista called Restart Manager that can help you release file locks via a user-mode code. Since you tagged it as C++, based on this article here's a small code sample to do that:
#include <RestartManager.h>
#pragma comment(lib ,"Rstrtmgr.lib")
BOOL ReleaseFileLock(LPCTSTR pFilePath)
{
BOOL bResult = FALSE;
DWORD dwSession;
WCHAR szSessionKey[CCH_RM_SESSION_KEY+1] = { 0 };
DWORD dwError = RmStartSession(&dwSession, 0, szSessionKey);
if (dwError == ERROR_SUCCESS)
{
dwError = RmRegisterResources(dwSession, 1, &pFilePath,
0, NULL, 0, NULL);
if (dwError == ERROR_SUCCESS)
{
UINT nProcInfoNeeded = 0;
UINT nProcInfo = 0;
RM_PROCESS_INFO rgpi[1];
DWORD dwReason;
dwError = RmGetList(dwSession, &nProcInfoNeeded,
&nProcInfo, rgpi, &dwReason);
if (dwError == ERROR_SUCCESS ||
dwError == ERROR_MORE_DATA)
{
if(nProcInfoNeeded > 0)
{
//If current process does not have enough privileges to close one of
//the "offending" processes, you'll get ERROR_FAIL_NOACTION_REBOOT
dwError = RmShutdown(dwSession, RmForceShutdown, NULL);
if (dwError == ERROR_SUCCESS)
{
bResult = TRUE;
}
}
else
bResult = TRUE;
}
}
}
RmEndSession(dwSession);
SetLastError(dwError);
return bResult;
}
I just met same problem. The DLL was locked by svchost.exe process (Windows Audio, DHCP Client, Windows Event Log, TCP/IP NetBIOS Helper, Security Center, Task Scheduler)
Solution: close Event Viewer! :)

C++ Check if specific process is running

I have a C++ DLL that i am writing that needs to check if a particular process is running.
the dll will be launched application will be running in:
c:\Directory\application.exe
there is a subdirectory within that that has another executable in it:
c:\Directory\SubDirectory\application2.exe
What the DLL needs to do when it runs if check that application2.exe is running, most importantly that it is running within that folder -- there will be multiple copies running, so we need to ensure that the correct one is running.
I have the following code that is working well at detecting that the application2.exe is running, but it does not take the file path into consideration:
HANDLE pss = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
PROCESSENTRY32 pe = { 0 };
pe.dwSize = sizeof(pe);
if (Process32First(pss, &pe))
{
do
{
if(wcscmp(pe.szExeFile, L"application2.exe") == 0)
{
CloseHandle(pss);
return (1);
}
}
while(Process32Next(pss, &pe));
}
CloseHandle(pss);
How can I check that the path of the process matches the path of the application which called the DLL?
Use WMI for this.
From the command line you can do:
wmic process where "executablepath = 'c:\path\to\executable.exe'" get ProcessId
You can use the WMI apis from C++ to do something similar.
http://www.codeproject.com/Articles/10539/Making-WMI-Queries-In-C
I have been given a solution that works for this, in case anyone else searching here it is:
HANDLE ProcessSnap;
PROCESSENTRY32 Pe32;
unsigned int LoopCounter = 0;
Pe32.dwSize = sizeof(PROCESSENTRY32);
ProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
Process32First(ProcessSnap, &Pe32);
wchar_t TermPath[MAX_PATH];
GetModuleFileName(NULL, TermPath, MAX_PATH);
wstring WTermPath(TermPath);
int index = WTermPath.find(L"\\application.exe");
wstring Path = WTermPath.substr(0, (index));
Path = Path + L"\\SubDirectory\\Application2.exe";
do
{
HANDLE Process;
wchar_t FilePath[MAX_PATH];
Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, Pe32.th32ProcessID);
if (Process)
{
GetModuleFileNameEx(Process, 0, FilePath, MAX_PATH);
wstring WFilePath(FilePath);
if(WFilePath == Path)
{
CloseHandle(ProcessSnap);
return (1);
}
CloseHandle(Process);
}
LoopCounter++;
} while (Process32Next(ProcessSnap, &Pe32));
CloseHandle(ProcessSnap);