This commit is contained in:
Yemdust 2026-08-05 00:06:02 +02:00 committed by GitHub
commit dbb674d34f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 283 additions and 111 deletions

View File

@ -43,7 +43,9 @@ CRITICAL_SECTION engineStepActiveCr;
// Workaround for a bug in the kernel with x64 emulation on ARM
DWORD ContextControlFlags = []
{
DWORD flags = CONTEXT_CONTROL;
// Preserve hardware-breakpoint state whenever a control-context update is
// written back. This is especially important across WoW64 mode switches.
DWORD flags = CONTEXT_CONTROL | CONTEXT_DEBUG_REGISTERS;
typedef BOOL(WINAPI * type_IsWow64Process2)(HANDLE, USHORT*, USHORT*);
auto p_IsWow64Process2 = (type_IsWow64Process2)GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "IsWow64Process2");
if(p_IsWow64Process2)

View File

@ -1,6 +1,9 @@
#include "stdafx.h"
#include "definitions.h"
#include "Global.Engine.Context.h"
#include "Global.Debugger.h"
#include "Global.Engine.h"
#include "Global.Handle.h"
#ifdef _WIN64
//https://stackoverflow.com/a/869597/1806760
@ -134,6 +137,51 @@ PGETXSTATEFEATURESMASK _GetXStateFeaturesMask = NULL;
LOCATEXSTATEFEATURE _LocateXStateFeature = NULL;
SETXSTATEFEATURESMASK _SetXStateFeaturesMask = NULL;
EngineContextMode EngineGetThreadContextMode(HANDLE hThread)
{
#ifndef _WIN64
(void)hThread;
return EngineContextMode::X86;
#else
if(hThread != NULL)
{
CONTEXT context = {};
context.ContextFlags = CONTEXT_CONTROL;
if(GetThreadContext(hThread, &context))
{
// Windows uses selector 0x23 for 32-bit compatibility mode and
// selector 0x33 for 64-bit user mode. Check every time because a
// WoW64 thread can transition between the two modes.
if(context.SegCs == 0x23)
return EngineContextMode::X86;
if(context.SegCs == 0x33)
return EngineContextMode::X64;
}
}
return EngineContextMode::X64;
#endif
}
EngineContextMode EngineGetCurrentContextMode()
{
#ifndef _WIN64
return EngineContextMode::X86;
#else
HANDLE hThread = EngineOpenThread(THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, false, DBGEvent.dwThreadId);
if(hThread == NULL)
return EngineContextMode::X64;
auto mode = EngineGetThreadContextMode(hThread);
EngineCloseHandle(hThread);
return mode;
#endif
}
SIZE_T EngineGetContextPointerSize(EngineContextMode mode)
{
return mode == EngineContextMode::X86 ? sizeof(DWORD) : sizeof(DWORD64);
}
bool _SetFullContextDataEx(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext, bool AVX_PRIORITY)
{
CONTEXT DBGContext;

View File

@ -24,6 +24,19 @@ extern PGETXSTATEFEATURESMASK _GetXStateFeaturesMask;
extern LOCATEXSTATEFEATURE _LocateXStateFeature;
extern SETXSTATEFEATURESMASK _SetXStateFeaturesMask;
enum class EngineContextMode
{
X86,
X64,
};
// Determine the mode in which a thread is currently executing. A WoW64 thread
// can switch between 32-bit and 64-bit code, so this deliberately uses CS from
// the live thread context instead of the process image architecture.
EngineContextMode EngineGetThreadContextMode(HANDLE hThread);
EngineContextMode EngineGetCurrentContextMode();
SIZE_T EngineGetContextPointerSize(EngineContextMode mode);
bool _SetFullContextDataEx(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext, bool AVX_PRIORITY);
bool _GetFullContextDataEx(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext, bool avx);
bool InitXState(void);

View File

@ -5,6 +5,7 @@
#include "Global.Threader.h"
#include "Global.Librarian.h"
#include "Global.Engine.h"
#include "Global.Engine.Context.h"
__declspec(dllexport) void TITCALL ForceClose()
{
@ -43,14 +44,15 @@ __declspec(dllexport) void TITCALL StepInto(LPVOID StepCallBack)
if(engineStepThreads.find(DBGEvent.dwThreadId) == engineStepThreads.end())
{
ULONG_PTR ueCurrentPosition = GetContextData(UE_CIP);
bool is32Bit = EngineGetCurrentContextMode() == EngineContextMode::X86;
unsigned char instr[16];
MemoryReadSafe(dbgProcessInformation.hProcess, (void*)ueCurrentPosition, instr, sizeof(instr), 0);
char* DisassembledString = (char*)StaticDisassembleEx(ueCurrentPosition, (LPVOID)instr);
char* DisassembledString = (char*)EngineStaticDisassembleEx(ueCurrentPosition, (LPVOID)instr, is32Bit);
if(strstr(DisassembledString, "PUSHF"))
StepOver(StepCallBack);
else if(strstr(DisassembledString, "POP SS") || strstr(DisassembledString, "MOV SS")) //prevent the 'PUSH SS', 'POP SS' step trick
{
ueCurrentPosition += StaticLengthDisassemble((void*)instr);
ueCurrentPosition += EngineStaticLengthDisassemble((void*)instr, is32Bit);
SetBPX(ueCurrentPosition, UE_BREAKPOINT_TYPE_INT3 + UE_SINGLESHOOT, StepCallBack);
}
else
@ -71,12 +73,13 @@ __declspec(dllexport) void TITCALL StepInto(LPVOID StepCallBack)
__declspec(dllexport) void TITCALL StepOver(LPVOID StepCallBack)
{
ULONG_PTR ueCurrentPosition = GetContextData(UE_CIP);
bool is32Bit = EngineGetCurrentContextMode() == EngineContextMode::X86;
unsigned char instr[16];
MemoryReadSafe(dbgProcessInformation.hProcess, (void*)ueCurrentPosition, instr, sizeof(instr), 0);
char* DisassembledString = (char*)StaticDisassembleEx(ueCurrentPosition, (LPVOID)instr);
char* DisassembledString = (char*)EngineStaticDisassembleEx(ueCurrentPosition, (LPVOID)instr, is32Bit);
if(strstr(DisassembledString, "CALL") || strstr(DisassembledString, "REP") || strstr(DisassembledString, "PUSHF"))
{
ueCurrentPosition += StaticLengthDisassemble((void*)instr);
ueCurrentPosition += EngineStaticLengthDisassemble((void*)instr, is32Bit);
SetBPX(ueCurrentPosition, UE_BREAKPOINT_TYPE_INT3 + UE_SINGLESHOOT, StepCallBack);
}
else

View File

@ -7,6 +7,7 @@
#include "Global.Threader.h"
#include "Global.Librarian.h"
#include "Global.TLS.h"
#include "Global.Engine.Context.h"
#include <unordered_map>
#include <unordered_set>
#include <functional>
@ -14,6 +15,25 @@
#define UE_MODULEx86 0x2000;
#define UE_MODULEx64 0x2000;
static char* DisassembleCurrentInstruction(ULONG_PTR address, void* data)
{
bool is32Bit = EngineGetCurrentContextMode() == EngineContextMode::X86;
return (char*)EngineStaticDisassembleEx(address, data, is32Bit);
}
static void ClearTrapFlagFromStack()
{
auto mode = EngineGetCurrentContextMode();
SIZE_T pointerSize = EngineGetContextPointerSize(mode);
void* csp = (void*)GetContextData(UE_CSP);
DWORD64 data = 0;
if(ReadProcessMemory(dbgProcessInformation.hProcess, csp, &data, pointerSize, nullptr))
{
data &= ~DWORD64(UE_TRAP_FLAG);
WriteProcessMemory(dbgProcessInformation.hProcess, csp, &data, pointerSize, nullptr);
}
}
static void engineStep()
{
EnterCriticalSection(&engineStepActiveCr);
@ -591,6 +611,7 @@ __declspec(dllexport) void TITCALL DebugLoop()
switch((LONG)DBGEvent.u.Exception.ExceptionRecord.ExceptionCode)
{
case STATUS_BREAKPOINT:
case STATUS_WX86_BREAKPOINT:
{
bool bFoundBreakPoint = false;
BreakPointDetail FoundBreakPoint;
@ -644,7 +665,7 @@ __declspec(dllexport) void TITCALL DebugLoop()
ULONG_PTR ueCurrentPosition = FoundBreakPoint.BreakPointAddress;
unsigned char instr[16];
MemoryReadSafe(dbgProcessInformation.hProcess, (void*)ueCurrentPosition, instr, sizeof(instr), 0);
char* DisassembledString = (char*)StaticDisassembleEx(ueCurrentPosition, (LPVOID)instr);
char* DisassembledString = DisassembleCurrentInstruction(ueCurrentPosition, (LPVOID)instr);
if(strstr(DisassembledString, "PUSHF"))
PushfBPX = true;
}
@ -736,6 +757,7 @@ __declspec(dllexport) void TITCALL DebugLoop()
break;
case STATUS_SINGLE_STEP:
case STATUS_WX86_SINGLE_STEP:
{
if(IsDbgReplyLaterSupported)
{
@ -753,11 +775,7 @@ __declspec(dllexport) void TITCALL DebugLoop()
if(PushfBPX) //remove trap flag from stack
{
PushfBPX = false;
void* csp = (void*)GetContextData(UE_CSP);
ULONG_PTR data = 0;
ReadProcessMemory(dbgProcessInformation.hProcess, csp, &data, sizeof(ULONG_PTR), 0);
data &= ~UE_TRAP_FLAG;
WriteProcessMemory(dbgProcessInformation.hProcess, csp, &data, sizeof(ULONG_PTR), 0);
ClearTrapFlagFromStack();
}
if(ResetBPX) //restore 'normal' breakpoint
{
@ -945,7 +963,7 @@ __declspec(dllexport) void TITCALL DebugLoop()
ULONG_PTR ueCurrentPosition = GetContextData(UE_CIP);
unsigned char instr[16];
MemoryReadSafe(dbgProcessInformation.hProcess, (void*)ueCurrentPosition, instr, sizeof(instr), 0);
char* DisassembledString = (char*)StaticDisassembleEx(ueCurrentPosition, (LPVOID)instr);
char* DisassembledString = DisassembleCurrentInstruction(ueCurrentPosition, (LPVOID)instr);
if(strstr(DisassembledString, "PUSHF"))
PushfBPX = true;
}
@ -1184,7 +1202,7 @@ __declspec(dllexport) void TITCALL DebugLoop()
ULONG_PTR ueCurrentPosition = GetContextData(UE_CIP);
unsigned char instr[16];
MemoryReadSafe(dbgProcessInformation.hProcess, (void*)ueCurrentPosition, instr, sizeof(instr), nullptr);
char* DisassembledString = (char*)StaticDisassembleEx(ueCurrentPosition, (LPVOID)instr);
char* DisassembledString = DisassembleCurrentInstruction(ueCurrentPosition, (LPVOID)instr);
if(strstr(DisassembledString, "PUSHF"))
PushfBPX = true;
}
@ -1270,7 +1288,7 @@ __declspec(dllexport) void TITCALL DebugLoop()
ULONG_PTR ueCurrentPosition = FoundBreakPoint.BreakPointAddress;
unsigned char instr[16];
MemoryReadSafe(dbgProcessInformation.hProcess, (void*)ueCurrentPosition, instr, sizeof(instr), 0);
char* DisassembledString = (char*)StaticDisassembleEx(ueCurrentPosition, (LPVOID)instr);
char* DisassembledString = DisassembleCurrentInstruction(ueCurrentPosition, (LPVOID)instr);
if(strstr(DisassembledString, "PUSHF"))
PushfBPX = true;
}

View File

@ -1,6 +1,7 @@
#include "stdafx.h"
#include "definitions.h"
#include "Global.Debugger.h"
#include "Global.Engine.Context.h"
static char szParameterString[512];
@ -51,6 +52,8 @@ __declspec(dllexport) ULONG_PTR TITCALL GetFunctionParameter(HANDLE hProcess, DW
DWORD StackReadSize = 512;
DWORD StringReadSize = 512;
bool ValueIsPointer = false;
auto mode = EngineGetCurrentContextMode();
SIZE_T pointerSize = EngineGetContextPointerSize(mode);
if(ParameterType == UE_PARAMETER_BYTE)
{
@ -94,81 +97,55 @@ __declspec(dllexport) ULONG_PTR TITCALL GetFunctionParameter(HANDLE hProcess, DW
{
StackSecondReadSize = 0;
}
StackReadSize = sizeof(ULONG_PTR);
StackReadSize = (DWORD)pointerSize;
}
if(FunctionType >= UE_FUNCTION_STDCALL && FunctionType <= UE_FUNCTION_CCALL_CALL && FunctionType != UE_FUNCTION_FASTCALL_RET)
if(FunctionType >= UE_FUNCTION_STDCALL && FunctionType <= UE_FUNCTION_FASTCALL_CALL && FunctionType != UE_FUNCTION_FASTCALL_RET)
{
StackReadAddress = (ULONG_PTR)GetContextData(UE_CSP);
if(FunctionType != UE_FUNCTION_FASTCALL_CALL)
{
StackReadAddress = StackReadAddress + (ParameterNumber * sizeof(ULONG_PTR));
StackReadAddress = StackReadAddress + (ParameterNumber * pointerSize);
if(FunctionType >= UE_FUNCTION_STDCALL_CALL)
{
StackReadAddress = StackReadAddress - sizeof(ULONG_PTR);
StackReadAddress = StackReadAddress - pointerSize;
}
}
else
{
if(ParameterNumber <= 4)
DWORD registerCount = mode == EngineContextMode::X86 ? 2 : 4;
if(ParameterNumber <= registerCount)
{
static const DWORD x86Registers[] = { UE_ECX, UE_EDX };
static const DWORD x64Registers[] = { UE_RCX, UE_RDX, UE_R8, UE_R9 };
DWORD registerIndex = mode == EngineContextMode::X86
? x86Registers[ParameterNumber - 1]
: x64Registers[ParameterNumber - 1];
ULONG_PTR registerValue = (ULONG_PTR)GetContextData(registerIndex);
if(!ValueIsPointer)
return registerValue;
StackReadAddress = registerValue;
}
else
{
SIZE_T shadowSpace = mode == EngineContextMode::X86 ? 0 : 0x20;
StackReadAddress += shadowSpace + ((ParameterNumber - registerCount) * pointerSize) - pointerSize;
}
}
SIZE_T initialReadSize = ValueIsPointer ? pointerSize : (StackReadSize < sizeof(StackReadBuffer) ? StackReadSize : sizeof(StackReadBuffer));
if(ReadProcessMemory(hProcess, (LPVOID)StackReadAddress, &StackReadBuffer, initialReadSize, &ueNumberOfBytesRW))
{
if(!ValueIsPointer)
{
if(ParameterNumber == 1)
{
return((ULONG_PTR)GetContextData(UE_RCX));
}
else if(ParameterNumber == 2)
{
return((ULONG_PTR)GetContextData(UE_RDX));
}
else if(ParameterNumber == 3)
{
return((ULONG_PTR)GetContextData(UE_R8));
}
else if(ParameterNumber == 4)
{
return((ULONG_PTR)GetContextData(UE_R9));
}
}
else
{
if(ParameterNumber == 1)
{
StackReadAddress = (ULONG_PTR)GetContextData(UE_RCX);
}
else if(ParameterNumber == 2)
{
StackReadAddress = (ULONG_PTR)GetContextData(UE_RDX);
}
else if(ParameterNumber == 3)
{
StackReadAddress = (ULONG_PTR)GetContextData(UE_R8);
}
else if(ParameterNumber == 4)
{
StackReadAddress = (ULONG_PTR)GetContextData(UE_R9);
}
}
}
else
{
StackReadAddress = StackReadAddress + 0x20 + ((ParameterNumber - 4) * sizeof(ULONG_PTR)) - sizeof(ULONG_PTR);
}
}
if(ReadProcessMemory(hProcess, (LPVOID)StackReadAddress, &StackReadBuffer, sizeof(ULONG_PTR), &ueNumberOfBytesRW))
{
if(!ValueIsPointer)
{
RtlMoveMemory((LPVOID)((ULONG_PTR)&StackFinalBuffer + sizeof(ULONG_PTR) - StackReadSize), (LPVOID)((ULONG_PTR)&StackReadBuffer + sizeof(ULONG_PTR) - StackReadSize), StackReadSize);
RtlMoveMemory(&StackFinalBuffer, &StackReadBuffer, StackReadSize);
}
else
{
StackReadAddress = StackReadBuffer;
if(StackSecondReadSize > NULL)
{
if(ReadProcessMemory(hProcess, (LPVOID)StackReadAddress, &StackReadBuffer, sizeof(ULONG_PTR), &ueNumberOfBytesRW))
if(ReadProcessMemory(hProcess, (LPVOID)StackReadAddress, &StackReadBuffer, StackSecondReadSize, &ueNumberOfBytesRW))
{
RtlMoveMemory((LPVOID)((ULONG_PTR)&StackFinalBuffer + sizeof(ULONG_PTR) - StackSecondReadSize), (LPVOID)((ULONG_PTR)&StackReadBuffer + sizeof(ULONG_PTR) - StackSecondReadSize), StackSecondReadSize);
RtlMoveMemory(&StackFinalBuffer, &StackReadBuffer, StackSecondReadSize);
}
else
{
@ -218,6 +195,7 @@ __declspec(dllexport) ULONG_PTR TITCALL GetJumpDestinationEx(HANDLE hProcess, UL
DWORD CurrentInstructionSize;
int ReadMemData = NULL;
BYTE ReadByteData = NULL;
bool is32Bit = EngineGetCurrentContextMode() == EngineContextMode::X86;
if(hProcess != NULL)
{
@ -227,7 +205,7 @@ __declspec(dllexport) ULONG_PTR TITCALL GetJumpDestinationEx(HANDLE hProcess, UL
if(ReadProcessMemory(hProcess, (LPVOID)InstructionAddress, ReadMemory, MAXIMUM_INSTRUCTION_SIZE, &ueNumberOfBytesRead))
{
CompareMemory = (PMEMORY_CMP_HANDLER)ReadMemory;
CurrentInstructionSize = StaticLengthDisassemble(ReadMemory);
CurrentInstructionSize = EngineStaticLengthDisassemble(ReadMemory, is32Bit);
if(CompareMemory->DataByte[0] == 0xE9 && CurrentInstructionSize == 5)
{
RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)ReadMemory + 1), 4);
@ -305,7 +283,7 @@ __declspec(dllexport) ULONG_PTR TITCALL GetJumpDestinationEx(HANDLE hProcess, UL
{
RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)ReadMemory + 2), 4);
TargetedAddress = ReadMemData;
if(sizeof(HANDLE) == 8)
if(!is32Bit)
{
TargetedAddress = TargetedAddress + InstructionAddress;
}
@ -314,7 +292,7 @@ __declspec(dllexport) ULONG_PTR TITCALL GetJumpDestinationEx(HANDLE hProcess, UL
{
RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)ReadMemory + 2), 4);
TargetedAddress = ReadMemData;
if(sizeof(HANDLE) == 8)
if(!is32Bit)
{
TargetedAddress = TargetedAddress + InstructionAddress;
}
@ -362,7 +340,7 @@ __declspec(dllexport) ULONG_PTR TITCALL GetJumpDestinationEx(HANDLE hProcess, UL
else
{
CompareMemory = (PMEMORY_CMP_HANDLER)InstructionAddress;
CurrentInstructionSize = StaticLengthDisassemble((LPVOID)InstructionAddress);
CurrentInstructionSize = EngineStaticLengthDisassemble((LPVOID)InstructionAddress, is32Bit);
if(CompareMemory->DataByte[0] == 0xE9 && CurrentInstructionSize == 5)
{
RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)InstructionAddress + 1), 4);
@ -440,7 +418,7 @@ __declspec(dllexport) ULONG_PTR TITCALL GetJumpDestinationEx(HANDLE hProcess, UL
{
RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)InstructionAddress + 2), 4);
TargetedAddress = ReadMemData;
if(sizeof(HANDLE) == 8)
if(!is32Bit)
{
TargetedAddress = TargetedAddress + InstructionAddress;
}
@ -449,7 +427,7 @@ __declspec(dllexport) ULONG_PTR TITCALL GetJumpDestinationEx(HANDLE hProcess, UL
{
RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)InstructionAddress + 2), 4);
TargetedAddress = ReadMemData;
if(sizeof(HANDLE) == 8)
if(!is32Bit)
{
TargetedAddress = TargetedAddress + InstructionAddress;
}
@ -530,7 +508,8 @@ __declspec(dllexport) bool TITCALL IsJumpGoingToExecuteEx(HANDLE hProcess, HANDL
{
ThreadEflags = (DWORD)RegFlags;
}
DisassembledString = (char*)DisassembleEx(hProcess, (LPVOID)ThreadCIP, true);
auto mode = hThread != NULL ? EngineGetThreadContextMode(hThread) : EngineGetCurrentContextMode();
DisassembledString = (char*)EngineDisassembleEx(hProcess, (LPVOID)ThreadCIP, true, mode == EngineContextMode::X86);
if(DisassembledString != NULL)
{
if(ThreadEflags & (1 << 0))

View File

@ -43,15 +43,12 @@ __declspec(dllexport) void* TITCALL InitDebug(char* szFileName, char* szCommandL
}
}
static bool ProcessRelocations(char* imageCopy, ULONG_PTR imageSize, ULONG_PTR newImageBase, ULONG_PTR & oldImageBase)
template<typename NtHeaders>
static bool ProcessRelocationsForArchitecture(char* imageCopy, NtHeaders* pnth, ULONG_PTR newImageBase, ULONG_PTR & oldImageBase)
{
auto pnth = RtlImageNtHeader(imageCopy);
if(pnth == nullptr)
return false;
// Put the new base in the header
oldImageBase = pnth->OptionalHeader.ImageBase;
pnth->OptionalHeader.ImageBase = newImageBase;
// Put the new base in the header using the image's pointer width.
oldImageBase = ULONG_PTR(pnth->OptionalHeader.ImageBase);
pnth->OptionalHeader.ImageBase = decltype(pnth->OptionalHeader.ImageBase)(newImageBase);
// Nothing to do if relocations are stripped
if(pnth->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
@ -63,7 +60,7 @@ static bool ProcessRelocations(char* imageCopy, ULONG_PTR imageSize, ULONG_PTR n
return true;
// Process the relocations
auto delta = newImageBase - oldImageBase;
auto delta = LONG_PTR(newImageBase) - LONG_PTR(oldImageBase);
auto relocationItr = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)imageCopy + relocDir.VirtualAddress);
auto relocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)relocationItr + relocDir.Size);
@ -80,6 +77,20 @@ static bool ProcessRelocations(char* imageCopy, ULONG_PTR imageSize, ULONG_PTR n
return true;
}
static bool ProcessRelocations(char* imageCopy, ULONG_PTR newImageBase, ULONG_PTR & oldImageBase)
{
auto pnth = RtlImageNtHeader(imageCopy);
if(pnth == nullptr)
return false;
auto magic = ((PIMAGE_NT_HEADERS32)pnth)->OptionalHeader.Magic;
if(magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
return ProcessRelocationsForArchitecture(imageCopy, (PIMAGE_NT_HEADERS32)pnth, newImageBase, oldImageBase);
if(magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
return ProcessRelocationsForArchitecture(imageCopy, (PIMAGE_NT_HEADERS64)pnth, newImageBase, oldImageBase);
return false;
}
static bool RelocateImage(HANDLE hProcess, PVOID imageBase, SIZE_T imageSize)
{
constexpr auto pageSize = 0x1000;
@ -100,7 +111,7 @@ static bool RelocateImage(HANDLE hProcess, PVOID imageBase, SIZE_T imageSize)
// perform the actual relocations
ULONG_PTR oldImageBase = 0;
auto success = ProcessRelocations(imageCopy, imageSize, (ULONG_PTR)imageBase, oldImageBase);
auto success = ProcessRelocations(imageCopy, (ULONG_PTR)imageBase, oldImageBase);
// write back the pages
auto memWrite = [hProcess](PVOID ptr, LPCVOID data, SIZE_T size)
@ -165,28 +176,45 @@ static bool HollowProcessWithoutASLR(const wchar_t* szFileName, PROCESS_INFORMAT
auto hMapping = CreateFileMappingW(hFile, nullptr, SEC_IMAGE | PAGE_READONLY, 0, 0, nullptr);
if(hMapping)
{
CONTEXT ctx;
CONTEXT ctx = {};
ctx.ContextFlags = CONTEXT_ALL;
if(GetThreadContext(pi.hThread, &ctx))
{
PVOID imageBase;
// TODO: support wow64 processes
bool isWow64 = false;
ULONG_PTR pebAddress = 0;
SIZE_T imageBaseOffset = 0;
SIZE_T imageBaseSize = 0;
#ifdef _WIN64
auto & pebRegister = ctx.Rdx;
auto & entryPointRegister = ctx.Rcx;
#else
auto & pebRegister = ctx.Ebx;
auto & entryPointRegister = ctx.Eax;
#endif // _WIN64
if(ReadProcessMemory(pi.hProcess, (char*)pebRegister + offsetof(PEB, ImageBaseAddress), &imageBase, sizeof(PVOID), nullptr))
ULONG returnLength = 0;
if(NT_SUCCESS(NtQueryInformationProcess(pi.hProcess, ProcessWow64Information, &pebAddress, sizeof(pebAddress), &returnLength)) && pebAddress != 0)
{
if(ULONG_PTR(imageBase) == DebugModuleImageBase)
isWow64 = true;
imageBaseOffset = offsetof(PEB32, ImageBaseAddress);
imageBaseSize = sizeof(DWORD);
}
else
{
pebAddress = ctx.Rdx;
imageBaseOffset = offsetof(PEB64, ImageBaseAddress);
imageBaseSize = sizeof(DWORD64);
}
#else
pebAddress = ctx.Ebx;
imageBaseOffset = offsetof(PEB32, ImageBaseAddress);
imageBaseSize = sizeof(DWORD);
#endif // _WIN64
ULONG_PTR imageBaseValue = 0;
if(ReadProcessMemory(pi.hProcess, (char*)pebAddress + imageBaseOffset, &imageBaseValue, imageBaseSize, nullptr))
{
if(imageBaseValue == DebugModuleImageBase)
{
// Already at the right base
success = true;
}
else
{
auto imageBase = PVOID(imageBaseValue);
auto status = NtUnmapViewOfSection(pi.hProcess, imageBase);
if(status == STATUS_SUCCESS)
{
@ -201,23 +229,60 @@ static bool HollowProcessWithoutASLR(const wchar_t* szFileName, PROCESS_INFORMAT
}
if(status == STATUS_SUCCESS || status == STATUS_IMAGE_NOT_AT_BASE)
{
auto pebOk = WriteProcessMemory(pi.hProcess, (char*)pebRegister + offsetof(PEB, ImageBaseAddress), &imageBase, sizeof(PVOID), nullptr);
imageBaseValue = ULONG_PTR(imageBase);
auto pebOk = WriteProcessMemory(pi.hProcess, (char*)pebAddress + imageBaseOffset, &imageBaseValue, imageBaseSize, nullptr);
#ifdef _WIN64
if(pebOk && isWow64)
{
PROCESS_BASIC_INFORMATION processInfo = {};
if(NT_SUCCESS(NtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &processInfo, sizeof(processInfo), &returnLength)))
{
DWORD64 imageBase64 = imageBaseValue;
pebOk = WriteProcessMemory(pi.hProcess, (char*)processInfo.PebBaseAddress + offsetof(PEB64, ImageBaseAddress), &imageBase64, sizeof(imageBase64), nullptr);
}
else
{
pebOk = false;
}
}
#else
if(pebOk && IsThisProcessWow64())
{
auto peb64 = GetPEBLocation64(pi.hProcess);
DWORD64 imageBase64 = imageBaseValue;
pebOk = peb64 != nullptr && WriteProcessMemory(pi.hProcess, (char*)peb64 + offsetof(PEB64, ImageBaseAddress), &imageBase64, sizeof(imageBase64), nullptr);
}
#endif // _WIN64
auto relocatedOk = RelocateImage(pi.hProcess, imageBase, viewSize);
if(pebOk && relocatedOk)
{
auto expectedBase = DebugModuleImageBase == ULONG_PTR(imageBase);
DebugModuleImageBase = ULONG_PTR(imageBase);
entryPointRegister = DebugModuleImageBase + DebugModuleEntryPoint;
if(SetThreadContext(pi.hThread, &ctx))
auto expectedBase = DebugModuleImageBase == imageBaseValue;
DebugModuleImageBase = imageBaseValue;
auto entryPoint = DebugModuleImageBase + DebugModuleEntryPoint;
bool contextOk = false;
#ifdef _WIN64
if(isWow64)
{
success = expectedBase;
#ifndef _WIN64
// For Wow64 processes, also adjust the 64-bit PEB
if(IsThisProcessWow64() && !WriteProcessMemory(pi.hProcess, (char*)pebRegister - 0x1000 + 0x10, &imageBase, sizeof(PVOID), nullptr))
success = false;
#endif // _WIN64
WOW64_CONTEXT ctx32 = {};
ctx32.ContextFlags = WOW64_CONTEXT_INTEGER;
if(Wow64GetThreadContext(pi.hThread, &ctx32))
{
ctx32.Eax = DWORD(entryPoint);
contextOk = Wow64SetThreadContext(pi.hThread, &ctx32) != FALSE;
}
}
else
{
ctx.Rcx = entryPoint;
contextOk = SetThreadContext(pi.hThread, &ctx) != FALSE;
}
#else
ctx.Eax = DWORD(entryPoint);
contextOk = SetThreadContext(pi.hThread, &ctx) != FALSE;
#endif // _WIN64
if(contextOk)
success = expectedBase;
}
}
}
}

View File

@ -1,15 +1,31 @@
#include "stdafx.h"
#include "definitions.h"
#include "Global.Debugger.h"
#include "Global.Engine.Context.h"
#include "distorm.h"
static char engineDisassembledInstruction[128];
#if !defined(_WIN64)
_DecodeType DecodingType = Decode32Bits;
static bool DefaultIs32Bit()
{
#ifndef _WIN64
return true;
#else
_DecodeType DecodingType = Decode64Bits;
return false;
#endif
}
static _DecodeType GetDecodingType(bool Is32Bit)
{
return Is32Bit ? Decode32Bits : Decode64Bits;
}
static bool GetProcessMode(HANDLE hProcess)
{
if(hProcess != NULL && hProcess == dbgProcessInformation.hProcess && DBGEvent.dwThreadId != 0)
return EngineGetCurrentContextMode() == EngineContextMode::X86;
return DefaultIs32Bit();
}
SIZE_T IsBadReadPtrRemote(HANDLE hProcess, const VOID* lp, SIZE_T length)
@ -62,7 +78,7 @@ SIZE_T IsBadReadPtrRemote(HANDLE hProcess, const VOID* lp, SIZE_T length)
return 0;
}
__declspec(dllexport) void* TITCALL StaticDisassembleEx(ULONG_PTR DisassmStart, LPVOID DisassmAddress)
void* EngineStaticDisassembleEx(ULONG_PTR DisassmStart, LPVOID DisassmAddress, bool Is32Bit)
{
_DecodedInst engineDecodedInstructions[1];
unsigned int DecodedInstructionsCount = 0;
@ -70,7 +86,7 @@ __declspec(dllexport) void* TITCALL StaticDisassembleEx(ULONG_PTR DisassmStart,
int MaxDisassmSize = MAXIMUM_INSTRUCTION_SIZE; // (int)IsBadReadPtrRemote(GetCurrentProcess(), DisassmAddress, MAXIMUM_INSTRUCTION_SIZE);
if(MaxDisassmSize)
{
if(distorm_decode((ULONG_PTR)DisassmStart, (const unsigned char*)DisassmAddress, MaxDisassmSize, DecodingType, engineDecodedInstructions, _countof(engineDecodedInstructions), &DecodedInstructionsCount) != DECRES_INPUTERR)
if(distorm_decode((ULONG_PTR)DisassmStart, (const unsigned char*)DisassmAddress, MaxDisassmSize, GetDecodingType(Is32Bit), engineDecodedInstructions, _countof(engineDecodedInstructions), &DecodedInstructionsCount) != DECRES_INPUTERR)
{
RtlZeroMemory(engineDisassembledInstruction, sizeof(engineDisassembledInstruction));
@ -87,12 +103,17 @@ __declspec(dllexport) void* TITCALL StaticDisassembleEx(ULONG_PTR DisassmStart,
return 0;
}
__declspec(dllexport) void* TITCALL StaticDisassembleEx(ULONG_PTR DisassmStart, LPVOID DisassmAddress)
{
return EngineStaticDisassembleEx(DisassmStart, DisassmAddress, DefaultIs32Bit());
}
__declspec(dllexport) void* TITCALL StaticDisassemble(LPVOID DisassmAddress)
{
return StaticDisassembleEx((ULONG_PTR)DisassmAddress, DisassmAddress);
}
__declspec(dllexport) void* TITCALL DisassembleEx(HANDLE hProcess, LPVOID DisassmAddress, bool ReturnInstructionType)
void* EngineDisassembleEx(HANDLE hProcess, LPVOID DisassmAddress, bool ReturnInstructionType, bool Is32Bit)
{
_DecodedInst engineDecodedInstructions[1];
unsigned int DecodedInstructionsCount = 0;
@ -107,7 +128,7 @@ __declspec(dllexport) void* TITCALL DisassembleEx(HANDLE hProcess, LPVOID Disass
BOOL rpm = MemoryReadSafe(hProcess, DisassmAddress, readBuffer, MaxDisassmSize, 0);
if(rpm)
{
if(distorm_decode((ULONG_PTR)DisassmAddress, readBuffer, MaxDisassmSize, DecodingType, engineDecodedInstructions, _countof(engineDecodedInstructions), &DecodedInstructionsCount) != DECRES_INPUTERR)
if(distorm_decode((ULONG_PTR)DisassmAddress, readBuffer, MaxDisassmSize, GetDecodingType(Is32Bit), engineDecodedInstructions, _countof(engineDecodedInstructions), &DecodedInstructionsCount) != DECRES_INPUTERR)
{
RtlZeroMemory(engineDisassembledInstruction, sizeof(engineDisassembledInstruction));
@ -130,17 +151,27 @@ __declspec(dllexport) void* TITCALL DisassembleEx(HANDLE hProcess, LPVOID Disass
return 0;
}
__declspec(dllexport) void* TITCALL DisassembleEx(HANDLE hProcess, LPVOID DisassmAddress, bool ReturnInstructionType)
{
return EngineDisassembleEx(hProcess, DisassmAddress, ReturnInstructionType, GetProcessMode(hProcess));
}
__declspec(dllexport) void* TITCALL Disassemble(LPVOID DisassmAddress)
{
return(DisassembleEx(dbgProcessInformation.hProcess, DisassmAddress, false));
return DisassembleEx(dbgProcessInformation.hProcess, DisassmAddress, false);
}
long EngineStaticLengthDisassemble(LPVOID DisassmAddress, bool Is32Bit)
{
return EngineLengthDisassembleEx(GetCurrentProcess(), DisassmAddress, Is32Bit);
}
__declspec(dllexport) long TITCALL StaticLengthDisassemble(LPVOID DisassmAddress)
{
return LengthDisassembleEx(GetCurrentProcess(), DisassmAddress);
return EngineStaticLengthDisassemble(DisassmAddress, DefaultIs32Bit());
}
__declspec(dllexport) long TITCALL LengthDisassembleEx(HANDLE hProcess, LPVOID DisassmAddress)
long EngineLengthDisassembleEx(HANDLE hProcess, LPVOID DisassmAddress, bool Is32Bit)
{
unsigned int DecodedInstructionsCount = 0;
_CodeInfo decomposerCi = {0};
@ -155,7 +186,7 @@ __declspec(dllexport) long TITCALL LengthDisassembleEx(HANDLE hProcess, LPVOID D
{
decomposerCi.code = readBuffer;
decomposerCi.codeLen = MaxDisassmSize;
decomposerCi.dt = DecodingType;
decomposerCi.dt = GetDecodingType(Is32Bit);
decomposerCi.codeOffset = (LONG_PTR)DisassmAddress;
if(distorm_decompose(&decomposerCi, decomposerResult, _countof(decomposerResult), &DecodedInstructionsCount) != DECRES_INPUTERR)
@ -171,6 +202,11 @@ __declspec(dllexport) long TITCALL LengthDisassembleEx(HANDLE hProcess, LPVOID D
return -1;
}
__declspec(dllexport) long TITCALL LengthDisassembleEx(HANDLE hProcess, LPVOID DisassmAddress)
{
return EngineLengthDisassembleEx(hProcess, DisassmAddress, GetProcessMode(hProcess));
}
__declspec(dllexport) long TITCALL LengthDisassemble(LPVOID DisassmAddress)
{
return LengthDisassembleEx(dbgProcessInformation.hProcess, DisassmAddress);

View File

@ -158,6 +158,14 @@ __declspec(dllexport) void* TITCALL Disassemble(LPVOID DisassmAddress);
__declspec(dllexport) long TITCALL StaticLengthDisassemble(LPVOID DisassmAddress);
__declspec(dllexport) long TITCALL LengthDisassembleEx(HANDLE hProcess, LPVOID DisassmAddress);
__declspec(dllexport) long TITCALL LengthDisassemble(LPVOID DisassmAddress);
// Internal variants used when the current thread mode is known. The exported
// static APIs keep their historical build-architecture behavior.
void* EngineStaticDisassembleEx(ULONG_PTR DisassmStart, LPVOID DisassmAddress, bool Is32Bit);
void* EngineDisassembleEx(HANDLE hProcess, LPVOID DisassmAddress, bool ReturnInstructionType, bool Is32Bit);
long EngineStaticLengthDisassemble(LPVOID DisassmAddress, bool Is32Bit);
long EngineLengthDisassembleEx(HANDLE hProcess, LPVOID DisassmAddress, bool Is32Bit);
__declspec(dllexport) void* TITCALL InitDebug(char* szFileName, char* szCommandLine, char* szCurrentFolder);
__declspec(dllexport) void* TITCALL InitDebugW(wchar_t* szFileName, wchar_t* szCommandLine, wchar_t* szCurrentFolder);
__declspec(dllexport) void* TITCALL InitNativeDebug(char* szFileName, char* szCommandLine, char* szCurrentFolder);