Escaping trapflag/single step - c++

I'm writing a program that traces the execution of other programs. I'm using dynamic instruction instrumentation to track the behavior of x86's CMP instruction.
I'm using the windows debugging api to control the behavior of the debugged program. I start the program with the 'debug only this process' flag, and then set the trap flag on the main thread.
I then enter the main debugging loop:
bool cDebugger::ProcessNextDebugEvent(bool Verbose)
{
bool Result = true;
DEBUG_EVENT Event = { 0 };
DWORD Status = DBG_CONTINUE;
if (!WaitForDebugEvent(&Event, INFINITE))
{
_Reporter("Error: WaitForDebugEvent: " + to_string(GetLastError()));
return Result;
}
else
{
if (Event.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
{
if (Verbose)
_Reporter("Created process: " + GetFilenameFromHandle(Event.u.CreateProcessInfo.hFile));
}
else if (Event.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT)
{
if (Verbose)
_Reporter("Dll: " + GetFilenameFromHandle(Event.u.LoadDll.hFile) + " loaded at: " + to_string((unsigned int)Event.u.LoadDll.lpBaseOfDll));
_Dlls.insert(make_pair((unsigned int)Event.u.LoadDll.lpBaseOfDll, GetFilenameFromHandle(Event.u.LoadDll.hFile)));
}
else if (Event.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT)
{
if (Verbose)
_Reporter("Thread[" + to_string(Event.dwThreadId) + "] created at: " + to_string((unsigned int)Event.u.CreateThread.lpStartAddress));
_Threads.push_back(Event.dwThreadId);
}
else if (Event.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT)
{
if (Verbose)
_Reporter("Thread[" + to_string(Event.dwThreadId) + "] exited with: " + to_string(Event.u.ExitThread.dwExitCode));
auto It = std::find(_Threads.begin(), _Threads.end(), Event.dwThreadId);
if (It != _Threads.end())
_Threads.erase(It);
}
else if (Event.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT)
{
if (Verbose)
_Reporter("Dll " + _Dlls[(unsigned int)Event.u.UnloadDll.lpBaseOfDll] + " unloaded at : " + to_string((unsigned int)Event.u.UnloadDll.lpBaseOfDll));
}
else if (Event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
{
if (Verbose)
_Reporter("Process exited with: " + to_string(Event.u.ExitProcess.dwExitCode));
Result = false;
_Threads.clear();
}
else if (Event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
{
if (Event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP)
{
Status = DBG_EXCEPTION_HANDLED;
}
else
{
Status = DBG_EXCEPTION_NOT_HANDLED;
}
}
for (size_t i = 0; i < _Threads.size(); i++)
{
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, _Threads[i]);
if (hThread == NULL)
{
_Reporter("Error: Failed to open thread: " + to_string(GetLastError()));
}
else
{
CONTEXT ThreadContext = GetThreadContext(hThread);
ProcessStep(ThreadContext, hThread);
ThreadContext.EFlags |= 0x100; // Set trap flag.
SetThreadContext(hThread, ThreadContext);
CloseHandle(hThread);
}
}
if (!ContinueDebugEvent(Event.dwProcessId, Event.dwThreadId, Status))
{
_Reporter("Error: ContinueDebugEvent: " + to_string(GetLastError()));
}
}
return Result;
}
As you can see I loop through all threads at the end of the function to make sure that the single-step exception will trigger on every next instruction in every thread.
However sometimes execution seems to 'escape' this trap, often executing millions of instructions before being caught again by the next debugging event.
I wrote another small application to test the behavior of my program:
int main(int argc, char* argv[])
{
//__asm int 3h
if (argc == 41234123)
{
printf("Got one\n");
}
return 0;
}
The expected output of the tracer should be:
0xDEADBEEF CMP 1 41234123
However somehow the tracer does not record this instruction (indicating that no debug event was raised, and that the trap flag was not set).
Can anybody see if I'm doing something wrong in my debug loop? Or what kind of behavior of the test program (loading of a dll) could be responsible for this?

The problem had something to do with code entering kernel space when calling windows apis. My solution was to set the page protection of the executable section of the test program to PAGE_GUARD:
SYSTEM_INFO Info;
GetSystemInfo(&Info);
DWORD StartAddress = (DWORD)Info.lpMinimumApplicationAddress;
DWORD StopAddress = (DWORD)Info.lpMaximumApplicationAddress;
DWORD PageSize = 0;
PageSize = Info.dwPageSize;
_Sections.clear();
for (DWORD AddressPointer = StartAddress; AddressPointer < StopAddress; AddressPointer += PageSize)
{
MEMORY_BASIC_INFORMATION Buffer;
VirtualQueryEx(_Process.GetHandle(), (LPCVOID)AddressPointer, &Buffer, sizeof(Buffer));
if (CheckBit(Buffer.Protect, 4) || CheckBit(Buffer.Protect, 5) || CheckBit(Buffer.Protect, 6) || CheckBit(Buffer.Protect, 7))
{
if (Buffer.State == MEM_COMMIT)
{
_Sections.push_back(make_pair((unsigned int)Buffer.BaseAddress, (unsigned int)Buffer.RegionSize));
AddressPointer = (unsigned int)Buffer.BaseAddress + (unsigned int)Buffer.RegionSize;
}
}
}
void cDebugger::SetPageGuard()
{
for (size_t i = 0; i < _Sections.size(); i++)
{
DWORD Dummy;
VirtualProtectEx(_Process.GetHandle(), (LPVOID)_Sections[i].first, _Sections[i].second, PAGE_GUARD | PAGE_EXECUTE_READWRITE, &Dummy);
}
}
This way I regain control because the system will fire a EXCEPTION_GUARD_PAGE when execution returns to a guarded page.
if (Event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP)
{
Status = DBG_CONTINUE;
if (!_Tracing)
{
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, Event.dwThreadId);
CONTEXT ThreadContext = GetThreadContext(hThread);
if (ThreadContext.Eip == _EntryAddress)
{
ClearHardwareBreakpoint(0, hThread);
_Tracing = true;
}
CloseHandle(hThread);
}
SetPageGuard();
_Guarded = true;
}
else if (Event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
{
Status = DBG_CONTINUE;
}
else if (Event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_GUARD_PAGE)
{
Status = DBG_CONTINUE; // fires when processor lands on guarded pages
}
else
{
Status = DBG_EXCEPTION_NOT_HANDLED;
}
This solution is not perfect. There are possibly still some situations under which execution can still escape the 'trap'. But it solved my most immediate problem (being able to see the comparisons in my test program).

Related

Why thread stuck? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed last year.
Improve this question
I'm implementing a multiple threads download manager on Windows using C++.
The main thread starts download manage thread M, M starts several download threads D.
Each D will do the HTTP data transfer using library cpr which is a wrapper around libcurl.
After starts some D threads, M enters a loop, keep watching the download progress.
The strange thing: once the second D started, or I abort the first D by return error code(an integer other then 0, I return 1.) from the libcurl's CURLOPT_XFERINFOFUNCTION callback, M's loop will stop. (There's one debugging output inside M's loop. I notice its stop by the disappear of that output from console. Maybe it's not stop, just going into some waiting state instead...)
Both M and D thread are started by STL's std::thread.
Have been scratched by this problem a whole day. Any clue will be appreciated...
This is the M thread entrance:
void HttpDownloader1::MasterThreadFunc_()
{
int loop_count = 0;
// start the first download thread
if (!SplitDownload_(nullptr))
{
status_ = Status::ERRONEOUS;
return;
}
uint64_t prev_downloaded_bytes = recorder_->GetDownloadedBytes();
for (loop_count = 0; download_threads_.size() > 0; loop_count++)
//while (true)
{
loop_count++;
#ifdef _DEBUG
Debug_("main loop, threads: " + std::to_string(download_threads_.size()));
#endif
std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 0.5s
DownloadThread* splitable_segment = nullptr;
auto it = download_threads_.begin();
while (it != download_threads_.end())
{
DownloadThread* thread = *it;
if (thread->status_ == Status::FINISH)
{
delete thread;
it = download_threads_.erase(it);
}
else
{
switch (thread->status_)
{
case Status::RUNNING:
default:
recorder_->MarkFinish(thread->begin_, thread->pos_ - 1);
// part of this segment may have been splited to other download thread
//thread->end_ = recorder_->GetSegmentEnd(thread->pos_);
break;
case Status::SUCCESSFUL:
if (recorder_->IsInitialized())
{
thread->CloseFile();
recorder_->MarkFinish(thread->begin_, thread->pos_ - 1);
}
else
{
if (!PrepareFile_(*it))
status_ = Status::ERRONEOUS;
}
splitable_segment = *it;
break;
case Status::ERRONEOUS:
if (++retry_ > kMaxHttpRetry)
{
status_ = Status::ERRONEOUS;
}
else
{
thread->CloseFile();
recorder_->MarkFailed(thread->pos_, thread->end_);
splitable_segment = *it;
}
break;
}
it++;
}
}
// break out if error occured
if (status_ == Status::ERRONEOUS)
{
break;
}
// if download completed
if (recorder_->IsFinish())
{
status_ = Status::SUCCESSFUL;
break;
}
// calculate download speed every 1 second
if ((loop_count & 1) == 1)
{
auto bytes = recorder_->GetDownloadedBytes();
bytes_per_second_ = bytes - prev_downloaded_bytes;
prev_downloaded_bytes = bytes;
}
// save progress info every 2 seconds
if ((loop_count & 3) == 3)
{
recorder_->Save();
}
// split download when any thread is available or every 4 seconds
if (splitable_segment || (loop_count & 7) == 7)
{
if (splitable_segment != nullptr)
SplitDownload_(splitable_segment);
else if (download_threads_.size() < max_threads_)
SplitDownload_(nullptr);
}
}
master_thread_.detach();
status_ = status_ != Status::ERRONEOUS ? Status::SUCCESSFUL : status_;
}
This is how M start D thread:
bool HttpDownloader1::SplitDownload_(DownloadThread* thread)
{
if (!recorder_->IsInitialized())
{
if (!thread)
thread = CreateDownloadThread_();
thread->begin_ = 0;
thread->end_ = 0;
}
else
{
int64_t begin, end;
if (recorder_->GetTask(&begin, &end))
{
// initialize this segment
if (!thread)
thread = CreateDownloadThread_();
thread->begin_ = begin;
thread->end_ = end;
thread->pos_ = thread->begin_;
if (thread->file_ == nullptr)
{
//errno_t e = fopen_s(&thread->file_, target_.GetPath().c_str(), "rb+");
thread->file_ = fopen(target_.GetPath().c_str(), "rb+");
//if (e == 0 && thread->file_)
if (thread->file_)
{
fseek(thread->file_, (long)thread->begin_, SEEK_SET);
}
else
{
thread->status_ = Status::ERRONEOUS;
return false;
}
}
}
else
{
// no more segment to download or split, remove this thread if it exists.
if (thread)
thread->status_ = Status::FINISH;
}
}
if (thread && thread->status_ != Status::FINISH)
{
thread->status_ = Status::RUNNING;
thread->thread_ = std::thread(&HttpDownloader1::DownloadThreadFunc_, this, thread);
thread->thread_.detach();
}
return true;
}
This is the D thread entrance:
void HttpDownloader1::DownloadThreadFunc_(DownloadThread* thread)
{
cpr::Response rsp;
if (thread->file_ == nullptr)
{
rsp = cpr::Get(
cpr::Url(target_.url_.c_str()),
cpr::ConnectTimeout(std::chrono::seconds(kConnectionTimeout)),
cpr::Timeout(std::chrono::seconds(kTransmitTimeout)),
cpr::VerifySsl(false),
cpr::Header{ { "Range", thread->GetRangeHeaderString().c_str() } },
cpr::CurlOption({ CURLOPT_NOPROGRESS, 1 }),
cpr::CurlOption({ CURLOPT_WRITEDATA, nullptr }),
cpr::CurlOption({ CURLOPT_WRITEFUNCTION, &HttpDownloader1::WriteCallback_ })
);
}
else
{
rsp = cpr::Get(
cpr::Url(target_.url_.c_str()),
cpr::ConnectTimeout(std::chrono::seconds(kConnectionTimeout)),
cpr::Timeout(std::chrono::seconds(kTransmitTimeout)),
cpr::VerifySsl(false),
cpr::Header{ { "Range", thread->GetRangeHeaderString().c_str() } },
cpr::CurlOption({ CURLOPT_NOPROGRESS, 0 }),
cpr::CurlOption({ CURLOPT_XFERINFODATA, thread }),
cpr::CurlOption({ CURLOPT_XFERINFOFUNCTION, &HttpDownloader1::ProgressCallback_ }),
cpr::CurlOption({ CURLOPT_WRITEDATA, thread->file_ }),
cpr::CurlOption({ CURLOPT_WRITEFUNCTION, fwrite })
);
}
if (rsp.status_code == 0)
{
thread->status_ = Status::ERRONEOUS;
Log_("thread:" + std::to_string(thread->id_) + " error: HTTP status code 0");
}
else if (rsp.status_code >= 400)
{
thread->status_ = Status::ERRONEOUS;
Log_("thread:" + std::to_string(thread->id_) + " erorr: HTTP status code " + std::to_string(rsp.status_code));
}
else if (rsp.error.code != cpr::ErrorCode::OK)
{
thread->status_ = Status::ERRONEOUS;
Log_("thread:" + std::to_string(thread->id_) + "error: " + rsp.error.message);
}
else
{
if (thread->file_ == nullptr)
thread->response_header_ = rsp.header;
thread->status_ = Status::SUCCESSFUL;
}
}
This is libcurl's progress callback:
int HttpDownloader1::ProgressCallback_(
void* clientp, std::uint64_t dltotal, std::uint64_t dlnow, std::uint64_t ultotal, std::uint64_t ulnow
) {
auto thread = (DownloadThread*)clientp;
if (dlnow > 0)
{
thread->pos_ = thread->begin_ + dlnow;
if (thread->pos_ > thread->end_)
return 1;
}
return 0;
}
Answer: Because I made a stupid mistake...
Details:
The M thread didn't got stuck(halt abnormally), it's just in a dead loop.
The loop isn't in the main loop of M, but inside the recorder_->MarkFinish(...) call, where I forgot incrementing the iterator at one of the if branch when loop a list container by while(...) {...}.
So when I placed a breakpoint at the recorder_->MarkFinish() line, it wouldn't be caught.
How I found that eventually:
I don't have much experience at multiple thread programming. After scratching my head for nearly a whole day, I thought there must be some low level details unfamiliar to me. So I post this question.
#Raymond comments brought back my confidence. I begun to add debug outputs line by line inside the M thread's main loop trying to find out what it was doing when it seemed stuck. And noticed that each time the error occurred, the outputs would disappear right after that recorder_->MarkFinish(...) call. So I went into that function and caught the carelessly code bellow:
while (it != segments_.end())
{
Segment& seg = *it;
if (seg.begin_ > end) break;
if (seg.end_ < start) continue; // !
if (start <= seg.begin_ && seg.begin_ <= end)
seg.begin_ = end + 1;
if (start <= seg.end_ && seg.end_ <= end)
seg.end_ = start - 1;
if (seg.end_ < seg.begin_)
it = segments_.erase(it);
else
it++;
}
Hope this might help reducing some of the mysterious sense about the problem you meet.💀

Infinite loop while debugging a thread

I'm trying to attach a Hardware breakpoint to a game process and I succed. Then I'm trying to loop through the Exceptions and wait for the one that I've put in there, which is also working fine. The problem is that after it happens it goes into infinite loop that I cannot brake. Can you advise?
The reason for me doing that is that I want to stop the thread at this point, read the EAX value with the use of Context and then proceed with the process.
Header.h includes the functions that are called here and they all work fine, thus Im not including it at this point.
#include "Header.h"
#include
int main() {
SetDebugPrivilege(TRUE);
DWORD dwProcessID = 0;
DWORD dwGame = 0;
printf("Looking for game process...\n");
while (dwProcessID == 0) {
dwProcessID = GetProcessID(L"PathOfExile.exe");
if (dwProcessID != 0)
dwGame = 1;
Sleep(100);
}
printf("dwProcessID = %p\n", dwProcessID);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessID);
MODULEENTRY32 module;
module.dwSize = sizeof(MODULEENTRY32);
Module32First(snapshot, &module);
printf("PoE base address = %p\n", module.modBaseAddr);
hpChangeBreakpoint = (DWORD*)((char *)module.modBaseAddr + 0x1AAD20);
std::cout << hpChangeBreakpoint << std::endl;
//hpChangeBreakpoint = 0x013FB279;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwProcessID);
BOOL bDebugging = DebugActiveProcess(dwProcessID);
printf("bDebugging = %d\n", bDebugging);
DWORD dwThreadID = GetProcessThreadID(dwProcessID);
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadID);
CONTEXT parentCtx;
parentCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if (GetThreadContext(hThread, &parentCtx))
{
parentCtx.Dr0 = (DWORD)hpChangeBreakpoint;
parentCtx.Dr7 = 0x00000001;
std::cout << "GetThreadContext successful" << std::endl;
SetThreadContext(hThread, &parentCtx);
}
DEBUG_EVENT DebugEvent;
DWORD dbgFlag = DBG_CONTINUE;
DWORD *currentHpPointerAddress = nullptr;
DWORD *maxHpPointerAddress = nullptr;
BOOLEAN bQuit = FALSE;
while (!bQuit && WaitForDebugEvent(&DebugEvent, INFINITE))
{
dbgFlag = DBG_CONTINUE;
switch (DebugEvent.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
switch (DebugEvent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_SINGLE_STEP:
if (DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress == (void*)hpChangeBreakpoint)
{
#define RESUME_FLAG 0x10000
CONTEXT childContext;
childContext.ContextFlags = CONTEXT_FULL;
if (GetThreadContext(hThread, &childContext))
{
childContext.EFlags |= RESUME_FLAG;
SetThreadContext(hThread, &childContext);
std::cout << "current HP: " << childContext.Ecx << std::endl;
currentHpPointerAddress = (DWORD*)((char *)childContext.Edi + 0x8E0);
maxHpPointerAddress = (DWORD*)((char *)childContext.Edi + 0x8E4);
}
if (GetThreadContext(hThread, &parentCtx))
{
parentCtx.Dr0 = 0;
parentCtx.Dr7 = 0x400;
SetThreadContext(hThread, &parentCtx);
bQuit = TRUE;
}
}
else
dbgFlag = DBG_EXCEPTION_NOT_HANDLED;
break;
default:
dbgFlag = DBG_EXCEPTION_NOT_HANDLED;
}
break;
case LOAD_DLL_DEBUG_EVENT:
{
CloseHandle(DebugEvent.u.LoadDll.hFile);
break;
}
case CREATE_PROCESS_DEBUG_EVENT:
{
CloseHandle(DebugEvent.u.CreateProcessInfo.hFile);
break;
}
case EXIT_PROCESS_DEBUG_EVENT:
break;
default:
__nop();
}
if (!ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, dbgFlag))
{
break;
}
if (bQuit)
DebugActiveProcessStop(dwProcessID);
}
while (1)
{
WORD currentHP = 0;
WORD maxHP = 0;
if (
ReadProcessMemory(hProcess, currentHpPointerAddress, &currentHP, sizeof(currentHP), NULL) == 0
|| ReadProcessMemory(hProcess, maxHpPointerAddress, &maxHP, sizeof(maxHP), NULL) == 0
)
{
printf("Failed to read memory: %u\n", GetLastError());
}
else {
std::cout << "HP: " << currentHP << " / " << maxHP << std::endl;
}
Sleep(1000);
}
system("pause>nul");
return 0;
}
When I run it, the game works fine until the breakpoint happens, when it does, i get infinite "breakpoint" cout's spam and when I debug it, this line:
if (DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress == (void*)hpChangeBreakpoint)
is always true, but the dwFirstChance flag is 1, so its always a new exception? The only thing that changes in this infinite loop is the hThread, is always different. I feel like im missing something because of my lack of knowledge, thus would appreciate any help or hints to right direction. thank you!
are you listen/know about Resume Flag (RF) ? you need set it for step over DrX brealpoint
so code must be next
#define RESUME_FLAG 0x10000
CONTEXT Context = {};
Context.ContextFlags = CONTEXT_CONTROL;// not need CONTEXT_FULL here;
if (GetThreadContext(hThread, &Context))
{
Context.EFlags |= RESUME_FLAG; // !!! this line is key point
SetThreadContext(hThread, &Context);
}
this will be work begin from win2003 or windows vista. unfortunately XP not let you set this flag in CONTEXT. so here you need remove Dr0 breakpoint for step over it ( or patch XP kernel - search for 0x003E0DD7 DWORD in ntoskrnl code and replace it to 0x003F0DD7 - this is Eflags mask - different in RESUME_FLAG )
also let some optimization advice - you not need call OpenThread every time when EXCEPTION_DEBUG_EVENT.
at first you already have this thread handle
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadID);
simply not close it, after you call SetThreadContext
and exception can occur only in context of this thread, all other threads not affected by this.
at second you never close thread handle, opened in EXCEPTION_DEBUG_EVENT - so you already have resource leaks.
debugger got thread handles on CREATE_THREAD_DEBUG_EVENT and CREATE_PROCESS_DEBUG_EVENT and MUST close it (or just or usual maintain it and close on EXIT_THREAD_DEBUG_EVENT and EXIT_PROCESS_DEBUG_EVENT )
you not handle LOAD_DLL_DEBUG_EVENT and as result not close file handle.
your code have HUGE handle leaks !
SuspendThread / ResumeThread - for what ?! absolute senseless - thread (and all threads in process) already suspended in this point
struct CThread : LIST_ENTRY
{
HANDLE _hThread;
ULONG _dwThreadId;
CThread(HANDLE hThread, ULONG dwThreadId)
{
_hThread = hThread;
_dwThreadId = dwThreadId;
}
~CThread()
{
//CloseHandle(_hThread);// will be closed in ContinueDebugEvent
}
static CThread* get(ULONG dwThreadId, PLIST_ENTRY ThreadListHead, CThread* pHintThread)
{
if (pHintThread && pHintThread->_dwThreadId == dwThreadId)
{
return pHintThread;
}
PLIST_ENTRY entry = ThreadListHead;
while ((entry = entry->Flink) != ThreadListHead)
{
pHintThread = static_cast<CThread*>(entry);
if (pHintThread->_dwThreadId == dwThreadId)
{
return pHintThread;
}
}
return 0;//??
}
static void DeleteAll(PLIST_ENTRY ThreadListHead)
{
PLIST_ENTRY entry = ThreadListHead->Flink;
while (entry != ThreadListHead)
{
CThread* pThread = static_cast<CThread*>(entry);
entry = entry->Flink;
delete pThread;
}
}
};
void RunDebuggerLoop()
{
BOOL bQuit = FALSE;
LIST_ENTRY ThreadListHead = { &ThreadListHead, &ThreadListHead };
CThread* pThread = 0;
DEBUG_EVENT de;
BOOLEAN bFirst = TRUE;
while (!bQuit && WaitForDebugEvent(&de, INFINITE))
{
NTSTATUS status = DBG_CONTINUE;
switch(de.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
if (
!de.u.Exception.dwFirstChance
||
!(pThread = CThread::get(de.dwThreadId, &ThreadListHead, pThread))
)
{
bQuit = TRUE;
continue;
}
status = DBG_EXCEPTION_NOT_HANDLED;
switch (de.u.Exception.ExceptionRecord.ExceptionCode)
{
case STATUS_BREAKPOINT:
case STATUS_WX86_BREAKPOINT:
if (bFirst)
{
bFirst = FALSE;
status = DBG_CONTINUE;
}
break;
case STATUS_SINGLE_STEP:
case STATUS_WX86_SINGLE_STEP:
{
::CONTEXT ctx = {};
ctx.ContextFlags = CONTEXT_CONTROL;
if (GetThreadContext(pThread->_hThread, &ctx))
{
ctx.EFlags |= RESUME_FLAG;
SetThreadContext(pThread->_hThread, &ctx);
}
}
break;
case STATUS_ACCESS_VIOLATION:
if (de.u.Exception.ExceptionRecord.NumberParameters > 1)
{
ULONG_PTR ptr = de.u.Exception.ExceptionRecord.ExceptionInformation[1];
}
break;
}
break;
case CREATE_PROCESS_DEBUG_EVENT:
CloseHandle(de.u.CreateProcessInfo.hFile);
//CloseHandle(de.u.CreateProcessInfo.hProcess);// will be auto closed in ContinueDebugEvent
de.u.CreateThread.hThread = de.u.CreateProcessInfo.hThread;
case CREATE_THREAD_DEBUG_EVENT:
if (pThread = new CThread(de.u.CreateThread.hThread, de.dwThreadId))
{
InsertHeadList(&ThreadListHead, pThread);
}
break;
case EXIT_THREAD_DEBUG_EVENT:
if (pThread = CThread::get(de.dwThreadId, &ThreadListHead, pThread))
{
RemoveEntryList(pThread);
delete pThread;
pThread = 0;
}
break;
case LOAD_DLL_DEBUG_EVENT:
CloseHandle(de.u.LoadDll.hFile);
break;
case EXIT_PROCESS_DEBUG_EVENT:
bQuit = TRUE;
break;
case OUTPUT_DEBUG_STRING_EVENT:
case UNLOAD_DLL_DEBUG_EVENT:
__nop();
break;
default:
__nop();
}
if (!ContinueDebugEvent(de.dwProcessId, de.dwThreadId, status))
{
break;
}
}
CThread::DeleteAll(&ThreadListHead);
}
void Ep()
{
// tag by * in begin of CommandLine
PWSTR CommandLine = GetCommandLine();
if (!CommandLine || *CommandLine != '*')
{
// debugger case
WCHAR FileName[MAX_PATH];
if (ULONG n = GetModuleFileName(0, FileName, RTL_NUMBER_OF(FileName)))
{
if (n < MAX_PATH)
{
PROCESS_INFORMATION pi;
STARTUPINFO si = { sizeof(si) };
PWSTR newCommandLine = (PWSTR)alloca((wcslen(CommandLine) + 2)*sizeof(WCHAR));
*newCommandLine = '*';
wcscpy(newCommandLine + 1, CommandLine);
if (CreateProcessW(FileName, newCommandLine, 0, 0, 0, DEBUG_PROCESS, 0, 0, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
RunDebuggerLoop();
}
}
}
ExitProcess(0);
}
else
{
// main case
wcscpy(CommandLine, CommandLine + 1);
OutputDebugStringA("AAAAAA\n");
if (MessageBoxW(0, L"xxx", CommandLine, MB_YESNO) == IDYES)
{
OutputDebugStringW(L"WWWWWWWW\n");
}
ExitProcess(0);
}
}
Big thanks for the time you've spent answering me. I'm sorry if some of the questions are weird, but Im a JS dev and what I'm doing here is my hobby. What i know is that it feels like a different and way deeper world then my JS.. ;)
I did edit the code, also removed what you've mentioned is redundant. The suspend/resume of the thread was there because between them I had some memory modyfications, but based on what you said, that the thread is suspended at this point anyway, even if I would modify the memory, there's no need for them?
Going back to the subject, the infinite loop is still here. Ive added the RF flag, but I'm just starting to read through the articles on that so apart from just adding it, I also understand why. Meanwhile, would you be so kind to give me another hint on why it might still not be working?
Also, I've added LOAD_DLL_DEBUG_EVENT handling and I'm closing the handler straight away as I don't need to do anything else with that at this point(do i?). What I dont entirely get is to when excatly should I close the handlers received from CREATE_PROCESS and CREATE_THREAD debug event? I'm trying to wrap my mind of how the debugger works, its my 4th day with it so far, but as i see it, this is what happens:
WaitForDebugEvent receives a debug event, as long as its not mine, its being handled by ContinueDebugEvent with DBG_EXCEPTION_NOT_HANDLED, so its being passed back and the game handles it.
Finally WaitForDebugEvent receives my debug event, which is EXCEPTION_SINGLE_STEP, I do my stuff in there and then makes it continue with DBG_CONTINUE - that flags the exception as handled by me, and system just keeps going after it. Is that correct?
My actual code that still loops and prints "Breakpoint" in infinite loop:
#include "Header.h"
#include <iostream>
int main() {
hpChangeBreakpoint = 0x013FB279;
SetDebugPrivilege(TRUE);
DWORD dwProcessID = 0;
DWORD dwGame = 0;
printf("Looking for game process...\n");
while (dwProcessID == 0) {
dwProcessID = GetProcessID(L"PathOfExile.exe");
if (dwProcessID != 0)
dwGame = 1;
Sleep(100);
}
printf("dwProcessID = %p\n", dwProcessID);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwProcessID);
BOOL bDebugging = DebugActiveProcess(dwProcessID);
printf("bDebugging = %d\n", bDebugging);
DWORD dwThreadID = GetProcessThreadID(dwProcessID);
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadID);
CONTEXT context;
context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
if (GetThreadContext(hThread, &context))
{
context.Dr0 = hpChangeBreakpoint;
context.Dr7 = 0x00000001;
std::cout << "GetThreadContext successful" << std::endl;
SetThreadContext(hThread, &context);
}
DEBUG_EVENT DebugEvent;
BOOL bContinueDebugging = false;
for(;;)
{
WaitForDebugEvent(&DebugEvent, INFINITE);
switch (DebugEvent.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
switch (DebugEvent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_SINGLE_STEP:
if (DebugEvent.u.Exception.ExceptionRecord.ExceptionAddress == (void*)hpChangeBreakpoint)
{
#define RESUME_FLAG 0x10000
CONTEXT Context;
Context.ContextFlags = CONTEXT_CONTROL;
Context.EFlags |= RESUME_FLAG;
std::cout << "Breakpoint" << std::endl;
bContinueDebugging = true;
}
if (bContinueDebugging)
{
// DBG_CONTINUE to tell the program we have handled the exception
ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_CONTINUE);
bContinueDebugging = false;
}
else // if the exception was not handled by our exception-handler, we want the program to handle it, so..
ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
break;
default:
ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
}
break;
case LOAD_DLL_DEBUG_EVENT:
{
std::cout << "load dll debug event" << std::endl;
CloseHandle(DebugEvent.u.LoadDll.hFile);
break;
}
default:
ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
}
}
system("pause>nul");
return 0;
}

C++ SIGINT and SIGSTP over ctrl+c and ctrl+z

I am writing on a shell and want to implement the signals SIGSTP and SIGINT.
When the user starts a new process and presses CTRL+C it should send a SIGINT to the process and when CTRL+Z is pressed the process should get the SIGSTP signal.
Here is my code so far:
string inputNew = input;
vector<char*> arguments;
size_t lastChar = 0;
for(int i = 0; i < input.size(); i++)
{
char& c = input[i];
if((c == ' ' || c == '\t'||c == '\n') && lastChar != i)
{
c = '\0';
arguments.push_back(&input[0] + lastChar);
lastChar = i+1;
}
}
bool checkIfBackground(string & input)
{
size_t lastChar = input.size() - 1;
if(input[lastChar] == '&')
{
return true;
}
return false;
}
if((pid = fork()) < 0) {
exit(1);
} else if(pid == 0) {
execvp(arguments[0], &arguments[0]);
exit(1);
} else if(checkIfBackground(inputNew) == false) {
int status;
pid_t pid_r;
if(waitpid(pid, &status, 0) < 0) {
cout << "PID not known!";
}
} else {
cout << "Prozess is waiting in the background." << endl;
}
I have no idea how to implement the SIGSTP and SIGINT signals inside my code.
See the sigaction(2) manual pages. It explains how to set up an implement a signal handler.
Note that a signal handler is asynchronous. This has a number of implications. Read the manual page, and spend some time in Google.

