This commit is contained in:
ζeh Matt 2020-10-10 11:56:07 +03:00 committed by GitHub
commit 611ff80162
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 758 additions and 20 deletions

View File

@ -1,5 +1,6 @@
#include "Debugger.h"
#include "Debugger.Thread.Registers.h"
#include "Emulation.h"
namespace GleeBug
{
@ -24,12 +25,37 @@ namespace GleeBug
return;
}
bool allowEmulation = true;
bool inEmulation = false;
while (!mBreakDebugger)
{
//wait for a debug event
mIsRunning = true;
if (!MyWaitForDebugEvent(&mDebugEvent, INFINITE))
break;
// We go over all active processes and see if any emulator has an active event
// if thats the case process the emulated event first.
if (inEmulation)
{
inEmulation = false;
for (auto&& process : mProcesses)
{
if (process.second->emulator.WaitForEvent(mDebugEvent))
{
inEmulation = true;
break;
}
}
}
// Emulated events have priority over normal debug events.
if (!inEmulation)
{
if (!MyWaitForDebugEvent(&mDebugEvent, INFINITE))
break;
}
mIsRunning = false;
//set default continue status
@ -117,8 +143,18 @@ namespace GleeBug
}
//continue the debug event
if (!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, mContinueStatus))
break;
if (allowEmulation && mThread != nullptr && mThread->isSingleStepping)
{
auto& emulator = mProcess->emulator;
inEmulation = emulator.Emulate(mThread);
}
if (inEmulation == false)
{
if (!ContinueDebugEvent(mDebugEvent.dwProcessId, mDebugEvent.dwThreadId, mContinueStatus))
break;
}
if (mDetach || mDetachAndBreak)
{
@ -133,4 +169,4 @@ namespace GleeBug
mProcess = nullptr;
mIsDebugging = false;
}
};
};

View File

@ -225,7 +225,6 @@ namespace GleeBug
bool Process::SetNewPageProtection(ptr page, MemoryBreakpointData & data, MemoryType type)
{
DPRINTF();
//TODO: handle PAGE_NOACCESS and such correctly (since it cannot be combined with PAGE_GUARD)
auto found = memoryBreakpointPages.find(page);
@ -268,7 +267,6 @@ namespace GleeBug
bool Process::SetMemoryBreakpoint(ptr address, ptr size, MemoryType type, bool singleshoot)
{
DPRINTF();
dprintf("SetMemoryBreakpoint(%p, %p, %d, %d)\n", address, size, type, singleshoot);
//TODO: error reporting
@ -421,4 +419,4 @@ namespace GleeBug
return false;
}
}
};
};

View File

@ -15,7 +15,8 @@ namespace GleeBug
createProcessInfo(createProcessInfo),
thread(nullptr),
systemBreakpoint(false),
permanentDep(false)
permanentDep(false),
emulator(this)
{
for (int i = 0; i < HWBP_COUNT; i++)
hardwareBreakpoints[i].internal.hardware.enabled = false;
@ -58,4 +59,4 @@ namespace GleeBug
}
thread->StepInto(cbStep);
}
};
};

View File

