static void HandleCapstoneOperand(Capstone & cp, int opindex, DISASM_ARG* arg) { const cs_x86 & x86 = cp.x86(); const cs_x86_op & op = x86.operands[opindex]; arg->segment = SEG_DEFAULT; strcpy_s(arg->mnemonic, cp.OperandText(opindex).c_str()); switch(op.type) { case X86_OP_REG: { const char* regname = cp.RegName((x86_reg)op.reg); arg->type = arg_normal; uint value; if(!valfromstring(regname, &value, true, true)) value = 0; arg->constant = arg->value = value; } break; case X86_OP_IMM: { arg->type = arg_normal; arg->constant = arg->value = (duint)op.imm; } break; case X86_OP_MEM: { arg->type = arg_memory; const x86_op_mem & mem = op.mem; if(mem.base == X86_REG_RIP) //rip-relative arg->constant = cp.Address() + (duint)mem.disp + cp.Size(); else arg->constant = (duint)mem.disp; uint value; if(!valfromstring(arg->mnemonic, &value, true, true)) return; arg->value = value; if(DbgMemIsValidReadPtr(value)) { switch(op.size) { case 1: DbgMemRead(value, (unsigned char*)&arg->memvalue, 1); break; case 2: DbgMemRead(value, (unsigned char*)&arg->memvalue, 2); break; case 4: DbgMemRead(value, (unsigned char*)&arg->memvalue, 4); break; case 8: DbgMemRead(value, (unsigned char*)&arg->memvalue, 8); break; } } } break; } }
bool HandleSegSelectorOperand(XEDPARSE* Parse, const char* Value, InstOperand* Operand) { char selector[64]; char offset[64]; // Copy the prefix into a buffer strcpy(selector, Value); *strchr(selector, ':') = '\0'; // Copy the offset strcpy(offset, strrchr(Value, ':') + 1); // The segment selector is always a number from 0 to 0xFFFF if(strlen(selector) > 0) { ULONGLONG selVal = 0; if(!valfromstring(selector, &selVal) || abs((LONGLONG)selVal) > USHRT_MAX) { strcpy(Parse->error, "Invalid segment selector value"); return false; } Operand->Sel.Selector = selVal & 0xFFFF; } else { strcpy(Parse->error, "Invalid segment selector"); return false; } // Determine offset if(strlen(offset) <= 0) { strcpy(Parse->error, "Invalid offset"); return false; } // Ex: 033:X86SwitchTo64BitMode ULONGLONG offsetVal = 0; if(!valfromstring(offset, &offsetVal) && !(Parse->cbUnknown && Parse->cbUnknown(offset, &offsetVal))) { sprintf(Parse->error, "Unable to parse offset '%s'", offset); return false; } Operand->Sel.Offset = offsetVal & 0xFFFFFFFF; return true; }
bool ExHandlerGetUnhandled(std::vector<duint> & Entries) { // Try the address for Windows Vista+ static duint addr_BasepCurrentTopLevelFilter = 0; #ifdef _WIN64 auto symbol = "BasepCurrentTopLevelFilter"; #else auto symbol = "_BasepCurrentTopLevelFilter"; #endif if(addr_BasepCurrentTopLevelFilter || valfromstring(symbol, &addr_BasepCurrentTopLevelFilter)) { // Read external pointer duint handlerValue = 0; if(!MemRead(addr_BasepCurrentTopLevelFilter, &handlerValue, sizeof(duint))) return false; // Decode with remote process cookie if(!MemDecodePointer(&handlerValue, true)) return false; Entries.push_back(handlerValue); return true; } return false; }
bool cbInstrAssemble(int argc, char* argv[]) { if(IsArgumentsLessThan(argc, 3)) return false; duint addr = 0; if(!valfromstring(argv[1], &addr)) { dprintf(QT_TRANSLATE_NOOP("DBG", "Invalid expression: \"%s\"!\n"), argv[1]); return false; } if(!DbgMemIsValidReadPtr(addr)) { dprintf(QT_TRANSLATE_NOOP("DBG", "Invalid address: %p!\n"), addr); return false; } bool fillnop = false; if(argc > 3) fillnop = true; char error[MAX_ERROR_SIZE] = ""; int size = 0; if(!assembleat(addr, argv[2], &size, error, fillnop)) { varset("$result", size, false); dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to assemble \"%s\" (%s)\n"), argv[2], error); return false; } varset("$result", size, false); GuiUpdateAllViews(); return true; }
bool AnalyzeOperand(XEDPARSE* Parse, const char* Value, InstOperand* Operand) { REG registerVal = RegFromString(Value); ULONGLONG immVal = 0; if(registerVal != REG_INVALID) { // Register Operand->Type = OPERAND_REG; Operand->Segment = REG_INVALID; Operand->Size = RegGetSize(registerVal); Operand->XedEOSZ = OpsizeToEosz(Operand->Size); Operand->Reg.Reg = registerVal; Operand->Reg.XedReg = RegToXed(registerVal); } else if(strchr(Value, '[') && strchr(Value, ']')) { // Memory Operand->Type = OPERAND_MEM; Operand->Segment = REG_INVALID; Operand->Size = SIZE_UNSET; Operand->XedEOSZ = EOSZ_64_32(Parse->x64); return HandleMemoryOperand(Parse, Value, Operand); } else if(strchr(Value, ':')) { // Segment selector operand Operand->Type = OPERAND_SEGSEL; Operand->Segment = REG_INVALID; Operand->Size = SIZE_DWORD; Operand->XedEOSZ = EOSZ_64_32(Parse->x64); return HandleSegSelectorOperand(Parse, Value, Operand); } else if(valfromstring(Value, &immVal) || (Parse->cbUnknown && Parse->cbUnknown(Value, &immVal))) { // Immediate Operand->Type = OPERAND_IMM; Operand->Segment = REG_INVALID; Operand->Size = OpsizeFromValue(immVal); Operand->XedEOSZ = EOSZ_64_32(Parse->x64); Operand->Imm.Signed = (Value[0] == '-'); Operand->Imm.imm = immVal; } else { // Unknown Operand->Type = OPERAND_INVALID; sprintf(Parse->error, "Unknown operand identifier '%s'", Value); return false; } return true; }
bool cbInstrZzz(int argc, char* argv[]) { duint value = 100; if(argc > 1) if(!valfromstring(argv[1], &value, false)) return false; auto ms = DWORD(value); if(ms == INFINITE) ms = 100; Sleep(ms); return true; }
bool cbInstrGpa(int argc, char* argv[]) { if(IsArgumentsLessThan(argc, 2)) return false; char newcmd[deflen] = ""; if(argc >= 3) sprintf_s(newcmd, "\"%s\":%s", argv[2], argv[1]); else sprintf_s(newcmd, "%s", argv[1]); duint result = 0; if(!valfromstring(newcmd, &result, false)) return false; varset("$RESULT", result, false); return true; }
bool cbDelWatch(int argc, char* argv[]) { if(argc < 2) { dputs(QT_TRANSLATE_NOOP("DBG", "No enough arguments for delwatch\n")); return false; } duint id; bool ok = valfromstring(argv[1], &id); if(!ok) { dputs(QT_TRANSLATE_NOOP("DBG", "Error expression in argument 1.\n")); return false; } WatchDelete((unsigned int)id); return true; }
void SetMemoryDisplacementOrBase(XEDPARSE* Parse, const char* Value, InstOperand* Operand) { // Displacement = name or number // Base = register REG registerVal = RegFromString(Value); ULONGLONG disp = 0; if(registerVal != REG_INVALID) { // If the base is already set, then use IMPLICIT scale // REG + (REG * 1) if(Operand->Mem.Base) { SetMemoryIndexOrScale(Parse, Value, Operand); SetMemoryIndexOrScale(Parse, "1", Operand); return; } // It's the base Operand->Mem.Base = true; Operand->Mem.BaseVal = registerVal; } else if(valfromstring(Value, &disp) || (Parse->cbUnknown && Parse->cbUnknown(Value, &disp))) { // It's the displacement // // Displacement is either /8, /32, or /64 // 5h = 101b Operand->Mem.Disp = true; Operand->Mem.DispVal = disp; bool sign = (Value[0] == '-'); if(sign) Operand->Mem.DispWidth = OpsizeFromInt(xed_shortest_width_signed(disp, 0x5)); else Operand->Mem.DispWidth = OpsizeFromInt(xed_shortest_width_unsigned(disp, 0x5)); Operand->Mem.DispWidth = PromoteImmediateWidth(sign, disp, Operand->Mem.DispWidth); } else { sprintf(Parse->error, "Unknown displacement or base '%s'", Value); } }
bool cbSetWatchName(int argc, char* argv[]) { if(argc < 3) { dputs(QT_TRANSLATE_NOOP("DBG", "No enough arguments for SetWatchName")); return false; } duint id; bool ok = valfromstring(argv[1], &id); if(ok) { WatchModifyName((unsigned int)id, argv[2]); return true; } else { dputs(QT_TRANSLATE_NOOP("DBG", "Error expression in argument 1.\n")); return false; } }
bool ExHandlerGetVCH(std::vector<duint> & Entries, bool UseVEH) { // VECTORED_HANDLER_LIST LdrpVectorHandlerList[2]; static duint addr_LdrpVectorHandlerList = 0; if(!addr_LdrpVectorHandlerList && !valfromstring("ntdll:LdrpVectorHandlerList", &addr_LdrpVectorHandlerList)) return false; // Increase array index when using continue handlers if(!UseVEH) addr_LdrpVectorHandlerList += (1 * sizeof(VECTORED_HANDLER_LIST)); // Read head entry VECTORED_HANDLER_LIST list; memset(&list, 0, sizeof(VECTORED_HANDLER_LIST)); if(!MemRead(addr_LdrpVectorHandlerList, &list, sizeof(VECTORED_HANDLER_LIST))) return false; // Sub-entries in list duint listCurrent = (duint)list.Next; duint listEnd = addr_LdrpVectorHandlerList; while(listCurrent && listCurrent != listEnd) { duint handler = (duint)list.VectoredHandler; MemDecodePointer(&handler); Entries.push_back(handler); // Move to next element memset(&list, 0, sizeof(VECTORED_HANDLER_LIST)); if(!MemRead(listCurrent, &list, sizeof(VECTORED_HANDLER_LIST))) break; listCurrent = (duint)list.Next; } return true; }
bool ExHandlerGetVCH(std::vector<duint> & Entries, bool GetVEH) { // VECTORED_HANDLER_LIST LdrpVectorHandlerList[2]; static duint addr_LdrpVectorHandlerList = 0; duint addrInc = sizeof(duint); //Vista+ has an extra ULONG_PTR in front of the structure #ifdef _WIN64 auto symbol = "LdrpVectorHandlerList"; #else auto symbol = "_LdrpVectorHandlerList"; #endif if(!addr_LdrpVectorHandlerList && !valfromstring(symbol, &addr_LdrpVectorHandlerList)) return false; // Increase array index when using continue handlers if(!GetVEH) addrInc += sizeof(duint) + sizeof(LIST_ENTRY); //Vista+ has an extra ULONG_PTR // Read head entry auto list_head = addr_LdrpVectorHandlerList + addrInc; duint cur_entry; if(!MemRead(list_head, &cur_entry, sizeof(cur_entry))) return false; auto count = 0; while(cur_entry != list_head && count++ < MAX_HANDLER_DEPTH) { VEH_ENTRY_VISTA entry; if(!MemRead(cur_entry, &entry, sizeof(entry))) return false; auto handler = entry.VectoredHandler; if(!MemDecodePointer(&handler, true)) return false; Entries.push_back(handler); if(!MemRead(cur_entry, &cur_entry, sizeof(cur_entry))) return false; } return true; }
bool ExHandlerGetVEH(std::vector<duint> & Entries) { // Try the address for Windows XP first (or older) // // VECTORED_EXCEPTION_NODE RtlpCalloutEntryList; static duint addr_RtlpCalloutEntryList = 0; if(addr_RtlpCalloutEntryList || valfromstring("ntdll:RtlpCalloutEntryList", &addr_RtlpCalloutEntryList)) { // Read header node VECTORED_EXCEPTION_NODE node; memset(&node, 0, sizeof(VECTORED_EXCEPTION_NODE)); if(!MemRead(addr_RtlpCalloutEntryList, &node, sizeof(VECTORED_EXCEPTION_NODE))) return false; // Move to the next link duint listCurrent = (duint)node.ListEntry.Flink; duint listEnd = addr_RtlpCalloutEntryList; while(listCurrent && listCurrent != listEnd) { duint handler = (duint)node.handler; MemDecodePointer(&handler); Entries.push_back(handler); // Move to next element memset(&node, 0, sizeof(VECTORED_EXCEPTION_NODE)); if(!MemRead(listCurrent, &node, sizeof(VECTORED_EXCEPTION_NODE))) break; listCurrent = (duint)node.ListEntry.Flink; } } // Otherwise try the Windows Vista or newer version return ExHandlerGetVCH(Entries, true); }
bool ExHandlerGetVEH(std::vector<duint> & Entries) { // Try the address for Windows XP first (or older) // // VECTORED_EXCEPTION_NODE RtlpCalloutEntryList; static duint addr_RtlpCalloutEntryList = 0; #ifdef _WIN64 auto symbol = "RtlpCalloutEntryList"; #else auto symbol = "_RtlpCalloutEntryList"; #endif if(addr_RtlpCalloutEntryList || valfromstring(symbol, &addr_RtlpCalloutEntryList)) { // Read head entry auto list_head = addr_RtlpCalloutEntryList; duint cur_entry; if(!MemRead(list_head, &cur_entry, sizeof(cur_entry))) return false; auto count = 0; while(cur_entry != list_head && count++ < MAX_HANDLER_DEPTH) { VEH_ENTRY_XP entry; if(!MemRead(cur_entry, &entry, sizeof(entry))) return false; auto handler = entry.VectoredHandler; MemDecodePointer(&handler, false); //TODO: Windows XP doesn't allow a remote process to query this value Entries.push_back(handler); if(!MemRead(cur_entry, &cur_entry, sizeof(cur_entry))) return false; } return true; } // Otherwise try the Windows Vista or newer version return ExHandlerGetVCH(Entries, true); }
bool cbSetWatchdog(int argc, char* argv[]) { if(argc < 2) { dputs(QT_TRANSLATE_NOOP("DBG", "No enough arguments for delwatch\n")); return false; } duint id; bool ok = valfromstring(argv[1], &id); if(!ok) { dputs(QT_TRANSLATE_NOOP("DBG", "Error expression in argument 1.\n")); return false; } WATCHDOGMODE mode; if(argc > 2) { if(_stricmp(argv[2], "disabled") == 0) mode = WATCHDOGMODE::MODE_DISABLED; else if(_stricmp(argv[2], "changed") == 0) mode = WATCHDOGMODE::MODE_CHANGED; else if(_stricmp(argv[2], "unchanged") == 0) mode = WATCHDOGMODE::MODE_UNCHANGED; else if(_stricmp(argv[2], "istrue") == 0) mode = WATCHDOGMODE::MODE_ISTRUE; else if(_stricmp(argv[2], "isfalse") == 0) mode = WATCHDOGMODE::MODE_ISFALSE; else { dputs(QT_TRANSLATE_NOOP("DBG", "Unknown watchdog mode.\n")); return false; } } else mode = (WatchGetWatchdogEnabled((unsigned int)id) == WATCHDOGMODE::MODE_DISABLED) ? WATCHDOGMODE::MODE_CHANGED : WATCHDOGMODE::MODE_DISABLED; WatchSetWatchdogMode((unsigned int)id, mode); return true; }
bool cbSetWatchExpression(int argc, char* argv[]) { if(argc < 3) { dputs(QT_TRANSLATE_NOOP("DBG", "No enough arguments for SetWatchExpression")); return false; } duint id; bool ok = valfromstring(argv[1], &id); if(ok) { WATCHVARTYPE varType; if(argc > 3) { if(_stricmp(argv[3], "uint") == 0) varType = WATCHVARTYPE::TYPE_UINT; else if(_stricmp(argv[3], "int") == 0) varType = WATCHVARTYPE::TYPE_INT; else if(_stricmp(argv[3], "float") == 0) varType = WATCHVARTYPE::TYPE_FLOAT; else if(_stricmp(argv[3], "ascii") == 0) varType = WATCHVARTYPE::TYPE_ASCII; else if(_stricmp(argv[3], "unicode") == 0) varType = WATCHVARTYPE::TYPE_UNICODE; else varType = WATCHVARTYPE::TYPE_UINT; } else varType = WATCHVARTYPE::TYPE_UINT; WatchModifyExpr((unsigned int)id, argv[2], varType); return true; } else { dputs(QT_TRANSLATE_NOOP("DBG", "Error expression in argument 1.\n")); return false; } }
void SetMemoryIndexOrScale(XEDPARSE* Parse, const char* Value, InstOperand* Operand) { // Index = register // Scale = 1, 2, 4, or 8 REG registerVal = RegFromString(Value); ULONGLONG scale = 0; if(registerVal != REG_INVALID) { // It's the index Operand->Mem.Index = true; Operand->Mem.IndexVal = registerVal; } else if(valfromstring(Value, &scale)) { // It's the scale Operand->Mem.Scale = true; Operand->Mem.ScaleVal = scale; } else { sprintf(Parse->error, "Unknown index or scale '%s'", Value); } }
extern "C" DLL_EXPORT bool _dbg_valfromstring(const char* string, duint* value) { return valfromstring(string, value); }
bool cbDebugLoadLib(int argc, char* argv[]) { if(argc < 2) { dputs(QT_TRANSLATE_NOOP("DBG", "Error: you must specify the name of the DLL to load\n")); return false; } LoadLibThreadID = fdProcessInfo->dwThreadId; HANDLE LoadLibThread = ThreadGetHandle((DWORD)LoadLibThreadID); DLLNameMem = MemAllocRemote(0, strlen(argv[1]) + 1); ASMAddr = MemAllocRemote(0, 0x1000); if(!DLLNameMem || !ASMAddr) { dputs(QT_TRANSLATE_NOOP("DBG", "Error: couldn't allocate memory in debuggee")); return false; } if(!MemWrite(DLLNameMem, argv[1], strlen(argv[1]))) { dputs(QT_TRANSLATE_NOOP("DBG", "Error: couldn't write process memory")); return false; } int size = 0; int counter = 0; duint LoadLibraryA = 0; char command[50] = ""; char error[MAX_ERROR_SIZE] = ""; GetFullContextDataEx(LoadLibThread, &backupctx); if(!valfromstring("kernel32:LoadLibraryA", &LoadLibraryA, false)) { dputs(QT_TRANSLATE_NOOP("DBG", "Error: couldn't get kernel32:LoadLibraryA")); return false; } // Arch specific asm code #ifdef _WIN64 sprintf_s(command, "mov rcx, %p", DLLNameMem); #else sprintf_s(command, "push %p", DLLNameMem); #endif // _WIN64 assembleat(ASMAddr, command, &size, error, true); counter += size; #ifdef _WIN64 sprintf_s(command, "mov rax, %p", LoadLibraryA); assembleat(ASMAddr + counter, command, &size, error, true); counter += size; sprintf_s(command, "call rax"); #else sprintf_s(command, "call %p", LoadLibraryA); #endif // _WIN64 assembleat(ASMAddr + counter, command, &size, error, true); counter += size; SetContextDataEx(LoadLibThread, UE_CIP, ASMAddr); auto ok = SetBPX(ASMAddr + counter, UE_SINGLESHOOT | UE_BREAKPOINT_TYPE_INT3, (void*)cbDebugLoadLibBPX); ThreadSuspendAll(); ResumeThread(LoadLibThread); unlock(WAITID_RUN); return ok; }