Implement all TitanEngine functionality (finally)

This commit is contained in:
Duncan Ogilvie 2018-10-08 20:22:23 +02:00
parent 642e8956d3
commit 2ee4dc0f83
31 changed files with 1120 additions and 699 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ Release/
docs/
.vs/
*.VC.db
*.aps

View File

@ -1,4 +1,5 @@
#include "Debugger.h"
#include "Debugger.Thread.Registers.h"
namespace GleeBug
{
@ -48,7 +49,7 @@ namespace GleeBug
mContinueStatus = DBG_CONTINUE;
//set back the instruction pointer
mRegisters->Gip = info.address;
Registers(mThread->hThread, CONTEXT_CONTROL).Gip = info.address;
//restore the original breakpoint byte and do an internal step
mProcess->MemWriteUnsafe(info.address, info.internal.software.oldbytes, info.internal.software.size);
@ -107,27 +108,28 @@ namespace GleeBug
void Debugger::exceptionHardwareBreakpoint(ptr exceptionAddress)
{
//determine the hardware breakpoint triggered
ptr dr6 = mRegisters->Dr6();
Registers registers(mThread->hThread, CONTEXT_DEBUG_REGISTERS);
ptr dr6 = registers.Dr6();
HardwareSlot breakpointSlot;
ptr breakpointAddress;
if (exceptionAddress == mRegisters->Dr0() || dr6 & 0x1)
if (exceptionAddress == registers.Dr0() || dr6 & 0x1)
{
breakpointAddress = mRegisters->Dr0();
breakpointAddress = registers.Dr0();
breakpointSlot = HardwareSlot::Dr0;
}
else if (exceptionAddress == mRegisters->Dr1() || dr6 & 0x2)
else if (exceptionAddress == registers.Dr1() || dr6 & 0x2)
{
breakpointAddress = mRegisters->Dr1();
breakpointAddress = registers.Dr1();
breakpointSlot = HardwareSlot::Dr1;
}
else if (exceptionAddress == mRegisters->Dr2() || dr6 & 0x4)
else if (exceptionAddress == registers.Dr2() || dr6 & 0x4)
{
breakpointAddress = mRegisters->Dr2();
breakpointAddress = registers.Dr2();
breakpointSlot = HardwareSlot::Dr2;
}
else if (exceptionAddress == mRegisters->Dr3() || dr6 & 0x8)
else if (exceptionAddress == registers.Dr3() || dr6 & 0x8)
{
breakpointAddress = mRegisters->Dr3();
breakpointAddress = registers.Dr3();
breakpointSlot = HardwareSlot::Dr3;
}
else
@ -192,7 +194,7 @@ namespace GleeBug
//We restore the protection
if (!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.OldProtect))
{
sprintf_s(error, "MemProtect failed on 0x%p", foundPage->first);
sprintf_s(error, "MemProtect failed on 0x%p", (void*)foundPage->first);
cbInternalError(error);
}
@ -225,7 +227,7 @@ namespace GleeBug
auto foundInfo = mProcess->breakpoints.find({ BreakpointType::Memory, foundRange->first });
if (foundInfo == mProcess->breakpoints.end())
{
sprintf_s(error, "inconsistent memory breakpoint at 0x%p", exceptionAddress);
sprintf_s(error, "inconsistent memory breakpoint at 0x%p", (void*)exceptionAddress);
cbInternalError(error);
return;
}
@ -243,7 +245,7 @@ namespace GleeBug
if (bpxPage == mProcess->memoryBreakpointPages.end())
{
sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", exceptionAddress & ~(PAGE_SIZE - 1));
sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", (void*)(exceptionAddress & ~(PAGE_SIZE - 1)));
cbInternalError(error);
return;
}
@ -260,7 +262,7 @@ namespace GleeBug
//We restore the protection
if (!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
{
sprintf_s(error, "MemProtect failed on 0x%p", pageAddr);
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
cbInternalError(error);
}
@ -323,7 +325,7 @@ namespace GleeBug
//FIXED:
if (!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
{
sprintf_s(error, "MemProtect failed on 0x%p", pageAddr);
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
cbInternalError(error);
}
//Pass info as well
@ -384,7 +386,7 @@ namespace GleeBug
//We restore the protection
if (!mProcess->MemProtect(foundPage->first, PAGE_SIZE, foundPage->second.OldProtect))
{
sprintf_s(error, "MemProtect failed on 0x%p", foundPage->first);
sprintf_s(error, "MemProtect failed on 0x%p", (void*)foundPage->first);
cbInternalError(error);
}
@ -417,7 +419,7 @@ namespace GleeBug
auto foundInfo = mProcess->breakpoints.find({ BreakpointType::Memory, foundRange->first });
if (foundInfo == mProcess->breakpoints.end())
{
sprintf_s(error, "inconsistent memory breakpoint at 0x%p", exceptionAddress);
sprintf_s(error, "inconsistent memory breakpoint at 0x%p", (void*)exceptionAddress);
cbInternalError(error);
return;
}
@ -435,7 +437,7 @@ namespace GleeBug
if (bpxPage == mProcess->memoryBreakpointPages.end())
{
sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", exceptionAddress & ~(PAGE_SIZE - 1));
sprintf_s(error, "Process::memoryBreakPointPages data structure is incosistent, should dump page at 0x%p", (void*)(exceptionAddress & ~(PAGE_SIZE - 1)));
cbInternalError(error);
return;
}
@ -480,7 +482,7 @@ namespace GleeBug
//FIXED:
if (!mProcess->MemProtect(pageAddr, PAGE_SIZE, pageProperties.OldProtect))
{
sprintf_s(error, "MemProtect failed on 0x%p", pageAddr);
sprintf_s(error, "MemProtect failed on 0x%p", (void*)pageAddr);
cbInternalError(error);
}
//Pass info as well

View File

@ -29,11 +29,6 @@ namespace GleeBug
createProcess.lpThreadLocalBase,
createProcess.lpStartAddress) });
mThread = mProcess->thread = mProcess->threads.find(mDebugEvent.dwThreadId)->second.get();
mRegisters = &mThread->registers;
//read thread context from main thread
if (!mThread->RegReadContext())
cbInternalError("Thread::RegReadContext() failed!");
//call the debug event callback
cbCreateProcessEvent(createProcess, *mProcess);
@ -58,6 +53,5 @@ namespace GleeBug
//set the current process
mProcess = nullptr;
mThread = nullptr;
mRegisters = nullptr;
}
};

View File

@ -13,9 +13,6 @@ namespace GleeBug
//set the current thread
mThread = mProcess->thread = mProcess->threads.find(mDebugEvent.dwThreadId)->second.get();
mRegisters = &mThread->registers;
if (!mThread->RegReadContext())
cbInternalError("Thread::RegReadContext() failed!");
//call the debug event callback
cbCreateThreadEvent(createThread, *mThread);
@ -31,6 +28,5 @@ namespace GleeBug
//set the current thread
mThread = mProcess->thread = nullptr;
mRegisters = nullptr;
}
};

View File

@ -1,4 +1,5 @@
#include "Debugger.h"
#include "Debugger.Thread.Registers.h"
namespace GleeBug
{
@ -43,17 +44,14 @@ namespace GleeBug
if (threadFound != mProcess->threads.end())
{
mThread = mProcess->thread = threadFound->second.get();
mRegisters = &mThread->registers;
}
else
{
mThread = mProcess->thread = nullptr;
mRegisters = nullptr;
}
}
else
{
mRegisters = nullptr;
mThread = nullptr;
if (mProcess)
{
@ -62,10 +60,6 @@ namespace GleeBug
}
}
//read register contexts
if(mProcess && !mProcess->RegReadContext())
cbInternalError("Process::RegReadContext() failed!");
//call the pre debug event callback
cbPreDebugEvent(mDebugEvent);
@ -119,13 +113,9 @@ namespace GleeBug
if (mDetach && mThread)
{
if (mThread->isInternalStepping || mThread->isSingleStepping)
mThread->registers.TrapFlag = false;
Registers(mThread->hThread, CONTEXT_CONTROL).TrapFlag = false;
}
//write register contexts
if(mProcess && !mProcess->RegWriteContext())
cbInternalError("Process::RegWriteContext() failed!");
//continue the debug event
if (!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, mContinueStatus))
break;

View File

@ -1,4 +1,5 @@
#include "Debugger.Process.h"
#include "Debugger.Thread.Registers.h"
#define ZYDIS_EXPORTS
#define ZYDIS_ENABLE_FEATURE_IMPLICITLY_USED_REGISTERS
@ -22,7 +23,7 @@ namespace GleeBug
void Process::StepOver(const StepCallback & cbStep)
{
auto gip = thread->registers.Gip();
auto gip = Registers(thread->hThread, CONTEXT_CONTROL).Gip();
unsigned char data[16];
if (MemReadSafe(gip, data, sizeof(data)))
{

View File

@ -396,25 +396,6 @@ namespace GleeBug
static_cast<void>(static_cast<Debugger*>(debugger));
StepOver(std::bind(callback, debugger));
}
bool RegReadContext()
{
//TODO: lazily retrieve the context
auto result = true;
for(auto & thread : this->threads)
if(!thread.second->RegReadContext())
result = false;
return result;
}
bool RegWriteContext()
{
auto result = true;
for(auto & thread : this->threads)
if(!thread.second->RegWriteContext())
result = false;
return result;
}
};
};

View File

