Я пишу программу, которая отслеживает выполнение других программ. Я использую динамическую инструкцию для отслеживания поведения инструкции CMP x86.Escaping trapflag/single step
Я использую отладку windows api для управления поведением отлаживаемой программы. Я запускаю программу с флагом «debug only this process», а затем устанавливаю флаг trap в основном потоке.
тогда я вхожу в основной цикл отладки:
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;
}
Как вы можете видеть, что цикл через все нити в конце функции, чтобы убедиться, что одномоментная исключение вызовет на каждой следующей инструкции в каждый поток. Однако иногда выполнение, похоже, «убегает» от этой ловушки, часто выполняя миллионы инструкций, прежде чем снова поймать следующее событие отладки.
Я написал еще одно небольшое приложение, чтобы проверить поведение моей программы:
int main(int argc, char* argv[])
{
//__asm int 3h
if (argc == 41234123)
{
printf("Got one\n");
}
return 0;
}
Ожидаемый выход индикатора должен быть:
0xDEADBEEF CMP 1 41234123
Однако как-то трассировщик не записывает эту инструкцию (указывая, что событие отладки не было поднято и что флаг ловушки не был установлен).
Может ли кто-нибудь увидеть, что я делаю что-то не так в моей петле отладки? Или какое поведение тестовой программы (загрузка DLL) может быть причиной этого?
Вы уверены, что компилятор сгенерировал инструкцию «CMP» и использовал кодировку для команды, которую вы ожидаете? Где вы код, который печатает ожидаемый результат? –
Да, я дважды проверил с дизассемблером, чтобы убедиться, что на самом деле есть инструкция CMP, а не TEST или что-то еще. Он есть, и он выполняется только в том случае, что мой трассировщик его не видит. – user513647