distorm starts to work

This commit is contained in:
PatrickvL 2017-01-09 18:27:32 +01:00
parent a6ec272604
commit 5acc167a07
3 changed files with 294 additions and 158 deletions

Binary file not shown.

View File

@ -145,83 +145,13 @@ extern "C" CXBXKRNL_API void NTAPI EmuWarning(const char *szWarningMessage, ...)
}
#endif
// exception handler
extern int EmuException(LPEXCEPTION_POINTERS e)
{
g_bEmuException = true;
// notify user
{
char buffer[256];
if(e->ExceptionRecord->ExceptionCode == 0x80000003)
void EmuExceptionPrintDebugInformation(LPEXCEPTION_POINTERS e, bool IsBreakpointException)
{
// print debug information
{
if (IsBreakpointException)
printf("EmuMain (0x%X): Recieved Breakpoint Exception (int 3)\n", GetCurrentThreadId());
printf("\n"
" EIP := 0x%.08X EFL := 0x%.08X\n"
" EAX := 0x%.08X EBX := 0x%.08X ECX := 0x%.08X EDX := 0x%.08X\n"
" ESI := 0x%.08X EDI := 0x%.08X ESP := 0x%.08X EBP := 0x%.08X\n"
" CR2 := 0x%.08X\n"
"\n",
e->ContextRecord->Eip, e->ContextRecord->EFlags,
e->ContextRecord->Eax, e->ContextRecord->Ebx, e->ContextRecord->Ecx, e->ContextRecord->Edx,
e->ContextRecord->Esi, e->ContextRecord->Edi, e->ContextRecord->Esp, e->ContextRecord->Ebp,
e->ContextRecord->Dr2);
#ifdef _DEBUG
CONTEXT Context = *(e->ContextRecord);
EmuPrintStackTrace(&Context);
#endif
}
fflush(stdout);
sprintf(buffer,
"Recieved Breakpoint Exception (int 3) @ EIP := 0x%.08X\n"
"\n"
" Press Abort to terminate emulation.\n"
" Press Retry to debug.\n"
" Press Ignore to continue emulation.",
e->ContextRecord->Eip);
e->ContextRecord->Eip += 1;
int ret = MessageBox(g_hEmuWindow, buffer, "Cxbx-Reloaded", MB_ICONSTOP | MB_ABORTRETRYIGNORE);
if(ret == IDABORT)
{
printf("EmuMain (0x%X): Aborting Emulation\n", GetCurrentThreadId());
fflush(stdout);
if(CxbxKrnl_hEmuParent != NULL)
SendMessage(CxbxKrnl_hEmuParent, WM_PARENTNOTIFY, WM_DESTROY, 0);
ExitProcess(1);
}
else if(ret == IDIGNORE)
{
printf("EmuMain (0x%X): Ignored Breakpoint Exception\n", GetCurrentThreadId());
g_bEmuException = false;
return EXCEPTION_CONTINUE_EXECUTION;
}
}
else
{
// Pass the exception to our X86 implementation, to try and execute the failing instruction
if (EmuX86_DecodeException(e))
{
g_bEmuException = false;
return EXCEPTION_CONTINUE_EXECUTION;
}
// print debug information
{
printf("EmuMain (0x%X): Recieved Exception (Code := 0x%.08X)\n", GetCurrentThreadId(), e->ExceptionRecord->ExceptionCode);
printf("\n"
@ -242,15 +172,9 @@ extern int EmuException(LPEXCEPTION_POINTERS e)
}
fflush(stdout);
}
sprintf(buffer,
"Recieved Exception Code 0x%.08X @ EIP := 0x%.08X\n"
"\n"
" Press \"OK\" to terminate emulation.\n"
" Press \"Cancel\" to debug.",
e->ExceptionRecord->ExceptionCode, e->ContextRecord->Eip);
if(MessageBox(g_hEmuWindow, buffer, "Cxbx-Reloaded", MB_ICONSTOP | MB_OKCANCEL) == IDOK)
void EmuExceptionExitProcess()
{
printf("EmuMain (0x%X): Aborting Emulation\n", GetCurrentThreadId());
fflush(stdout);
@ -260,11 +184,86 @@ extern int EmuException(LPEXCEPTION_POINTERS e)
ExitProcess(1);
}
bool EmuExceptionBreakpointAsk(LPEXCEPTION_POINTERS e)
{
EmuExceptionPrintDebugInformation(e, /*IsBreakpointException=*/true);
char buffer[256];
sprintf(buffer,
"Recieved Breakpoint Exception (int 3) @ EIP := 0x%.08X\n"
"\n"
" Press Abort to terminate emulation.\n"
" Press Retry to debug.\n"
" Press Ignore to continue emulation.",
e->ContextRecord->Eip);
int ret = MessageBox(g_hEmuWindow, buffer, "Cxbx-Reloaded", MB_ICONSTOP | MB_ABORTRETRYIGNORE);
if (ret == IDABORT)
{
EmuExceptionExitProcess();
}
else if (ret == IDIGNORE)
{
printf("EmuMain (0x%X): Ignored Breakpoint Exception\n", GetCurrentThreadId());
fflush(stdout);
e->ContextRecord->Eip += 1; // TODO : Skip actual instruction size bytes
return true;
}
return false;
}
void EmuExceptionNonBreakpointUnhandledShow(LPEXCEPTION_POINTERS e)
{
EmuExceptionPrintDebugInformation(e, /*IsBreakpointException=*/false);
char buffer[256];
sprintf(buffer,
"Recieved Exception Code 0x%.08X @ EIP := 0x%.08X\n"
"\n"
" Press \"OK\" to terminate emulation.\n"
" Press \"Cancel\" to debug.",
e->ExceptionRecord->ExceptionCode, e->ContextRecord->Eip);
if (MessageBox(g_hEmuWindow, buffer, "Cxbx-Reloaded", MB_ICONSTOP | MB_OKCANCEL) == IDOK)
{
EmuExceptionExitProcess();
}
}
// exception handler
extern int EmuException(LPEXCEPTION_POINTERS e)
{
g_bEmuException = true;
if (e->ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
{
// notify user
if (EmuExceptionBreakpointAsk(e))
{
// We're allowed to continue :
g_bEmuException = false;
return EXCEPTION_CONTINUE_EXECUTION;
}
}
else
{
// Pass the exception to our X86 implementation, to try and execute the failing instruction
if (EmuX86_DecodeException(e))
{
// We're allowed to continue :
g_bEmuException = false;
return EXCEPTION_CONTINUE_EXECUTION;
}
// notify user
EmuExceptionNonBreakpointUnhandledShow(e);
}
// Unhandled exception :
g_bEmuException = false;
return EXCEPTION_CONTINUE_SEARCH;
}

View File

@ -101,9 +101,9 @@ uint16_t EmuX86_Read16(uint32_t addr)
EmuWarning("EmuX86_Read16(0x%08X) Forwarding to EmuX86_Read32...", addr);
uint16_t value;
if (addr & 2)
value = (uint16_t)EmuX86_Read32(addr - 2);
value = (uint16_t)(EmuX86_Read32(addr - 2) >> 16);
else
value = (uint16_t)(EmuX86_Read32(addr) >> 16);
value = (uint16_t)EmuX86_Read32(addr);
EmuWarning("EmuX86_Read16(0x%08X) = 0x%04X", addr, value);
return value;
@ -114,9 +114,9 @@ uint8_t EmuX86_Read8(uint32_t addr)
EmuWarning("EmuX86_Read8(0x%08X) Forwarding to EmuX86_Read16...", addr);
uint8_t value;
if (addr & 1)
value = (uint8_t)EmuX86_Read16(addr - 1);
value = (uint8_t)(EmuX86_Read16(addr - 1) >> 8);
else
value = (uint8_t)(EmuX86_Read16(addr) >> 8);
value = (uint8_t)EmuX86_Read16(addr);
EmuWarning("EmuX86_Read8(0x%08X) = 0x%02X", addr, value);
return value;
@ -180,41 +180,31 @@ inline bool EmuX86_GetRegisterValue(uint32_t* output, LPEXCEPTION_POINTERS e, ui
return true;
}
inline bool EmuX86_DecodeMemoryOperand(uint32_t* output, LPEXCEPTION_POINTERS e, _DInst& info, int operand)
uint32_t EmuX86_Distorm_O_SMEM_Addr(LPEXCEPTION_POINTERS e, _DInst& info, int operand)
{
uint32_t base;
EmuX86_GetRegisterValue(&base, e, info.ops[operand].index);
return base + info.disp;
}
uint32_t EmuX86_Distorm_O_MEM_Addr(LPEXCEPTION_POINTERS e, _DInst& info, int operand)
{
uint32_t base = 0;
EmuX86_GetRegisterValue(&base, e, info.base);
uint32_t index = 0;
if (!EmuX86_GetRegisterValue(&base, e, info.ops[operand].index) || !EmuX86_GetRegisterValue(&index, e, info.ops[operand].index)) {
return false;
EmuX86_GetRegisterValue(&index, e, info.ops[operand].index);
if (info.scale >= 2)
return base + (index * info.scale) + info.disp;
else
return base + index + info.disp;
}
*output = base + (index * info.scale) + info.imm.dword;
return true;
}
bool EmuX86_ReadValueFromSource(LPEXCEPTION_POINTERS e, _DInst& info, int operand, OUT uint32_t *value)
void EmuX86_ReadAddr(uint32_t srcAddr, uint16_t size, OUT uint32_t *value)
{
switch (info.ops[operand].type) {
// TODO : other operand.type
case O_IMM:
{
*value = info.imm.dword;
break;
}
case O_REG:
{
if (!EmuX86_GetRegisterValue(value, e, info.ops[operand].index))
return false;
break;
}
case O_MEM:
{
uint32_t srcAddr = 0;
if (!EmuX86_DecodeMemoryOperand(&srcAddr, e, info, operand))
return false;
switch (info.ops[operand].size) {
switch (size) {
case 8:
*value = EmuX86_Read8(srcAddr);
break;
@ -225,10 +215,97 @@ bool EmuX86_ReadValueFromSource(LPEXCEPTION_POINTERS e, _DInst& info, int operan
*value = EmuX86_Read32(srcAddr);
break;
default:
// TODO : Handle other sizes?
break;
}
}
void EmuX86_WriteAddr(uint32_t destAddr, uint16_t size, uint32_t value)
{
switch (size) {
case 8:
EmuX86_Write8(destAddr, value & 0xFF);
break;
case 16:
EmuX86_Write16(destAddr, value & 0xFFFF);
break;
case 32:
EmuX86_Write32(destAddr, value);
break;
default:
// TODO : Handle other sizes?
break;
}
}
bool EmuX86_ReadValueFromSource(LPEXCEPTION_POINTERS e, _DInst& info, int operand, OUT uint32_t *value)
{
switch (info.ops[operand].type) {
case O_NONE:
{
// ignore operand
}
case O_REG:
{
if (!EmuX86_GetRegisterValue(value, e, info.ops[operand].index))
return false;
break;
}
case O_IMM:
{
switch (info.ops[operand].size) {
case 8:
*value = info.imm.byte;
break;
case 16:
*value = info.imm.word;
break;
case 32:
*value = info.imm.dword;
break;
// TODO : Handle other sizes?
}
break;
}
case O_IMM1:
{
// TODO
return false;
}
case O_IMM2:
{
// TODO
return false;
}
case O_DISP:
{
uint32_t srcAddr = info.disp;
EmuX86_ReadAddr(srcAddr, info.ops[operand].size, value);
break;
}
case O_SMEM:
{
uint32_t srcAddr = EmuX86_Distorm_O_SMEM_Addr(e, info, operand);
EmuX86_ReadAddr(srcAddr, info.ops[operand].size, value);
break;
}
case O_MEM:
{
uint32_t srcAddr = EmuX86_Distorm_O_MEM_Addr(e, info, operand);
EmuX86_ReadAddr(srcAddr, info.ops[operand].size, value);
break;
}
case O_PC:
{
// TODO
return false;
}
case O_PTR:
{
// TODO
return false;
}
default:
return false;
}
@ -239,6 +316,10 @@ bool EmuX86_ReadValueFromSource(LPEXCEPTION_POINTERS e, _DInst& info, int operan
bool EmuX86_WriteValueToDestination(LPEXCEPTION_POINTERS e, _DInst& info, int operand, uint32_t value)
{
switch (info.ops[operand].type) {
case O_NONE:
{
// ignore operand
}
case O_REG:
{
DWORD* pDstReg = EmuX86_GetRegisterPointer(e, info.ops[operand].index);
@ -260,27 +341,49 @@ bool EmuX86_WriteValueToDestination(LPEXCEPTION_POINTERS e, _DInst& info, int op
}
break;
}
case O_MEM:
case O_IMM:
{
uint32_t destAddr = 0;
if (!EmuX86_DecodeMemoryOperand(&destAddr, e, info, operand))
return false;
switch (info.ops[operand].size) {
case 8:
EmuX86_Write8(destAddr, value & 0xFF);
break;
case 16:
EmuX86_Write16(destAddr, value & 0xFFFF);
break;
case 32:
EmuX86_Write32(destAddr, value);
break;
default:
// TODO
return false;
}
case O_IMM1:
{
// TODO
return false;
}
case O_IMM2:
{
// TODO
return false;
}
case O_DISP:
{
uint32_t destAddr = info.disp;
EmuX86_WriteAddr(destAddr, info.ops[operand].size, value);
break;
}
case O_SMEM:
{
uint32_t destAddr = EmuX86_Distorm_O_SMEM_Addr(e, info, operand);
EmuX86_WriteAddr(destAddr, info.ops[operand].size, value);
break;
}
case O_MEM:
{
uint32_t destAddr = EmuX86_Distorm_O_MEM_Addr(e, info, operand);
EmuX86_WriteAddr(destAddr, info.ops[operand].size, value);
break;
}
case O_PC:
{
// TODO
return false;
}
case O_PTR:
{
// TODO
return false;
}
default:
return false;
}
@ -306,6 +409,24 @@ bool EmuX86_MOV(LPEXCEPTION_POINTERS e, _DInst& info)
return true;
}
bool EmuX86_MOVZX(LPEXCEPTION_POINTERS e, _DInst& info)
{
// TODO : Test this refactoring
// MOV reads value from source :
uint32_t value = 0;
if (!EmuX86_ReadValueFromSource(e, info, 1, &value))
return false;
// MOV writes value to destination :
if (!EmuX86_WriteValueToDestination(e, info, 0, value))
return false;
// Note : MOV instructions never update CPU flags
return true;
}
inline void EmuX86_SetFlag(LPEXCEPTION_POINTERS e, int flag, int value)
{
e->ContextRecord->EFlags ^= (-value ^ e->ContextRecord->EFlags) & (1 << flag);
@ -361,7 +482,13 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
ci.codeOffset = 0;
ci.dt = (_DecodeType)Decode32Bits;
ci.features = DF_NONE;
if (DECRES_SUCCESS != distorm_decompose(&ci, &info, 1, &decodedInstructionsCount))
// Checking for DECRES_SUCCESS won't work, since we're passing distorm_decompose
// a codeLen big enough to decode any instruction-length, plus distorm doesn't
// halt cleanly after reaching maxInstructions 1. So instead, just call distorm :
distorm_decompose(&ci, &info, /*maxInstructions=*/1, &decodedInstructionsCount);
// and check if it successfully decoded one instruction :
if (decodedInstructionsCount != 1)
{
EmuWarning("EmuX86: Error decoding opcode at 0x%08X\n", e->ContextRecord->Eip);
}
@ -374,6 +501,12 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
break;
}
goto unimplemented_opcode;
case I_MOVZX:
if (EmuX86_MOVZX(e, info)) {
break;
}
goto unimplemented_opcode;
case I_TEST:
if (EmuX86_TEST(e, info)) {
@ -384,8 +517,12 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
case I_WBINVD:
// We can safely ignore this
break;
default:
goto unimplemented_opcode;
}
// When falling through here, the instruction was handled correctly,
// skip over the instruction and continue execution :
e->ContextRecord->Eip += info.size;
return true;