@ -1,4 +1,5 @@
#include "Debugger.Thread.h"
#include "Debugger.Thread.Registers.h"
#define BITSET(a,x) (a|=1<<x)
#define BITCLEAR(a,x) (a&=~(1<<x))
@ -186,6 +187,8 @@ namespace GleeBug
if ((address % int(size) != 0))
return false;
Registers registers(hThread, CONTEXT_DEBUG_REGISTERS);
//set the address register
switch (slot)
{
@ -218,6 +221,8 @@ namespace GleeBug
bool Thread::DeleteHardwareBreakpoint(HardwareSlot slot)
{
Registers registers(hThread, CONTEXT_DEBUG_REGISTERS);
//zero the address register
switch (slot)
{

View File

@ -56,8 +56,6 @@ namespace GleeBug
{
ptr Registers::Get(R reg)
{
handleLazyContext();
switch (reg)
{
case R::DR0:
@ -260,8 +258,6 @@ namespace GleeBug
void Registers::Set(R reg, ptr value)
{
handleLazyContext();
switch (reg)
{
case R::DR0:
@ -530,22 +526,22 @@ namespace GleeBug
break;
case R::GS:
mContext.SegGs = value;
mContext.SegGs = (WORD)value;
break;
case R::FS:
mContext.SegFs = value;
mContext.SegFs = (WORD)value;
break;
case R::ES:
mContext.SegEs = value;
mContext.SegEs = (WORD)value;
break;
case R::DS:
mContext.SegDs = value;
mContext.SegDs = (WORD)value;
break;
case R::CS:
mContext.SegCs = value;
mContext.SegCs = (WORD)value;
break;
case R::SS:
mContext.SegSs = value;
mContext.SegSs = (WORD)value;
break;
default:
@ -555,15 +551,11 @@ namespace GleeBug
bool Registers::GetFlag(F flag)
{
handleLazyContext();
return (mContext.EFlags & ptr(flag)) == ptr(flag);
}
void Registers::SetFlag(F flag, bool set)
{
handleLazyContext();
if (set)
mContext.EFlags |= ptr(flag);
else
@ -572,8 +564,6 @@ namespace GleeBug
void* Registers::getPtr(R reg)
{
handleLazyContext();
switch (reg)
{
case R::DR0:

View File

@ -8,6 +8,8 @@
*/
enum class R
{
Invalid,
DR0,
DR1,
DR2,

View File

@ -2,7 +2,7 @@
namespace GleeBug
{
Registers::Registers() :
Registers::Registers(HANDLE hThread, DWORD ContextFlags) :
Dr0(this),
Dr1(this),
Dr2(this),
@ -106,54 +106,27 @@ namespace GleeBug
TrapFlag(this),
ResumeFlag(this)
{
memset(&this->mContext, 0, sizeof(CONTEXT));
InitializeCriticalSection(&mCr);
memset(&mContext, 0, sizeof(CONTEXT));
mContext.ContextFlags = ContextFlags;
if (!!GetThreadContext(hThread, &mContext))
{
this->hThread = hThread;
memcpy(&mOldContext, &mContext, sizeof(CONTEXT));
}
else
{
this->hThread = nullptr;
}
}
LockedPtr<CONTEXT> Registers::GetContext()
Registers::~Registers()
{
handleLazyContext();
return LockedPtr<CONTEXT>(&mCr, &mContext);
if (hThread && memcmp(&mContext, &mOldContext, sizeof(CONTEXT)) != 0)
SetThreadContext(hThread, &mContext);
}
/*void Registers::SetContext(const CONTEXT & context)
PCONTEXT Registers::GetContext()
{
handleLazyContext();
this->mContext = context;
}*/
void Registers::setContextLazy(CONTEXT* oldContext, HANDLE hThread)
{
this->mLazyOldContext = oldContext;
this->mLazyThread = hThread;
this->mLazySet = true;
}
bool Registers::handleLazyContext()
{
ScopedCriticalSection lock(&mCr);
if(!this->mLazySet)
return true;
if(!this->mLazyOldContext || !this->mLazyThread) //assert
__debugbreak();
auto oldContext = this->mLazyOldContext;
auto lazyThread = this->mLazyThread;
this->mLazyOldContext = nullptr;
this->mLazyThread = nullptr;
this->mLazySet = false;
//TODO: handle failure of GetThreadContext
auto result = false;
if(GetThreadContext(lazyThread, oldContext))
{
this->mContext = *oldContext;
result = true;
}
return result;
return &mContext;
}
};

View File

@ -5,63 +5,6 @@
namespace GleeBug
{
class ScopedCriticalSection
{
PCRITICAL_SECTION cr;
public:
ScopedCriticalSection(PCRITICAL_SECTION cr)
: cr(cr)
{
EnterCriticalSection(cr);
}
~ScopedCriticalSection()
{
LeaveCriticalSection(cr);
}
};
template<class T>
class LockedPtr
{
PCRITICAL_SECTION locker;
T* ptr;
public:
explicit LockedPtr(PCRITICAL_SECTION locker, T* ptr)
: locker(locker), ptr(ptr)
{
EnterCriticalSection(locker);
}
~LockedPtr()
{
LeaveCriticalSection(locker);
}
LockedPtr(const LockedPtr<T> &) = delete;
LockedPtr<T> &operator=(const LockedPtr<T> &) = delete;
LockedPtr(LockedPtr<T> && other)
: locker(other.locker), ptr(other.ptr)
{
other.locker = nullptr;
other.ptr = nullptr;
}
/*operator T*() const
{
return ptr;
}*/
T* operator->() const
{
return ptr;
}
};
/**
\brief Thread register context.
*/
@ -71,15 +14,10 @@ namespace GleeBug
friend class Thread;
public:
/**
\brief Default constructor.
*/
Registers();
/**
\brief Copy constructor.
*/
Registers(HANDLE hThread, DWORD ContextFlags = CONTEXT_ALL);
~Registers();
Registers(const Registers &) = delete;
Registers(const Registers &&) = delete;
#include "Debugger.Thread.Registers.Register.h"
@ -219,34 +157,12 @@ namespace GleeBug
\brief Gets a pointer to the context object.
\return This function will never return a nullptr.
*/
LockedPtr<CONTEXT> GetContext();
/**
\brief Sets the CONTEXT.
\param context The context to set.
*/
//void SetContext(const CONTEXT & context);
PCONTEXT GetContext();
private:
HANDLE hThread;
CONTEXT mContext;
CRITICAL_SECTION mCr;
LPCONTEXT mLazyOldContext = nullptr;
HANDLE mLazyThread = nullptr;
bool mLazySet = false;
/**
\brief Lazily set CONTEXT. This will only actually retrieve the context if a function in this thread is called.
\param oldContext Pointer to the old context, used to determine if updates are required.
\param hThread Handle of the thread to get the context from if required.
*/
void setContextLazy(CONTEXT* oldContext, HANDLE hThread);
/**
\brief Retrieve the actual context if setContextLazy has been called.
\return Whether retrieving the actual context was successful.
*/
bool handleLazyContext();
CONTEXT mOldContext;
void* getPtr(R reg);
};

View File

@ -1,4 +1,5 @@
#include "Debugger.Thread.h"
#include "Debugger.Thread.Registers.h"
namespace GleeBug
{
@ -13,29 +14,9 @@ namespace GleeBug
{
}
bool Thread::RegReadContext()
{
memset(&this->mOldContext, 0, sizeof(CONTEXT));
this->mOldContext.ContextFlags = CONTEXT_ALL; //TODO: granular control over what's required
this->registers.setContextLazy(&this->mOldContext, this->hThread);
return true;
}
bool Thread::RegWriteContext()
{
//check if something actually changed
if (this->registers.mLazySet || memcmp(&this->mOldContext, &this->registers.mContext, sizeof(CONTEXT)) == 0)
return true;
//update the context
if(SetThreadContext(this->hThread, &this->registers.mContext))
return true;
__debugbreak();
return false;
}
void Thread::StepInto()
{
registers.TrapFlag.Set();
Registers(hThread).TrapFlag.Set();
isSingleStepping = true;
}
@ -57,7 +38,7 @@ namespace GleeBug
void Thread::StepInternal(const StepCallback & cbStep)
{
registers.TrapFlag.Set();
Registers(hThread).TrapFlag.Set();
isInternalStepping = true;
cbInternalStep = cbStep;
}

View File

@ -2,7 +2,6 @@
#define DEBUGGER_THREAD_H
#include "Debugger.Global.h"
#include "Debugger.Thread.Registers.h"
#include "Debugger.Breakpoint.h"
namespace GleeBug
@ -18,7 +17,6 @@ namespace GleeBug
ptr lpThreadLocalBase;
ptr lpStartAddress;
Registers registers;
StepCallbackVector stepCallbacks;
bool isSingleStepping;
bool isInternalStepping;
@ -38,18 +36,6 @@ namespace GleeBug
*/
Thread(const Thread & other) = delete;
/**
\brief Read the register context from the thread. This fills the RegistersInfo member.
\return true if it succeeds, false if it fails.
*/
bool RegReadContext();
/**
\brief Write the register context to the thread. This does nothing if the registers did not change.
\return true if it succeeds, false if it fails.
*/
bool RegWriteContext();
/**
\brief Step into.
*/
@ -121,9 +107,6 @@ namespace GleeBug
\return true if it succeeds, false if it fails.
*/
bool Resume();
private:
CONTEXT mOldContext;
};
};

View File

@ -1,4 +1,5 @@
#include "Debugger.h"
#include "Debugger.Thread.Registers.h"
namespace GleeBug
{
@ -14,7 +15,8 @@ namespace GleeBug
bool Debugger::Init(const wchar_t* szFilePath,
const wchar_t* szCommandLine,
const wchar_t* szCurrentDirectory,
bool newConsole)
bool newConsole,
bool startSuspended)
{
memset(&mMainStartupInfo, 0, sizeof(mMainStartupInfo));
memset(&mMainProcess, 0, sizeof(mMainProcess));
@ -40,7 +42,7 @@ namespace GleeBug
nullptr,
nullptr,
FALSE,
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | (newConsole ? CREATE_NEW_CONSOLE : 0),
DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS | (newConsole ? CREATE_NEW_CONSOLE : 0) | (startSuspended ? CREATE_SUSPENDED : 0),
nullptr,
szCurrentDirectory,
&mMainStartupInfo,
@ -72,8 +74,7 @@ namespace GleeBug
bool Debugger::UnsafeDetach()
{
mRegisters->TrapFlag = false;
mThread->RegWriteContext();
Registers(mThread->hThread, CONTEXT_CONTROL).TrapFlag = false;
return !!DebugActiveProcessStop(mMainProcess.dwProcessId);
}
@ -85,12 +86,11 @@ namespace GleeBug
bool Debugger::UnsafeDetachAndBreak()
{
if (!mProcess || !mThread || !mRegisters) //fail when there is no process or thread currently specified
if (!mProcess || !mThread) //fail when there is no process or thread currently specified
return false;
//trigger an EXCEPTION_SINGLE_STEP in the debuggee
mRegisters->TrapFlag = true;
mThread->RegWriteContext();
Registers(mThread->hThread, CONTEXT_CONTROL).TrapFlag = true;
//detach from the process
return UnsafeDetach();

View File

@ -39,7 +39,8 @@ namespace GleeBug
bool Init(const wchar_t* szFilePath,
const wchar_t* szCommandLine,
const wchar_t* szCurrentDirectory,
bool newConsole = true);
bool newConsole = true,
bool startSuspended = false);
/**
\brief Attach to a debuggee.
@ -301,11 +302,6 @@ namespace GleeBug
\brief The current thread (can be null in some cases). Should be a copy of mProcess->thread.
*/
Thread* mThread = nullptr;
/**
\brief The current thread registers (can be null in some cases). Should be a copy of mThread->registers.
*/
Registers* mRegisters = nullptr;
};
};

View File

@ -120,7 +120,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -138,7 +138,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View File

@ -2,6 +2,7 @@
#define MYDEBUGGER_H
#include <GleeBug/Debugger.h>
#include <GleeBug/Debugger.Thread.Registers.h>
using namespace GleeBug;
@ -11,36 +12,36 @@ protected:
void cbMemoryBreakpoint2(const BreakpointInfo & info)
{
printf("Reached memory breakpoint#2! GIP: 0x%p\n",
mRegisters->Gip());
(void*)Registers(mThread->hThread).Gip());
}
void cbMemoryBreakpoint(const BreakpointInfo & info)
{
unsigned char dataToExec[4];
const char tmp[] = "aaaa";
Registers registers(mThread->hThread);
printf("Reached memory breakpoint! GIP: 0x%p\n",
mRegisters->Gip());
(void*)registers.Gip());
mProcess->MemReadUnsafe(mRegisters->Gip(), dataToExec, 4);
mProcess->MemReadUnsafe(registers.Gip(), dataToExec, 4);
printf("\n What are my bytes? I am so lost.. Dump: ");
for (int i = 0; i < 4; i++)
{
printf("%02X ", dataToExec[i]);
}
mProcess->DeleteMemoryBreakpoint(mRegisters->Gip());
mProcess->DeleteMemoryBreakpoint(registers.Gip());
memcpy(dataToExec, tmp, 4);
mProcess->MemReadUnsafe(mRegisters->Gip(), dataToExec, 4);
mProcess->MemReadUnsafe(registers.Gip(), dataToExec, 4);
printf("\n What are my bytes? I am so lost.. Dump: ");
for (int i = 0; i < 4; i++)
{
printf("%02X ", dataToExec[i]);
}
mProcess->SetMemoryBreakpoint(mRegisters->Gip() + 1, 0x1, this, &MyDebugger::cbMemoryBreakpoint2, MemoryType::Access, false);
mProcess->SetMemoryBreakpoint(registers.Gip() + 1, 0x1, this, &MyDebugger::cbMemoryBreakpoint2, MemoryType::Access, false);
memcpy(dataToExec, tmp, 4);
mProcess->MemReadUnsafe(mRegisters->Gip(), dataToExec, 4);
mProcess->MemReadUnsafe(registers.Gip(), dataToExec, 4);
printf("\n What are my bytes? I am so lost.. Dump: ");
for (int i = 0; i < 4; i++)
{
@ -50,14 +51,15 @@ protected:
void cbEntryBreakpoint(const BreakpointInfo & info)
{
Registers registers(mThread->hThread);
printf("Reached entry breakpoint! GIP: 0x%p\n",
mRegisters->Gip());
(void*)registers.Gip());
#ifdef _WIN64
auto addr = mRegisters->Rbx();
auto addr = registers.Rbx();
#else
auto addr = mRegisters->Esi();
auto addr = registers.Esi();
#endif //_WIN64
printf("Addr: 0x%p\n", addr);
printf("Addr: 0x%p\n", (void*)addr);
if (mProcess->SetMemoryBreakpoint(addr, 0x10000, this, &MyDebugger::cbMemoryBreakpoint, MemoryType::Execute, false))
puts("Memory breakpoint set!");
else
@ -72,29 +74,32 @@ protected:
mThread->StepInto([this]()
{
printf("Step after entry breakpoint! GIP: 0x%p\n",
mRegisters->Gip());
registers.Gip());
});*/
}
void cbEntryHardwareBreakpoint(const BreakpointInfo & info)
{
Registers registers(mThread->hThread);
printf("Reached entry hardware breakpoint! GIP: 0x%p\n",
mRegisters->Gip());
(void*)registers.Gip());
if (mProcess->DeleteHardwareBreakpoint(info.address))
printf("Entry hardware breakpoint deleted!\n");
else
printf("Failed to delete entry hardware breakpoint...\n");
mThread->StepInto([this]()
{
Registers registers(mThread->hThread);
printf("Step after entry hardware breakpoint! GIP: 0x%p\n",
mRegisters->Gip());
(void*)registers.Gip());
});
}
void cbStepSystem()
{
Registers registers(mThread->hThread);
printf("Reached step after system breakpoint, GIP: 0x%p!\n",
mRegisters->Gip());
(void*)registers.Gip());
}
void cbCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO & createProcess, const Process & process) override
@ -102,7 +107,7 @@ protected:
ptr entry = ptr(createProcess.lpStartAddress);
printf("Process %d created with entry 0x%p\n",
mDebugEvent.dwProcessId,
entry);
(void*)entry);
/*HardwareSlot slot;
if (mProcess->GetFreeHardwareBreakpointSlot(slot))
{
@ -121,9 +126,9 @@ protected:
entry = ptr(createProcess.lpBaseOfImage) + 0x108F; //MembpTest, main.cpp:43 (x32)
#endif //_WIN64
if(mProcess->SetBreakpoint(entry, this, &MyDebugger::cbEntryBreakpoint, true))
printf("Breakpoint set at 0x%p!\n", entry);
printf("Breakpoint set at 0x%p!\n", (void*)entry);
else
printf("Failed to set breakpoint at 0x%p...\b", entry);
printf("Failed to set breakpoint at 0x%p...\b", (void*)entry);
uint8 test[5];
ptr start = entry - 2;
printf("unsafe: ");
@ -179,7 +184,7 @@ protected:
exceptionInfo.ExceptionRecord.ExceptionCode,
exceptionInfo.ExceptionRecord.ExceptionAddress);
for (DWORD i = 0; i < exceptionInfo.ExceptionRecord.NumberParameters; i++)
printf(" ExceptionInformation[%d] = 0x%p\n", i, exceptionInfo.ExceptionRecord.ExceptionInformation[i]);
printf(" ExceptionInformation[%d] = 0x%p\n", i, (void*)exceptionInfo.ExceptionRecord.ExceptionInformation[i]);
}
void cbDebugStringEvent(const OUTPUT_DEBUG_STRING_INFO & debugString) override
@ -198,14 +203,16 @@ protected:
void cbAttachBreakpoint() override
{
Registers registers(mThread->hThread);
printf("Attach breakpoint reached, GIP: 0x%p\n",
mRegisters->Gip());
(void*)registers.Gip());
}
void cbSystemBreakpoint() override
{
Registers registers(mThread->hThread);
printf("System breakpoint reached, GIP: 0x%p\n",
mRegisters->Gip());
(void*)registers.Gip());
mThread->StepInto(this, &MyDebugger::cbStepSystem);
}
@ -218,16 +225,17 @@ protected:
void cbBreakpoint(const BreakpointInfo & info) override
{
printf("Breakpoint on 0x%p!\n",
info.address);
(void*)info.address);
}
void cbUnhandledException(const EXCEPTION_RECORD & exceptionRecord, bool firstChance) override
{
Registers registers(mThread->hThread);
printf("Unhandled exception (%s) 0x%08X on 0x%p, GIP: 0x%p\n",
firstChance ? "first chance" : "second chance",
exceptionRecord.ExceptionCode,
exceptionRecord.ExceptionAddress,
mRegisters->Gip());
(void*)registers.Gip());
}
};

View File

@ -114,7 +114,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -131,7 +131,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View File

@ -56,7 +56,7 @@ static void printNtHeaders(T inth)
puts("\n Optional Header:");
printf(" Magic : %04X\n", ioh->Magic);
printf(" EntryPoint: %08X\n", ioh->AddressOfEntryPoint);
printf(" ImageBase : %p\n", PVOID(ioh->ImageBase));
printf(" ImageBase : %llX\n", (uint64_t)ioh->ImageBase);
printf(" Subsystem : %04X\n", ioh->Subsystem);
}
@ -156,7 +156,7 @@ static void testCorkami()
printf("file: %ws\n\n", fileName.c_str());
}
}
printf("\n%d/%d parsed OK!\n", okCount, _countof(peTestFiles));
printf("\n%d/%zu parsed OK!\n", okCount, _countof(peTestFiles));
}
int main()

View File

@ -1,10 +1,13 @@
#include <GleeBug/Debugger.h>
#include <GleeBug/Static.Pe.h>
#include <GleeBug/Static.Bufferfile.h>
#include <GleeBug/Debugger.Thread.Registers.h>
#include "TitanEngine.h"
#include "ntdll.h"
#include "FileMap.h"
#include "PEB.h"
#include "Global.Engine.Context.h"
#include "Hider.h"
// Related to floating x87 registers
#define GetSTInTOPStackFromStatusWord(StatusWord) ((StatusWord & 0x3800) >> 11)
@ -13,137 +16,13 @@
#define GetRegisterAreaOf87register(register_area, x87r0_position, index) (((char *) register_area) + 10 * Calculatex87registerPositionInRegisterArea(x87r0_position, index) )
#define GetSTValueFromIndex(x87r0_position, index) ((x87r0_position + index) % 8)
#ifdef _WIN64
//https://stackoverflow.com/a/869597/1806760
template<typename T> struct identity
{
typedef T type;
};
template<typename Dst> Dst implicit_cast(typename identity<Dst>::type t)
{
return t;
}
//https://github.com/electron/crashpad/blob/4054e6cba3ba023d9c00260518ec2912607ae17c/snapshot/cpu_context.cc
enum
{
kX87TagValid = 0,
kX87TagZero,
kX87TagSpecial,
kX87TagEmpty,
};
typedef uint8_t X87Register[10];
union X87OrMMXRegister
{
struct
{
X87Register st;
uint8_t st_reserved[6];
};
struct
{
uint8_t mm_value[8];
uint8_t mm_reserved[8];
};
};
static_assert(sizeof(X87OrMMXRegister) == sizeof(M128A), "sizeof(X87OrMMXRegister) != sizeof(M128A)");
static uint16_t FxsaveToFsaveTagWord(
uint16_t fsw,
uint8_t fxsave_tag,
const X87OrMMXRegister* st_mm)
{
// The x87 tag word (in both abridged and full form) identifies physical
// registers, but |st_mm| is arranged in logical stack order. In order to map
// physical tag word bits to the logical stack registers they correspond to,
// the "stack top" value from the x87 status word is necessary.
int stack_top = (fsw >> 11) & 0x7;
uint16_t fsave_tag = 0;
for(int physical_index = 0; physical_index < 8; ++physical_index)
{
bool fxsave_bit = (fxsave_tag & (1 << physical_index)) != 0;
uint8_t fsave_bits;
if(fxsave_bit)
{
int st_index = (physical_index + 8 - stack_top) % 8;
const X87Register & st = st_mm[st_index].st;
uint32_t exponent = ((st[9] & 0x7f) << 8) | st[8];
if(exponent == 0x7fff)
{
// Infinity, NaN, pseudo-infinity, or pseudo-NaN. If it was important to
// distinguish between these, the J bit and the M bit (the most
// significant bit of |fraction|) could be consulted.
fsave_bits = kX87TagSpecial;
}
else
{
// The integer bit the "J bit".
bool integer_bit = (st[7] & 0x80) != 0;
if(exponent == 0)
{
uint64_t fraction = ((implicit_cast<uint64_t>(st[7]) & 0x7f) << 56) |
(implicit_cast<uint64_t>(st[6]) << 48) |
(implicit_cast<uint64_t>(st[5]) << 40) |
(implicit_cast<uint64_t>(st[4]) << 32) |
(implicit_cast<uint32_t>(st[3]) << 24) |
(st[2] << 16) | (st[1] << 8) | st[0];
if(!integer_bit && fraction == 0)
{
fsave_bits = kX87TagZero;
}
else
{
// Denormal (if the J bit is clear) or pseudo-denormal.
fsave_bits = kX87TagSpecial;
}
}
else if(integer_bit)
{
fsave_bits = kX87TagValid;
}
else
{
// Unnormal.
fsave_bits = kX87TagSpecial;
}
}
}
else
{
fsave_bits = kX87TagEmpty;
}
fsave_tag |= (fsave_bits << (physical_index * 2));
}
return fsave_tag;
}
static uint8_t FsaveToFxsaveTagWord(uint16_t fsave_tag)
{
uint8_t fxsave_tag = 0;
for(int physical_index = 0; physical_index < 8; ++physical_index)
{
const uint8_t fsave_bits = (fsave_tag >> (physical_index * 2)) & 0x3;
const bool fxsave_bit = fsave_bits != kX87TagEmpty;
fxsave_tag |= fxsave_bit << physical_index;
}
return fxsave_tag;
}
#endif //_WIN64
using namespace GleeBug;
class Emulator : public Debugger
{
public:
HINSTANCE engineHandle;
//Debugger
PROCESS_INFORMATION* InitDebugW(const wchar_t* szFileName, const wchar_t* szCommandLine, const wchar_t* szCurrentFolder)
{
@ -153,9 +32,31 @@ public:
return &mMainProcess;
}
PROCESS_INFORMATION* InitDLLDebugW(const wchar_t* szFileName, bool ReserveModuleBase, const wchar_t* szCommandLine, const wchar_t* szCurrentFolder, LPVOID EntryCallBack)
PROCESS_INFORMATION* InitDLLDebugW(const wchar_t* szFileName, bool /* ReserveModuleBase = false */, const wchar_t* szCommandLine, const wchar_t* szCurrentFolder, LPVOID /*EntryCallBack = 0 */)
{
//TODO
wcscpy_s(szDebuggeeName, szFileName);
if (TryExtractDllLoader())
{
mCbATTACHBREAKPOINT = nullptr;
if (!Init(szDebuggeeName, szCommandLine, szCurrentFolder, true, true))
return nullptr;
wchar_t szName[256] = L"";
swprintf(szName, 256, L"Local\\szLibraryName%X", mMainProcess.dwProcessId);
//TODO: close this once we actually see the DLL is loaded in the process
HANDLE DebugDLLFileMapping = CreateFileMappingW(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, 512 * sizeof(wchar_t), szName);
if (DebugDLLFileMapping)
{
const size_t filemapSize = 512;
wchar_t* szLibraryPathMapping = (wchar_t*)MapViewOfFile(DebugDLLFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, filemapSize * sizeof(wchar_t));
if (szLibraryPathMapping)
{
wcscpy_s(szLibraryPathMapping, filemapSize, szFileName);
UnmapViewOfFile(szLibraryPathMapping);
}
}
ResumeThread(mMainProcess.hThread);
return &mMainProcess;
}
return nullptr;
}
@ -288,23 +189,7 @@ public:
//Misc
void* GetPEBLocation(HANDLE hProcess)
{
ULONG RequiredLen = 0;
void* PebAddress = 0;
PROCESS_BASIC_INFORMATION myProcessBasicInformation[5] = { 0 };
if(NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, sizeof(PROCESS_BASIC_INFORMATION), &RequiredLen) == 0)
{
PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
}
else
{
if(NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, RequiredLen, &RequiredLen) == 0)
{
PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
}
}
return PebAddress;
return GetPEBLocation_(hProcess);
}
void* GetPEBLocation64(HANDLE hProcess)
@ -375,67 +260,7 @@ public:
bool HideDebugger(HANDLE hProcess, DWORD PatchAPILevel)
{
PEB_CURRENT myPEB = { 0 };
SIZE_T ueNumberOfBytesRead = 0;
void* heapFlagsAddress = 0;
DWORD heapFlags = 0;
void* heapForceFlagsAddress = 0;
DWORD heapForceFlags = 0;
#ifndef _WIN64
PEB64 myPEB64 = { 0 };
void* AddressOfPEB64 = GetPEBLocation64(hProcess);
#endif
void* AddressOfPEB = GetPEBLocation(hProcess);
if(!AddressOfPEB)
return false;
if(ReadProcessMemory(hProcess, AddressOfPEB, (void*)&myPEB, sizeof(PEB_CURRENT), &ueNumberOfBytesRead))
{
#ifndef _WIN64
if(AddressOfPEB64)
{
ReadProcessMemory(hProcess, AddressOfPEB64, (void*)&myPEB64, sizeof(PEB64), &ueNumberOfBytesRead);
}
#endif
myPEB.BeingDebugged = FALSE;
myPEB.NtGlobalFlag &= ~0x70;
#ifndef _WIN64
myPEB64.BeingDebugged = FALSE;
myPEB64.NtGlobalFlag &= ~0x70;
#endif
#ifdef _WIN64
heapFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapFlagsOffset(true));
heapForceFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapForceFlagsOffset(true));
#else
heapFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapFlagsOffset(false));
heapForceFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapForceFlagsOffset(false));
#endif //_WIN64
ReadProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0);
ReadProcessMemory(hProcess, heapForceFlagsAddress, &heapForceFlags, sizeof(DWORD), 0);
heapFlags &= HEAP_GROWABLE;
heapForceFlags = 0;
WriteProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0);
WriteProcessMemory(hProcess, heapForceFlagsAddress, &heapForceFlags, sizeof(DWORD), 0);
if(WriteProcessMemory(hProcess, AddressOfPEB, (void*)&myPEB, sizeof(PEB_CURRENT), &ueNumberOfBytesRead))
{
#ifndef _WIN64
if(AddressOfPEB64)
{
WriteProcessMemory(hProcess, AddressOfPEB64, (void*)&myPEB64, sizeof(PEB64), &ueNumberOfBytesRead);
}
#endif
return true;
}
}
return false;
return FixPebInProcess(hProcess);
}
HANDLE TitanOpenProcess(DWORD dwDesiredAccess, bool bInheritHandle, DWORD dwProcessId)
@ -479,220 +304,178 @@ public:
struct ThreadSuspender
{
ThreadSuspender(Thread* thread, bool running, bool writeRegs)
: thread(running ? thread : nullptr), writeRegs(writeRegs)
ThreadSuspender(HANDLE hThread, bool running)
: hThread(running ? hThread : nullptr)
{
if(this->thread)
{
this->thread->Suspend();
this->thread->RegReadContext();
}
if (this->hThread)
SuspendThread(this->hThread);
}
ThreadSuspender(const ThreadSuspender &) = delete;
ThreadSuspender(const ThreadSuspender &&) = delete;
~ThreadSuspender()
{
if(this->thread)
{
if(this->writeRegs)
this->thread->RegWriteContext();
this->thread->Resume();
}
if (this->hThread)
ResumeThread(this->hThread);
}
Thread* thread;
bool writeRegs;
HANDLE hThread;
};
//Registers
ULONG_PTR GetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister)
{
if(!hActiveThread)
if (!hActiveThread)
return 0;
auto thread = threadFromHandle(hActiveThread);
if(!thread)
return 0;
ThreadSuspender suspender(thread, mIsRunning, false);
return thread->registers.Get(registerFromDword(IndexOfRegister));
ThreadSuspender suspender(hActiveThread, mIsRunning);
auto r = registerFromDword(IndexOfRegister);
if (r == Registers::R::Invalid)
__debugbreak();
return Registers(hActiveThread).Get(r);
}
bool SetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister, ULONG_PTR NewRegisterValue)
{
auto thread = threadFromHandle(hActiveThread);
if (!thread)
return false;
ThreadSuspender suspender(thread, mIsRunning, true);
thread->registers.Set(registerFromDword(IndexOfRegister), NewRegisterValue);
if (!hActiveThread)
return 0;
ThreadSuspender suspender(hActiveThread, mIsRunning);
auto r = registerFromDword(IndexOfRegister);
if (r != Registers::R::Invalid)
{
Registers(hActiveThread).Set(r, NewRegisterValue);
return true;
}
bool GetFullContextDataEx(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext)
TITAN_ENGINE_CONTEXT_t titcontext;
if (!_GetFullContextDataEx(hActiveThread, &titcontext, IndexOfRegister >= UE_MXCSR))
return false;
bool avx_priority = false;
switch (IndexOfRegister)
{
if(!hActiveThread)
return false;
auto thread = threadFromHandle(hActiveThread);
if (!thread || !titcontext)
return false;
ThreadSuspender suspender(thread, mIsRunning, false);
auto context = thread->registers.GetContext();
memset(titcontext, 0, sizeof(TITAN_ENGINE_CONTEXT_t));
//General purpose registers
titcontext->cax = thread->registers.Gax();
titcontext->ccx = thread->registers.Gcx();
titcontext->cdx = thread->registers.Gdx();
titcontext->cbx = thread->registers.Gbx();
titcontext->csp = thread->registers.Gsp();
titcontext->cbp = thread->registers.Gbp();
titcontext->csi = thread->registers.Gsi();
titcontext->cdi = thread->registers.Gdi();
case UE_X87_STATUSWORD:
{
titcontext.x87fpu.StatusWord = WORD(NewRegisterValue);
break;
}
case UE_X87_CONTROLWORD:
{
titcontext.x87fpu.ControlWord = WORD(NewRegisterValue);
break;
}
case UE_X87_TAGWORD:
{
titcontext.x87fpu.TagWord = WORD(NewRegisterValue);
break;
}
case UE_MXCSR:
{
titcontext.MxCsr = DWORD(NewRegisterValue);
break;
}
case UE_XMM0:
case UE_XMM1:
case UE_XMM2:
case UE_XMM3:
case UE_XMM4:
case UE_XMM5:
case UE_XMM6:
case UE_XMM7:
#ifdef _WIN64
titcontext->r8 = thread->registers.R8();
titcontext->r9 = thread->registers.R9();
titcontext->r10 = thread->registers.R10();
titcontext->r11 = thread->registers.R11();
titcontext->r12 = thread->registers.R12();
titcontext->r13 = thread->registers.R13();
titcontext->r14 = thread->registers.R14();
titcontext->r15 = thread->registers.R15();
case UE_XMM8:
case UE_XMM9:
case UE_XMM10:
case UE_XMM11:
case UE_XMM12:
case UE_XMM13:
case UE_XMM14:
case UE_XMM15:
#endif //_WIN64
titcontext->cip = thread->registers.Gip();
// Flags
titcontext->eflags = thread->registers.Eflags();
// Debug registers
titcontext->dr0 = thread->registers.Dr0();
titcontext->dr1 = thread->registers.Dr1();
titcontext->dr2 = thread->registers.Dr2();
titcontext->dr3 = thread->registers.Dr3();
titcontext->dr6 = thread->registers.Dr6();
titcontext->dr7 = thread->registers.Dr7();
// Segments
titcontext->gs = thread->registers.Gs();
titcontext->fs = thread->registers.Fs();
titcontext->es = thread->registers.Es();
titcontext->ds = thread->registers.Ds();
titcontext->cs = thread->registers.Cs();
titcontext->ss = thread->registers.Ss();
// x87
{
memcpy(&(titcontext.XmmRegisters[IndexOfRegister - UE_XMM0]), (void*)NewRegisterValue, 16);
break;
}
case UE_MMX0:
case UE_MMX1:
case UE_MMX2:
case UE_MMX3:
case UE_MMX4:
case UE_MMX5:
case UE_MMX6:
case UE_MMX7:
{
int STInTopStack = GetSTInTOPStackFromStatusWord(titcontext.x87fpu.StatusWord);
DWORD x87r0_position = Getx87r0PositionInRegisterArea(STInTopStack);
memcpy(((uint64_t*)GetRegisterAreaOf87register(titcontext.RegisterArea, x87r0_position, IndexOfRegister - UE_MMX0)), (char*)NewRegisterValue, 8);
break;
}
case UE_x87_r0:
case UE_x87_r1:
case UE_x87_r2:
case UE_x87_r3:
case UE_x87_r4:
case UE_x87_r5:
case UE_x87_r6:
case UE_x87_r7:
{
int STInTopStack = GetSTInTOPStackFromStatusWord(titcontext.x87fpu.StatusWord);
DWORD x87r0_position = Getx87r0PositionInRegisterArea(STInTopStack);
memcpy(((uint64_t*)GetRegisterAreaOf87register(titcontext.RegisterArea, x87r0_position, IndexOfRegister - UE_x87_r0)), (void*)NewRegisterValue, 10);
break;
}
case UE_YMM0:
case UE_YMM1:
case UE_YMM2:
case UE_YMM3:
case UE_YMM4:
case UE_YMM5:
case UE_YMM6:
case UE_YMM7:
#ifdef _WIN64
titcontext->x87fpu.ControlWord = context->FltSave.ControlWord;
titcontext->x87fpu.StatusWord = context->FltSave.StatusWord;
titcontext->x87fpu.TagWord = FxsaveToFsaveTagWord(context->FltSave.StatusWord, context->FltSave.TagWord, (const X87OrMMXRegister*)context->FltSave.FloatRegisters);
titcontext->x87fpu.ErrorSelector = context->FltSave.ErrorSelector;
titcontext->x87fpu.ErrorOffset = context->FltSave.ErrorOffset;
titcontext->x87fpu.DataSelector = context->FltSave.DataSelector;
titcontext->x87fpu.DataOffset = context->FltSave.DataOffset;
// Skip titcontext->x87fpu.Cr0NpxState (https://github.com/x64dbg/x64dbg/issues/255)
titcontext->MxCsr = context->MxCsr;
for(int i = 0; i < 8; i++)
memcpy(&titcontext->RegisterArea[i * 10], &context->FltSave.FloatRegisters[i], 10);
for(int i = 0; i < 16; i++)
memcpy(&titcontext->XmmRegisters[i], &context->FltSave.XmmRegisters[i], 16);
#else //x86
titcontext->x87fpu.ControlWord = (WORD)context->FloatSave.ControlWord;
titcontext->x87fpu.StatusWord = (WORD)context->FloatSave.StatusWord;
titcontext->x87fpu.TagWord = (WORD)context->FloatSave.TagWord;
titcontext->x87fpu.ErrorSelector = context->FloatSave.ErrorSelector;
titcontext->x87fpu.ErrorOffset = context->FloatSave.ErrorOffset;
titcontext->x87fpu.DataSelector = context->FloatSave.DataSelector;
titcontext->x87fpu.DataOffset = context->FloatSave.DataOffset;
titcontext->x87fpu.Cr0NpxState = context->FloatSave.Cr0NpxState;
memcpy(titcontext->RegisterArea, context->FloatSave.RegisterArea, 80);
// MXCSR ExtendedRegisters[24]
memcpy(&(titcontext->MxCsr), &(context->ExtendedRegisters[24]), sizeof(titcontext->MxCsr));
// for x86 copy the 8 Xmm Registers from ExtendedRegisters[(10+n)*16]; (n is the index of the xmm register) to the XMM register
for(int i = 0; i < 8; i++)
memcpy(&(titcontext->XmmRegisters[i]), &context->ExtendedRegisters[(10 + i) * 16], 16);
case UE_YMM8:
case UE_YMM9:
case UE_YMM10:
case UE_YMM11:
case UE_YMM12:
case UE_YMM13:
case UE_YMM14:
case UE_YMM15:
#endif //_WIN64
{
avx_priority = true;
memcpy(&titcontext.YmmRegisters[IndexOfRegister - UE_YMM0], (void*)NewRegisterValue, 32);
break;
}
//TODO: AVX
return true;
default: __debugbreak();
}
return _SetFullContextDataEx(hActiveThread, &titcontext, avx_priority);
}
bool SetFullContextDataEx(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext)
{
auto thread = threadFromHandle(hActiveThread);
if (!thread || !titcontext)
return false;
ThreadSuspender suspender(thread, mIsRunning, true);
auto context = thread->registers.GetContext();
// General purpose registers
thread->registers.Gax = titcontext->cax;
thread->registers.Gcx = titcontext->ccx;
thread->registers.Gdx = titcontext->cdx;
thread->registers.Gbx = titcontext->cbx;
thread->registers.Gsp = titcontext->csp;
thread->registers.Gbp = titcontext->cbp;
thread->registers.Gsi = titcontext->csi;
thread->registers.Gdi = titcontext->cdi;
#ifdef _WIN64
thread->registers.R8 = titcontext->r8;
thread->registers.R9 = titcontext->r9;
thread->registers.R10 = titcontext->r10;
thread->registers.R11 = titcontext->r11;
thread->registers.R12 = titcontext->r12;
thread->registers.R13 = titcontext->r13;
thread->registers.R14 = titcontext->r14;
thread->registers.R15 = titcontext->r15;
#endif //_WIN64
thread->registers.Gip = titcontext->cip;
// Flags
thread->registers.Eflags = uint32(titcontext->eflags);
// Debug registers
thread->registers.Dr0 = titcontext->dr0;
thread->registers.Dr1 = titcontext->dr1;
thread->registers.Dr2 = titcontext->dr2;
thread->registers.Dr3 = titcontext->dr3;
thread->registers.Dr6 = titcontext->dr6;
thread->registers.Dr7 = titcontext->dr7;
// Segments
thread->registers.Gs = titcontext->gs;
thread->registers.Fs = titcontext->fs;
thread->registers.Es = titcontext->es;
thread->registers.Ds = titcontext->ds;
thread->registers.Cs = titcontext->cs;
thread->registers.Ss = titcontext->ss;
// x87
#ifdef _WIN64
context->FltSave.ControlWord = titcontext->x87fpu.ControlWord;
context->FltSave.StatusWord = titcontext->x87fpu.StatusWord;
context->FltSave.TagWord = FsaveToFxsaveTagWord(titcontext->x87fpu.TagWord);
context->FltSave.ErrorSelector = (WORD)titcontext->x87fpu.ErrorSelector;
context->FltSave.ErrorOffset = titcontext->x87fpu.ErrorOffset;
context->FltSave.DataSelector = (WORD)titcontext->x87fpu.DataSelector;
context->FltSave.DataOffset = titcontext->x87fpu.DataOffset;
// Skip titcontext->x87fpu.Cr0NpxState
context->MxCsr = titcontext->MxCsr;
ThreadSuspender suspender(hActiveThread, mIsRunning);
return _SetFullContextDataEx(hActiveThread, titcontext, false);
}
for(int i = 0; i < 8; i++)
memcpy(&context->FltSave.FloatRegisters[i], &(titcontext->RegisterArea[i * 10]), 10);
for(int i = 0; i < 16; i++)
memcpy(&(context->FltSave.XmmRegisters[i]), &(titcontext->XmmRegisters[i]), 16);
#else //x86
context->FloatSave.ControlWord = titcontext->x87fpu.ControlWord;
context->FloatSave.StatusWord = titcontext->x87fpu.StatusWord;
context->FloatSave.TagWord = titcontext->x87fpu.TagWord;
context->FloatSave.ErrorSelector = titcontext->x87fpu.ErrorSelector;
context->FloatSave.ErrorOffset = titcontext->x87fpu.ErrorOffset;
context->FloatSave.DataSelector = titcontext->x87fpu.DataSelector;
context->FloatSave.DataOffset = titcontext->x87fpu.DataOffset;
context->FloatSave.Cr0NpxState = titcontext->x87fpu.Cr0NpxState;
memcpy(context->FloatSave.RegisterArea, titcontext->RegisterArea, 80);
// MXCSR ExtendedRegisters[24]
memcpy(&(context->ExtendedRegisters[24]), &titcontext->MxCsr, sizeof(titcontext->MxCsr));
// for x86 copy the 8 Xmm Registers from ExtendedRegisters[(10+n)*16]; (n is the index of the xmm register) to the XMM register
for(int i = 0; i < 8; i++)
memcpy(&context->ExtendedRegisters[(10 + i) * 16], &(titcontext->XmmRegisters[i]), 16);
#endif //_WIN64
//TODO: AVX
return true;
bool GetFullContextDataEx(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext)
{
ThreadSuspender suspender(hActiveThread, mIsRunning);
return _GetFullContextDataEx(hActiveThread, titcontext, true);
}
void GetMMXRegisters(uint64_t mmx[8], TITAN_ENGINE_CONTEXT_t* titcontext)
@ -701,7 +484,7 @@ public:
DWORD x87r0_position = Getx87r0PositionInRegisterArea(STInTopStack);
int i;
for(i = 0; i < 8; i++)
for (i = 0; i < 8; i++)
mmx[i] = *((uint64_t*)GetRegisterAreaOf87register(titcontext->RegisterArea, x87r0_position, i));
}
@ -718,7 +501,7 @@ public:
int STInTopStack = GetSTInTOPStackFromStatusWord(titcontext->x87fpu.StatusWord);
DWORD x87r0_position = Getx87r0PositionInRegisterArea(STInTopStack);
for(int i = 0; i < 8; i++)
for (int i = 0; i < 8; i++)
{
memcpy(x87FPURegisters[i].data, GetRegisterAreaOf87register(titcontext->RegisterArea, x87r0_position, i), 10);
x87FPURegisters[i].st_value = GetSTValueFromIndex(x87r0_position, i);
@ -925,7 +708,6 @@ public:
{
for(auto & thread : mProcess->threads)
thread.second->Suspend();
mProcess->RegReadContext();
}
if(!mProcess->SetHardwareBreakpoint(bpxAddress,
(HardwareSlot)IndexOfRegister, [bpxCallBack](const BreakpointInfo & info)
@ -935,7 +717,6 @@ public:
return false;
if(running)
{
mProcess->RegWriteContext();
for(auto & thread : mProcess->threads)
thread.second->Resume();
}
@ -1045,7 +826,7 @@ protected:
}
private: //functions
static Registers::R registerFromDword(DWORD IndexOfRegister)
inline Registers::R registerFromDword(DWORD IndexOfRegister)
{
switch (IndexOfRegister)
{
@ -1093,14 +874,15 @@ private: //functions
case UE_SEG_DS: return Registers::R::DS;
case UE_SEG_CS: return Registers::R::CS;
case UE_SEG_SS: return Registers::R::SS;
default:
__debugbreak();
return Registers::R::EAX;
default: return Registers::R::Invalid;
}
}
std::unordered_map<HANDLE, Thread*> threadFromHandleCache;
// Disable warnings about pointer truncation for the THREAD_BASIC_INFORMATION
#pragma warning(push)
#pragma warning(disable: 4311 4302)
Thread* threadFromHandle(HANDLE hThread)
{
auto found = threadFromHandleCache.find(hThread);
@ -1123,6 +905,7 @@ private: //functions
threadFromHandleCache[hThread] = result;
return result;
}
#pragma warning(pop)
std::unordered_map<HANDLE, Process*> processFromHandleCache;
@ -1313,6 +1096,53 @@ private: //functions
}
#endif
bool EngineExtractResource(char* szResourceName, wchar_t* szExtractedFileName)
{
bool result = false;
HRSRC hResource = FindResourceA(engineHandle, (LPCSTR)szResourceName, "BINARY");
if (hResource != NULL)
{
HGLOBAL hResourceGlobal = LoadResource(engineHandle, hResource);
if (hResourceGlobal != NULL)
{
DWORD ResourceSize = SizeofResource(engineHandle, hResource);
LPVOID ResourceData = LockResource(hResourceGlobal);
HANDLE hFile = CreateFileW(szExtractedFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD NumberOfBytesWritten;
if (WriteFile(hFile, ResourceData, ResourceSize, &NumberOfBytesWritten, NULL))
result = true;
CloseHandle(hFile);
}
}
}
return result;
}
bool TryExtractDllLoader(bool failedBefore = false)
{
wchar_t* szPath = wcsrchr(szDebuggeeName, L'\\');
if (szPath)
szPath[1] = '\0';
wchar_t DLLLoaderName[64] = L"";
#ifdef _WIN64
swprintf_s(DLLLoaderName, L"DLLLoader64_%.4X.exe", GetTickCount() & 0xFFFF);
#else
swprintf_s(DLLLoaderName, L"DLLLoader32_%.4X.exe", GetTickCount() & 0xFFFF);
#endif //_WIN64
wcscat_s(szDebuggeeName, DLLLoaderName);
#ifdef _WIN64
if (EngineExtractResource("LOADERX64", szDebuggeeName))
#else
if (EngineExtractResource("LOADERX86", szDebuggeeName))
#endif //_WIN64
return true;
return !failedBefore &&
GetModuleFileNameW(engineHandle, szDebuggeeName, _countof(szDebuggeeName)) &&
TryExtractDllLoader(true);
}
private: //variables
bool mSetDebugPrivilege = false;
typedef void(*CUSTOMHANDLER)(const void*);
@ -1332,4 +1162,5 @@ private: //variables
CUSTOMHANDLER mCbDEBUGEVENT = nullptr;
STEPCALLBACK mCbATTACHBREAKPOINT = nullptr;
PROCESS_INFORMATION* mAttachProcessInfo = nullptr;
wchar_t szDebuggeeName[MAX_PATH] = L"";
};