@ -6,6 +6,7 @@
#include "Debugger.Dll.h"
#include "Debugger.Breakpoint.h"
#include "Static.Pattern.h"
#include "Emulation.h"
namespace GleeBug
{
@ -31,6 +32,7 @@ namespace GleeBug
BreakpointInfo hardwareBreakpoints[4];
MemoryBreakpointSet memoryBreakpointRanges;
MemoryBreakpointMap memoryBreakpointPages;
X86Emulator emulator;
/**
\brief Constructor.
@ -399,4 +401,4 @@ namespace GleeBug
};
};
#endif //DEBUGGER_PROCESS_H
#endif //DEBUGGER_PROCESS_H

View File

@ -52,4 +52,4 @@ namespace GleeBug
{
return ResumeThread(hThread) != -1;
}
};
};

183
GleeBug/Emulation.Helpers.h Normal file
View File

@ -0,0 +1,183 @@
#ifndef EMULATIONHELPERS_H
#define EMULATIONHELPERS_H
#include <assert.h>
namespace GleeBug
{
template<typename T>
inline T getRegisterValue(const ZydisRegister reg, Registers& regs)
{
switch (reg)
{
// 64 Bit.
case ZYDIS_REGISTER_RAX:
return (T)regs.Rax.Get();
case ZYDIS_REGISTER_RBX:
return (T)regs.Rbx.Get();
case ZYDIS_REGISTER_RCX:
return (T)regs.Rcx.Get();
case ZYDIS_REGISTER_RDX:
return (T)regs.Rdx.Get();
case ZYDIS_REGISTER_RBP:
return (T)regs.Rbp.Get();
case ZYDIS_REGISTER_RSP:
return (T)regs.Rsp.Get();
case ZYDIS_REGISTER_RSI:
return (T)regs.Rsi.Get();
case ZYDIS_REGISTER_RDI:
return (T)regs.Rdi.Get();
case ZYDIS_REGISTER_R8:
return (T)regs.R8.Get();
case ZYDIS_REGISTER_R9:
return (T)regs.R9.Get();
case ZYDIS_REGISTER_R10:
return (T)regs.R10.Get();
case ZYDIS_REGISTER_R11:
return (T)regs.R11.Get();
case ZYDIS_REGISTER_R12:
return (T)regs.R12.Get();
case ZYDIS_REGISTER_R13:
return (T)regs.R13.Get();
case ZYDIS_REGISTER_R14:
return (T)regs.R14.Get();
// 32 bit
case ZYDIS_REGISTER_EAX:
return (T)regs.Eax.Get();
case ZYDIS_REGISTER_EBX:
return (T)regs.Ebx.Get();
case ZYDIS_REGISTER_ECX:
return (T)regs.Ecx.Get();
case ZYDIS_REGISTER_EDX:
return (T)regs.Edx.Get();
case ZYDIS_REGISTER_EBP:
return (T)regs.Ebp.Get();
case ZYDIS_REGISTER_ESP:
return (T)regs.Esp.Get();
case ZYDIS_REGISTER_ESI:
return (T)regs.Esi.Get();
case ZYDIS_REGISTER_EDI:
return (T)regs.Edi.Get();
case ZYDIS_REGISTER_R8D:
return (T)regs.R8d.Get();
case ZYDIS_REGISTER_R9D:
return (T)regs.R9d.Get();
case ZYDIS_REGISTER_R10D:
return (T)regs.R10d.Get();
case ZYDIS_REGISTER_R11D:
return (T)regs.R11d.Get();
case ZYDIS_REGISTER_R12D:
return (T)regs.R12d.Get();
case ZYDIS_REGISTER_R13D:
return (T)regs.R13d.Get();
case ZYDIS_REGISTER_R14D:
return (T)regs.R14d.Get();
default:
assert(false);
}
}
template<typename T>
inline void setRegisterValue(const ZydisRegister reg, Registers& regs, T val)
{
switch (reg)
{
// 64 bit.
case ZYDIS_REGISTER_RAX:
return regs.Rax.Set(val);
case ZYDIS_REGISTER_RBX:
return regs.Rbx.Set(val);
case ZYDIS_REGISTER_RCX:
return regs.Rcx.Set(val);
case ZYDIS_REGISTER_RDX:
return regs.Rdx.Set(val);
case ZYDIS_REGISTER_RBP:
return regs.Rbp.Set(val);
case ZYDIS_REGISTER_RSP:
return regs.Rsp.Set(val);
case ZYDIS_REGISTER_RSI:
return regs.Rsi.Set(val);
case ZYDIS_REGISTER_RDI:
return regs.Rdi.Set(val);
case ZYDIS_REGISTER_R8:
return regs.R8.Set(val);
case ZYDIS_REGISTER_R9:
return regs.R9.Set(val);
case ZYDIS_REGISTER_R10:
return regs.R10.Set(val);
case ZYDIS_REGISTER_R11:
return regs.R11.Set(val);
case ZYDIS_REGISTER_R12:
return regs.R12.Set(val);
case ZYDIS_REGISTER_R13:
return regs.R13.Set(val);
case ZYDIS_REGISTER_R14:
return regs.R14.Set(val);
// 32 bit
case ZYDIS_REGISTER_EAX:
return regs.Eax.Set(val);
case ZYDIS_REGISTER_EBX:
return regs.Ebx.Set(val);
case ZYDIS_REGISTER_ECX:
return regs.Ecx.Set(val);
case ZYDIS_REGISTER_EDX:
return regs.Edx.Set(val);
case ZYDIS_REGISTER_EBP:
return regs.Ebp.Set(val);
case ZYDIS_REGISTER_ESP:
return regs.Esp.Set(val);
case ZYDIS_REGISTER_ESI:
return regs.Esi.Set(val);
case ZYDIS_REGISTER_EDI:
return regs.Edi.Set(val);
case ZYDIS_REGISTER_R8D:
return regs.R8d.Set(val);
case ZYDIS_REGISTER_R9D:
return regs.R9d.Set(val);
case ZYDIS_REGISTER_R10D:
return regs.R10d.Set(val);
case ZYDIS_REGISTER_R11D:
return regs.R11d.Set(val);
case ZYDIS_REGISTER_R12D:
return regs.R12d.Set(val);
case ZYDIS_REGISTER_R13D:
return regs.R13d.Set(val);
case ZYDIS_REGISTER_R14D:
return regs.R14d.Set(val);
default:
assert(false);
}
}
inline void setCondFlag(uint32_t& flags, int64_t cond, uint32_t f)
{
if(!!cond)
flags |= f;
}
inline bool isParity(uint32_t v)
{
v ^= v >> 1;
v ^= v >> 2;
v = (v & 0x11111111U) * 0x11111111U;
return (v >> 28) & 1;
}
inline bool isParity(uint64_t v)
{
v ^= v >> 1;
v ^= v >> 2;
v = (v & 0x1111111111111111UL) * 0x1111111111111111UL;
return (v >> 60) & 1;
}
template<typename T>
inline T xor2(T x)
{
return (((x) ^ ((x) >> 1)) & 0x1);
}
} // GleeBug
#endif // EMULATIONHELPERS_H

View File

@ -0,0 +1,266 @@
#include "Emulation.Instructions.h"
#include "Debugger.Thread.Registers.h"
#include "Emulation.Helpers.h"
#include <limits>
#include <stdint.h>
#include <unordered_map>
namespace GleeBug {
namespace Emulation {
enum EFLAGS
{
EFL_CF = (1 << 0),
EFL_PF = (1 << 2),
EFL_AF = (1 << 4),
EFL_ZF = (1 << 6),
EFL_SF = (1 << 7),
EFL_DF = (1 << 10),
EFL_OF = (1 << 11),
};
inline const size_t InstructionDataHash(size_t state, const void* data, const size_t len)
{
const uint8_t *buf = reinterpret_cast<const uint8_t*>(data);
for (size_t i = 0; i < len; ++buf, ++i)
{
state ^= ((i & 1) == 0) ? ((state << 7) ^ (*buf) * (state >> 3)) :
(~((state << 11) + ((*buf) ^ (state >> 5))));
}
return state;
}
template<typename T>
inline const size_t InstructionDataHash(const T& data)
{
return InstructionDataHash(0x811c9dc5, &data, sizeof(T));
}
inline const size_t InstructionOperandHash(size_t N, uint16_t TYPE)
{
return InstructionDataHash(InstructionDataHash(N));
}
template<size_t N, uint16_t TYPE>
struct OpSig
{
static constexpr size_t Hash() noexcept
{
return InstructionOperandHash(N, TYPE);
}
static bool Matches(const ZydisInstructionInfo& instr, const ZydisOperandInfo& op)
{
if(op.type != TYPE)
return false;
if(op.size != N)
return false;
return true;
}
};
using OpNone = OpSig<0, ZYDIS_OPERAND_TYPE_UNUSED>;
template<uint16 MNEMONIC,
typename OP0 = OpNone,
typename OP1 = OpNone,
typename OP2 = OpNone,
typename OP3 = OpNone,
typename OP4 = OpNone>
struct InstrSig : X86Instruction
{
static constexpr size_t Hash() noexcept
{
return InstructionDataHash(InstructionDataHash(N));
}
virtual uint16_t GetMnemonic() const
{
return MNEMONIC;
}
virtual bool Matches(const ZydisInstructionInfo& info) const
{
if(info.mnemonic != MNEMONIC)
return false;
if (!OP0::Matches(info, info.operands[0]))
return false;
if (!OP1::Matches(info, info.operands[1]))
return false;
if (!OP2::Matches(info, info.operands[2]))
return false;
if (!OP3::Matches(info, info.operands[3]))
return false;
if (!OP4::Matches(info, info.operands[4]))
return false;
return true;
}
};
static std::vector<std::vector<X86Instruction*>> _registeredInstructions;
template<typename T>
struct X86InstructionRegistrator
{
T inst;
X86InstructionRegistrator()
{
uint16_t groupId = inst.GetMnemonic();
if (groupId >= _registeredInstructions.size())
{
_registeredInstructions.resize(groupId + 1);
}
_registeredInstructions[groupId].push_back(&inst);
}
};
#define REGISTER_X86_INSTRUCTION(instrCls) static X86InstructionRegistrator<##instrCls##> __##instrCls##__
template<typename T>
struct SubImpl
{
static T Execute(T val1, T val2, Registers& regs, uint32_t flagsOut)
{
constexpr int NumBits = sizeof(T) * 8;
constexpr T SignMask = T(1) << (NumBits - 1);
constexpr T InvMask = ~T(0);
T res = val1 - val2;
flagsOut = 0;
setCondFlag(flagsOut, res & SignMask, EFL_SF);
setCondFlag(flagsOut, (res & InvMask) == 0, EFL_ZF);
setCondFlag(flagsOut, isParity(res & 0xFF), EFL_PF);
T bc = (res & (~val1 | val2)) | (~val1 & val2);
setCondFlag(flagsOut, bc & SignMask, EFL_CF);
setCondFlag(flagsOut, xor2(bc >> (NumBits - 2)), EFL_OF);
setCondFlag(flagsOut, bc & 0x08, EFL_AF);
return res;
}
};
struct Instr_MovR32R32 : InstrSig< ZYDIS_MNEMONIC_MOV, OpSig<32, ZYDIS_OPERAND_TYPE_REGISTER>, OpSig<32, ZYDIS_OPERAND_TYPE_REGISTER> >
{
virtual bool Execute(const ZydisInstructionInfo& info, X86Context& ctx) const override
{
int32_t val1 = getRegisterValue<int32_t>(info.operands[1].reg, ctx.regs);
setRegisterValue(info.operands[0].reg, ctx.regs, val1);
return true;
}
};
struct Instr_MovR32I32 : InstrSig< ZYDIS_MNEMONIC_MOV, OpSig<32, ZYDIS_OPERAND_TYPE_REGISTER>, OpSig<32, ZYDIS_OPERAND_TYPE_IMMEDIATE> >
{
virtual bool Execute(const ZydisInstructionInfo& info, X86Context& ctx) const override
{
int32_t val1 = info.operands[1].imm.value.sdword;
setRegisterValue(info.operands[0].reg, ctx.regs, val1);
return true;
}
};
struct Instr_MovR64R64 : InstrSig< ZYDIS_MNEMONIC_MOV, OpSig<64, ZYDIS_OPERAND_TYPE_REGISTER>, OpSig<64, ZYDIS_OPERAND_TYPE_REGISTER> >
{
virtual bool Execute(const ZydisInstructionInfo& info, X86Context& ctx) const override
{
int64_t val2 = getRegisterValue<int64_t>(info.operands[1].reg, ctx.regs);
setRegisterValue(info.operands[0].reg, ctx.regs, val2);
return true;
}
};
struct Instr_Sub32 : InstrSig< ZYDIS_MNEMONIC_SUB, OpSig<32, ZYDIS_OPERAND_TYPE_REGISTER>, OpSig<32, ZYDIS_OPERAND_TYPE_IMMEDIATE> >
{
virtual bool Execute(const ZydisInstructionInfo& info, X86Context& ctx) const override
{
// Value is sign extended.
int32_t val1 = getRegisterValue<int32_t>(info.operands[0].reg, ctx.regs);
int32_t val2 = info.operands[1].imm.value.sdword;
uint32_t flagsOut = 0;
int32_t res = SubImpl<uint32_t>::Execute(val1, val2, ctx.regs, flagsOut);
setRegisterValue(info.operands[0].reg, ctx.regs, res);
ctx.regs.Eflags.Set(ctx.regs.Eflags.Get() | flagsOut);
return true;
}
};
struct Instr_SubR64I64 : InstrSig< ZYDIS_MNEMONIC_SUB, OpSig<64, ZYDIS_OPERAND_TYPE_REGISTER>, OpSig<64, ZYDIS_OPERAND_TYPE_IMMEDIATE> >
{
virtual bool Execute(const ZydisInstructionInfo& info, X86Context& ctx) const override
{
// Value is sign extended.
int64_t val1 = getRegisterValue<int64_t>(info.operands[0].reg, ctx.regs);
int64_t val2 = info.operands[1].imm.value.sqword;
uint32_t flagsOut = 0;
int64_t res = SubImpl<uint64_t>::Execute(val1, val2, ctx.regs, flagsOut);
setRegisterValue(info.operands[0].reg, ctx.regs, res);
ctx.regs.Eflags.Set(ctx.regs.Eflags.Get() | flagsOut);
return true;
}
};
struct Instr_SubR64I32 : InstrSig< ZYDIS_MNEMONIC_SUB, OpSig<64, ZYDIS_OPERAND_TYPE_REGISTER>, OpSig<32, ZYDIS_OPERAND_TYPE_IMMEDIATE> >
{
virtual bool Execute(const ZydisInstructionInfo& info, X86Context& ctx) const override
{
// Value is sign extended.
int64_t val1 = getRegisterValue<int64_t>(info.operands[0].reg, ctx.regs);
int64_t val2 = info.operands[1].imm.value.sdword;
uint32_t flagsOut = 0;
int64_t res = SubImpl<uint64_t>::Execute(val1, val2, ctx.regs, flagsOut);
setRegisterValue(info.operands[0].reg, ctx.regs, res);
ctx.regs.Eflags.Set(ctx.regs.Eflags.Get() | flagsOut);
return true;
}
};
static bool _initialzed = false;
const X86Instruction* LookupInstruction(const ZydisInstructionInfo& info)
{
if (_initialzed == false)
{
REGISTER_X86_INSTRUCTION(Instr_MovR32R32);
REGISTER_X86_INSTRUCTION(Instr_MovR32I32);
REGISTER_X86_INSTRUCTION(Instr_MovR64R64);
REGISTER_X86_INSTRUCTION(Instr_Sub32);
REGISTER_X86_INSTRUCTION(Instr_SubR64I64);
REGISTER_X86_INSTRUCTION(Instr_SubR64I32);
_initialzed = true;
}
if(info.mnemonic >= _registeredInstructions.size())
return nullptr;
auto& group = _registeredInstructions[info.mnemonic];
if(group.empty())
return nullptr;
for (X86Instruction *instr : group)
{
if (instr->Matches(info))
return instr;
}
return nullptr;
}
}
}

View File

@ -0,0 +1,41 @@
#ifndef EMULATIONINSTRUCTIONS_H
#define EMULATIONINSTRUCTIONS_H
#include "Debugger.Global.h"
#include "Debugger.Process.h"
#include "Debugger.Breakpoint.h"
#include "Debugger.Thread.h"
#include "Debugger.Thread.Registers.h"
#define ZYDIS_EXPORTS
#define ZYDIS_ENABLE_FEATURE_IMPLICITLY_USED_REGISTERS
#define ZYDIS_ENABLE_FEATURE_AFFECTED_FLAGS
#include <Zydis/Zydis.h>
namespace GleeBug {
namespace Emulation {
struct X86Context
{
Registers& regs;
Thread& thread;
explicit X86Context(Registers& inRegs, Thread& inThread) : regs(inRegs),
thread(inThread)
{
}
};
struct X86Instruction
{
virtual uint16_t GetMnemonic() const = 0;
virtual bool Matches(const ZydisInstructionInfo& info) const = 0;
virtual bool Execute(const ZydisInstructionInfo& info, X86Context& ctx) const = 0;
};
const X86Instruction* LookupInstruction(const ZydisInstructionInfo& info);
} // Emulation
} // GleeBug
#endif // EMULATIONINSTRUCTIONS_H

148
GleeBug/Emulation.cpp Normal file
View File

@ -0,0 +1,148 @@
#include "GleeBug.h"
#include "Emulation.h"
#include "Emulation.Instructions.h"
#include "Debugger.Thread.Registers.h"
#include "Debugger.Thread.Registers.Flag.h"
#define ZYDIS_EXPORTS
#define ZYDIS_ENABLE_FEATURE_IMPLICITLY_USED_REGISTERS
#define ZYDIS_ENABLE_FEATURE_AFFECTED_FLAGS
#include <Zydis/Zydis.h>
#include <Zydis/Decoder.h>
#include <Zydis/Formatter.h>
namespace GleeBug {
#ifdef _WIN64
static constexpr ZydisOperatingMode ZYDIS_OPERATING_MODE = ZYDIS_OPERATING_MODE_64BIT;
#else
static constexpr ZydisOperatingMode ZYDIS_OPERATING_MODE = ZYDIS_OPERATING_MODE_32BIT;
#endif
X86Emulator::X86Emulator(Process* process)
: _process(process)
{
}
bool X86Emulator::IsActive() const
{
return _active;
}
bool X86Emulator::WaitForEvent(DEBUG_EVENT& debugEvent)
{
if(_hasEvent == false)
return false;
debugEvent = _currentEvent;
_hasEvent = false;
return true;
}
bool GenerateDebugEvent(const ZydisInstructionInfo& instrInfo, Emulation::X86Context& ctx, DEBUG_EVENT& debugEvent)
{
if (ctx.regs.TrapFlag)
{
debugEvent.dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
auto& exData = debugEvent.u.Exception;
exData.ExceptionRecord.ExceptionCode = STATUS_SINGLE_STEP;
exData.ExceptionRecord.ExceptionAddress = (PVOID)ctx.regs.Gip.Get();
exData.ExceptionRecord.NumberParameters = 0;
exData.dwFirstChance = 1;
return true;
}
// TODO: Deal with breakpoint emulation.
return false;
}
bool X86Emulator::Emulate(Thread* thread)
{
SetActiveThread(thread);
uint8_t instrBytes[16];
ptr bytesRead = 0;
if (!_process->MemRead(_registers->Gip.Get(), instrBytes, sizeof(instrBytes), &bytesRead))
{
Flush();
return false;
}
const ptr curIP = _registers->Gip.Get();
ZydisInstructionInfo instrInfo;
if (ZYDIS_SUCCESS(ZydisDecode(ZYDIS_OPERATING_MODE, instrBytes, 16, curIP, &instrInfo)))
{
#ifdef _DEBUG
ZydisInstructionFormatter formatter;
ZydisFormatterInitInstructionFormatter(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
char decodedInstr[128];
ZydisFormatterFormatInstruction(&formatter, &instrInfo, decodedInstr, sizeof(decodedInstr));
#endif
const Emulation::X86Instruction *instr = Emulation::LookupInstruction(instrInfo);
if (instr == nullptr)
{
Flush();
return false;
}
bool isSingleStepping = _activeThread->isInternalStepping || _activeThread->isSingleStepping;
Emulation::X86Context ctx(*_registers, *_activeThread);
if (instr->Execute(instrInfo, ctx))
{
_registers->Gip.Set(curIP + instrInfo.length);
}
//dprintf("Stepped with emulation at %p\n", curIP);
_currentEvent.dwProcessId = _process->dwProcessId;
_currentEvent.dwThreadId = _activeThread->dwThreadId;
if (GenerateDebugEvent(instrInfo, ctx, _currentEvent))
{
if (isSingleStepping)
{
ctx.regs.TrapFlag = false;
}
_hasEvent = true;
Flush();
}
}
else
{
Flush();
return false;
}
return true;
}
void X86Emulator::Flush()
{
if (_registers != nullptr)
{
delete _registers;
_registers = nullptr;
}
_activeThread = nullptr;
}
void X86Emulator::SetActiveThread(Thread *thread)
{
if (_activeThread != thread)
{
// Commit current state if we change threads between.
Flush();
_registers = new Registers(thread->hThread, CONTEXT_CONTROL | CONTEXT_DEBUG_REGISTERS | CONTEXT_INTEGER);
_activeThread = thread;
}
}
}

39
GleeBug/Emulation.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef EMULATION_H
#define EMULATION_H
#include "Debugger.Global.h"
#include "Debugger.Breakpoint.h"
#include "Debugger.Thread.h"
#include "Debugger.Thread.Registers.h"
#include <deque>
namespace GleeBug
{
class Process;
class X86Emulator
{
bool _active = false;
Thread *_activeThread = nullptr;
Registers* _registers = nullptr;
Process* _process = nullptr;
bool _hasEvent = false;
DEBUG_EVENT _currentEvent{};
public:
X86Emulator(Process* process);
bool IsActive() const;
bool WaitForEvent(DEBUG_EVENT& debugEvent);
bool Emulate(Thread* thread);
void Flush();
private:
void SetActiveThread(Thread *thread);
};
} // GleeBug
#endif // EMULATION_H

View File

@ -25,10 +25,14 @@
#define X64DBG_MOD L"x32dbg.dll"
#endif //_WIN64
#define DPRINTF() \
static auto dprintf = (int(*)(const char* format, ...))GetProcAddress(GetModuleHandleW(X64DBG_MOD), "_plugin_logprintf"); \
if(!dprintf) \
dprintf = printf
template<typename... Args>
inline void dprintf(const char *fmt, Args... args)
{
static auto fn = (int(*)(const char* format, ...))GetProcAddress(GetModuleHandleW(X64DBG_MOD), "_plugin_logprintf");
if (!fn)
fn = printf;
fn(fmt, args...);
}
#ifdef _WIN64
#define GleeArchValue(x32value, x64value) x64value
@ -72,4 +76,4 @@ namespace GleeBug
};
}
#endif //GLEEBUG_H
#endif //GLEEBUG_H

View File

@ -167,6 +167,8 @@
<ClCompile Include="Debugger.Thread.HardwareBreakpoint.cpp" />
<ClCompile Include="Debugger.Thread.Registers.cpp" />
<ClCompile Include="Debugger.Thread.Registers.GetSet.cpp" />
<ClCompile Include="Emulation.cpp" />
<ClCompile Include="Emulation.Instructions.cpp" />
<ClCompile Include="Static.BufferFile.cpp" />
<ClCompile Include="Static.File.cpp" />
<ClCompile Include="Static.Pattern.cpp" />
@ -194,6 +196,9 @@
<ClInclude Include="Debugger.Thread.Registers.Flag.h" />
<ClInclude Include="Debugger.Thread.Registers.h" />
<ClInclude Include="Debugger.Thread.Registers.Register.h" />
<ClInclude Include="Emulation.h" />
<ClInclude Include="Emulation.Helpers.h" />
<ClInclude Include="Emulation.Instructions.h" />
<ClInclude Include="GleeBug.h" />
<ClInclude Include="oprintf.h" />
<ClInclude Include="Static.BufferFile.h" />

View File

@ -104,6 +104,12 @@
<ClCompile Include="zyan-disassembler-engine\src\Zydis.c">
<Filter>Source Files\Zydis</Filter>
</ClCompile>
<ClCompile Include="Emulation.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Emulation.Instructions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Debugger.h">
@ -193,6 +199,15 @@
<ClInclude Include="oprintf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Emulation.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Emulation.Instructions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Emulation.Helpers.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="zyan-disassembler-engine\include\Zydis\Internal\GeneratedTypes.inc">

View File

@ -18,7 +18,7 @@
using namespace GleeBug;
class Emulator : public Debugger
class TitanEngineEmulator : public Debugger
{
public:
HINSTANCE engineHandle;

View File

@ -1,7 +1,7 @@
#include "ntdll.h"
#include "Emulator.h"
Emulator emu;
TitanEngineEmulator emu;
//Debugger basics
__declspec(dllexport) void* TITCALL InitDebugW(const wchar_t* szFileName, const wchar_t* szCommandLine, const wchar_t* szCurrentFolder)
@ -286,4 +286,4 @@ BOOL WINAPI DllMain(
if (fdwReason == DLL_PROCESS_ATTACH)
emu.engineHandle = hinstDLL;
return TRUE;
}
}