Windows 7 - CreateProcess w/ DEBUG_PROCESS Access Violation - c++

ok...burned out on this one...scratching my head all day. I have a very simple, single purpose c++ DLL (StartApplication.dll) used to start an application.
Works fine in WinXP, but not in win7
Uses CreateProcess() with DEBUG_PROCESS (so i can wait for the program to finish before terminating).
If I monitor processes in Task Manager, I can see the process start, but no window is created and nothing further happens
If I change to NORMAL_PRIORITY_CLASS, the program will execute as it should (but i lose the ability to wait around before terminating as I can only do this while debugging)
Error code gives me STATUS_ACCESS_VIOLATION
I have UAC turned off and setting the executable to run as Administrator and with WinXP compatibility does nothing
Heres the code. Any thoughts would be greatly appreciated
//...blah blah...handful of stuff preceding this to set up command line and
//directories etc....not of use here probably...
SECURITY_ATTRIBUTES sa = {0}; sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
STARTUPINFO si = {0}; si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = (NULL == stdOutFileName)? INVALID_HANDLE_VALUE :
::CreateFile(stdOutFileName, GENERIC_WRITE, FILE_SHARE_READ, &sa
, CREATE_ALWAYS, 0, NULL);
si.hStdError = (NULL == stdErrFileName)? INVALID_HANDLE_VALUE :
::CreateFile(stdErrFileName, GENERIC_WRITE, FILE_SHARE_READ, &sa
, CREATE_ALWAYS, 0, NULL)
PROCESS_INFORMATION pi = {0};
if (::CreateProcess(useApplicationName? applicationName : NULL, processCommandLine
, NULL, NULL, TRUE, /*NORMAL_PRIORITY_CLASS*/DEBUG_PROCESS, NULL, currentDirectory, &si, &pi))
{
BOOL cont = TRUE;
while (cont)
{
DWORD continueStatus = DBG_CONTINUE;
DEBUG_EVENT debugEvent = {0};
if (!::WaitForDebugEvent(&debugEvent, INFINITE))
{
errorCode = ErrorCode_Other;
::TerminateProcess(pi.hProcess, 0);
break;
}
else
{
switch (debugEvent.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
case EXCEPTION_DATATYPE_MISALIGNMENT:
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_FLT_INEXACT_RESULT:
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_FLT_UNDERFLOW:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_OVERFLOW:
case EXCEPTION_PRIV_INSTRUCTION:
case EXCEPTION_IN_PAGE_ERROR:
case EXCEPTION_ILLEGAL_INSTRUCTION:
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
case EXCEPTION_STACK_OVERFLOW:
case EXCEPTION_INVALID_DISPOSITION:
case EXCEPTION_INVALID_HANDLE:
errorCode = ErrorCode_ApplicationException;
*exceptionCode = debugEvent.u.Exception.
ExceptionRecord.ExceptionCode;
::TerminateProcess(pi.hProcess, 0);
break;
default:
;
}
break;
case EXIT_PROCESS_DEBUG_EVENT:
cont = FALSE;
break;
default:
;
}
::ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId
, continueStatus);
}
}
::GetExitCodeProcess(pi.hProcess, reinterpret_cast<LPDWORD>(exitCode));
::CloseHandle(pi.hProcess);
::CloseHandle(pi.hThread);
}
if (INVALID_HANDLE_VALUE != si.hStdOutput)
::CloseHandle(si.hStdOutput);
if (INVALID_HANDLE_VALUE != si.hStdError)
::CloseHandle(si.hStdError);
return errorCode;
}

Your code terminates the whole process after the first exception occures.
Normally you should let the program take care of exceptions, only if the exception wasn't handled the process will terminate.
To see if an exception was fatal (ie. not handled the first time around) check u.Exception.dwFirstChance:
If it's 0, set your error codes accordingly and terminate.
otherwise, the exception occured for the first time, you should call ContinueDebugEvent with DBG_EXCEPTION_NOT_HANDLED to pass the exception to the process.
EDIT
If you only want to watch exceptions and not handle them from inside the debugger, you should always continue with DBG_EXCEPTION_NOT_HANDLED.
There's one catch:
Right before the main thread starts, Windows raises an INT3 exception which needs to be passed to the process (DBG_CONTINUE).
Pseudo code:
bool FirstInt3 = true;
while (cont)
{
DWORD continueStatus = DBG_EXCEPTION_NOT_HANDLED;
// ....
switch(...)
{
case EXCEPTION_DEBUG_EVENT:
if(!FirstChance)
{
// Fatal exception
// Log Exception that terminated the program here
// Don't do anything else, Windows automatically terminates the process
// You will get an EXIT_PROCESS_DEBUG_EVENT on the next event
}
switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_BREAKPOINT:
if(FirstInt3)
{
FirstInt3 = false;
continueStatus = DBG_CONTINUE;
break;
}
default:
// Log ExceptionCode here
break;
}
break;
}

If I've understand you correctly, you're using DEBUG_PROCESS just so that you can wait until the process exits. That's major overkill.
To wait until the process has exited, use WaitForSingleObject (or another wait function as appropriate) on pi.hProcess.

#pezcode is right - don't just end the process on receiving first exception from the debuggee, let it run normally. Debugger (your code) will anyway receive all exceptions occurring in the debuggee (first chance exceptions).
I would suggest you to first minimize the debugger-loop logic, and also try not to attach and handles to process. Keep it simple first, then move ahead.

Related

Programmatically Setting Breakpoints on Multi-threaded 64-bit Applications

I have adapted some code from other sources (primarily here) and had no avail in my circumstance. I am attaching to a 64-bit application that has upwards of 100 threads at any given time. There are two issues I have, somewhat unrelated:
Whenever the code hits DebugActiveProcess(pid), the attached application freezes.
The code I have only sets a breakpoint on the main thread, but I need it on more than one - ideally all.
I have confirmed that when the code hits SetThreadContext(hThread, &ctx) the dr0 and dr7 registers change as intended, so that much is fine. The only issues I can see right now are the process freezing and setting more than one breakpoint (I thought of iterating for every single thread which would be fine one-time, but when it gets into the while loop that would obviously be problematic and very resource-consuming). I should also note that I can attach the CheatEngine debugger to the application, and breakpoints work fine with no issues. Below is the code I'm using:
DWORD GetProcessThreadID(DWORD dwProcessID)
{
THREADENTRY32 te = { sizeof(THREADENTRY32) };
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (Thread32First(hSnapshot, &te))
while (Thread32Next(hSnapshot, &te))
if (te.th32OwnerProcessID == dwProcessID)
return te.th32ThreadID;
return NULL;
}
BOOL SetDebugPrivilege(BOOL State)
{
HANDLE hToken;
TOKEN_PRIVILEGES token_privileges;
DWORD dwSize;
ZeroMemory(&token_privileges, sizeof(token_privileges));
token_privileges.PrivilegeCount = 1;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
return FALSE;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &token_privileges.Privileges[0].Luid))
{
CloseHandle(hToken);
return FALSE;
}
if (State)
token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED;
if (!AdjustTokenPrivileges(hToken, FALSE, &token_privileges, 0, NULL, &dwSize))
{
CloseHandle(hToken);
return FALSE;
}
return CloseHandle(hToken);
}
void CreateBreakpoint(DWORD pid, DWORD64 addr) {
DebugActiveProcess(pid);
DebugSetProcessKillOnExit(false);
DWORD_PTR dwThreadID = GetProcessThreadID(pid);
std::cout << std::hex << dwThreadID << std::endl;
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadID);
SetDebugPrivilege(true);
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS | CONTEXT_INTEGER;
ctx.Dr0 = addr;
ctx.Dr7 = 0x00000001;
SetThreadContext(hThread, &ctx);
DEBUG_EVENT dbgEvent;
while (true) {
if (WaitForDebugEvent(&dbgEvent, INFINITE) == 0)
break;
if (dbgEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT &&
dbgEvent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP) // EXCEPTION_BREAKPOINT
{
if (dbgEvent.u.Exception.ExceptionRecord.ExceptionAddress == (LPVOID)addr)
{
GetThreadContext(hThread, &ctx);
std::cout << ctx.Rax << "\n";
ctx.Dr7 = 0;
SetThreadContext(hThread, &ctx);
}
}
ContinueDebugEvent(dbgEvent.dwProcessId, dbgEvent.dwThreadId, DBG_CONTINUE);
}
}
It may be worth noting that this is a C++ extension to a python script, but that shouldn't really be relevant, and even if I run the code standalone it runs into the same issues. Also, I'm not an expert in C++ so I apologize if there are any misunderstandings.
I agree with Taekahn, unless you give more information on what you are trying to do, why not use a normal debugger? if you just want to read the registers, any debugger can do that. You can even set breakpoints in disassembly or random addresses, or set data breakpoints.
IDK about gdb, but even in visual studio you can set conditions and actions on breakpoints. It's not as powerfull as c++ code but again, without more informations...
If you want to modify the behavior of the application, that's not how we do it, and using a debugger can actually cause issues.

WaitForMultipleObjects() access denied

I have this below thread function, that simply wait on two kernel objects to be signaled.
The waiting function always return WAIT_FAILED with error code 5 (access denied) and I can't tell why.
unsigned __stdcall func(void * p_this){
ReceiverThread * ThisObj = (ReceiverThread *)p_this;
HANDLE ClientsMutex = ClientsInterface::GetClientsMutex();
HANDLE WaitFor[2];
WaitFor[0] = ThisObj->PassiveEvent;
WaitFor[1] = ClientsMutex;
res = WaitForMultipleObjects(2, WaitFor, TRUE, INFINITE);
switch (res)
{
case WAIT_OBJECT_0: // both signal
if(!Clients->empty()){
dosomthing();
ReleaseMutex(ClientsMutex);
ResetEvent(WaitFor[0]);
}
break;
case WAIT_ABANDONED_0:
MessageBox(NULL, "WAIT_ABANDONED", "WAIT ERR", MB_OK);
break;
case WAIT_TIMEOUT:
MessageBox(NULL, "TimeOut !", "WAIT ERR", MB_OK);
break;
case WAIT_FAILED:
MessageBox(NULL, "Function Failure !", to_string(GetLastError()).c_str() , MB_OK);
break;
}
}
The event initialization is as follow:
PassiveEvent = CreateEvent(
NULL,
TRUE, // ResetEvent is required to set the event to non-signal state.
FALSE, // non-signaled initial state.
NULL
);
The mutex initialization is as follow:
Mutex = CreateMutex(NULL, FALSE, NULL);
I know it's little opaque, but that's all the information, maybe I'm missing something that is clear, but I can't tell why the WaitForMultipleObjects() get access denied. any ideas?

Memory issues with CreateProcess

I have written a Windows Service program in C++. One of the tasks it performs is to run a very large business app written in PowerBuilder. It performs a bunch of database processes and transfers data back and forth with SharePoint. The PowerBuilder app gets to a certain point where it aborts and the likely cause is because services have a limited 'desktop heap' compared to normal desktop apps.
As a test we tried using a generic service app called AlwaysUp to run the PowerBuilder app and somehow it has no problems at all. I am stumped as to why AlwaysUp has no issues. Here is the code I use to launch the PowerBuilder app:
// report running status
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(hStatus, &ServiceStatus);
// run the application
event = CreateEvent(0, FALSE, FALSE, 0);
if ( CreateProcess( NULL, CommandLine, NULL, NULL, FALSE,
DETACHED_PROCESS | dwPriority, NULL,
szModule, &si, &pi ) == 0 ) {
// CreateProcess Failed
return 0;
}
// wait for either the process to end or stop event
WaitHandles[0] = pi.hProcess;
WaitHandles[1] = event;
do {
dwError = WaitForMultipleObjects(2, WaitHandles, FALSE, 60000);
switch ( dwError ) {
case WAIT_OBJECT_0:
// process ended
bRunning = FALSE;
break;
case WAIT_OBJECT_0+1:
// event triggered
bRunning = FALSE;
break;
case WAIT_TIMEOUT:
// timeout
break;
default:
// error
bRunning = FALSE;
break;
}
} while ( bRunning );
// close the handles
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(event);

Call to WaitForSingleObject not clear in combination with CreateProcess

I came across the following code in a program that keeps track of processes:
void StartProcess(const std::wstring& processName, const CString& argument)
{
...
STARTUPINFO stInfo;
PROCESS_INFORMATION prInfo;
ZeroMemory( &stInfo, sizeof(stInfo) );
stInfo.cb = sizeof(stInfo);
stInfo.dwFlags=STARTF_USESHOWWINDOW;
stInfo.wShowWindow=SW_SHOWDEFAULT;
bRet = CreateProcess(NULL,
(LPTSTR)(LPCTSTR)sCmdline,
NULL,
NULL,
TRUE,
CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS,
NULL,
_T("."),
&stInfo,
&prInfo);
// Create process has gone OK and we have to wait.
if (bRet)
{
bRet = FALSE;
int nRetWait = WaitForSingleObject(prInfo.hProcess,0);
if (nRetWait == WAIT_OBJECT_0)
{
// Get the exit code of the process
DWORD dwExitCode = 0;
::GetExitCodeProcess(prInfo.hProcess, &dwExitCode);
if (0 == dwExitCode)
{
// The program succeeded
m_StartedServices.push_back(prInfo.dwProcessId;);
bRet = TRUE;
}
}
}
}
The code should start a process and then in a later stadium terminate it (using m_StartedServices). However I am wondering what added value the calls to WaitForSingleObject and GetExitCodeProcess have. I have looked around a bit and it seems that the WaitForSingleObject with a timeout of 0 is used to check if a process is still running, but it is just created, so why check? And why check the exit code of a process that is still running?
Can anybody clear this up?
Also I found that calls:
CloseHandle(prInfo.hThread);
CloseHandle(prInfo.hProcess);
are missing in this function. Have I found a handle leak, or is there some magic that would automatically close the handles?

Reading from a pipe randomly fails