View File

@ -0,0 +1,482 @@
#include "Global.Engine.Context.h"
#include <vector>
typedef int(*p_printf)(const char*, ...);
static p_printf hax()
{
auto d = p_printf(GetProcAddress(GetModuleHandleW(L"x64dbg.dll"), "_plugin_logprintf"));
return d ? d : printf;
}
static auto dprintf = hax();
#ifdef _WIN64
//https://stackoverflow.com/a/869597/1806760
template<typename T> struct identity
{
typedef T type;
};
template<typename Dst> Dst implicit_cast(typename identity<Dst>::type t)
{
return t;
}
//https://github.com/electron/crashpad/blob/4054e6cba3ba023d9c00260518ec2912607ae17c/snapshot/cpu_context.cc
enum
{
kX87TagValid = 0,
kX87TagZero,
kX87TagSpecial,
kX87TagEmpty,
};
typedef uint8_t X87Register[10];
union X87OrMMXRegister
{
struct
{
X87Register st;
uint8_t st_reserved[6];
};
struct
{
uint8_t mm_value[8];
uint8_t mm_reserved[8];
};
};
static_assert(sizeof(X87OrMMXRegister) == sizeof(M128A), "sizeof(X87OrMMXRegister) != sizeof(M128A)");
static uint16_t FxsaveToFsaveTagWord(
uint16_t fsw,
uint8_t fxsave_tag,
const X87OrMMXRegister* st_mm)
{
// The x87 tag word (in both abridged and full form) identifies physical
// registers, but |st_mm| is arranged in logical stack order. In order to map
// physical tag word bits to the logical stack registers they correspond to,
// the "stack top" value from the x87 status word is necessary.
int stack_top = (fsw >> 11) & 0x7;
uint16_t fsave_tag = 0;
for(int physical_index = 0; physical_index < 8; ++physical_index)
{
bool fxsave_bit = (fxsave_tag & (1 << physical_index)) != 0;
uint8_t fsave_bits;
if(fxsave_bit)
{
int st_index = (physical_index + 8 - stack_top) % 8;
const X87Register & st = st_mm[st_index].st;
uint32_t exponent = ((st[9] & 0x7f) << 8) | st[8];
if(exponent == 0x7fff)
{
// Infinity, NaN, pseudo-infinity, or pseudo-NaN. If it was important to
// distinguish between these, the J bit and the M bit (the most
// significant bit of |fraction|) could be consulted.
fsave_bits = kX87TagSpecial;
}
else
{
// The integer bit the "J bit".
bool integer_bit = (st[7] & 0x80) != 0;
if(exponent == 0)
{
uint64_t fraction = ((implicit_cast<uint64_t>(st[7]) & 0x7f) << 56) |
(implicit_cast<uint64_t>(st[6]) << 48) |
(implicit_cast<uint64_t>(st[5]) << 40) |
(implicit_cast<uint64_t>(st[4]) << 32) |
(implicit_cast<uint32_t>(st[3]) << 24) |
(st[2] << 16) | (st[1] << 8) | st[0];
if(!integer_bit && fraction == 0)
{
fsave_bits = kX87TagZero;
}
else
{
// Denormal (if the J bit is clear) or pseudo-denormal.
fsave_bits = kX87TagSpecial;
}
}
else if(integer_bit)
{
fsave_bits = kX87TagValid;
}
else
{
// Unnormal.
fsave_bits = kX87TagSpecial;
}
}
}
else
{
fsave_bits = kX87TagEmpty;
}
fsave_tag |= (fsave_bits << (physical_index * 2));
}
return fsave_tag;
}
static uint8_t FsaveToFxsaveTagWord(uint16_t fsave_tag)
{
uint8_t fxsave_tag = 0;
for(int physical_index = 0; physical_index < 8; ++physical_index)
{
const uint8_t fsave_bits = (fsave_tag >> (physical_index * 2)) & 0x3;
const bool fxsave_bit = fsave_bits != kX87TagEmpty;
fxsave_tag |= fxsave_bit << physical_index;
}
return fxsave_tag;
}
#endif //_WIN64
PGETENABLEDXSTATEFEATURES _GetEnabledXStateFeatures = NULL;
PINITIALIZECONTEXT _InitializeContext = NULL;
PGETXSTATEFEATURESMASK _GetXStateFeaturesMask = NULL;
LOCATEXSTATEFEATURE _LocateXStateFeature = NULL;
SETXSTATEFEATURESMASK _SetXStateFeaturesMask = NULL;
static bool SetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext)
{
if (InitXState() == false)
return false;
DWORD64 FeatureMask = _GetEnabledXStateFeatures();
if ((FeatureMask & XSTATE_MASK_AVX) == 0)
return false;
DWORD ContextSize = 0;
BOOL Success = _InitializeContext(NULL,
CONTEXT_ALL | CONTEXT_XSTATE,
NULL,
&ContextSize);
if ((Success == TRUE) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
return false;
std::vector<unsigned char> dataBuffer;
dataBuffer.resize(ContextSize);
PVOID Buffer = dataBuffer.data();
if (Buffer == NULL)
return false;
PCONTEXT Context;
Success = _InitializeContext(Buffer,
CONTEXT_ALL | CONTEXT_XSTATE,
&Context,
&ContextSize);
if (Success == FALSE)
return false;
if (_SetXStateFeaturesMask(Context, XSTATE_MASK_AVX) == FALSE)
return false;
if (GetThreadContext(hActiveThread, Context) == FALSE)
return false;
if (_GetXStateFeaturesMask(Context, &FeatureMask) == FALSE)
return false;
DWORD FeatureLength;
XmmRegister_t* Sse = (XmmRegister_t*)_LocateXStateFeature(Context, XSTATE_LEGACY_SSE, &FeatureLength);
XmmRegister_t* Avx = (XmmRegister_t*)_LocateXStateFeature(Context, XSTATE_AVX, NULL);
int NumberOfRegisters = FeatureLength / sizeof(Sse[0]);
if (Sse != NULL) //If the feature is unsupported by the processor it will return NULL
{
for (int i = 0; i < NumberOfRegisters; i++)
Sse[i] = titcontext->YmmRegisters[i].Low;
}
if (Avx != NULL) //If the feature is unsupported by the processor it will return NULL
{
for (int i = 0; i < NumberOfRegisters; i++)
Avx[i] = titcontext->YmmRegisters[i].High;
}
return (SetThreadContext(hActiveThread, Context) == TRUE);
}
static bool GetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext)
{
if (InitXState() == false)
return false;
DWORD64 FeatureMask = _GetEnabledXStateFeatures();
if ((FeatureMask & XSTATE_MASK_AVX) == 0)
return false;
DWORD ContextSize = 0;
BOOL Success = _InitializeContext(NULL,
CONTEXT_ALL | CONTEXT_XSTATE,
NULL,
&ContextSize);
if ((Success == TRUE) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
return false;
std::vector<unsigned char> dataBuffer;
dataBuffer.resize(ContextSize);
PVOID Buffer = dataBuffer.data();
if (Buffer == NULL)
return false;
PCONTEXT Context;
Success = _InitializeContext(Buffer,
CONTEXT_ALL | CONTEXT_XSTATE,
&Context,
&ContextSize);
if (Success == FALSE)
return false;
if (_SetXStateFeaturesMask(Context, XSTATE_MASK_AVX) == FALSE)
return false;
if (GetThreadContext(hActiveThread, Context) == FALSE)
return false;
if (_GetXStateFeaturesMask(Context, &FeatureMask) == FALSE)
return false;
DWORD FeatureLength;
XmmRegister_t* Sse = (XmmRegister_t*)_LocateXStateFeature(Context, XSTATE_LEGACY_SSE, &FeatureLength);
XmmRegister_t* Avx = (XmmRegister_t*)_LocateXStateFeature(Context, XSTATE_AVX, NULL);
int NumberOfRegisters = FeatureLength / sizeof(Sse[0]);
if (Sse != NULL) //If the feature is unsupported by the processor it will return NULL
{
for (int i = 0; i < NumberOfRegisters; i++)
titcontext->YmmRegisters[i].Low = Sse[i];
}
if (Avx != NULL) //If the feature is unsupported by the processor it will return NULL
{
for (int i = 0; i < NumberOfRegisters; i++)
titcontext->YmmRegisters[i].High = Avx[i];
}
return true;
}
bool _SetFullContextDataEx(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext, bool AVX_PRIORITY)
{
CONTEXT DBGContext;
memset(&DBGContext, 0, sizeof(DBGContext));
DBGContext.ContextFlags = CONTEXT_ALL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS;
if (!GetThreadContext(hActiveThread, &DBGContext))
return false;
DBGContext.EFlags = (DWORD)titcontext->eflags;
DBGContext.Dr0 = titcontext->dr0;
DBGContext.Dr1 = titcontext->dr1;
DBGContext.Dr2 = titcontext->dr2;
DBGContext.Dr3 = titcontext->dr3;
DBGContext.Dr6 = titcontext->dr6;
DBGContext.Dr7 = titcontext->dr7;
DBGContext.SegGs = titcontext->gs;
DBGContext.SegFs = titcontext->fs;
DBGContext.SegEs = titcontext->es;
DBGContext.SegDs = titcontext->ds;
DBGContext.SegCs = titcontext->cs;
DBGContext.SegSs = titcontext->ss;
#ifdef _WIN64 //x64
DBGContext.Rax = titcontext->cax;
DBGContext.Rbx = titcontext->cbx;
DBGContext.Rcx = titcontext->ccx;
DBGContext.Rdx = titcontext->cdx;
DBGContext.Rdi = titcontext->cdi;
DBGContext.Rsi = titcontext->csi;
DBGContext.Rbp = titcontext->cbp;
DBGContext.Rsp = titcontext->csp;
DBGContext.Rip = titcontext->cip;
DBGContext.R8 = titcontext->r8;
DBGContext.R9 = titcontext->r9;
DBGContext.R10 = titcontext->r10;
DBGContext.R11 = titcontext->r11;
DBGContext.R12 = titcontext->r12;
DBGContext.R13 = titcontext->r13;
DBGContext.R14 = titcontext->r14;
DBGContext.R15 = titcontext->r15;
DBGContext.FltSave.ControlWord = titcontext->x87fpu.ControlWord;
DBGContext.FltSave.StatusWord = titcontext->x87fpu.StatusWord;
DBGContext.FltSave.TagWord = FsaveToFxsaveTagWord(titcontext->x87fpu.TagWord);
DBGContext.FltSave.ErrorSelector = (WORD)titcontext->x87fpu.ErrorSelector;
DBGContext.FltSave.ErrorOffset = titcontext->x87fpu.ErrorOffset;
DBGContext.FltSave.DataSelector = (WORD)titcontext->x87fpu.DataSelector;
DBGContext.FltSave.DataOffset = titcontext->x87fpu.DataOffset;
// Skip titcontext->x87fpu.Cr0NpxState
DBGContext.MxCsr = titcontext->MxCsr;
for(int i = 0; i < 8; i++)
memcpy(& DBGContext.FltSave.FloatRegisters[i], &(titcontext->RegisterArea[i * 10]), 10);
for(int i = 0; i < 16; i++)
memcpy(& (DBGContext.FltSave.XmmRegisters[i]), & (titcontext->XmmRegisters[i]), 16);
#else //x86
DBGContext.Eax = titcontext->cax;
DBGContext.Ebx = titcontext->cbx;
DBGContext.Ecx = titcontext->ccx;
DBGContext.Edx = titcontext->cdx;
DBGContext.Edi = titcontext->cdi;
DBGContext.Esi = titcontext->csi;
DBGContext.Ebp = titcontext->cbp;
DBGContext.Esp = titcontext->csp;
DBGContext.Eip = titcontext->cip;
DBGContext.FloatSave.ControlWord = titcontext->x87fpu.ControlWord;
DBGContext.FloatSave.StatusWord = titcontext->x87fpu.StatusWord;
DBGContext.FloatSave.TagWord = titcontext->x87fpu.TagWord;
DBGContext.FloatSave.ErrorSelector = titcontext->x87fpu.ErrorSelector;
DBGContext.FloatSave.ErrorOffset = titcontext->x87fpu.ErrorOffset;
DBGContext.FloatSave.DataSelector = titcontext->x87fpu.DataSelector;
DBGContext.FloatSave.DataOffset = titcontext->x87fpu.DataOffset;
DBGContext.FloatSave.Cr0NpxState = titcontext->x87fpu.Cr0NpxState;
memcpy(DBGContext.FloatSave.RegisterArea, titcontext->RegisterArea, 80);
// MXCSR ExtendedRegisters[24]
memcpy(& (DBGContext.ExtendedRegisters[24]), & titcontext->MxCsr, sizeof(titcontext->MxCsr));
// for x86 copy the 8 Xmm Registers from ExtendedRegisters[(10+n)*16]; (n is the index of the xmm register) to the XMM register
for(int i = 0; i < 8; i++)
memcpy(& DBGContext.ExtendedRegisters[(10 + i) * 16], &(titcontext->XmmRegisters[i]), 16);
#endif
bool returnf = !!SetThreadContext(hActiveThread, &DBGContext);
if (AVX_PRIORITY)
SetAVXContext(hActiveThread, titcontext);
return returnf;
}
bool _GetFullContextDataEx(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext, bool avx)
{
CONTEXT DBGContext;
memset(&DBGContext, 0, sizeof(CONTEXT));
memset(titcontext, 0, sizeof(TITAN_ENGINE_CONTEXT_t));
DBGContext.ContextFlags = CONTEXT_ALL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS;
if(!GetThreadContext(hActiveThread, &DBGContext))
return false;
titcontext->eflags = DBGContext.EFlags;
titcontext->dr0 = DBGContext.Dr0;
titcontext->dr1 = DBGContext.Dr1;
titcontext->dr2 = DBGContext.Dr2;
titcontext->dr3 = DBGContext.Dr3;
titcontext->dr6 = DBGContext.Dr6;
titcontext->dr7 = DBGContext.Dr7;
titcontext->gs = (unsigned short) DBGContext.SegGs;
titcontext->fs = (unsigned short) DBGContext.SegFs;
titcontext->es = (unsigned short) DBGContext.SegEs;
titcontext->ds = (unsigned short) DBGContext.SegDs;
titcontext->cs = (unsigned short) DBGContext.SegCs;
titcontext->ss = (unsigned short) DBGContext.SegSs;
#ifdef _WIN64 //x64
titcontext->cax = DBGContext.Rax;
titcontext->cbx = DBGContext.Rbx;
titcontext->ccx = DBGContext.Rcx;
titcontext->cdx = DBGContext.Rdx;
titcontext->cdi = DBGContext.Rdi;
titcontext->csi = DBGContext.Rsi;
titcontext->cbp = DBGContext.Rbp;
titcontext->csp = DBGContext.Rsp;
titcontext->cip = DBGContext.Rip;
titcontext->r8 = DBGContext.R8;
titcontext->r9 = DBGContext.R9;
titcontext->r10 = DBGContext.R10;
titcontext->r11 = DBGContext.R11;
titcontext->r12 = DBGContext.R12;
titcontext->r13 = DBGContext.R13;
titcontext->r14 = DBGContext.R14;
titcontext->r15 = DBGContext.R15;
titcontext->x87fpu.ControlWord = DBGContext.FltSave.ControlWord;
titcontext->x87fpu.StatusWord = DBGContext.FltSave.StatusWord;
titcontext->x87fpu.TagWord = FxsaveToFsaveTagWord(DBGContext.FltSave.StatusWord, DBGContext.FltSave.TagWord, (const X87OrMMXRegister*)DBGContext.FltSave.FloatRegisters);
titcontext->x87fpu.ErrorSelector = DBGContext.FltSave.ErrorSelector;
titcontext->x87fpu.ErrorOffset = DBGContext.FltSave.ErrorOffset;
titcontext->x87fpu.DataSelector = DBGContext.FltSave.DataSelector;
titcontext->x87fpu.DataOffset = DBGContext.FltSave.DataOffset;
// Skip titcontext->x87fpu.Cr0NpxState (https://github.com/x64dbg/x64dbg/issues/255)
titcontext->MxCsr = DBGContext.MxCsr;
for(int i = 0; i < 8; i++)
memcpy(&titcontext->RegisterArea[i * 10], &DBGContext.FltSave.FloatRegisters[i], 10);
for(int i = 0; i < 16; i++)
memcpy(&titcontext->XmmRegisters[i], &DBGContext.FltSave.XmmRegisters[i], 16);
#else //x86
titcontext->cax = DBGContext.Eax;
titcontext->cbx = DBGContext.Ebx;
titcontext->ccx = DBGContext.Ecx;
titcontext->cdx = DBGContext.Edx;
titcontext->cdi = DBGContext.Edi;
titcontext->csi = DBGContext.Esi;
titcontext->cbp = DBGContext.Ebp;
titcontext->csp = DBGContext.Esp;
titcontext->cip = DBGContext.Eip;
titcontext->x87fpu.ControlWord = (WORD) DBGContext.FloatSave.ControlWord;
titcontext->x87fpu.StatusWord = (WORD) DBGContext.FloatSave.StatusWord;
titcontext->x87fpu.TagWord = (WORD) DBGContext.FloatSave.TagWord;
titcontext->x87fpu.ErrorSelector = DBGContext.FloatSave.ErrorSelector;
titcontext->x87fpu.ErrorOffset = DBGContext.FloatSave.ErrorOffset;
titcontext->x87fpu.DataSelector = DBGContext.FloatSave.DataSelector;
titcontext->x87fpu.DataOffset = DBGContext.FloatSave.DataOffset;
titcontext->x87fpu.Cr0NpxState = DBGContext.FloatSave.Cr0NpxState;
memcpy(titcontext->RegisterArea, DBGContext.FloatSave.RegisterArea, 80);
// MXCSR ExtendedRegisters[24]
memcpy(& (titcontext->MxCsr), & (DBGContext.ExtendedRegisters[24]), sizeof(titcontext->MxCsr));
// for x86 copy the 8 Xmm Registers from ExtendedRegisters[(10+n)*16]; (n is the index of the xmm register) to the XMM register
for(int i = 0; i < 8; i++)
memcpy(&(titcontext->XmmRegisters[i]), & DBGContext.ExtendedRegisters[(10 + i) * 16], 16);
#endif
if(avx)
GetAVXContext(hActiveThread, titcontext);
return true;
}
bool InitXState()
{
static bool init = false;
if(!init)
{
init = true;
HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
if(kernel32 != NULL)
{
_GetEnabledXStateFeatures = (PGETENABLEDXSTATEFEATURES)GetProcAddress(kernel32, "GetEnabledXStateFeatures");
_InitializeContext = (PINITIALIZECONTEXT)GetProcAddress(kernel32, "InitializeContext");
_GetXStateFeaturesMask = (PGETXSTATEFEATURESMASK)GetProcAddress(kernel32, "GetXStateFeaturesMask");
_LocateXStateFeature = (LOCATEXSTATEFEATURE)GetProcAddress(kernel32, "LocateXStateFeature");
_SetXStateFeaturesMask = (SETXSTATEFEATURESMASK)GetProcAddress(kernel32, "SetXStateFeaturesMask");
}
}
return (_GetEnabledXStateFeatures != NULL &&
_InitializeContext != NULL &&
_GetXStateFeaturesMask != NULL &&
_LocateXStateFeature != NULL &&
_SetXStateFeaturesMask != NULL);
}

View File

@ -0,0 +1,33 @@
#ifndef _GLOBAL_ENGINE_CONTEXT_H
#define _GLOBAL_ENGINE_CONTEXT_H
#include "TitanEngine.h"
#undef CONTEXT_XSTATE
#if defined(_M_X64)
#define CONTEXT_XSTATE (0x00100040)
#else
#define CONTEXT_XSTATE (0x00010040)
#endif
#define XSTATE_AVX (XSTATE_GSSE)
#define XSTATE_MASK_AVX (XSTATE_MASK_GSSE)
typedef DWORD64(WINAPI* PGETENABLEDXSTATEFEATURES)();
typedef BOOL (WINAPI* PINITIALIZECONTEXT)(PVOID Buffer, DWORD ContextFlags, PCONTEXT* Context, PDWORD ContextLength);
typedef BOOL (WINAPI* PGETXSTATEFEATURESMASK)(PCONTEXT Context, PDWORD64 FeatureMask);
typedef PVOID(WINAPI* LOCATEXSTATEFEATURE)(PCONTEXT Context, DWORD FeatureId, PDWORD Length);
typedef BOOL (WINAPI* SETXSTATEFEATURESMASK)(PCONTEXT Context, DWORD64 FeatureMask);
extern PGETENABLEDXSTATEFEATURES _GetEnabledXStateFeatures;
extern PINITIALIZECONTEXT _InitializeContext;
extern PGETXSTATEFEATURESMASK _GetXStateFeaturesMask;
extern LOCATEXSTATEFEATURE _LocateXStateFeature;
extern SETXSTATEFEATURESMASK _SetXStateFeaturesMask;
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);
#endif //_GLOBAL_ENGINE_CONTEXT_H

