/
githubmirror
/
x64dbg
Обзор
Документация
Войти
/
githubmirror
/
x64dbg
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
development
src/zydis_wrapper/zydis_wrapper.cpp
970 строк
29 KB
Duncan Ogilvie
Fix printf warnings on linux
17 авг 2025, 22:08
17 авг 2025, 22:08
cc98366
Код
Авторство
О чём код?
#ifndef NOMINMAX #define NOMINMAX #endif // NOMINMAX #include "zydis_wrapper.h" #include <algorithm> #include <stdexcept> #include <cstring> #include <cinttypes> static const char* ZydisMnemonicGetStringHook(ZydisMnemonic mnemonic) { switch(mnemonic) { case ZYDIS_MNEMONIC_JZ: return "je"; case ZYDIS_MNEMONIC_JNZ: return "jne"; case ZYDIS_MNEMONIC_JNBE: return "ja"; case ZYDIS_MNEMONIC_JNB: return "jae"; case ZYDIS_MNEMONIC_JNLE: return "jg"; case ZYDIS_MNEMONIC_JNL: return "jge"; case ZYDIS_MNEMONIC_CMOVNBE: return "cmova"; case ZYDIS_MNEMONIC_CMOVNB: return "cmovae"; case ZYDIS_MNEMONIC_CMOVZ: return "cmove"; case ZYDIS_MNEMONIC_CMOVNLE: return "cmovg"; case ZYDIS_MNEMONIC_CMOVNL: return "cmovge"; case ZYDIS_MNEMONIC_CMOVNZ: return "cmovne"; case ZYDIS_MNEMONIC_SETNBE: return "seta"; case ZYDIS_MNEMONIC_SETNB: return "setae"; case ZYDIS_MNEMONIC_SETZ: return "sete"; case ZYDIS_MNEMONIC_SETNLE: return "setg"; case ZYDIS_MNEMONIC_SETNL: return "setge"; case ZYDIS_MNEMONIC_SETNZ: return "setne"; default: return ZydisMnemonicGetString(mnemonic); } } Zydis::Zydis(bool disasm64) { Reset(disasm64); ZydisFormatterInit(&mFormatter, ZYDIS_FORMATTER_STYLE_INTEL); ZydisFormatterSetProperty(&mFormatter, ZYDIS_FORMATTER_PROP_FORCE_SIZE, ZYAN_TRUE); ZydisFormatterSetProperty(&mFormatter, ZYDIS_FORMATTER_PROP_FORCE_SEGMENT, ZYAN_TRUE); } void Zydis::Reset(bool disasm64) { mSuccess = false; mDisasm64 = disasm64; memset(&mInstr, 0, sizeof(mInstr)); if(disasm64) ZydisDecoderInit(&mDecoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64); else ZydisDecoderInit(&mDecoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_STACK_WIDTH_32); } bool Zydis::Disassemble(uint64_t addr, const unsigned char data[MAX_DISASM_BUFFER]) { return Disassemble(addr, data, MAX_DISASM_BUFFER); } bool Zydis::Disassemble(uint64_t addr, const unsigned char* data, size_t size) { if(data == nullptr || size == 0) return false; mAddr = addr; mSuccess = false; // Decode instruction. if(!ZYAN_SUCCESS(ZydisDecoderDecodeFull(&mDecoder, data, size, &mInstr.info, mInstr.operands))) return false; // Format it to human readable representation. if(!ZYAN_SUCCESS(ZydisFormatterFormatInstruction( &mFormatter, &mInstr.info, mInstr.operands, mInstr.info.operand_count, mInstrText, sizeof(mInstrText), mAddr, nullptr))) return false; for(ZyanU8 i = 0; i < mInstr.info.operand_count; ++i) { auto & op = mInstr.operands[i]; // Rebase IMM if relative and DISP if absolute (codebase expects it this way). // Once, at some point in time, the disassembler is abstracted away more and more, // we should probably refrain from hacking the Zydis data structure and perform // such transformations in the getters instead. if(op.type == ZYDIS_OPERAND_TYPE_IMMEDIATE && op.imm.is_relative) { ZydisCalcAbsoluteAddress(&mInstr.info, &op, mAddr, &op.imm.value.u); op.imm.is_relative = false; //hack to prevent OperandText from returning bogus values } else if(op.type == ZYDIS_OPERAND_TYPE_MEMORY && op.mem.base == ZYDIS_REGISTER_NONE && op.mem.index == ZYDIS_REGISTER_NONE && op.mem.disp.value != 0) { //TODO: what is this used for? ZydisCalcAbsoluteAddress(&mInstr.info, &op, mAddr, (uint64_t*)&op.mem.disp.value); } } mSuccess = true; return true; } bool Zydis::DisassembleSafe(uint64_t addr, const unsigned char* data, size_t size) { unsigned char dataSafe[MAX_DISASM_BUFFER]; memset(dataSafe, 0, sizeof(dataSafe)); memcpy(dataSafe, data, std::min(sizeof(dataSafe), size)); return Disassemble(addr, dataSafe); } const ZydisDisassembledInstruction* Zydis::GetInstr() const { if(!Success()) return nullptr; return &mInstr; } bool Zydis::Success() const { return mSuccess; } const char* Zydis::RegName(ZydisRegister reg) const { switch(reg) { case ZYDIS_REGISTER_ST0: return "st(0)"; case ZYDIS_REGISTER_ST1: return "st(1)"; case ZYDIS_REGISTER_ST2: return "st(2)"; case ZYDIS_REGISTER_ST3: return "st(3)"; case ZYDIS_REGISTER_ST4: return "st(4)"; case ZYDIS_REGISTER_ST5: return "st(5)"; case ZYDIS_REGISTER_ST6: return "st(6)"; case ZYDIS_REGISTER_ST7: return "st(7)"; default: return ZydisRegisterGetString(reg); } } std::string Zydis::OperandText(uint8_t opindex) const { if(!Success() || opindex >= mInstr.info.operand_count) return {}; auto & op = mInstr.operands[opindex]; char buf[200] = {}; if(!ZYAN_SUCCESS(ZydisFormatterFormatOperand(&this->mFormatter, &mInstr.info, &op, buf, sizeof(buf), mAddr, nullptr))) return {}; //Extract only the part inside the [] if(op.type == ZYDIS_OPERAND_TYPE_MEMORY) { auto openBracket = strchr(buf, '['); if(openBracket) { std::string result; result = openBracket + 1; if(result.back() == ']') result.pop_back(); return result; } } return buf; } uint8_t Zydis::Size() const { if(!Success()) return 1; return GetInstr()->info.length; } uint64_t Zydis::Address() const { if(!Success()) return 0; return mAddr; } bool Zydis::IsFilling() const { if(!Success()) return false; switch(mInstr.info.mnemonic) { case ZYDIS_MNEMONIC_NOP: case ZYDIS_MNEMONIC_INT3: return true; default: return false; } } bool Zydis::IsBranchType(std::underlying_type<BranchType>::type bt) const { if(!Success()) return false; std::underlying_type<BranchType>::type ref = 0; const auto & op0 = mInstr.operands[0]; switch(mInstr.info.mnemonic) { case ZYDIS_MNEMONIC_RET: ref = (mInstr.info.meta.branch_type == ZYDIS_BRANCH_TYPE_FAR) ? BTFarRet : BTRet; break; case ZYDIS_MNEMONIC_CALL: ref = (mInstr.info.meta.branch_type == ZYDIS_BRANCH_TYPE_FAR) ? BTFarCall : BTCall; break; case ZYDIS_MNEMONIC_JMP: ref = (mInstr.info.meta.branch_type == ZYDIS_BRANCH_TYPE_FAR) ? BTFarJmp : BTUncondJmp; break; case ZYDIS_MNEMONIC_JB: case ZYDIS_MNEMONIC_JBE: case ZYDIS_MNEMONIC_JCXZ: case ZYDIS_MNEMONIC_JECXZ: case ZYDIS_MNEMONIC_JKNZD: case ZYDIS_MNEMONIC_JKZD: case ZYDIS_MNEMONIC_JL: case ZYDIS_MNEMONIC_JLE: case ZYDIS_MNEMONIC_JNB: case ZYDIS_MNEMONIC_JNBE: case ZYDIS_MNEMONIC_JNL: case ZYDIS_MNEMONIC_JNLE: case ZYDIS_MNEMONIC_JNO: case ZYDIS_MNEMONIC_JNP: case ZYDIS_MNEMONIC_JNS: case ZYDIS_MNEMONIC_JNZ: case ZYDIS_MNEMONIC_JO: case ZYDIS_MNEMONIC_JP: case ZYDIS_MNEMONIC_JRCXZ: case ZYDIS_MNEMONIC_JS: case ZYDIS_MNEMONIC_JZ: ref = BTCondJmp; break; case ZYDIS_MNEMONIC_SYSCALL: case ZYDIS_MNEMONIC_SYSENTER: ref = BTSyscall; break; case ZYDIS_MNEMONIC_SYSRET: case ZYDIS_MNEMONIC_SYSEXIT: ref = BTSysret; break; case ZYDIS_MNEMONIC_INT: ref = BTInt; break; case ZYDIS_MNEMONIC_INT3: ref = BTInt3; break; case ZYDIS_MNEMONIC_INT1: ref = BTInt1; break; case ZYDIS_MNEMONIC_IRET: case ZYDIS_MNEMONIC_IRETD: case ZYDIS_MNEMONIC_IRETQ: ref = BTIret; break; case ZYDIS_MNEMONIC_XBEGIN: ref = BTXbegin; break; case ZYDIS_MNEMONIC_XABORT: ref = BTXabort; break; case ZYDIS_MNEMONIC_RSM: ref = BTRsm; break; case ZYDIS_MNEMONIC_LOOP: case ZYDIS_MNEMONIC_LOOPE: case ZYDIS_MNEMONIC_LOOPNE: ref = BTLoop; default: ; } return (bt & ref) != 0; } ZydisMnemonic Zydis::GetId() const { if(!Success()) return ZYDIS_MNEMONIC_INVALID; return mInstr.info.mnemonic; } std::string Zydis::InstructionText(bool replaceRipRelative) const { if(!Success()) return "???"; std::string result = mInstrText; // TODO (ath): We can do that a whole lot sexier using formatter hooks if(mDisasm64 && replaceRipRelative) { //replace [rip +/- 0x?] with the actual address bool ripPlus = true; auto found = result.find("[rip + "); if(found == std::string::npos) { ripPlus = false; found = result.find("[rip - "); } if(found != std::string::npos) { auto wVA = Address(); auto end = result.find(']', found); auto ripStr = result.substr(found + 1, end - found - 1); uint64_t offset; #ifdef _MSC_VER sscanf_s(ripStr.substr(ripStr.rfind(' ') + 1).c_str(), "%" PRIx64, &offset); #else sscanf(ripStr.substr(ripStr.rfind(' ') + 1).c_str(), "%" PRIx64, &offset); #endif // _MSC_VER auto dest = ripPlus ? (wVA + offset + Size()) : (wVA - offset + Size()); char buf[20]; #ifdef _MSC_VER sprintf_s(buf, "0x%" PRIx64, dest); #else snprintf(buf, sizeof(buf), "0x%" PRIx64, dest); #endif // _MSC_VER result.replace(found + 1, ripStr.length(), buf); } } return result; } uint8_t Zydis::TotalOpCount() const { if(!Success()) return 0; return mInstr.info.operand_count; } uint8_t Zydis::OpCount() const { if(!Success()) return 0; return mInstr.info.operand_count_visible; } const ZydisDecodedOperand & Zydis::operator[](uint8_t index) const { if(!Success() || index >= TotalOpCount()) throw std::out_of_range("Operand out of range"); return mInstr.operands[index]; } bool Zydis::IsSafeNopRegOp(const ZydisDecodedOperand & op) const { if(!mDisasm64) return true; if(op.type != ZYDIS_OPERAND_TYPE_REGISTER) return true; //a non-register is safe switch(op.reg.value) { case ZYDIS_REGISTER_EAX: case ZYDIS_REGISTER_EBX: case ZYDIS_REGISTER_ECX: case ZYDIS_REGISTER_EDX: case ZYDIS_REGISTER_EBP: case ZYDIS_REGISTER_ESP: case ZYDIS_REGISTER_ESI: case ZYDIS_REGISTER_EDI: case ZYDIS_REGISTER_R8D: case ZYDIS_REGISTER_R9D: case ZYDIS_REGISTER_R10D: case ZYDIS_REGISTER_R11D: case ZYDIS_REGISTER_R12D: case ZYDIS_REGISTER_R13D: case ZYDIS_REGISTER_R14D: case ZYDIS_REGISTER_R15D: return false; //32 bit register modifications clear the high part of the 64 bit register default: return true; //all other registers are safe } } bool Zydis::IsNop() const { if(!Success()) return false; const auto & ops = mInstr.operands; switch(mInstr.info.mnemonic) { case ZYDIS_MNEMONIC_NOP: case ZYDIS_MNEMONIC_PAUSE: case ZYDIS_MNEMONIC_FNOP: // nop return true; case ZYDIS_MNEMONIC_MOV: case ZYDIS_MNEMONIC_CMOVB: case ZYDIS_MNEMONIC_CMOVBE: case ZYDIS_MNEMONIC_CMOVL: case ZYDIS_MNEMONIC_CMOVLE: case ZYDIS_MNEMONIC_CMOVNB: case ZYDIS_MNEMONIC_CMOVNBE: case ZYDIS_MNEMONIC_CMOVNL: case ZYDIS_MNEMONIC_CMOVNLE: case ZYDIS_MNEMONIC_CMOVNO: case ZYDIS_MNEMONIC_CMOVNP: case ZYDIS_MNEMONIC_CMOVNS: case ZYDIS_MNEMONIC_CMOVNZ: case ZYDIS_MNEMONIC_CMOVO: case ZYDIS_MNEMONIC_CMOVP: case ZYDIS_MNEMONIC_CMOVS: case ZYDIS_MNEMONIC_CMOVZ: case ZYDIS_MNEMONIC_MOVAPS: case ZYDIS_MNEMONIC_MOVAPD: case ZYDIS_MNEMONIC_MOVUPS: case ZYDIS_MNEMONIC_MOVUPD: case ZYDIS_MNEMONIC_XCHG: // mov edi, edi return ops[0].type == ZYDIS_OPERAND_TYPE_REGISTER && ops[1].type == ZYDIS_OPERAND_TYPE_REGISTER && ops[0].reg.value == ops[1].reg.value && IsSafeNopRegOp(ops[0]); case ZYDIS_MNEMONIC_LEA: { // lea eax, [eax + 0] auto reg = ops[0].reg.value; auto mem = ops[1].mem; return ops[0].type == ZYDIS_OPERAND_TYPE_REGISTER && ops[1].type == ZYDIS_OPERAND_TYPE_REGISTER && mem.disp.value == 0 && ((mem.index == ZYDIS_REGISTER_NONE && mem.base == reg) || (mem.index == reg && mem.base == ZYDIS_REGISTER_NONE && mem.scale == 1)) && IsSafeNopRegOp(ops[0]); } case ZYDIS_MNEMONIC_JB: case ZYDIS_MNEMONIC_JBE: case ZYDIS_MNEMONIC_JCXZ: case ZYDIS_MNEMONIC_JECXZ: case ZYDIS_MNEMONIC_JKNZD: case ZYDIS_MNEMONIC_JKZD: case ZYDIS_MNEMONIC_JL: case ZYDIS_MNEMONIC_JLE: case ZYDIS_MNEMONIC_JMP: case ZYDIS_MNEMONIC_JNB: case ZYDIS_MNEMONIC_JNBE: case ZYDIS_MNEMONIC_JNL: case ZYDIS_MNEMONIC_JNLE: case ZYDIS_MNEMONIC_JNO: case ZYDIS_MNEMONIC_JNP: case ZYDIS_MNEMONIC_JNS: case ZYDIS_MNEMONIC_JNZ: case ZYDIS_MNEMONIC_JO: case ZYDIS_MNEMONIC_JP: case ZYDIS_MNEMONIC_JRCXZ: case ZYDIS_MNEMONIC_JS: case ZYDIS_MNEMONIC_JZ: // jmp $0 return ops[0].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && ops[0].imm.value.u == this->Address() + this->Size(); case ZYDIS_MNEMONIC_SHL: case ZYDIS_MNEMONIC_SHR: case ZYDIS_MNEMONIC_ROL: case ZYDIS_MNEMONIC_ROR: case ZYDIS_MNEMONIC_SAR: // shl eax, 0 return ops[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && ops[1].imm.value.u == 0 && IsSafeNopRegOp(ops[0]); case ZYDIS_MNEMONIC_SHLD: case ZYDIS_MNEMONIC_SHRD: // shld eax, ebx, 0 return ops[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE && ops[2].imm.value.u == 0 && IsSafeNopRegOp(ops[0]) && IsSafeNopRegOp(ops[1]); default: return false; } } bool Zydis::IsPushPop() const { if(!Success()) return false; switch(mInstr.info.meta.category) { case ZYDIS_CATEGORY_PUSH: case ZYDIS_CATEGORY_POP: return true; default: return false; } } bool Zydis::IsUnusual() const { if(!Success()) return false; auto id = mInstr.info.mnemonic; return mInstr.info.attributes & ZYDIS_ATTRIB_IS_PRIVILEGED || mInstr.info.meta.category == ZYDIS_CATEGORY_IO || mInstr.info.meta.category == ZYDIS_CATEGORY_IOSTRINGOP || mInstr.info.meta.category == ZYDIS_CATEGORY_RDWRFSGS || mInstr.info.meta.category == ZYDIS_CATEGORY_SGX || mInstr.info.meta.category == ZYDIS_CATEGORY_INTERRUPT || id == ZYDIS_MNEMONIC_SYSCALL || id == ZYDIS_MNEMONIC_SYSENTER || id == ZYDIS_MNEMONIC_CPUID || id == ZYDIS_MNEMONIC_RDTSC || id == ZYDIS_MNEMONIC_RDTSCP || id == ZYDIS_MNEMONIC_RDRAND || id == ZYDIS_MNEMONIC_RDSEED || id == ZYDIS_MNEMONIC_RDPID || id == ZYDIS_MNEMONIC_RDPKRU // || id == ZYDIS_MNEMONIC_RDPRU || id == ZYDIS_MNEMONIC_UD1 || id == ZYDIS_MNEMONIC_UD2 || id == ZYDIS_MNEMONIC_VMCALL || id == ZYDIS_MNEMONIC_VMFUNC || id == ZYDIS_MNEMONIC_OUTSB || id == ZYDIS_MNEMONIC_OUTSW || id == ZYDIS_MNEMONIC_OUTSD || id == ZYDIS_MNEMONIC_WRPKRU; } std::string Zydis::Mnemonic() const { if(!Success()) return "???"; return ZydisMnemonicGetStringHook(mInstr.info.mnemonic); } const char* Zydis::MemSizeName(size_t size) const { switch(size) { case 1: return "byte"; case 2: return "word"; case 4: return "dword"; case 6: return "fword"; case 8: return "qword"; case 10: return "tword"; case 14: return "m14"; case 16: return "xmmword"; case 28: return "m28"; case 32: return "yword"; case 64: return "zword"; default: return nullptr; } } uint64_t Zydis::BranchDestination() const { if(!Success() || mInstr.operands[0].type != ZYDIS_OPERAND_TYPE_IMMEDIATE /*|| !mInstr.operands[0].imm.isRelative HACKED*/) return 0; return uint64_t(mInstr.operands[0].imm.value.u); } uint64_t Zydis::ResolveOpValue(uint8_t opindex, const std::function<uint64_t(ZydisRegister)> & resolveReg) const { uint64_t dest = 0; const auto & op = mInstr.operands[opindex]; switch(op.type) { case ZYDIS_OPERAND_TYPE_IMMEDIATE: dest = uint64_t(op.imm.value.u); if(!IsBranchType(Zydis::BTJmp | Zydis::BTCall | Zydis::BTLoop | Zydis::BTXbegin)) dest &= (uint64_t(-1) >> (sizeof(uint64_t) * 8 - mInstr.info.operand_width)); break; case ZYDIS_OPERAND_TYPE_REGISTER: dest = resolveReg(op.reg.value); break; case ZYDIS_OPERAND_TYPE_MEMORY: dest = uint64_t(op.mem.disp.value); if(op.mem.base == ZYDIS_REGISTER_RIP) //rip-relative dest += Address() + Size(); else dest += resolveReg(op.mem.base) + resolveReg(op.mem.index) * op.mem.scale; break; default: break; } return dest; } Zydis::VectorElementType Zydis::getVectorElementType(uint8_t opindex) const { if(!Success()) return Zydis::VETDefault; if(opindex >= mInstr.info.operand_count) return Zydis::VETDefault; const auto & op = mInstr.operands[opindex]; switch(op.element_type) { case ZYDIS_ELEMENT_TYPE_FLOAT32: return Zydis::VETFloat32; case ZYDIS_ELEMENT_TYPE_FLOAT64: return Zydis::VETFloat64; default: return Zydis::VETDefault; } } bool Zydis::IsBranchGoingToExecute(uint32_t eflags, uint64_t ccx) const { if(!Success()) return false; return IsBranchGoingToExecute(mInstr.info.mnemonic, eflags, ccx); } bool Zydis::IsBranchGoingToExecute(ZydisMnemonic id, uint32_t eflags, uint64_t ccx) { auto bCF = (eflags & (1 << 0)) != 0; auto bPF = (eflags & (1 << 2)) != 0; auto bZF = (eflags & (1 << 6)) != 0; auto bSF = (eflags & (1 << 7)) != 0; auto bOF = (eflags & (1 << 11)) != 0; switch(id) { case ZYDIS_MNEMONIC_CALL: case ZYDIS_MNEMONIC_JMP: case ZYDIS_MNEMONIC_RET: return true; case ZYDIS_MNEMONIC_JNB: //jump short if above or equal return !bCF; case ZYDIS_MNEMONIC_JNBE: //jump short if above return !bCF && !bZF; case ZYDIS_MNEMONIC_JBE: //jump short if below or equal/not above return bCF || bZF; case ZYDIS_MNEMONIC_JB: //jump short if below/not above nor equal/carry return bCF; case ZYDIS_MNEMONIC_JCXZ: //jump short if ecx register is zero case ZYDIS_MNEMONIC_JECXZ: //jump short if ecx register is zero case ZYDIS_MNEMONIC_JRCXZ: //jump short if rcx register is zero return ccx == 0; case ZYDIS_MNEMONIC_JZ: //jump short if equal return bZF; case ZYDIS_MNEMONIC_JNL: //jump short if greater or equal return bSF == bOF; case ZYDIS_MNEMONIC_JNLE: //jump short if greater return !bZF && bSF == bOF; case ZYDIS_MNEMONIC_JLE: //jump short if less or equal/not greater return bZF || bSF != bOF; case ZYDIS_MNEMONIC_JL: //jump short if less/not greater return bSF != bOF; case ZYDIS_MNEMONIC_JNZ: //jump short if not equal/not zero return !bZF; case ZYDIS_MNEMONIC_JNO: //jump short if not overflow return !bOF; case ZYDIS_MNEMONIC_JNP: //jump short if not parity/parity odd return !bPF; case ZYDIS_MNEMONIC_JNS: //jump short if not sign return !bSF; case ZYDIS_MNEMONIC_JO: //jump short if overflow return bOF; case ZYDIS_MNEMONIC_JP: //jump short if parity/parity even return bPF; case ZYDIS_MNEMONIC_JS: //jump short if sign return bSF; case ZYDIS_MNEMONIC_LOOP: //decrement count; jump short if ecx!=0 return ccx != 1; case ZYDIS_MNEMONIC_LOOPE: //decrement count; jump short if ecx!=0 and zf=1 return ccx != 1 && bZF; case ZYDIS_MNEMONIC_LOOPNE: //decrement count; jump short if ecx!=0 and zf=0 return ccx != 1 && !bZF; default: return false; } } bool Zydis::IsConditionalGoingToExecute(uint32_t eflags, uint64_t ccx) const { if(!Success()) return false; return IsConditionalGoingToExecute(mInstr.info.mnemonic, eflags, ccx); } bool Zydis::IsConditionalGoingToExecute(ZydisMnemonic id, uint32_t eflags, uint64_t ccx) { auto bCF = (eflags & (1 << 0)) != 0; auto bPF = (eflags & (1 << 2)) != 0; auto bZF = (eflags & (1 << 6)) != 0; auto bSF = (eflags & (1 << 7)) != 0; auto bOF = (eflags & (1 << 11)) != 0; switch(id) { case ZYDIS_MNEMONIC_CMOVNBE: //conditional move - above/not below nor equal return !bCF && !bZF; case ZYDIS_MNEMONIC_CMOVNB: //conditional move - above or equal/not below/not carry return !bCF; case ZYDIS_MNEMONIC_CMOVB: //conditional move - below/not above nor equal/carry return bCF; case ZYDIS_MNEMONIC_CMOVBE: //conditional move - below or equal/not above return bCF || bZF; case ZYDIS_MNEMONIC_CMOVZ: //conditional move - equal/zero return bZF; case ZYDIS_MNEMONIC_CMOVNLE: //conditional move - greater/not less nor equal return !bZF && bSF == bOF; case ZYDIS_MNEMONIC_CMOVNL: //conditional move - greater or equal/not less return bSF == bOF; case ZYDIS_MNEMONIC_CMOVL: //conditional move - less/not greater nor equal return bSF != bOF; case ZYDIS_MNEMONIC_CMOVLE: //conditional move - less or equal/not greater return bZF || bSF != bOF; case ZYDIS_MNEMONIC_CMOVNZ: //conditional move - not equal/not zero return !bZF; case ZYDIS_MNEMONIC_CMOVNO: //conditional move - not overflow return !bOF; case ZYDIS_MNEMONIC_CMOVNP: //conditional move - not parity/parity odd return !bPF; case ZYDIS_MNEMONIC_CMOVNS: //conditional move - not sign return !bSF; case ZYDIS_MNEMONIC_CMOVO: //conditional move - overflow return bOF; case ZYDIS_MNEMONIC_CMOVP: //conditional move - parity/parity even return bPF; case ZYDIS_MNEMONIC_CMOVS: //conditional move - sign return bSF; case ZYDIS_MNEMONIC_FCMOVBE: //fp conditional move - below or equal return bCF || bZF; case ZYDIS_MNEMONIC_FCMOVB: //fp conditional move - below return bCF; case ZYDIS_MNEMONIC_FCMOVE: //fp conditional move - equal return bZF; case ZYDIS_MNEMONIC_FCMOVNBE: //fp conditional move - not below or equal return !bCF && !bZF; case ZYDIS_MNEMONIC_FCMOVNB: //fp conditional move - not below return !bCF; case ZYDIS_MNEMONIC_FCMOVNE: //fp conditional move - not equal return !bZF; case ZYDIS_MNEMONIC_FCMOVNU: //fp conditional move - not unordered return !bPF; case ZYDIS_MNEMONIC_FCMOVU: //fp conditional move - unordered return bPF; case ZYDIS_MNEMONIC_SETNBE: //set byte on condition - above/not below nor equal return !bCF && !bZF; case ZYDIS_MNEMONIC_SETNB: //set byte on condition - above or equal/not below/not carry return !bCF; case ZYDIS_MNEMONIC_SETB: //set byte on condition - below/not above nor equal/carry return bCF; case ZYDIS_MNEMONIC_SETBE: //set byte on condition - below or equal/not above return bCF || bZF; case ZYDIS_MNEMONIC_SETZ: //set byte on condition - equal/zero return bZF; case ZYDIS_MNEMONIC_SETNLE: //set byte on condition - greater/not less nor equal return !bZF && bSF == bOF; case ZYDIS_MNEMONIC_SETNL: //set byte on condition - greater or equal/not less return bSF == bOF; case ZYDIS_MNEMONIC_SETL: //set byte on condition - less/not greater nor equal return bSF != bOF; case ZYDIS_MNEMONIC_SETLE: //set byte on condition - less or equal/not greater return bZF || bSF != bOF; case ZYDIS_MNEMONIC_SETNZ: //set byte on condition - not equal/not zero return !bZF; case ZYDIS_MNEMONIC_SETNO: //set byte on condition - not overflow return !bOF; case ZYDIS_MNEMONIC_SETNP: //set byte on condition - not parity/parity odd return !bPF; case ZYDIS_MNEMONIC_SETNS: //set byte on condition - not sign return !bSF; case ZYDIS_MNEMONIC_SETO: //set byte on condition - overflow return bOF; case ZYDIS_MNEMONIC_SETP: //set byte on condition - parity/parity even return bPF; case ZYDIS_MNEMONIC_SETS: //set byte on condition - sign return bSF; default: return true; } } void Zydis::RegInfo(uint8_t regs[ZYDIS_REGISTER_MAX_VALUE + 1]) const { memset(regs, 0, sizeof(uint8_t) * (ZYDIS_REGISTER_MAX_VALUE + 1)); if(!Success() || IsNop()) return; for(int i = 0; i < mInstr.info.operand_count; ++i) { const auto & op = mInstr.operands[i]; switch(op.type) { case ZYDIS_OPERAND_TYPE_REGISTER: { switch(op.actions) { case ZYDIS_OPERAND_ACTION_READ: case ZYDIS_OPERAND_ACTION_CONDREAD: regs[op.reg.value] |= RAIRead; break; case ZYDIS_OPERAND_ACTION_WRITE: case ZYDIS_OPERAND_ACTION_CONDWRITE: regs[op.reg.value] |= RAIWrite; break; case ZYDIS_OPERAND_ACTION_READWRITE: case ZYDIS_OPERAND_ACTION_READ_CONDWRITE: case ZYDIS_OPERAND_ACTION_CONDREAD_WRITE: regs[op.reg.value] |= RAIRead | RAIWrite; break; } regs[op.reg.value] |= op.visibility == ZYDIS_OPERAND_VISIBILITY_HIDDEN ? RAIImplicit : RAIExplicit; } break; case ZYDIS_OPERAND_TYPE_MEMORY: { regs[op.mem.segment] |= RAIRead | RAIExplicit; if(op.mem.base != ZYDIS_REGISTER_NONE) regs[op.mem.base] |= RAIRead | RAIExplicit; if(op.mem.index != ZYDIS_REGISTER_NONE) regs[op.mem.index] |= RAIRead | RAIExplicit; } break; default: break; } } } void Zydis::FlagInfo(uint8_t info[32]) const { auto instr = GetInstr(); if(instr == nullptr) { memset(info, 0, 32); return; } for(uint8_t i = 0; i < 32; i++) { auto flag = 1u << i; uint8_t rai = Zydis::RAINone; if(FlagName(flag) != nullptr) { const auto & flags = *instr->info.cpu_flags; if((flags.tested & flag) == flag) { rai |= Zydis::RAIRead; } auto writeMask = flags.modified | flags.set_0 | flags.set_1 | flags.undefined; if((writeMask & flag) == flag) { rai |= Zydis::RAIWrite; } } info[i] = rai; } } const char* Zydis::FlagName(uint32_t flag) const { switch(flag) { case ZYDIS_CPUFLAG_CF: return "CF"; case ZYDIS_CPUFLAG_PF: return "PF"; case ZYDIS_CPUFLAG_AF: return "AF"; case ZYDIS_CPUFLAG_ZF: return "ZF"; case ZYDIS_CPUFLAG_SF: return "SF"; case ZYDIS_CPUFLAG_TF: return "TF"; case ZYDIS_CPUFLAG_IF: return "IF"; case ZYDIS_CPUFLAG_DF: return "DF"; case ZYDIS_CPUFLAG_OF: return "OF"; case ZYDIS_CPUFLAG_IOPL: return "IOPL"; case ZYDIS_CPUFLAG_NT: return "NT"; case ZYDIS_CPUFLAG_RF: return "RF"; case ZYDIS_CPUFLAG_VM: return "VM"; case ZYDIS_CPUFLAG_AC: return "AC"; case ZYDIS_CPUFLAG_VIF: return "VIF"; case ZYDIS_CPUFLAG_VIP: return "VIP"; case ZYDIS_CPUFLAG_ID: return "ID"; default: return nullptr; } } void Zydis::BytesGroup(uint8_t* prefixSize, uint8_t* opcodeSize, uint8_t* group1Size, uint8_t* group2Size, uint8_t* group3Size) const { if(Success()) { *prefixSize = mInstr.info.raw.prefix_count; *group1Size = mInstr.info.raw.disp.size / 8; *group2Size = mInstr.info.raw.imm[0].size / 8; *group3Size = mInstr.info.raw.imm[1].size / 8; *opcodeSize = mInstr.info.length - *prefixSize - *group1Size - *group2Size - *group3Size; } else { *prefixSize = 0; *opcodeSize = mInstr.info.length; *group1Size = 0; *group2Size = 0; *group3Size = 0; } }