Memory Allocation for threads in C++

How to Explicitly Allocate memory to a Thread in C++ ? Am using Windows API for Multi-threading.While running sometimes it executes correctly but sometimes it shows "Heap Corruption","Unhandled Exception".Please guide me
This is the main() where i create the threads.
int main(int argc,char *argv[])
{
HANDLE hthread[MAX_THREADS];
//DWORD threadid;
FILETIME creation,exit,kernel,user;
SYSTEMTIME st1,st2;
//THREADENTRY32 entry;
char szEntrytime[255],szExittime[255];
directories.push_front(argv[1]);
files.clear();
Sem = CreateSemaphore(NULL,MAX_SEM_COUNT,MAX_SEM_COUNT,NULL);
if (Sem == NULL)
{
printf("CreateSemaphore error: %d\n", GetLastError());
return 1;
}
for(int i= 0;i<MAX_THREADS;i++)
{
hthread[i] = CreateThread(NULL,0,List,NULL,0,&threadid);
//hthread[i] = HeapAlloc(GetProcessHeap(),HEAP_NO_SERIALIZE,1024*30);
if( hthread[i] == NULL )
{
printf("CreateThread error: %d\n", GetLastError());
return 1;
}
}
Inside Thread
while(!directories.empty())
{
string path = directories.front();
string spec = path + "\\" + "*";
WaitForSingleObject(Sem,0L);
directories.pop_front();
ReleaseSemaphore(Sem,1,NULL);
HANDLE hfind = FindFirstFileA(spec.c_str(),&ffd);
if(hfind == INVALID_HANDLE_VALUE)
continue;
cout<< path <<endl;;
do
{
if(strcmp(ffd.cFileName,".") && strcmp(ffd.cFileName,".."))
{
if(ffd.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
{
WaitForSingleObject(Sem,0L);
directories.push_front(path + "\\" + ffd.cFileName);
ReleaseSemaphore(Sem,1,NULL);
}
else
{
files.push_back(path + "\\" + ffd.cFileName);
Files++;
}
}
}while(FindNextFileA(hfind,&ffd));
Use following logic for your threads (pseudo-code):
while ( true ) {
lock()
if ( empty ) {
unlock;
sleep;
continue;
} else {
get_one_dir;
remove_that_dir_from_list;
unlock;
}
process_the_dir;
continue;
}
For lock, use a Critical Section, and lock/unlock again when you want to push a new dir in the list.
Use same lock/unlock logic when reading/writing the files vector.
Use critical section for access shared resource:
EnterCriticalSection(&my_section);
//perform data manipulation per-thread
LeaveCriticalSection(&my_section);
Do not forget to initialize the critical section before using.
See this question to get help Problems using EnterCriticalSection

What means lne "The thread 'Win32 Thread' (0x17d0) has exited with code 2:"?

After i closed my compiled multithread dialog based app in MFC, i saw line:
The thread 'Win32 Thread' (0x17d0) has exited with code 2
Instead of:
The thread 'Win32 Thread' (0x17d0) has exited with code 0
But all closed correctly. What does it mean?
Edit:
Here is thread func:
UINT CrMainDlg::WorkerThreadProc(LPVOID Param)
{
if(Param == NULL)
{
AfxMessageBox(L"Params in thread func are equal to NULL!");
return 0;
}
inputParam* p = (inputParam*)Param;
int startIndex = p->index;
int index = p->curIndex;
int direction = 1;
for (int i = 0; (static_cast<unsigned>(startIndex + i) >= 0) && (static_cast<unsigned>(startIndex + i) < ThumbnailList.size()); i += direction)
{
if (flagToThreadFinished)
{
break;
}
if (ThumbnailList.size() == 0)
{
AfxMessageBox(L"Here it is!!");
}
EnterCriticalSection(&CriticalSection);
if (ThumbnailList[startIndex + i].second->IsLoaded)
{
i += direction;
continue;
}
CString path = ThumbnailList[startIndex + i].first;
try
{
ThumbnailList[startIndex + i].second->LoadThumbNail(path);
WPARAM a = MAKEWPARAM(startIndex + i, 0);
::PostMessage(p->m_hWnd, THUMBNAIL_WAS_LOADED, a, 0);
}
catch (...)
{
AfxMessageBox(L"Something bad was happend while loading!");
}
LeaveCriticalSection(&CriticalSection);
if (startIndex != p->index)
{
startIndex = p->index;
i = -1;
direction = 1;
continue;
}
if (startIndex + i == ThumbnailList.size() - 1)
{
i = -1;
direction = -1;
continue;
}
}
return 0;
}
And here is ON_CLOSE dialog handler:
void CrMainDlg::OnClose()
{
flagToThreadFinished = true;
DWORD check = WaitForSingleObject(thread, INFINITE);
DWORD checkError = GetLastError();
for (std::vector <std::pair<CString, CommonThumbnail*>>::iterator someIter = ThumbnailList.begin(); someIter != ThumbnailList.end(); someIter++)
{
if (someIter->second != nullptr)
{
delete someIter->second;
}
}
ThumbnailList.clear();
flagToThreadFinished = false;
CDialogEx::OnClose();
}
Value of GetLastError is 3435973836;