I'm writing an integration test driver for a command-line executable. I control both the driver and the executable, so I can make guarantees about their behaviour- for example, the executable never reads from stdin, it just takes command-line arguments, does its thing, and then writes output to a file and stdout.
I wish to capture both the exit code and the stdout of the process for verification.
Here's the code that I'm using:
#include <Windows.h>
class Pipe {
HANDLE ReadHandle;
HANDLE writehandle;
public:
Pipe() {
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
CreatePipe(&ReadHandle, &writehandle, &saAttr, 0);
}
HANDLE WriteHandle() {
return writehandle;
}
std::string Contents() {
CloseHandle(writehandle);
DWORD dwRead;
CHAR chBuf[1024];
BOOL bSuccess = FALSE;
std::string result;
for (;;)
{
bSuccess = ReadFile(ReadHandle, chBuf, 1024, &dwRead, NULL);
if (!bSuccess) break;
result += std::string(chBuf, chBuf + dwRead);
if (dwRead < 1024)
break;
}
return result;
}
~Pipe() {
CloseHandle(ReadHandle);
}
};
Wide::Driver::ProcessResult Wide::Driver::StartAndWaitForProcess(std::string name, std::vector<std::string> args, Util::optional<unsigned> timeout)
{
ProcessResult result;
Pipe stdoutpipe;
PROCESS_INFORMATION info = { 0 };
STARTUPINFO startinfo = { sizeof(STARTUPINFO) };
std::string final_args = name;
for (auto arg : args)
final_args += " " + arg;
startinfo.hStdOutput = stdoutpipe.WriteHandle();
startinfo.hStdError = INVALID_HANDLE_VALUE;
startinfo.hStdInput = INVALID_HANDLE_VALUE;
startinfo.dwFlags |= STARTF_USESTDHANDLES;
auto proc = CreateProcess(
name.c_str(),
&final_args[0],
nullptr,
nullptr,
TRUE,
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW,
nullptr,
nullptr,
&startinfo,
&info
);
if (!proc) {
DWORD dw = GetLastError();
const char* message;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&message, 0, nullptr);
std::string err = message;
LocalFree((void*)message);
throw std::runtime_error(err);
}
if (timeout == 0)
timeout = INFINITE;
result.std_out = stdoutpipe.Contents();
if (WaitForSingleObject(info.hProcess, timeout ? *timeout : INFINITE) == WAIT_TIMEOUT)
TerminateProcess(info.hProcess, 1);
DWORD exit_code;
GetExitCodeProcess(info.hProcess, &exit_code);
CloseHandle(info.hProcess);
CloseHandle(info.hThread);
result.exitcode = exit_code;
if (exit_code != 0)
return result;
return result;
}
I've got 259 integration tests that I run in this way. Some take longer than others. When I run the suite, about 1-3 will fail - different ones each time. I've looked at the outcome in the debugger, and the stdout is cut off half way through. If I don't try to capture the stdout, all the tests succeed every time, so I know that it's based around the stdout capture.
The timeout is specified, but it's a very generous 60 seconds- much longer than the tests take to run ordinarily. I spawn a new process for each test.
How can I capture stdout in a more reliable way, without getting random failures?
As a final note, it takes a long time to run the suite to capture the failure in the debugger, so it may take a while to service any requests for further information.
I have a theory about this, but I'm not wholly certain. The key is in the loop condition for reading the stdout of the process.
std::string result;
for (;;)
{
bSuccess = ReadFile(ReadHandle, chBuf, 1024, &dwRead, NULL);
if (!bSuccess) break;
result += std::string(chBuf, chBuf + dwRead);
if (dwRead < 1024)
break;
}
return result;
There's actually an implicit assumption here. ReadFile is a blocking API, so we would assume that it keeps blocking until it has the data we asked for or input has ended. But I hypothesize that in fact, ReadFile may return before it has a block as big as we asked for, even if the pipe has not terminated. This would cause the input reading loop to terminate.
Since the parent is no longer reading stdout, the child trying to write stdout may block waiting for somebody to clear the buffer- effectively a deadlock since nobody will. Therefore, the timeout will trigger and terminate the process, recording a failure.
The MSDN docs say this:
The ReadFile function returns when one of the following conditions occur:
The number of bytes requested is read.
A write operation completes on the write end of the pipe.
An asynchronous handle is being used and the read is occurring asynchronously.
An error occurs.
It does not say that it will return when a write operation completes and the number of bytes requested is available. In fact, it makes no comment about the write operation making as many bytes as you requested available. So effectively, it behaves semi-asynchronously, even when called synchronously.
I have rewritten the loop as follows:
std::string result;
for (;;)
{
bSuccess = ReadFile(ReadHandle, chBuf, 1024, &dwRead, NULL);
if (!bSuccess || dwRead == 0) break;
result += std::string(chBuf, chBuf + dwRead);
}
return result;
So far I have been unable to reproduce the failures with this loop (and the tests complete noticably faster).