203
TitanEngineEmulator/Hider.h Normal file
View File

@ -0,0 +1,203 @@
#pragma once
#include "ntdll.h"
#include "PEB.h"
#ifdef _WIN64
#pragma comment(lib, "ntdll_x64.lib")
#else
#pragma comment(lib, "ntdll_x86.lib")
#endif
//Quote from The Ultimate Anti-Debugging Reference by Peter Ferrie
//Flags field exists at offset 0x0C in the heap on the 32-bit versions of Windows NT, Windows 2000, and Windows XP; and at offset 0x40 on the 32-bit versions of Windows Vista and later.
//Flags field exists at offset 0x14 in the heap on the 64-bit versions of Windows XP, and at offset 0x70 in the heap on the 64-bit versions of Windows Vista and later.
//ForceFlags field exists at offset 0x10 in the heap on the 32-bit versions of Windows NT, Windows 2000, and Windows XP; and at offset 0x44 on the 32-bit versions of Windows Vista and later.
//ForceFlags field exists at offset 0x18 in the heap on the 64-bit versions of Windows XP, and at offset 0x74 in the heap on the 64-bit versions of Windows Vista and later.
static bool
IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
DWORDLONG const dwlConditionMask = VerSetConditionMask(
VerSetConditionMask(
VerSetConditionMask(
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
VER_MINORVERSION, VER_GREATER_EQUAL),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
osvi.dwMajorVersion = wMajorVersion;
osvi.dwMinorVersion = wMinorVersion;
osvi.wServicePackMajor = wServicePackMajor;
return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}
static bool
IsWindowsVistaOrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
}
static int getHeapFlagsOffset(bool x64)
{
if (x64) //x64 offsets
{
if (IsWindowsVistaOrGreater())
{
return 0x70;
}
else
{
return 0x14;
}
}
else //x86 offsets
{
if (IsWindowsVistaOrGreater())
{
return 0x40;
}
else
{
return 0x0C;
}
}
}
static int getHeapForceFlagsOffset(bool x64)
{
if (x64) //x64 offsets
{
if (IsWindowsVistaOrGreater())
{
return 0x74;
}
else
{
return 0x18;
}
}
else //x86 offsets
{
if (IsWindowsVistaOrGreater())
{
return 0x44;
}
else
{
return 0x10;
}
}
}
static void* GetPEBLocation_(HANDLE hProcess)
{
ULONG RequiredLen = 0;
void* PebAddress = 0;
PROCESS_BASIC_INFORMATION myProcessBasicInformation[5] = { 0 };
if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, sizeof(PROCESS_BASIC_INFORMATION), &RequiredLen) == 0)
{
PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
}
else
{
if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, RequiredLen, &RequiredLen) == 0)
{
PebAddress = (void*)myProcessBasicInformation->PebBaseAddress;
}
}
return PebAddress;
}
static bool PebPatchHeapFlags(PEB_CURRENT* peb, HANDLE hProcess)
{
#ifdef _WIN64
const auto is_x64 = true;
#else
const auto is_x64 = false;
#endif
std::vector<PVOID> heaps;
heaps.resize(peb->NumberOfHeaps);
if (ReadProcessMemory(hProcess, (PVOID)peb->ProcessHeaps, (PVOID)heaps.data(), heaps.size() * sizeof(PVOID), nullptr) == FALSE)
return false;
std::basic_string<uint8_t> heap;
heap.resize(0x100); // hacky
for (DWORD i = 0; i < peb->NumberOfHeaps; i++)
{
if (ReadProcessMemory(hProcess, heaps[i], (PVOID)heap.data(), heap.size(), nullptr) == FALSE)
return false;
auto flags = (DWORD *)(heap.data() + getHeapFlagsOffset(is_x64));
auto force_flags = (DWORD *)(heap.data() + getHeapForceFlagsOffset(is_x64));
if (i == 0)
{
// Default heap.
*flags &= HEAP_GROWABLE;
}
else
{
// Flags from RtlCreateHeap/HeapCreate.
*flags &= (HEAP_GROWABLE | HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_CREATE_ENABLE_EXECUTE);
}
*force_flags = 0;
if (WriteProcessMemory(hProcess, heaps[i], (PVOID)heap.data(), heap.size(), nullptr) == FALSE)
return false;
}
return true;
}
static bool FixPebInProcess(HANDLE hProcess)
{
PEB_CURRENT myPEB = { 0 };
SIZE_T ueNumberOfBytesRead = 0;
void* heapFlagsAddress = 0;
DWORD heapFlags = 0;
void* heapForceFlagsAddress = 0;
DWORD heapForceFlags = 0;
void* AddressOfPEB = GetPEBLocation(hProcess);
if (!AddressOfPEB)
return false;
if (ReadProcessMemory(hProcess, AddressOfPEB, (void*)&myPEB, sizeof(PEB_CURRENT), &ueNumberOfBytesRead))
{
myPEB.BeingDebugged = FALSE;
myPEB.NtGlobalFlag &= ~0x70;
#ifdef _WIN64
heapFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapFlagsOffset(true));
heapForceFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapForceFlagsOffset(true));
#else
heapFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapFlagsOffset(false));
heapForceFlagsAddress = (void*)((LONG_PTR)myPEB.ProcessHeap + getHeapForceFlagsOffset(false));
#endif //_WIN64
ReadProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0);
ReadProcessMemory(hProcess, heapForceFlagsAddress, &heapForceFlags, sizeof(DWORD), 0);
heapFlags &= HEAP_GROWABLE;
heapForceFlags = 0;
WriteProcessMemory(hProcess, heapFlagsAddress, &heapFlags, sizeof(DWORD), 0);
WriteProcessMemory(hProcess, heapForceFlagsAddress, &heapForceFlags, sizeof(DWORD), 0);
PebPatchHeapFlags(&myPEB, hProcess);
if (WriteProcessMemory(hProcess, AddressOfPEB, (void*)&myPEB, sizeof(PEB_CURRENT), &ueNumberOfBytesRead))
{
return true;
}
}
return false;
}

Binary file not shown.

View File

@ -238,3 +238,14 @@ __declspec(dllexport) void TITCALL StepInto(LPVOID traceCallBack)
{
emu.StepInto(traceCallBack);
}
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
)
{
if (fdwReason == DLL_PROCESS_ATTACH)
emu.engineHandle = hinstDLL;
return TRUE;
}

View File

@ -122,7 +122,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -139,7 +139,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -150,14 +150,21 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Global.Engine.Context.cpp" />
<ClCompile Include="TitanEngineEmulator.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Emulator.h" />
<ClInclude Include="FileMap.h" />
<ClInclude Include="Global.Engine.Context.h" />
<ClInclude Include="Hider.h" />
<ClInclude Include="PEB.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="TitanEngine.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="TitanEngine.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -9,11 +9,17 @@
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{042de20e-5da8-4247-81ff-f0b401bb7732}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="TitanEngineEmulator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Global.Engine.Context.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="TitanEngine.h">
@ -28,5 +34,19 @@
<ClInclude Include="PEB.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Global.Engine.Context.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Hider.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="TitanEngine.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,15 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by TitanEngine.rc
//
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 106
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif