mirror of https://github.com/x64dbg/TitanEngine
Clean up TTD API
This commit is contained in:
parent
5ce48fef05
commit
21ef77f31f
|
|
@ -5,6 +5,7 @@
|
|||
#include "Global.Mapping.h"
|
||||
#include "Global.Engine.Hash.h"
|
||||
#include "Global.Debugger.h"
|
||||
#include <mutex>
|
||||
|
||||
bool engineCheckForwarders = true;
|
||||
bool engineAlowModuleLoading = false;
|
||||
|
|
@ -20,6 +21,7 @@ bool engineSafeAttach = false;
|
|||
bool engineMembpAlt = false;
|
||||
bool engineDisableAslr = false;
|
||||
bool engineSafeStep = true;
|
||||
bool engineWow64SingleStepWorkaround = true;
|
||||
|
||||
char engineFoundDLLName[512] = {0};
|
||||
char engineFoundAPIName[512] = {0};
|
||||
|
|
@ -30,6 +32,91 @@ LPVOID engineDependencyFiles;
|
|||
LPVOID engineDependencyFilesCWP;
|
||||
void* EngineStartUnpackingCallBack;
|
||||
|
||||
namespace
|
||||
{
|
||||
std::mutex pauseMutex;
|
||||
LPVOID pauseCallback = nullptr;
|
||||
ULONGLONG pauseRequestTime = 0;
|
||||
ULONG_PTR pauseBreakInStart = 0;
|
||||
DWORD pauseBreakInThreadId = 0;
|
||||
bool pauseBreakInExpected = false;
|
||||
}
|
||||
|
||||
bool EngineBeginPause(LPVOID Callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(pauseMutex);
|
||||
if(pauseCallback)
|
||||
return false;
|
||||
pauseCallback = Callback;
|
||||
pauseRequestTime = GetTickCount64();
|
||||
pauseBreakInStart = 0;
|
||||
pauseBreakInThreadId = 0;
|
||||
pauseBreakInExpected = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EnginePauseShouldEscalate(TitanPausePolicy MaximumPolicy)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(pauseMutex);
|
||||
return pauseCallback && !pauseBreakInExpected && MaximumPolicy == UE_PAUSE_POLICY_AGGRESSIVE &&
|
||||
GetTickCount64() - pauseRequestTime >= 2000;
|
||||
}
|
||||
|
||||
void EngineExpectPauseBreakIn(ULONG_PTR StartAddress)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(pauseMutex);
|
||||
pauseBreakInExpected = true;
|
||||
pauseBreakInStart = StartAddress;
|
||||
pauseBreakInThreadId = 0;
|
||||
}
|
||||
|
||||
void EngineCancelPauseBreakIn()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(pauseMutex);
|
||||
pauseBreakInExpected = false;
|
||||
pauseBreakInStart = 0;
|
||||
pauseBreakInThreadId = 0;
|
||||
}
|
||||
|
||||
void EngineObservePauseThread(DWORD ThreadId, ULONG_PTR StartAddress)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(pauseMutex);
|
||||
if(pauseBreakInExpected && pauseBreakInStart && StartAddress == pauseBreakInStart)
|
||||
pauseBreakInThreadId = ThreadId;
|
||||
}
|
||||
|
||||
bool EngineIsPauseBreakInEvent(DWORD ThreadId)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(pauseMutex);
|
||||
return pauseBreakInExpected && pauseBreakInThreadId && pauseBreakInThreadId == ThreadId;
|
||||
}
|
||||
|
||||
void EngineCompletePause()
|
||||
{
|
||||
LPVOID callback = nullptr;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(pauseMutex);
|
||||
callback = pauseCallback;
|
||||
pauseCallback = nullptr;
|
||||
pauseRequestTime = 0;
|
||||
pauseBreakInStart = 0;
|
||||
pauseBreakInThreadId = 0;
|
||||
pauseBreakInExpected = false;
|
||||
}
|
||||
if(callback)
|
||||
((void(TITCALL*)())callback)();
|
||||
}
|
||||
|
||||
void EngineCancelPause()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(pauseMutex);
|
||||
pauseCallback = nullptr;
|
||||
pauseRequestTime = 0;
|
||||
pauseBreakInStart = 0;
|
||||
pauseBreakInThreadId = 0;
|
||||
pauseBreakInExpected = false;
|
||||
}
|
||||
|
||||
// Global.Engine.functions:
|
||||
void EngineInit()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,10 +23,19 @@ extern bool engineSafeAttach;
|
|||
extern bool engineMembpAlt;
|
||||
extern bool engineDisableAslr;
|
||||
extern bool engineSafeStep;
|
||||
extern bool engineWow64SingleStepWorkaround;
|
||||
|
||||
//Global.Engine.Functions
|
||||
void EngineInit();
|
||||
bool EngineIsThereFreeHardwareBreakSlot(LPDWORD FreeRegister);
|
||||
bool EngineBeginPause(LPVOID Callback);
|
||||
bool EnginePauseShouldEscalate(TitanPausePolicy MaximumPolicy);
|
||||
void EngineExpectPauseBreakIn(ULONG_PTR StartAddress);
|
||||
void EngineCancelPauseBreakIn();
|
||||
void EngineObservePauseThread(DWORD ThreadId, ULONG_PTR StartAddress);
|
||||
bool EngineIsPauseBreakInEvent(DWORD ThreadId);
|
||||
void EngineCompletePause();
|
||||
void EngineCancelPause();
|
||||
bool EngineFileExists(char* szFileName);
|
||||
void EngineCreatePathForFile(char* szFileName);
|
||||
void EngineCreatePathForFileW(wchar_t* szFileName);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,27 @@ __declspec(dllexport) void TITCALL ForceClose()
|
|||
|
||||
__declspec(dllexport) void TITCALL StepInto(LPVOID StepCallBack)
|
||||
{
|
||||
#ifndef _WIN64
|
||||
// A WOW64 transition through `ljmp 33h` cannot be completed reliably with
|
||||
// the x86 trap flag. Treat the return address already on the x86 stack as
|
||||
// an engine-owned one-shot step target instead. The frontend only requests
|
||||
// StepInto and does not need to know which execution mechanism is used.
|
||||
if(engineWow64SingleStepWorkaround)
|
||||
{
|
||||
unsigned char data[7] = {};
|
||||
auto cip = GetContextData(UE_CIP);
|
||||
if(MemoryReadSafe(dbgProcessInformation.hProcess, (void*)cip, data, sizeof(data), nullptr) &&
|
||||
data[0] == 0xEA && data[5] == 0x33 && data[6] == 0x00)
|
||||
{
|
||||
ULONG_PTR returnAddress = 0;
|
||||
auto csp = GetContextData(UE_CSP);
|
||||
if(MemoryReadSafe(dbgProcessInformation.hProcess, (void*)csp, &returnAddress,
|
||||
sizeof(returnAddress), nullptr) &&
|
||||
SetBPX(returnAddress, UE_SINGLESHOOT, StepCallBack))
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
EnterCriticalSection(&engineStepActiveCr);
|
||||
// Arm a single-step for the current event thread only. State is per-thread, so a
|
||||
// step already pending on another thread does not block this one.
|
||||
|
|
|
|||
|
|
@ -175,7 +175,8 @@ __declspec(dllexport) bool TITCALL GetSessionInfo(TITAN_SESSION_INFO* SessionInf
|
|||
UE_SESSION_CAP_CONTEXT_READ | UE_SESSION_CAP_FORWARD_EXECUTION |
|
||||
UE_SESSION_CAP_MEMORY_WRITE | UE_SESSION_CAP_CONTEXT_WRITE |
|
||||
UE_SESSION_CAP_PROCESS_CONTROL | UE_SESSION_CAP_THREAD_CONTROL |
|
||||
UE_SESSION_CAP_NATIVE_HANDLES | UE_SESSION_CAP_EXCEPTION_CONTINUE;
|
||||
UE_SESSION_CAP_NATIVE_HANDLES | UE_SESSION_CAP_EXCEPTION_CONTINUE |
|
||||
UE_SESSION_CAP_PAUSE_EXECUTION;
|
||||
#ifdef _WIN64
|
||||
SessionInfo->machineType = IMAGE_FILE_MACHINE_AMD64;
|
||||
#else
|
||||
|
|
@ -210,13 +211,13 @@ __declspec(dllexport) bool TITCALL ReplaySetPosition(const TITAN_REPLAY_POSITION
|
|||
return false;
|
||||
}
|
||||
|
||||
__declspec(dllexport) bool TITCALL ReplayRun(bool Reverse)
|
||||
__declspec(dllexport) bool TITCALL ReplayRunBack()
|
||||
{
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return false;
|
||||
}
|
||||
|
||||
__declspec(dllexport) bool TITCALL ReplayStep(bool Reverse, bool StepOver, TITANCBSTEP StepCallBack)
|
||||
__declspec(dllexport) bool TITCALL ReplayStepBack(TITANCBSTEP StepCallBack)
|
||||
{
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ static void engineStep()
|
|||
|
||||
__declspec(dllexport) void TITCALL DebugLoop()
|
||||
{
|
||||
EngineCancelPause();
|
||||
bool FirstBPX = true;
|
||||
bool ResetBPX = false;
|
||||
bool PushfBPX = false;
|
||||
|
|
@ -375,6 +376,8 @@ __declspec(dllexport) void TITCALL DebugLoop()
|
|||
NewThreadData.ThreadStartAddress = (void*)DBGEvent.u.CreateThread.lpStartAddress;
|
||||
NewThreadData.ThreadLocalBase = (void*)DBGEvent.u.CreateThread.lpThreadLocalBase;
|
||||
hListThread.push_back(NewThreadData);
|
||||
EngineObservePauseThread(DBGEvent.dwThreadId,
|
||||
(ULONG_PTR)DBGEvent.u.CreateThread.lpStartAddress);
|
||||
|
||||
//Set hardware breakpoints to all threads
|
||||
HANDLE hThread = NewThreadData.hThread;
|
||||
|
|
@ -588,6 +591,15 @@ __declspec(dllexport) void TITCALL DebugLoop()
|
|||
{
|
||||
DBGCode = DBG_EXCEPTION_NOT_HANDLED; //let the debuggee handle exceptions per default
|
||||
|
||||
if((DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT ||
|
||||
DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_WX86_BREAKPOINT) &&
|
||||
EngineIsPauseBreakInEvent(DBGEvent.dwThreadId))
|
||||
{
|
||||
DBGCode = DBG_CONTINUE;
|
||||
EngineCompletePause();
|
||||
break;
|
||||
}
|
||||
|
||||
if(DBGCustomHandler->chEverythingElse != NULL)
|
||||
{
|
||||
myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chEverythingElse);
|
||||
|
|
@ -1490,6 +1502,7 @@ continue_dbg_event:
|
|||
{
|
||||
RtlMoveMemory(&TerminateDBGEvent, &DBGEvent, sizeof(DEBUG_EVENT));
|
||||
}
|
||||
EngineCancelPause();
|
||||
ForceClose();
|
||||
engineFileIsBeingDebugged = false;
|
||||
DebuggerReset();
|
||||
|
|
|
|||
|
|
@ -55,6 +55,10 @@ __declspec(dllexport) void TITCALL SetEngineVariable(DWORD VariableId, bool Vari
|
|||
{
|
||||
engineSafeStep = VariableSet;
|
||||
}
|
||||
else if(VariableId == UE_ENGINE_WOW64_SINGLE_STEP_WORKAROUND)
|
||||
{
|
||||
engineWow64SingleStepWorkaround = VariableSet;
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(dllexport) bool TITCALL EngineCreateMissingDependencies(char* szFileName, char* szOutputFolder, bool LogCreatedFiles)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#include "definitions.h"
|
||||
#include "Global.Handle.h"
|
||||
#include "Global.Engine.h"
|
||||
#include "Global.Debugger.h"
|
||||
#include <TlHelp32.h>
|
||||
|
||||
// TitanEngine.Process.functions:
|
||||
__declspec(dllexport) long TITCALL GetActiveProcessId(char* szImageName)
|
||||
|
|
@ -178,9 +180,115 @@ __declspec(dllexport) bool TITCALL TitanTerminateProcess(HANDLE hProcess, DWORD
|
|||
return !!TerminateProcess(hProcess, exitCode);
|
||||
}
|
||||
|
||||
__declspec(dllexport) bool TITCALL TitanDebugBreakProcess(HANDLE hProcess)
|
||||
static ULONG_PTR pauseBreakInStartAddress()
|
||||
{
|
||||
return !!DebugBreakProcess(hProcess);
|
||||
auto localNtdll = GetModuleHandleW(L"ntdll.dll");
|
||||
auto localStart = localNtdll ? GetProcAddress(localNtdll, "DbgUiRemoteBreakin") : nullptr;
|
||||
if(!localStart || !dbgProcessInformation.dwProcessId)
|
||||
return 0;
|
||||
|
||||
auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
|
||||
dbgProcessInformation.dwProcessId);
|
||||
if(snapshot == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
MODULEENTRY32W module = {};
|
||||
module.dwSize = sizeof(module);
|
||||
ULONG_PTR result = 0;
|
||||
if(Module32FirstW(snapshot, &module))
|
||||
{
|
||||
do
|
||||
{
|
||||
if(!_wcsicmp(module.szModule, L"ntdll.dll"))
|
||||
{
|
||||
result = (ULONG_PTR)module.modBaseAddr +
|
||||
(ULONG_PTR)localStart - (ULONG_PTR)localNtdll;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(Module32NextW(snapshot, &module));
|
||||
}
|
||||
CloseHandle(snapshot);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool requestPauseBreakIn()
|
||||
{
|
||||
auto startAddress = pauseBreakInStartAddress();
|
||||
if(!startAddress)
|
||||
{
|
||||
SetLastError(ERROR_PROC_NOT_FOUND);
|
||||
return false;
|
||||
}
|
||||
EngineExpectPauseBreakIn(startAddress);
|
||||
if(DebugBreakProcess(dbgProcessInformation.hProcess))
|
||||
return true;
|
||||
EngineCancelPauseBreakIn();
|
||||
return false;
|
||||
}
|
||||
|
||||
__declspec(dllexport) bool TITCALL RequestPause(TitanPausePolicy MaximumPolicy, TITANCBPAUSE PauseCallback)
|
||||
{
|
||||
if(MaximumPolicy < UE_PAUSE_POLICY_NONINVASIVE || MaximumPolicy > UE_PAUSE_POLICY_AGGRESSIVE ||
|
||||
!PauseCallback || !engineFileIsBeingDebugged || !dbgProcessInformation.hProcess)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!EngineBeginPause((LPVOID)PauseCallback))
|
||||
{
|
||||
if(EnginePauseShouldEscalate(MaximumPolicy))
|
||||
requestPauseBreakIn(); // The original, less intrusive request remains pending on failure.
|
||||
return true;
|
||||
}
|
||||
|
||||
if(MaximumPolicy == UE_PAUSE_POLICY_NONINVASIVE)
|
||||
{
|
||||
EngineCancelPause();
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto threadId = DebugAttachedToProcess || !DBGEvent.dwThreadId
|
||||
? dbgProcessInformation.dwThreadId
|
||||
: DBGEvent.dwThreadId;
|
||||
auto thread = EngineOpenThread(THREAD_GETSETSUSPEND, false, threadId);
|
||||
if(!thread)
|
||||
{
|
||||
if(MaximumPolicy == UE_PAUSE_POLICY_AGGRESSIVE && requestPauseBreakIn())
|
||||
return true;
|
||||
EngineCancelPause();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto previousSuspendCount = SuspendThread(thread);
|
||||
if(previousSuspendCount != 0)
|
||||
{
|
||||
if(previousSuspendCount != (DWORD)-1)
|
||||
ResumeThread(thread);
|
||||
EngineCloseHandle(thread);
|
||||
if(MaximumPolicy == UE_PAUSE_POLICY_AGGRESSIVE && requestPauseBreakIn())
|
||||
return true;
|
||||
EngineCancelPause();
|
||||
SetLastError(ERROR_BUSY);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto cip = GetContextDataEx(thread, UE_CIP);
|
||||
auto armed = cip && SetBPX(cip, UE_SINGLESHOOT, (LPVOID)&EngineCompletePause);
|
||||
if(armed)
|
||||
PostThreadMessageW(threadId, WM_NULL, 0, 0);
|
||||
auto resumed = ResumeThread(thread) != (DWORD)-1;
|
||||
EngineCloseHandle(thread);
|
||||
if(armed && resumed)
|
||||
return true;
|
||||
if(armed)
|
||||
DeleteBPX(cip);
|
||||
|
||||
if(MaximumPolicy == UE_PAUSE_POLICY_AGGRESSIVE && requestPauseBreakIn())
|
||||
return true;
|
||||
EngineCancelPause();
|
||||
return false;
|
||||
}
|
||||
|
||||
__declspec(dllexport) HANDLE TITCALL TitanCreateRemoteThread(HANDLE hProcess, LPTHREAD_START_ROUTINE start, LPVOID argument, DWORD creationFlags, LPDWORD threadId)
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@ GetSessionInfo
|
|||
ReplayGetPosition
|
||||
ReplayGetExtent
|
||||
ReplaySetPosition
|
||||
ReplayRun
|
||||
ReplayStep
|
||||
ReplayRunBack
|
||||
ReplayStepBack
|
||||
InitNativeDebug
|
||||
InitNativeDebugW
|
||||
InitDebugEx
|
||||
|
|
@ -406,7 +406,7 @@ TitanGetModulePathW
|
|||
TitanCloseHandle
|
||||
ProcessIsWow64
|
||||
TitanTerminateProcess
|
||||
TitanDebugBreakProcess
|
||||
RequestPause
|
||||
TitanCreateRemoteThread
|
||||
TitanSuspendThread
|
||||
TitanResumeThread
|
||||
|
|
|
|||
|
|
@ -171,8 +171,8 @@ __declspec(dllexport) bool TITCALL GetSessionInfo(TITAN_SESSION_INFO* SessionInf
|
|||
__declspec(dllexport) bool TITCALL ReplayGetPosition(TITAN_REPLAY_POSITION* Position);
|
||||
__declspec(dllexport) bool TITCALL ReplayGetExtent(TITAN_REPLAY_POSITION* First, TITAN_REPLAY_POSITION* Last);
|
||||
__declspec(dllexport) bool TITCALL ReplaySetPosition(const TITAN_REPLAY_POSITION* Position);
|
||||
__declspec(dllexport) bool TITCALL ReplayRun(bool Reverse);
|
||||
__declspec(dllexport) bool TITCALL ReplayStep(bool Reverse, bool StepOver, TITANCBSTEP StepCallBack);
|
||||
__declspec(dllexport) bool TITCALL ReplayRunBack();
|
||||
__declspec(dllexport) bool TITCALL ReplayStepBack(TITANCBSTEP StepCallBack);
|
||||
__declspec(dllexport) void* TITCALL InitNativeDebug(char* szFileName, char* szCommandLine, char* szCurrentFolder);
|
||||
__declspec(dllexport) void* TITCALL InitNativeDebugW(wchar_t* szFileName, wchar_t* szCommandLine, wchar_t* szCurrentFolder);
|
||||
__declspec(dllexport) void* TITCALL InitDebugEx(char* szFileName, char* szCommandLine, char* szCurrentFolder, LPVOID EntryCallBack);
|
||||
|
|
@ -372,7 +372,7 @@ __declspec(dllexport) bool TITCALL TitanGetModulePathW(HANDLE hProcess, ULONG_PT
|
|||
__declspec(dllexport) bool TITCALL TitanCloseHandle(HANDLE hEngineHandle);
|
||||
__declspec(dllexport) bool TITCALL ProcessIsWow64(HANDLE hProcess, PBOOL isWow64);
|
||||
__declspec(dllexport) bool TITCALL TitanTerminateProcess(HANDLE hProcess, DWORD exitCode);
|
||||
__declspec(dllexport) bool TITCALL TitanDebugBreakProcess(HANDLE hProcess);
|
||||
__declspec(dllexport) bool TITCALL RequestPause(TitanPausePolicy MaximumPolicy, TITANCBPAUSE PauseCallback);
|
||||
__declspec(dllexport) HANDLE TITCALL TitanCreateRemoteThread(HANDLE hProcess, LPTHREAD_START_ROUTINE start, LPVOID argument, DWORD creationFlags, LPDWORD threadId);
|
||||
__declspec(dllexport) DWORD TITCALL TitanSuspendThread(HANDLE hThread);
|
||||
__declspec(dllexport) DWORD TITCALL TitanResumeThread(HANDLE hThread);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <stdint.h>
|
||||
|
||||
typedef void(*TITANCBSTEP)();
|
||||
typedef void(*TITANCBPAUSE)();
|
||||
|
||||
#ifndef _Out_writes_opt_
|
||||
#define _Out_writes_opt_(x)
|
||||
|
|
@ -155,6 +156,8 @@ enum TitanSessionCapability : uint64_t
|
|||
UE_SESSION_CAP_NATIVE_HANDLES = 1ull << 12,
|
||||
UE_SESSION_CAP_EXCEPTION_CONTINUE = 1ull << 13,
|
||||
UE_SESSION_CAP_TIMELINE_STATE = 1ull << 14,
|
||||
UE_SESSION_CAP_PAUSE_EXECUTION = 1ull << 16,
|
||||
UE_SESSION_CAP_NAVIGABLE_PROCESS_EXIT = 1ull << 17,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
|
@ -559,6 +562,14 @@ typedef struct HOOK_ENTRY
|
|||
#define UE_ENGINE_MEMBP_ALT 11
|
||||
#define UE_ENGINE_DISABLE_ASLR 12
|
||||
#define UE_ENGINE_SAFE_STEP 13
|
||||
#define UE_ENGINE_WOW64_SINGLE_STEP_WORKAROUND 14
|
||||
|
||||
enum TitanPausePolicy
|
||||
{
|
||||
UE_PAUSE_POLICY_NONINVASIVE = 0,
|
||||
UE_PAUSE_POLICY_STANDARD = 1,
|
||||
UE_PAUSE_POLICY_AGGRESSIVE = 2,
|
||||
};
|
||||
|
||||
#define UE_OPTION_REMOVEALL 1
|
||||
#define UE_OPTION_DISABLEALL 2
|
||||
|
|
|
|||
Loading…
Reference in New Issue