Подпишитесь на наш Telegram-канал, чтобы всегда быть в курсе важных обновлений! Перейти

Исходник CS2 x64 Decoder & Hooking Method [updated decoder]

Пользователь
Пользователь
Статус
Оффлайн
Регистрация
3 Янв 2020
Сообщения
162
Реакции
172
Hey all, I’m sharing a simple x64 decoder / hooking method that I made for personal learning purposes, figured i share this. This is bare bones,it won't be undetected or anything fancy It’s just a learning tool to help understand how x64 instruction decoding and function hooking work. was tested with various functions and works fine

The code supports a number of basic instructions and provides a framework for handling memory relocations and function trampolines especially for cs2 internal hooking experiment with it on your own.

This is open for improvements and feedback. Feel free contribute

It's a source no virus total needed

Key features:​

  • X64 Instruction Decoder – Decodes common x64 instructions.
  • Function Hooking – Creates trampolines and hooks functions.
  • Learning-Oriented – Comments throughout to help explain what each part does. yeah there is some ai comments
updated decoder works with every hook and improved a few things
cpp:
Expand Collapse Copy
namespace decoder {

    // ---[ 2. Opcode Tables ]---

    // Sourced and expanded to cover the vast majority of instructions
    // encountered in typical x64 code, mirroring MinHook's coverage needs.
    static const OpcodeInfo main_opcode_table[256] = {
        // 0x00 - 0x0F
        { "ADD", OF_MODRM }, { "ADD", OF_MODRM }, { "ADD", OF_MODRM }, { "ADD", OF_MODRM },
        { "ADD", OF_IMM8 }, { "ADD", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "OR", OF_MODRM }, { "OR", OF_MODRM }, { "OR", OF_MODRM }, { "OR", OF_MODRM },
        { "OR", OF_IMM8 }, { "OR", OF_IMM32 }, { nullptr, OF_NONE }, { "TWO_BYTE", OF_TWOBYTE },
        // 0x10 - 0x1F
        { "ADC", OF_MODRM }, { "ADC", OF_MODRM }, { "ADC", OF_MODRM }, { "ADC", OF_MODRM },
        { "ADC", OF_IMM8 }, { "ADC", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "SBB", OF_MODRM }, { "SBB", OF_MODRM }, { "SBB", OF_MODRM }, { "SBB", OF_MODRM },
        { "SBB", OF_IMM8 }, { "SBB", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        // 0x20 - 0x2F
        { "AND", OF_MODRM }, { "AND", OF_MODRM }, { "AND", OF_MODRM }, { "AND", OF_MODRM },
        { "AND", OF_IMM8 }, { "AND", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "SUB", OF_MODRM }, { "SUB", OF_MODRM }, { "SUB", OF_MODRM }, { "SUB", OF_MODRM },
        { "SUB", OF_IMM8 }, { "SUB", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        // 0x30 - 0x3F
        { "XOR", OF_MODRM }, { "XOR", OF_MODRM }, { "XOR", OF_MODRM }, { "XOR", OF_MODRM },
        { "XOR", OF_IMM8 }, { "XOR", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "CMP", OF_MODRM }, { "CMP", OF_MODRM }, { "CMP", OF_MODRM }, { "CMP", OF_MODRM },
        { "CMP", OF_IMM8 }, { "CMP", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        // 0x40 - 0x4F (REX prefixes are handled in the decoder logic)
        { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE },
        { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE },
        { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE },
        { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE },
        // 0x50 - 0x5F
        { "PUSH", OF_NONE }, { "PUSH", OF_NONE }, { "PUSH", OF_NONE }, { "PUSH", OF_NONE },
        { "PUSH", OF_NONE }, { "PUSH", OF_NONE }, { "PUSH", OF_NONE }, { "PUSH", OF_NONE },
        { "POP", OF_NONE }, { "POP", OF_NONE }, { "POP", OF_NONE }, { "POP", OF_NONE },
        { "POP", OF_NONE }, { "POP", OF_NONE }, { "POP", OF_NONE }, { "POP", OF_NONE },
        // 0x60 - 0x6F
        { nullptr, OF_NONE }, { nullptr, OF_NONE }, { "MOVS", OF_MODRM }, { "MOVS", OF_MODRM },
        { nullptr, OF_NONE }, { nullptr, OF_NONE }, { "OP_PREFIX", OF_NONE }, { "ADDR_PREFIX", OF_NONE },
        { "PUSH", OF_IMM32 }, { "IMUL", OF_MODRM | OF_IMM32 }, { "PUSH", OF_IMM8 }, { "IMUL", OF_MODRM | OF_IMM8 },
        { "INSB", OF_NONE }, { "INSW", OF_NONE }, { "OUTSB", OF_NONE }, { "OUTSW", OF_NONE },
        // 0x70 - 0x7F
        { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 },
        { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 },
        { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 },
        { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 },
        // 0x80 - 0x8F
        { "GRP1", OF_MODRM | OF_IMM8 }, { "GRP1", OF_MODRM | OF_IMM32 }, { nullptr, OF_NONE }, { "GRP1", OF_MODRM | OF_IMM8 },
        { "TEST", OF_MODRM }, { "TEST", OF_MODRM }, { "XCHG", OF_MODRM }, { "XCHG", OF_MODRM },
        { "MOV", OF_MODRM }, { "MOV", OF_MODRM }, { "MOV", OF_MODRM }, { "MOV", OF_MODRM },
        { "LEA", OF_MODRM }, { "MOV", OF_MODRM }, { "POP", OF_MODRM }, { "NOP", OF_NONE },
        // 0x90 - 0x9F
        { "NOP", OF_NONE }, { "XCHG", OF_NONE }, { "XCHG", OF_NONE }, { "XCHG", OF_NONE },
        { "XCHG", OF_NONE }, { "XCHG", OF_NONE }, { "XCHG", OF_NONE }, { "XCHG", OF_NONE },
        { "CBW", OF_NONE }, { "CWD", OF_NONE }, { "CALLF", OF_NONE }, { "WAIT", OF_NONE },
        { "PUSHF", OF_NONE }, { "POPF", OF_NONE }, { "SAHF", OF_NONE }, { "LAHF", OF_NONE },
        // 0xA0 - 0xAF
        { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 },
        { "MOVSB", OF_NONE }, { "MOVSW", OF_NONE }, { "CMPSB", OF_NONE }, { "CMPSW", OF_NONE },
        { "TEST", OF_IMM8 }, { "TEST", OF_IMM32 }, { "STOSB", OF_NONE }, { "STOSW", OF_NONE },
        { "LODSB", OF_NONE }, { "LODSW", OF_NONE }, { "SCASB", OF_NONE }, { "SCASW", OF_NONE },
        // 0xB0 - 0xBF
        { "MOV", OF_IMM8 }, { "MOV", OF_IMM8 }, { "MOV", OF_IMM8 }, { "MOV", OF_IMM8 },
        { "MOV", OF_IMM8 }, { "MOV", OF_IMM8 }, { "MOV", OF_IMM8 }, { "MOV", OF_IMM8 },
        { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 },
        { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 },
        // 0xC0 - 0xCF
        { "GRP2", OF_MODRM | OF_IMM8 }, { "GRP2", OF_MODRM | OF_IMM8 }, { "RET", OF_IMM16 }, { "RET", OF_NONE },
        { "LES", OF_MODRM }, { "LDS", OF_MODRM }, { "MOV", OF_MODRM | OF_IMM8 }, { "MOV", OF_MODRM | OF_IMM32 },
        { "ENTER", OF_NONE }, { "LEAVE", OF_NONE }, { "RETF", OF_IMM16 }, { "RETF", OF_NONE },
        { "INT3", OF_NONE }, { "INT", OF_IMM8 }, { "INTO", OF_NONE }, { "IRET", OF_NONE },
        // 0xD0 - 0xDF
        { "GRP2", OF_MODRM }, { "GRP2", OF_MODRM }, { "GRP2", OF_MODRM }, { "GRP2", OF_MODRM },
        { nullptr, OF_NONE }, { nullptr, OF_NONE }, { nullptr, OF_NONE }, { "XLAT", OF_NONE },
        { "FPU", OF_NONE }, { "FPU", OF_NONE }, { "FPU", OF_NONE }, { "FPU", OF_NONE },
        { "FPU", OF_NONE }, { "FPU", OF_NONE }, { "FPU", OF_NONE }, { "FPU", OF_NONE },
        // 0xE0 - 0xEF
        { "LOOPNE", OF_RELATIVE | OF_IMM8 }, { "LOOPE", OF_RELATIVE | OF_IMM8 }, { "LOOP", OF_RELATIVE | OF_IMM8 }, { "JRCXZ", OF_RELATIVE | OF_IMM8 },
        { "IN", OF_IMM8 }, { "IN", OF_NONE }, { "OUT", OF_IMM8 }, { "OUT", OF_NONE },
        { "CALL", OF_RELATIVE | OF_IMM32 }, { "JMP", OF_RELATIVE | OF_IMM32 }, { "JMPF", OF_NONE }, { "JMP", OF_RELATIVE | OF_IMM8 },
        { "IN", OF_IMM8 }, { "IN", OF_NONE }, { "OUT", OF_IMM8 }, { "OUT", OF_NONE },
        // 0xF0 - 0xFF
        { "LOCK", OF_NONE }, { nullptr, OF_NONE }, { "REPNE", OF_NONE }, { "REP", OF_NONE },
        { "HLT", OF_NONE }, { "CMC", OF_NONE }, { "GRP3", OF_MODRM }, { "GRP3", OF_MODRM },
        { "CLC", OF_NONE }, { "STC", OF_NONE }, { "CLI", OF_NONE }, { "STI", OF_NONE },
        { "CLD", OF_NONE }, { "STD", OF_NONE }, { "GRP4", OF_MODRM }, { "GRP5", OF_MODRM }
    };

    static const OpcodeInfo two_byte_opcode_table[256] = {
        // 0x00 - 0x0F
        { "GRP6", OF_MODRM }, { "GRP7", OF_MODRM }, { "LAR", OF_MODRM }, { "LSL", OF_MODRM },
        { nullptr, OF_NONE }, { "SYSCALL", OF_NONE }, { "CLTS", OF_NONE }, { "SYSRET", OF_NONE },
        { "INVD", OF_NONE }, { "WBINVD", OF_NONE }, { nullptr, OF_NONE }, { "UD2", OF_NONE },
        { nullptr, OF_NONE }, { "PREFETCH", OF_MODRM }, { "FEMMS", OF_NONE }, { nullptr, OF_NONE },

        // 0x10 - 0x1F (SSE)
        { "MOVUPS", OF_MODRM }, { "MOVUPS", OF_MODRM }, { "MOVSS", OF_MODRM }, { "MOVSS", OF_MODRM },
        { "MOVUPD", OF_MODRM }, { "MOVUPD", OF_MODRM }, { "MOVSD", OF_MODRM }, { "MOVSD", OF_MODRM },
        { "MOVLPS", OF_MODRM }, { "MOVLPS", OF_MODRM }, { "UNPCKLPS", OF_MODRM }, { "UNPCKHPS", OF_MODRM },
        { "MOVLPD", OF_MODRM }, { "MOVLPD", OF_MODRM }, { "UNPCKLPD", OF_MODRM }, { "UNPCKHPD", OF_MODRM },

        // 0x20 - 0x2F
        { "MOV", OF_MODRM }, { "MOV", OF_MODRM }, { "MOV", OF_MODRM }, { "MOV", OF_MODRM },
        { nullptr, OF_NONE }, { nullptr, OF_NONE }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "CVTPI2PS", OF_MODRM }, { "CVTTPS2PI", OF_MODRM }, { "CVTPS2PI", OF_MODRM }, { "CVTSI2SS", OF_MODRM },
        { "CVTPI2PD", OF_MODRM }, { "CVTTPD2PI", OF_MODRM }, { "CVTPD2PI", OF_MODRM }, { "CVTSI2SD", OF_MODRM },

        // 0x30 - 0x3F
        { "WRMSR", OF_NONE }, { "RDTSC", OF_NONE }, { "RDMSR", OF_NONE }, { "RDPMC", OF_NONE },
        { "SYSENTER", OF_NONE }, { "SYSEXIT", OF_NONE }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "THREE_BYTE_38", OF_THREEBYTE_38 }, { nullptr, OF_NONE }, { "THREE_BYTE_3A", OF_THREEBYTE_3A }, { nullptr, OF_NONE },
        { nullptr, OF_NONE }, { nullptr, OF_NONE }, { nullptr, OF_NONE }, { nullptr, OF_NONE },

        // 0x40 - 0x4F (CMOVcc)
        { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM },
        { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM },
        { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM },
        { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM },

        // 0x50 - 0x5F (SSE)
        { "MOVMSKPS", OF_MODRM }, { "SQRTPS", OF_MODRM }, { "RSQRTPS", OF_MODRM }, { "RCPPS", OF_MODRM },
        { "ANDPS", OF_MODRM }, { "ANDNPS", OF_MODRM }, { "ORPS", OF_MODRM }, { "XORPS", OF_MODRM },
        { "ADDPS", OF_MODRM }, { "MULPS", OF_MODRM }, { "CVTPS2PD", OF_MODRM }, { "CVTDQ2PS", OF_MODRM },
        { "SUBPS", OF_MODRM }, { "MINPS", OF_MODRM }, { "DIVPS", OF_MODRM }, { "MAXPS", OF_MODRM },

        // 0x60 - 0x6F (MMX/SSE)
        { "PUNPCKLBW", OF_MODRM }, { "PUNPCKLWD", OF_MODRM }, { "PUNPCKLDQ", OF_MODRM }, { "PACKSSWB", OF_MODRM },
        { "PCMPGTB", OF_MODRM }, { "PCMPGTW", OF_MODRM }, { "PCMPGTD", OF_MODRM }, { "PACKUSWB", OF_MODRM },
        { "PUNPCKHBW", OF_MODRM }, { "PUNPCKHWD", OF_MODRM }, { "PUNPCKHDQ", OF_MODRM }, { "PACKSSDW", OF_MODRM },
        { "PUNPCKLQDQ", OF_MODRM }, { "PUNPCKHQDQ", OF_MODRM }, { "MOVD", OF_MODRM }, { "MOVQ", OF_MODRM },

        // 0x70 - 0x7F (SSE)
        { "PSHUFW", OF_MODRM | OF_IMM8 }, { "GRP12", OF_MODRM }, { "GRP13", OF_MODRM }, { "GRP14", OF_MODRM },
        { "PCMPEQB", OF_MODRM }, { "PCMPEQW", OF_MODRM }, { "PCMPEQD", OF_MODRM }, { "EMMS", OF_NONE },
        { "VMREAD", OF_MODRM }, { "VMWRITE", OF_MODRM }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "HADDPD", OF_MODRM }, { "HSUBPD", OF_MODRM }, { "MOVD", OF_MODRM }, { "MOVQ", OF_MODRM },

        // 0x80 - 0x8F (Jcc near) - THIS IS THE CRITICAL FIX
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },

        // 0x90 - 0x9F (SETcc)
        { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM },
        { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM },
        { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM },
        { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM },

        // 0xA0 - 0xAF
        { "PUSH", OF_NONE }, { "POP", OF_NONE }, { "CPUID", OF_NONE }, { "BT", OF_MODRM },
        { "SHLD", OF_MODRM | OF_IMM8 }, { "SHLD", OF_MODRM }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "PUSH", OF_NONE }, { "POP", OF_NONE }, { "RSM", OF_NONE }, { "BTS", OF_MODRM },
        { "SHRD", OF_MODRM | OF_IMM8 }, { "SHRD", OF_MODRM }, { "GRP15", OF_MODRM }, { "IMUL", OF_MODRM },

        // 0xB0 - 0xBF
        { "CMPXCHG", OF_MODRM }, { "CMPXCHG", OF_MODRM }, { "LSS", OF_MODRM }, { "BTR", OF_MODRM },
        { "LFS", OF_MODRM }, { "LGS", OF_MODRM }, { "MOVZX", OF_MODRM }, { "MOVZX", OF_MODRM },
        { "POPCNT", OF_MODRM }, { "GRP10", OF_MODRM }, { "GRP8", OF_MODRM | OF_IMM8 }, { "BTC", OF_MODRM },
        { "BSF", OF_MODRM }, { "BSR", OF_MODRM }, { "MOVSX", OF_MODRM }, { "MOVSX", OF_MODRM },

        // 0xC0 - 0xCF
        { "XADD", OF_MODRM }, { "XADD", OF_MODRM }, { "CMPPS", OF_MODRM | OF_IMM8 }, { "MOVNTI", OF_MODRM },
        { "PINSRW", OF_MODRM | OF_IMM8 }, { "PEXTRW", OF_MODRM | OF_IMM8 }, { "SHUFPS", OF_MODRM | OF_IMM8 }, { "GRP9", OF_MODRM },
        { "BSWAP", OF_NONE }, { "BSWAP", OF_NONE }, { "BSWAP", OF_NONE }, { "BSWAP", OF_NONE },
        { "BSWAP", OF_NONE }, { "BSWAP", OF_NONE }, { "BSWAP", OF_NONE }, { "BSWAP", OF_NONE },

        // 0xD0 - 0xDF (MMX/SSE)
        { "ADDSUBPD", OF_MODRM }, { "PSRLW", OF_MODRM }, { "PSRLD", OF_MODRM }, { "PSRLQ", OF_MODRM },
        { "PADDQ", OF_MODRM }, { "PMULLW", OF_MODRM }, { "MOVQ", OF_MODRM }, { "PMOVMSKB", OF_MODRM },
        { "PSUBUSB", OF_MODRM }, { "PSUBUSW", OF_MODRM }, { "PMINUB", OF_MODRM }, { "PAND", OF_MODRM },
        { "PADDUSB", OF_MODRM }, { "PADDUSW", OF_MODRM }, { "PMAXUB", OF_MODRM }, { "PANDN", OF_MODRM },

        // 0xE0 - 0xEF (MMX/SSE)
        { "PAVGB", OF_MODRM }, { "PSRAW", OF_MODRM }, { "PSRAD", OF_MODRM }, { "PAVGW", OF_MODRM },
        { "PMULHUW", OF_MODRM }, { "PMULHW", OF_MODRM }, { "CVTTPD2DQ", OF_MODRM }, { "MOVNTQ", OF_MODRM },
        { "PSUBSB", OF_MODRM }, { "PSUBSW", OF_MODRM }, { "PMINSW", OF_MODRM }, { "POR", OF_MODRM },
        { "PADDSB", OF_MODRM }, { "PADDSW", OF_MODRM }, { "PMAXSW", OF_MODRM }, { "PXOR", OF_MODRM },

        // 0xF0 - 0xFF (MMX/SSE)
        { "LDDQU", OF_MODRM }, { "PSLLW", OF_MODRM }, { "PSLLD", OF_MODRM }, { "PSLLQ", OF_MODRM },
        { "PMULUDQ", OF_MODRM }, { "PMADDWD", OF_MODRM }, { "PSADBW", OF_MODRM }, { "MASKMOVQ", OF_MODRM },
        { "PSUBB", OF_MODRM }, { "PSUBW", OF_MODRM }, { "PSUBD", OF_MODRM }, { "PSUBQ", OF_MODRM },
        { "PADDB", OF_MODRM }, { "PADDW", OF_MODRM }, { "PADDD", OF_MODRM }, { "UD0", OF_NONE }
    };


    // ---[ 3. Decoding and Relocation Logic ]---

    static ModRM decode_modrm(uint8_t b) {
        return { (uint8_t)((b >> 6) & 0x3), (uint8_t)((b >> 3) & 0x7), (uint8_t)(b & 0x7) };
    }

    // Return the total length of decoded instructions covering at least min_total_len bytes
    size_t length_disasm_until_min_bytes(uint8_t* code, size_t max_len, size_t min_total_len) {
        size_t total_len = 0;
        size_t cur_offset = 0;

        while (cur_offset < max_len && total_len < min_total_len) {
            Instruction inst;
            if (!decode_instruction(code + cur_offset, max_len - cur_offset, inst))
                break;
            total_len += inst.length;
            cur_offset += inst.length;
        }
        return total_len;
    }

    bool decode_instruction(const uint8_t* code, size_t max_len, Instruction& out_inst) {
        if (!code || max_len == 0) return false;

        out_inst = {};
        out_inst.address = code;

        size_t idx = 0;

        // Prefix Parsing
        bool possible_rex = true;
        while (idx < max_len) {
            uint8_t current_byte = code[idx];

            // VEX prefixes (C4, C5)
            if (current_byte == 0xC5 && idx + 1 < max_len) {
                out_inst.has_vex = true;
                out_inst.vex_prefix[0] = current_byte;
                out_inst.vex_prefix[1] = code[idx + 1];
                out_inst.vex_pp = (code[idx + 1] >> 0) & 0x3;
                out_inst.vex_L = (code[idx + 1] >> 2) & 0x1;
                out_inst.vex_vvvv = (~(code[idx + 1] >> 3)) & 0xF;
                idx += 2;
                goto opcode_parse;
            }
            if (current_byte == 0xC4 && idx + 2 < max_len) {
                out_inst.has_vex = true;
                out_inst.vex_prefix[0] = current_byte;
                out_inst.vex_prefix[1] = code[idx + 1];
                out_inst.vex_prefix[2] = code[idx + 2];
                out_inst.vex_pp = (code[idx + 2] >> 0) & 0x3;
                out_inst.vex_L = (code[idx + 2] >> 2) & 0x1;
                out_inst.vex_vvvv = (~(code[idx + 2] >> 3)) & 0xF;
                idx += 3;
                goto opcode_parse;
            }

            if (possible_rex && (current_byte >= 0x40 && current_byte <= 0x4F)) {
                out_inst.rex = current_byte;
                idx++;
                continue;
            }

            switch (current_byte) {
            case 0xF0: case 0xF2: case 0xF3: case 0x2E: case 0x36:
            case 0x3E: case 0x26: case 0x64: case 0x65: case 0x66: case 0x67:
                if (out_inst.num_prefixes < 4) {
                    out_inst.prefixes[out_inst.num_prefixes++] = current_byte;
                }
                idx++;
                possible_rex = false;
                continue;
            }
            break;
        }

    opcode_parse:
        if (idx >= max_len) return false;

        uint8_t opcode_byte = code[idx++];
        const OpcodeInfo* info = &main_opcode_table[opcode_byte];

        if (info->flags & OF_TWOBYTE) {
            if (idx >= max_len) return false;
            opcode_byte = code[idx++];
            info = &two_byte_opcode_table[opcode_byte];
            out_inst.is_two_byte = true;
            // Further check for three-byte opcodes, though tables are sparse
            if ((info->flags & OF_THREEBYTE_38) || (info->flags & OF_THREEBYTE_3A)) {
                // In a full implementation, you'd have 0F38/0F3A tables
                if (idx >= max_len) return false;
                opcode_byte = code[idx++];
                // info = &three_byte_table[opcode_byte];
                out_inst.is_three_byte = true;
            }
        }

        if (!info || !info->mnemonic) {
            out_inst.length = idx;
            out_inst.mnemonic = "unknown";
            return true;
        }

        out_inst.mnemonic = info->mnemonic;
        out_inst.opcode = opcode_byte;

        if (info->flags & OF_MODRM) {
            if (idx >= max_len) return false;
            out_inst.has_modrm = true;
            uint8_t modrm_byte = code[idx++];
            out_inst.modrm = modrm_byte;
            ModRM modrm = decode_modrm(modrm_byte);

            if (modrm.mod != 3 && modrm.rm == 4) {
                if (idx >= max_len) return false;
                out_inst.has_sib = true;
                out_inst.sib = code[idx++];
            }

            if (modrm.mod == 1) {
                if (idx >= max_len) return false;
                out_inst.disp_offset = idx;
                out_inst.displacement = *reinterpret_cast<const int8_t*>(&code[idx]);
                idx++;
            }
            else if (modrm.mod == 2 || (modrm.mod == 0 && modrm.rm == 5)) {
                if (idx + 4 > max_len) return false;
                out_inst.disp_offset = idx;
                out_inst.displacement = *reinterpret_cast<const int32_t*>(&code[idx]);
                if (modrm.mod == 0 && modrm.rm == 5) out_inst.is_rip_relative = true;
                idx += 4;
            }
        }

        size_t imm_size = 0;
        if (info->flags & OF_IMM8) imm_size = 1;
        else if (info->flags & OF_IMM16) imm_size = 2;
        else if (info->flags & OF_IMM32) imm_size = 4;
        else if ((info->flags & OF_IMM64) || (out_inst.rex & 0x08 && opcode_byte >= 0xB8 && opcode_byte <= 0xBF)) {
            imm_size = 8;
        }

        if (imm_size > 0) {
            if (idx + imm_size > max_len) return false;
            out_inst.imm_offset = idx;
            switch (imm_size) {
            case 1: out_inst.immediate = *reinterpret_cast<const int8_t*>(&code[idx]); break;
            case 2: out_inst.immediate = *reinterpret_cast<const int16_t*>(&code[idx]); break;
            case 4: out_inst.immediate = *reinterpret_cast<const int32_t*>(&code[idx]); break;
            case 8: out_inst.immediate = *reinterpret_cast<const int64_t*>(&code[idx]); break;
            }
            idx += imm_size;
        }

        out_inst.length = idx;
        return true;
    }

    void write_absolute_jump(uint8_t* buffer, void* destination) {
        buffer[0] = 0xFF;
        buffer[1] = 0x25;
        *reinterpret_cast<int32_t*>(&buffer[2]) = 0;
        *reinterpret_cast<uint64_t*>(&buffer[6]) = reinterpret_cast<uint64_t>(destination);
    }

    size_t get_relocated_length(const Instruction& inst) {
        // Handle decomposition of LOOP instructions. They become larger.
        // LOOP/LOOPZ/LOOPNZ are 2 bytes originally.
        switch (inst.opcode) {
        case 0xE0: // LOOPNE/LOOPNZ: dec ecx; jne/jnz target
        case 0xE1: // LOOPE/LOOPZ:   dec ecx; je/jz target
        case 0xE2: // LOOP:          dec ecx; jne/jnz target
            // Decomposes to: DEC ECX (1 byte) + Jcc NEAR (6 bytes) = 7 bytes.
            return 7;
        case 0xE3: // JRCXZ:         test rcx,rcx; jz target
            // Decomposes to: TEST RCX,RCX (3 bytes) + JZ NEAR (6 bytes) = 9 bytes.
            return 9;
        }

        if (inst.mnemonic == "Jcc") {
            // Expanded to J(!cc) NEAR skip + JMP ABS target
            return 20;
        }

        if (inst.mnemonic == "JMP" || inst.mnemonic == "CALL") {
            const OpcodeInfo* info = inst.is_two_byte ? &two_byte_opcode_table[inst.opcode] : &main_opcode_table[inst.opcode];
            if (info && (info->flags & OF_RELATIVE)) {
                // Expanded to JMP ABS target
                return 14;
            }
        }

        // All other instructions do not change in length.
        return inst.length;
    }

// Follows a chain of JMP instructions to find the real function address.
    uint8_t* resolve_jumps(uint8_t* func_ptr) {
        // We'll follow a maximum of 10 jumps to prevent infinite loops.
        for (int i = 0; i < 10; ++i) {
            Instruction inst;
            if (!decode_instruction(func_ptr, 16, inst)) {
                // Cannot decode, assume it's the real function.
                return func_ptr;
            }

            // We are only interested in unconditional jumps.
            if (inst.mnemonic != "JMP") {
                return func_ptr;
            }

            // This is the absolute address the JMP instruction points to.
            uint64_t target_address = 0;

            // Check if it's a relative JMP (e.g., JMP 0x...).
            const OpcodeInfo* info = inst.is_two_byte
                ? &two_byte_opcode_table[inst.opcode]
                : &main_opcode_table[inst.opcode];

            if (info && (info->flags & OF_RELATIVE)) {
                uint64_t next_ip = reinterpret_cast<uint64_t>(func_ptr) + inst.length;
                target_address = next_ip + inst.immediate;
            }
            // Check if it's a JMP via a memory pointer (e.g., JMP [rip+0x...]).
            else if (inst.is_rip_relative) {
                uint64_t next_ip = reinterpret_cast<uint64_t>(func_ptr) + inst.length;
                uint64_t pointer_address = next_ip + inst.displacement;
                // Read the 64-bit address from that memory location.
                target_address = *reinterpret_cast<uint64_t*>(pointer_address);
            }
            else {
                // It's another type of JMP (e.g., JMP RAX) that we can't resolve.
                // Assume we're at the destination.
                return func_ptr;
            }

            func_ptr = reinterpret_cast<uint8_t*>(target_address);
        }

        // If we've jumped 10 times, we're probably in a loop, return what we have.
        return func_ptr;
    }

    bool relocate_instruction(const Instruction& inst, uint8_t* trampoline_ptr, size_t& trampoline_len) {
        uint64_t original_addr = reinterpret_cast<uint64_t>(inst.address);
        uint64_t trampoline_addr = reinterpret_cast<uint64_t>(trampoline_ptr);
        uint64_t original_next_ip = original_addr + inst.length;

        // The absolute address of the original jump/call/loop target
        uint64_t original_target = original_next_ip + inst.immediate;

        // --- Special Handling for LOOP/JRCXZ Instructions ---
        switch (inst.opcode) {
        case 0xE0: // LOOPNE/LOOPNZ target -> DEC ECX; JNE target
        case 0xE1: // LOOPE/LOOPZ target  -> DEC ECX; JE target
        case 0xE2: // LOOP target         -> DEC ECX; JNZ target
        {
            // Get the corresponding Jcc near opcode (0x80 series)
            uint8_t jcc_opcode;
            if (inst.opcode == 0xE0) jcc_opcode = 0x85; // JNE
            else if (inst.opcode == 0xE1) jcc_opcode = 0x84; // JE
            else jcc_opcode = 0x85; // JNZ for LOOP

            // 1. Write 'DEC ECX' (opcode FF C9)
            // Note: LOOP instructions use ECX even in 64-bit mode unless a REX.W prefix is used, which is rare.
            trampoline_ptr[0] = 0xFF;
            trampoline_ptr[1] = 0xC9;

            // 2. Write the 6-byte near conditional jump to the absolute target
            trampoline_ptr[2] = 0x0F;
            trampoline_ptr[3] = jcc_opcode;
            int32_t relative_offset = static_cast<int32_t>(original_target - (trampoline_addr + 8)); // Target - End of this instruction
            *reinterpret_cast<int32_t*>(&trampoline_ptr[4]) = relative_offset;

            trampoline_len = 8; // DEC ECX (2 bytes) + Jcc NEAR (6 bytes)
            return true;
        }
        case 0xE3: // JRCXZ target -> TEST RCX, RCX; JZ target
        {
            // 1. Write 'TEST RCX, RCX' (opcode 48 85 C9)
            trampoline_ptr[0] = 0x48;
            trampoline_ptr[1] = 0x85;
            trampoline_ptr[2] = 0xC9;

            // 2. Write 'JZ NEAR' (opcode 0F 84) to the absolute target
            trampoline_ptr[3] = 0x0F;
            trampoline_ptr[4] = 0x84; // JZ
            int32_t relative_offset = static_cast<int32_t>(original_target - (trampoline_addr + 9)); // Target - End of this instruction
            *reinterpret_cast<int32_t*>(&trampoline_ptr[5]) = relative_offset;

            trampoline_len = 9; // TEST (3 bytes) + JZ NEAR (6 bytes)
            return true;
        }
        }

        // For all other instructions, start by copying the original bytes
        memcpy(trampoline_ptr, inst.address, inst.length);
        trampoline_len = inst.length;

        if (inst.is_rip_relative) {
            uint64_t rip_rel_target = original_next_ip + inst.displacement;
            int32_t new_disp = static_cast<int32_t>(rip_rel_target - (trampoline_addr + inst.length));
            *reinterpret_cast<int32_t*>(trampoline_ptr + inst.disp_offset) = new_disp;
            return true;
        }

        const OpcodeInfo* info = inst.is_two_byte ? &two_byte_opcode_table[inst.opcode] : &main_opcode_table[inst.opcode];
        if (info && (info->flags & OF_RELATIVE)) {
            if (inst.mnemonic == "JMP" || inst.mnemonic == "CALL") {
                write_absolute_jump(trampoline_ptr, reinterpret_cast<void*>(original_target));
                trampoline_len = 14;
            }
            else if (inst.mnemonic == "Jcc") {
                uint8_t condition = inst.opcode & 0x0F;
                uint8_t opposite_condition = condition ^ 1;

                trampoline_ptr[0] = 0x0F;
                trampoline_ptr[1] = 0x80 + opposite_condition;
                *reinterpret_cast<int32_t*>(&trampoline_ptr[2]) = 14;

                write_absolute_jump(trampoline_ptr + 6, reinterpret_cast<void*>(original_target));
                trampoline_len = 20;
            }
        }

        return true;
    }

    uint8_t* resolve_jump_thunk(uint8_t* fn, int depth) {
        if (depth > 10)
            return fn; // Prevent infinite recursion

        Instruction inst;
        // The instruction decoder is used here to find JMPs
        if (!decode_instruction(fn, 15, inst) || inst.mnemonic != "JMP") {
            return fn;
        }

        uint64_t target = 0;
        uint64_t next_ip = reinterpret_cast<uint64_t>(fn) + inst.length;

        // JMP rel32 (E9) or JMP rel8 (EB)
        if (inst.opcode == 0xE9 || inst.opcode == 0xEB) {
            target = next_ip + inst.immediate;
        }
        // JMP r/m64 (FF /4) with RIP-relative addressing
        else if (inst.opcode == 0xFF && inst.is_rip_relative) {
            uint8_t* effective_address = reinterpret_cast<uint8_t*>(next_ip + inst.displacement);
            if (!IsBadReadPtr(effective_address, sizeof(uint64_t))) {
                target = *reinterpret_cast<uint64_t*>(effective_address);
            }
            else {
                return fn; // Can't read memory
            }
        }
        else {
            return fn; // Not a simple JMP we can resolve
        }

        return resolve_jump_thunk(reinterpret_cast<uint8_t*>(target), depth + 1);
    }

} // namespace decoder

.h

c++:
Expand Collapse Copy
namespace decoder {

    // Global array of 64-bit register names for easy lookup.
    static const char* reg64[16] = {
        "RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
        "R8",  "R9",  "R10", "R11", "R12", "R13", "R14", "R15"
    };

    // Defines the type of an operand (Register, Memory, or Immediate value).
    enum class OperandType {
        REG,
        MEM,
        IMM
    };

    // Represents a single operand for an instruction.
    struct Operand {
        OperandType type;
        uint8_t size;
        int64_t value = 0;
        std::string text; // Formatted text for the operand (e.g., "RAX", "[RIP+0x1234]").
    };

    // Represents the SIB byte, used for complex memory addressing.
    struct SIB {
        uint8_t scale, index, base;
    };

    struct Instruction {
        const uint8_t* address;
        uint8_t length;
        std::string mnemonic;

        uint8_t prefixes[4];
        uint8_t num_prefixes;
        uint8_t rex;
        uint8_t opcode;
        bool is_two_byte;
        bool is_three_byte; // For 0F 38/3A opcodes

        bool has_modrm;
        uint8_t modrm;
        bool has_sib;
        uint8_t sib;

        uint8_t disp_offset;
        int32_t displacement;
        bool is_rip_relative;

        uint8_t imm_offset;
        int64_t immediate;

        // VEX Prefix Info
        bool has_vex;
        uint8_t vex_prefix[3];
        uint8_t vex_L;
        uint8_t vex_pp;
        uint8_t vex_vvvv;
    };

    // Represents the ModR/M byte fields.
    struct ModRM {
        uint8_t mod;
        uint8_t reg;
        uint8_t rm;
    };


// Describes the properties of an opcode.
    enum OpcodeFlags : uint32_t {
        OF_NONE = 0,
        OF_MODRM = 1 << 0,  // Instruction has a ModR/M byte
        OF_IMM8 = 1 << 1,  // Instruction has an 8-bit immediate
        OF_IMM16 = 1 << 2,  // Instruction has a 16-bit immediate
        OF_IMM32 = 1 << 3,  // Instruction has a 32-bit immediate
        OF_IMM64 = 1 << 4,  // Instruction has a 64-bit immediate
        OF_RELATIVE = 1 << 5,  // Immediate is a relative offset (for JMP, CALL, Jcc)
        OF_TWOBYTE = 1 << 6,  // Indicates a two-byte opcode map (0F xx)
        OF_THREEBYTE_38 = 1 << 7, // Three-byte opcode map (0F 38 xx)
        OF_THREEBYTE_3A = 1 << 8, // Three-byte opcode map (0F 3A xx)
    };

    // Maps an opcode to its mnemonic and properties.
    struct OpcodeInfo {
        const char* mnemonic;
        uint32_t flags;
    };

    bool decode_instruction(const uint8_t* code, size_t max_len, Instruction& out_inst);;
    bool relocate_instruction(const Instruction& inst, uint8_t* trampoline_ptr, size_t& trampoline_len);
    uint8_t* resolve_jump_thunk(uint8_t* fn, int depth);
    void write_absolute_jump(uint8_t* buffer, void* destination);
    size_t length_disasm_until_min_bytes(uint8_t* code, size_t max_len, size_t min_total_len);
    size_t get_relocated_length(const Instruction& inst);
    uint8_t* resolve_jumps(uint8_t* func_ptr);
} // namespace decoder
 

Вложения

Последнее редактирование:
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
прикольно, вроде крутая штука, но я не понял.
 
updated decoder works with every hook and improved a few things
cpp:
Expand Collapse Copy
namespace decoder {

    // ---[ 2. Opcode Tables ]---

    // Sourced and expanded to cover the vast majority of instructions
    // encountered in typical x64 code, mirroring MinHook's coverage needs.
    static const OpcodeInfo main_opcode_table[256] = {
        // 0x00 - 0x0F
        { "ADD", OF_MODRM }, { "ADD", OF_MODRM }, { "ADD", OF_MODRM }, { "ADD", OF_MODRM },
        { "ADD", OF_IMM8 }, { "ADD", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "OR", OF_MODRM }, { "OR", OF_MODRM }, { "OR", OF_MODRM }, { "OR", OF_MODRM },
        { "OR", OF_IMM8 }, { "OR", OF_IMM32 }, { nullptr, OF_NONE }, { "TWO_BYTE", OF_TWOBYTE },
        // 0x10 - 0x1F
        { "ADC", OF_MODRM }, { "ADC", OF_MODRM }, { "ADC", OF_MODRM }, { "ADC", OF_MODRM },
        { "ADC", OF_IMM8 }, { "ADC", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "SBB", OF_MODRM }, { "SBB", OF_MODRM }, { "SBB", OF_MODRM }, { "SBB", OF_MODRM },
        { "SBB", OF_IMM8 }, { "SBB", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        // 0x20 - 0x2F
        { "AND", OF_MODRM }, { "AND", OF_MODRM }, { "AND", OF_MODRM }, { "AND", OF_MODRM },
        { "AND", OF_IMM8 }, { "AND", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "SUB", OF_MODRM }, { "SUB", OF_MODRM }, { "SUB", OF_MODRM }, { "SUB", OF_MODRM },
        { "SUB", OF_IMM8 }, { "SUB", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        // 0x30 - 0x3F
        { "XOR", OF_MODRM }, { "XOR", OF_MODRM }, { "XOR", OF_MODRM }, { "XOR", OF_MODRM },
        { "XOR", OF_IMM8 }, { "XOR", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "CMP", OF_MODRM }, { "CMP", OF_MODRM }, { "CMP", OF_MODRM }, { "CMP", OF_MODRM },
        { "CMP", OF_IMM8 }, { "CMP", OF_IMM32 }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        // 0x40 - 0x4F (REX prefixes are handled in the decoder logic)
        { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE },
        { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE },
        { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE },
        { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE }, { "REX", OF_NONE },
        // 0x50 - 0x5F
        { "PUSH", OF_NONE }, { "PUSH", OF_NONE }, { "PUSH", OF_NONE }, { "PUSH", OF_NONE },
        { "PUSH", OF_NONE }, { "PUSH", OF_NONE }, { "PUSH", OF_NONE }, { "PUSH", OF_NONE },
        { "POP", OF_NONE }, { "POP", OF_NONE }, { "POP", OF_NONE }, { "POP", OF_NONE },
        { "POP", OF_NONE }, { "POP", OF_NONE }, { "POP", OF_NONE }, { "POP", OF_NONE },
        // 0x60 - 0x6F
        { nullptr, OF_NONE }, { nullptr, OF_NONE }, { "MOVS", OF_MODRM }, { "MOVS", OF_MODRM },
        { nullptr, OF_NONE }, { nullptr, OF_NONE }, { "OP_PREFIX", OF_NONE }, { "ADDR_PREFIX", OF_NONE },
        { "PUSH", OF_IMM32 }, { "IMUL", OF_MODRM | OF_IMM32 }, { "PUSH", OF_IMM8 }, { "IMUL", OF_MODRM | OF_IMM8 },
        { "INSB", OF_NONE }, { "INSW", OF_NONE }, { "OUTSB", OF_NONE }, { "OUTSW", OF_NONE },
        // 0x70 - 0x7F
        { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 },
        { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 },
        { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 },
        { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 }, { "Jcc", OF_RELATIVE | OF_IMM8 },
        // 0x80 - 0x8F
        { "GRP1", OF_MODRM | OF_IMM8 }, { "GRP1", OF_MODRM | OF_IMM32 }, { nullptr, OF_NONE }, { "GRP1", OF_MODRM | OF_IMM8 },
        { "TEST", OF_MODRM }, { "TEST", OF_MODRM }, { "XCHG", OF_MODRM }, { "XCHG", OF_MODRM },
        { "MOV", OF_MODRM }, { "MOV", OF_MODRM }, { "MOV", OF_MODRM }, { "MOV", OF_MODRM },
        { "LEA", OF_MODRM }, { "MOV", OF_MODRM }, { "POP", OF_MODRM }, { "NOP", OF_NONE },
        // 0x90 - 0x9F
        { "NOP", OF_NONE }, { "XCHG", OF_NONE }, { "XCHG", OF_NONE }, { "XCHG", OF_NONE },
        { "XCHG", OF_NONE }, { "XCHG", OF_NONE }, { "XCHG", OF_NONE }, { "XCHG", OF_NONE },
        { "CBW", OF_NONE }, { "CWD", OF_NONE }, { "CALLF", OF_NONE }, { "WAIT", OF_NONE },
        { "PUSHF", OF_NONE }, { "POPF", OF_NONE }, { "SAHF", OF_NONE }, { "LAHF", OF_NONE },
        // 0xA0 - 0xAF
        { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 },
        { "MOVSB", OF_NONE }, { "MOVSW", OF_NONE }, { "CMPSB", OF_NONE }, { "CMPSW", OF_NONE },
        { "TEST", OF_IMM8 }, { "TEST", OF_IMM32 }, { "STOSB", OF_NONE }, { "STOSW", OF_NONE },
        { "LODSB", OF_NONE }, { "LODSW", OF_NONE }, { "SCASB", OF_NONE }, { "SCASW", OF_NONE },
        // 0xB0 - 0xBF
        { "MOV", OF_IMM8 }, { "MOV", OF_IMM8 }, { "MOV", OF_IMM8 }, { "MOV", OF_IMM8 },
        { "MOV", OF_IMM8 }, { "MOV", OF_IMM8 }, { "MOV", OF_IMM8 }, { "MOV", OF_IMM8 },
        { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 },
        { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 }, { "MOV", OF_IMM64 },
        // 0xC0 - 0xCF
        { "GRP2", OF_MODRM | OF_IMM8 }, { "GRP2", OF_MODRM | OF_IMM8 }, { "RET", OF_IMM16 }, { "RET", OF_NONE },
        { "LES", OF_MODRM }, { "LDS", OF_MODRM }, { "MOV", OF_MODRM | OF_IMM8 }, { "MOV", OF_MODRM | OF_IMM32 },
        { "ENTER", OF_NONE }, { "LEAVE", OF_NONE }, { "RETF", OF_IMM16 }, { "RETF", OF_NONE },
        { "INT3", OF_NONE }, { "INT", OF_IMM8 }, { "INTO", OF_NONE }, { "IRET", OF_NONE },
        // 0xD0 - 0xDF
        { "GRP2", OF_MODRM }, { "GRP2", OF_MODRM }, { "GRP2", OF_MODRM }, { "GRP2", OF_MODRM },
        { nullptr, OF_NONE }, { nullptr, OF_NONE }, { nullptr, OF_NONE }, { "XLAT", OF_NONE },
        { "FPU", OF_NONE }, { "FPU", OF_NONE }, { "FPU", OF_NONE }, { "FPU", OF_NONE },
        { "FPU", OF_NONE }, { "FPU", OF_NONE }, { "FPU", OF_NONE }, { "FPU", OF_NONE },
        // 0xE0 - 0xEF
        { "LOOPNE", OF_RELATIVE | OF_IMM8 }, { "LOOPE", OF_RELATIVE | OF_IMM8 }, { "LOOP", OF_RELATIVE | OF_IMM8 }, { "JRCXZ", OF_RELATIVE | OF_IMM8 },
        { "IN", OF_IMM8 }, { "IN", OF_NONE }, { "OUT", OF_IMM8 }, { "OUT", OF_NONE },
        { "CALL", OF_RELATIVE | OF_IMM32 }, { "JMP", OF_RELATIVE | OF_IMM32 }, { "JMPF", OF_NONE }, { "JMP", OF_RELATIVE | OF_IMM8 },
        { "IN", OF_IMM8 }, { "IN", OF_NONE }, { "OUT", OF_IMM8 }, { "OUT", OF_NONE },
        // 0xF0 - 0xFF
        { "LOCK", OF_NONE }, { nullptr, OF_NONE }, { "REPNE", OF_NONE }, { "REP", OF_NONE },
        { "HLT", OF_NONE }, { "CMC", OF_NONE }, { "GRP3", OF_MODRM }, { "GRP3", OF_MODRM },
        { "CLC", OF_NONE }, { "STC", OF_NONE }, { "CLI", OF_NONE }, { "STI", OF_NONE },
        { "CLD", OF_NONE }, { "STD", OF_NONE }, { "GRP4", OF_MODRM }, { "GRP5", OF_MODRM }
    };

    static const OpcodeInfo two_byte_opcode_table[256] = {
        // 0x00 - 0x0F
        { "GRP6", OF_MODRM }, { "GRP7", OF_MODRM }, { "LAR", OF_MODRM }, { "LSL", OF_MODRM },
        { nullptr, OF_NONE }, { "SYSCALL", OF_NONE }, { "CLTS", OF_NONE }, { "SYSRET", OF_NONE },
        { "INVD", OF_NONE }, { "WBINVD", OF_NONE }, { nullptr, OF_NONE }, { "UD2", OF_NONE },
        { nullptr, OF_NONE }, { "PREFETCH", OF_MODRM }, { "FEMMS", OF_NONE }, { nullptr, OF_NONE },

        // 0x10 - 0x1F (SSE)
        { "MOVUPS", OF_MODRM }, { "MOVUPS", OF_MODRM }, { "MOVSS", OF_MODRM }, { "MOVSS", OF_MODRM },
        { "MOVUPD", OF_MODRM }, { "MOVUPD", OF_MODRM }, { "MOVSD", OF_MODRM }, { "MOVSD", OF_MODRM },
        { "MOVLPS", OF_MODRM }, { "MOVLPS", OF_MODRM }, { "UNPCKLPS", OF_MODRM }, { "UNPCKHPS", OF_MODRM },
        { "MOVLPD", OF_MODRM }, { "MOVLPD", OF_MODRM }, { "UNPCKLPD", OF_MODRM }, { "UNPCKHPD", OF_MODRM },

        // 0x20 - 0x2F
        { "MOV", OF_MODRM }, { "MOV", OF_MODRM }, { "MOV", OF_MODRM }, { "MOV", OF_MODRM },
        { nullptr, OF_NONE }, { nullptr, OF_NONE }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "CVTPI2PS", OF_MODRM }, { "CVTTPS2PI", OF_MODRM }, { "CVTPS2PI", OF_MODRM }, { "CVTSI2SS", OF_MODRM },
        { "CVTPI2PD", OF_MODRM }, { "CVTTPD2PI", OF_MODRM }, { "CVTPD2PI", OF_MODRM }, { "CVTSI2SD", OF_MODRM },

        // 0x30 - 0x3F
        { "WRMSR", OF_NONE }, { "RDTSC", OF_NONE }, { "RDMSR", OF_NONE }, { "RDPMC", OF_NONE },
        { "SYSENTER", OF_NONE }, { "SYSEXIT", OF_NONE }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "THREE_BYTE_38", OF_THREEBYTE_38 }, { nullptr, OF_NONE }, { "THREE_BYTE_3A", OF_THREEBYTE_3A }, { nullptr, OF_NONE },
        { nullptr, OF_NONE }, { nullptr, OF_NONE }, { nullptr, OF_NONE }, { nullptr, OF_NONE },

        // 0x40 - 0x4F (CMOVcc)
        { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM },
        { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM },
        { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM },
        { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM }, { "CMOVcc", OF_MODRM },

        // 0x50 - 0x5F (SSE)
        { "MOVMSKPS", OF_MODRM }, { "SQRTPS", OF_MODRM }, { "RSQRTPS", OF_MODRM }, { "RCPPS", OF_MODRM },
        { "ANDPS", OF_MODRM }, { "ANDNPS", OF_MODRM }, { "ORPS", OF_MODRM }, { "XORPS", OF_MODRM },
        { "ADDPS", OF_MODRM }, { "MULPS", OF_MODRM }, { "CVTPS2PD", OF_MODRM }, { "CVTDQ2PS", OF_MODRM },
        { "SUBPS", OF_MODRM }, { "MINPS", OF_MODRM }, { "DIVPS", OF_MODRM }, { "MAXPS", OF_MODRM },

        // 0x60 - 0x6F (MMX/SSE)
        { "PUNPCKLBW", OF_MODRM }, { "PUNPCKLWD", OF_MODRM }, { "PUNPCKLDQ", OF_MODRM }, { "PACKSSWB", OF_MODRM },
        { "PCMPGTB", OF_MODRM }, { "PCMPGTW", OF_MODRM }, { "PCMPGTD", OF_MODRM }, { "PACKUSWB", OF_MODRM },
        { "PUNPCKHBW", OF_MODRM }, { "PUNPCKHWD", OF_MODRM }, { "PUNPCKHDQ", OF_MODRM }, { "PACKSSDW", OF_MODRM },
        { "PUNPCKLQDQ", OF_MODRM }, { "PUNPCKHQDQ", OF_MODRM }, { "MOVD", OF_MODRM }, { "MOVQ", OF_MODRM },

        // 0x70 - 0x7F (SSE)
        { "PSHUFW", OF_MODRM | OF_IMM8 }, { "GRP12", OF_MODRM }, { "GRP13", OF_MODRM }, { "GRP14", OF_MODRM },
        { "PCMPEQB", OF_MODRM }, { "PCMPEQW", OF_MODRM }, { "PCMPEQD", OF_MODRM }, { "EMMS", OF_NONE },
        { "VMREAD", OF_MODRM }, { "VMWRITE", OF_MODRM }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "HADDPD", OF_MODRM }, { "HSUBPD", OF_MODRM }, { "MOVD", OF_MODRM }, { "MOVQ", OF_MODRM },

        // 0x80 - 0x8F (Jcc near) - THIS IS THE CRITICAL FIX
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },
        { "Jcc", OF_RELATIVE | OF_IMM32 }, { "Jcc", OF_RELATIVE | OF_IMM32 },

        // 0x90 - 0x9F (SETcc)
        { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM },
        { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM },
        { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM },
        { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM }, { "SETcc", OF_MODRM },

        // 0xA0 - 0xAF
        { "PUSH", OF_NONE }, { "POP", OF_NONE }, { "CPUID", OF_NONE }, { "BT", OF_MODRM },
        { "SHLD", OF_MODRM | OF_IMM8 }, { "SHLD", OF_MODRM }, { nullptr, OF_NONE }, { nullptr, OF_NONE },
        { "PUSH", OF_NONE }, { "POP", OF_NONE }, { "RSM", OF_NONE }, { "BTS", OF_MODRM },
        { "SHRD", OF_MODRM | OF_IMM8 }, { "SHRD", OF_MODRM }, { "GRP15", OF_MODRM }, { "IMUL", OF_MODRM },

        // 0xB0 - 0xBF
        { "CMPXCHG", OF_MODRM }, { "CMPXCHG", OF_MODRM }, { "LSS", OF_MODRM }, { "BTR", OF_MODRM },
        { "LFS", OF_MODRM }, { "LGS", OF_MODRM }, { "MOVZX", OF_MODRM }, { "MOVZX", OF_MODRM },
        { "POPCNT", OF_MODRM }, { "GRP10", OF_MODRM }, { "GRP8", OF_MODRM | OF_IMM8 }, { "BTC", OF_MODRM },
        { "BSF", OF_MODRM }, { "BSR", OF_MODRM }, { "MOVSX", OF_MODRM }, { "MOVSX", OF_MODRM },

        // 0xC0 - 0xCF
        { "XADD", OF_MODRM }, { "XADD", OF_MODRM }, { "CMPPS", OF_MODRM | OF_IMM8 }, { "MOVNTI", OF_MODRM },
        { "PINSRW", OF_MODRM | OF_IMM8 }, { "PEXTRW", OF_MODRM | OF_IMM8 }, { "SHUFPS", OF_MODRM | OF_IMM8 }, { "GRP9", OF_MODRM },
        { "BSWAP", OF_NONE }, { "BSWAP", OF_NONE }, { "BSWAP", OF_NONE }, { "BSWAP", OF_NONE },
        { "BSWAP", OF_NONE }, { "BSWAP", OF_NONE }, { "BSWAP", OF_NONE }, { "BSWAP", OF_NONE },

        // 0xD0 - 0xDF (MMX/SSE)
        { "ADDSUBPD", OF_MODRM }, { "PSRLW", OF_MODRM }, { "PSRLD", OF_MODRM }, { "PSRLQ", OF_MODRM },
        { "PADDQ", OF_MODRM }, { "PMULLW", OF_MODRM }, { "MOVQ", OF_MODRM }, { "PMOVMSKB", OF_MODRM },
        { "PSUBUSB", OF_MODRM }, { "PSUBUSW", OF_MODRM }, { "PMINUB", OF_MODRM }, { "PAND", OF_MODRM },
        { "PADDUSB", OF_MODRM }, { "PADDUSW", OF_MODRM }, { "PMAXUB", OF_MODRM }, { "PANDN", OF_MODRM },

        // 0xE0 - 0xEF (MMX/SSE)
        { "PAVGB", OF_MODRM }, { "PSRAW", OF_MODRM }, { "PSRAD", OF_MODRM }, { "PAVGW", OF_MODRM },
        { "PMULHUW", OF_MODRM }, { "PMULHW", OF_MODRM }, { "CVTTPD2DQ", OF_MODRM }, { "MOVNTQ", OF_MODRM },
        { "PSUBSB", OF_MODRM }, { "PSUBSW", OF_MODRM }, { "PMINSW", OF_MODRM }, { "POR", OF_MODRM },
        { "PADDSB", OF_MODRM }, { "PADDSW", OF_MODRM }, { "PMAXSW", OF_MODRM }, { "PXOR", OF_MODRM },

        // 0xF0 - 0xFF (MMX/SSE)
        { "LDDQU", OF_MODRM }, { "PSLLW", OF_MODRM }, { "PSLLD", OF_MODRM }, { "PSLLQ", OF_MODRM },
        { "PMULUDQ", OF_MODRM }, { "PMADDWD", OF_MODRM }, { "PSADBW", OF_MODRM }, { "MASKMOVQ", OF_MODRM },
        { "PSUBB", OF_MODRM }, { "PSUBW", OF_MODRM }, { "PSUBD", OF_MODRM }, { "PSUBQ", OF_MODRM },
        { "PADDB", OF_MODRM }, { "PADDW", OF_MODRM }, { "PADDD", OF_MODRM }, { "UD0", OF_NONE }
    };


    // ---[ 3. Decoding and Relocation Logic ]---

    static ModRM decode_modrm(uint8_t b) {
        return { (uint8_t)((b >> 6) & 0x3), (uint8_t)((b >> 3) & 0x7), (uint8_t)(b & 0x7) };
    }

    // Return the total length of decoded instructions covering at least min_total_len bytes
    size_t length_disasm_until_min_bytes(uint8_t* code, size_t max_len, size_t min_total_len) {
        size_t total_len = 0;
        size_t cur_offset = 0;

        while (cur_offset < max_len && total_len < min_total_len) {
            Instruction inst;
            if (!decode_instruction(code + cur_offset, max_len - cur_offset, inst))
                break;
            total_len += inst.length;
            cur_offset += inst.length;
        }
        return total_len;
    }

    bool decode_instruction(const uint8_t* code, size_t max_len, Instruction& out_inst) {
        if (!code || max_len == 0) return false;

        out_inst = {};
        out_inst.address = code;

        size_t idx = 0;

        // Prefix Parsing
        bool possible_rex = true;
        while (idx < max_len) {
            uint8_t current_byte = code[idx];

            // VEX prefixes (C4, C5)
            if (current_byte == 0xC5 && idx + 1 < max_len) {
                out_inst.has_vex = true;
                out_inst.vex_prefix[0] = current_byte;
                out_inst.vex_prefix[1] = code[idx + 1];
                out_inst.vex_pp = (code[idx + 1] >> 0) & 0x3;
                out_inst.vex_L = (code[idx + 1] >> 2) & 0x1;
                out_inst.vex_vvvv = (~(code[idx + 1] >> 3)) & 0xF;
                idx += 2;
                goto opcode_parse;
            }
            if (current_byte == 0xC4 && idx + 2 < max_len) {
                out_inst.has_vex = true;
                out_inst.vex_prefix[0] = current_byte;
                out_inst.vex_prefix[1] = code[idx + 1];
                out_inst.vex_prefix[2] = code[idx + 2];
                out_inst.vex_pp = (code[idx + 2] >> 0) & 0x3;
                out_inst.vex_L = (code[idx + 2] >> 2) & 0x1;
                out_inst.vex_vvvv = (~(code[idx + 2] >> 3)) & 0xF;
                idx += 3;
                goto opcode_parse;
            }

            if (possible_rex && (current_byte >= 0x40 && current_byte <= 0x4F)) {
                out_inst.rex = current_byte;
                idx++;
                continue;
            }

            switch (current_byte) {
            case 0xF0: case 0xF2: case 0xF3: case 0x2E: case 0x36:
            case 0x3E: case 0x26: case 0x64: case 0x65: case 0x66: case 0x67:
                if (out_inst.num_prefixes < 4) {
                    out_inst.prefixes[out_inst.num_prefixes++] = current_byte;
                }
                idx++;
                possible_rex = false;
                continue;
            }
            break;
        }

    opcode_parse:
        if (idx >= max_len) return false;

        uint8_t opcode_byte = code[idx++];
        const OpcodeInfo* info = &main_opcode_table[opcode_byte];

        if (info->flags & OF_TWOBYTE) {
            if (idx >= max_len) return false;
            opcode_byte = code[idx++];
            info = &two_byte_opcode_table[opcode_byte];
            out_inst.is_two_byte = true;
            // Further check for three-byte opcodes, though tables are sparse
            if ((info->flags & OF_THREEBYTE_38) || (info->flags & OF_THREEBYTE_3A)) {
                // In a full implementation, you'd have 0F38/0F3A tables
                if (idx >= max_len) return false;
                opcode_byte = code[idx++];
                // info = &three_byte_table[opcode_byte];
                out_inst.is_three_byte = true;
            }
        }

        if (!info || !info->mnemonic) {
            out_inst.length = idx;
            out_inst.mnemonic = "unknown";
            return true;
        }

        out_inst.mnemonic = info->mnemonic;
        out_inst.opcode = opcode_byte;

        if (info->flags & OF_MODRM) {
            if (idx >= max_len) return false;
            out_inst.has_modrm = true;
            uint8_t modrm_byte = code[idx++];
            out_inst.modrm = modrm_byte;
            ModRM modrm = decode_modrm(modrm_byte);

            if (modrm.mod != 3 && modrm.rm == 4) {
                if (idx >= max_len) return false;
                out_inst.has_sib = true;
                out_inst.sib = code[idx++];
            }

            if (modrm.mod == 1) {
                if (idx >= max_len) return false;
                out_inst.disp_offset = idx;
                out_inst.displacement = *reinterpret_cast<const int8_t*>(&code[idx]);
                idx++;
            }
            else if (modrm.mod == 2 || (modrm.mod == 0 && modrm.rm == 5)) {
                if (idx + 4 > max_len) return false;
                out_inst.disp_offset = idx;
                out_inst.displacement = *reinterpret_cast<const int32_t*>(&code[idx]);
                if (modrm.mod == 0 && modrm.rm == 5) out_inst.is_rip_relative = true;
                idx += 4;
            }
        }

        size_t imm_size = 0;
        if (info->flags & OF_IMM8) imm_size = 1;
        else if (info->flags & OF_IMM16) imm_size = 2;
        else if (info->flags & OF_IMM32) imm_size = 4;
        else if ((info->flags & OF_IMM64) || (out_inst.rex & 0x08 && opcode_byte >= 0xB8 && opcode_byte <= 0xBF)) {
            imm_size = 8;
        }

        if (imm_size > 0) {
            if (idx + imm_size > max_len) return false;
            out_inst.imm_offset = idx;
            switch (imm_size) {
            case 1: out_inst.immediate = *reinterpret_cast<const int8_t*>(&code[idx]); break;
            case 2: out_inst.immediate = *reinterpret_cast<const int16_t*>(&code[idx]); break;
            case 4: out_inst.immediate = *reinterpret_cast<const int32_t*>(&code[idx]); break;
            case 8: out_inst.immediate = *reinterpret_cast<const int64_t*>(&code[idx]); break;
            }
            idx += imm_size;
        }

        out_inst.length = idx;
        return true;
    }

    void write_absolute_jump(uint8_t* buffer, void* destination) {
        buffer[0] = 0xFF;
        buffer[1] = 0x25;
        *reinterpret_cast<int32_t*>(&buffer[2]) = 0;
        *reinterpret_cast<uint64_t*>(&buffer[6]) = reinterpret_cast<uint64_t>(destination);
    }

    size_t get_relocated_length(const Instruction& inst) {
        // Handle decomposition of LOOP instructions. They become larger.
        // LOOP/LOOPZ/LOOPNZ are 2 bytes originally.
        switch (inst.opcode) {
        case 0xE0: // LOOPNE/LOOPNZ: dec ecx; jne/jnz target
        case 0xE1: // LOOPE/LOOPZ:   dec ecx; je/jz target
        case 0xE2: // LOOP:          dec ecx; jne/jnz target
            // Decomposes to: DEC ECX (1 byte) + Jcc NEAR (6 bytes) = 7 bytes.
            return 7;
        case 0xE3: // JRCXZ:         test rcx,rcx; jz target
            // Decomposes to: TEST RCX,RCX (3 bytes) + JZ NEAR (6 bytes) = 9 bytes.
            return 9;
        }

        if (inst.mnemonic == "Jcc") {
            // Expanded to J(!cc) NEAR skip + JMP ABS target
            return 20;
        }

        if (inst.mnemonic == "JMP" || inst.mnemonic == "CALL") {
            const OpcodeInfo* info = inst.is_two_byte ? &two_byte_opcode_table[inst.opcode] : &main_opcode_table[inst.opcode];
            if (info && (info->flags & OF_RELATIVE)) {
                // Expanded to JMP ABS target
                return 14;
            }
        }

        // All other instructions do not change in length.
        return inst.length;
    }

// Follows a chain of JMP instructions to find the real function address.
    uint8_t* resolve_jumps(uint8_t* func_ptr) {
        // We'll follow a maximum of 10 jumps to prevent infinite loops.
        for (int i = 0; i < 10; ++i) {
            Instruction inst;
            if (!decode_instruction(func_ptr, 16, inst)) {
                // Cannot decode, assume it's the real function.
                return func_ptr;
            }

            // We are only interested in unconditional jumps.
            if (inst.mnemonic != "JMP") {
                return func_ptr;
            }

            // This is the absolute address the JMP instruction points to.
            uint64_t target_address = 0;

            // Check if it's a relative JMP (e.g., JMP 0x...).
            const OpcodeInfo* info = inst.is_two_byte
                ? &two_byte_opcode_table[inst.opcode]
                : &main_opcode_table[inst.opcode];

            if (info && (info->flags & OF_RELATIVE)) {
                uint64_t next_ip = reinterpret_cast<uint64_t>(func_ptr) + inst.length;
                target_address = next_ip + inst.immediate;
            }
            // Check if it's a JMP via a memory pointer (e.g., JMP [rip+0x...]).
            else if (inst.is_rip_relative) {
                uint64_t next_ip = reinterpret_cast<uint64_t>(func_ptr) + inst.length;
                uint64_t pointer_address = next_ip + inst.displacement;
                // Read the 64-bit address from that memory location.
                target_address = *reinterpret_cast<uint64_t*>(pointer_address);
            }
            else {
                // It's another type of JMP (e.g., JMP RAX) that we can't resolve.
                // Assume we're at the destination.
                return func_ptr;
            }

            func_ptr = reinterpret_cast<uint8_t*>(target_address);
        }

        // If we've jumped 10 times, we're probably in a loop, return what we have.
        return func_ptr;
    }

    bool relocate_instruction(const Instruction& inst, uint8_t* trampoline_ptr, size_t& trampoline_len) {
        uint64_t original_addr = reinterpret_cast<uint64_t>(inst.address);
        uint64_t trampoline_addr = reinterpret_cast<uint64_t>(trampoline_ptr);
        uint64_t original_next_ip = original_addr + inst.length;

        // The absolute address of the original jump/call/loop target
        uint64_t original_target = original_next_ip + inst.immediate;

        // --- Special Handling for LOOP/JRCXZ Instructions ---
        switch (inst.opcode) {
        case 0xE0: // LOOPNE/LOOPNZ target -> DEC ECX; JNE target
        case 0xE1: // LOOPE/LOOPZ target  -> DEC ECX; JE target
        case 0xE2: // LOOP target         -> DEC ECX; JNZ target
        {
            // Get the corresponding Jcc near opcode (0x80 series)
            uint8_t jcc_opcode;
            if (inst.opcode == 0xE0) jcc_opcode = 0x85; // JNE
            else if (inst.opcode == 0xE1) jcc_opcode = 0x84; // JE
            else jcc_opcode = 0x85; // JNZ for LOOP

            // 1. Write 'DEC ECX' (opcode FF C9)
            // Note: LOOP instructions use ECX even in 64-bit mode unless a REX.W prefix is used, which is rare.
            trampoline_ptr[0] = 0xFF;
            trampoline_ptr[1] = 0xC9;

            // 2. Write the 6-byte near conditional jump to the absolute target
            trampoline_ptr[2] = 0x0F;
            trampoline_ptr[3] = jcc_opcode;
            int32_t relative_offset = static_cast<int32_t>(original_target - (trampoline_addr + 8)); // Target - End of this instruction
            *reinterpret_cast<int32_t*>(&trampoline_ptr[4]) = relative_offset;

            trampoline_len = 8; // DEC ECX (2 bytes) + Jcc NEAR (6 bytes)
            return true;
        }
        case 0xE3: // JRCXZ target -> TEST RCX, RCX; JZ target
        {
            // 1. Write 'TEST RCX, RCX' (opcode 48 85 C9)
            trampoline_ptr[0] = 0x48;
            trampoline_ptr[1] = 0x85;
            trampoline_ptr[2] = 0xC9;

            // 2. Write 'JZ NEAR' (opcode 0F 84) to the absolute target
            trampoline_ptr[3] = 0x0F;
            trampoline_ptr[4] = 0x84; // JZ
            int32_t relative_offset = static_cast<int32_t>(original_target - (trampoline_addr + 9)); // Target - End of this instruction
            *reinterpret_cast<int32_t*>(&trampoline_ptr[5]) = relative_offset;

            trampoline_len = 9; // TEST (3 bytes) + JZ NEAR (6 bytes)
            return true;
        }
        }

        // For all other instructions, start by copying the original bytes
        memcpy(trampoline_ptr, inst.address, inst.length);
        trampoline_len = inst.length;

        if (inst.is_rip_relative) {
            uint64_t rip_rel_target = original_next_ip + inst.displacement;
            int32_t new_disp = static_cast<int32_t>(rip_rel_target - (trampoline_addr + inst.length));
            *reinterpret_cast<int32_t*>(trampoline_ptr + inst.disp_offset) = new_disp;
            return true;
        }

        const OpcodeInfo* info = inst.is_two_byte ? &two_byte_opcode_table[inst.opcode] : &main_opcode_table[inst.opcode];
        if (info && (info->flags & OF_RELATIVE)) {
            if (inst.mnemonic == "JMP" || inst.mnemonic == "CALL") {
                write_absolute_jump(trampoline_ptr, reinterpret_cast<void*>(original_target));
                trampoline_len = 14;
            }
            else if (inst.mnemonic == "Jcc") {
                uint8_t condition = inst.opcode & 0x0F;
                uint8_t opposite_condition = condition ^ 1;

                trampoline_ptr[0] = 0x0F;
                trampoline_ptr[1] = 0x80 + opposite_condition;
                *reinterpret_cast<int32_t*>(&trampoline_ptr[2]) = 14;

                write_absolute_jump(trampoline_ptr + 6, reinterpret_cast<void*>(original_target));
                trampoline_len = 20;
            }
        }

        return true;
    }

    uint8_t* resolve_jump_thunk(uint8_t* fn, int depth) {
        if (depth > 10)
            return fn; // Prevent infinite recursion

        Instruction inst;
        // The instruction decoder is used here to find JMPs
        if (!decode_instruction(fn, 15, inst) || inst.mnemonic != "JMP") {
            return fn;
        }

        uint64_t target = 0;
        uint64_t next_ip = reinterpret_cast<uint64_t>(fn) + inst.length;

        // JMP rel32 (E9) or JMP rel8 (EB)
        if (inst.opcode == 0xE9 || inst.opcode == 0xEB) {
            target = next_ip + inst.immediate;
        }
        // JMP r/m64 (FF /4) with RIP-relative addressing
        else if (inst.opcode == 0xFF && inst.is_rip_relative) {
            uint8_t* effective_address = reinterpret_cast<uint8_t*>(next_ip + inst.displacement);
            if (!IsBadReadPtr(effective_address, sizeof(uint64_t))) {
                target = *reinterpret_cast<uint64_t*>(effective_address);
            }
            else {
                return fn; // Can't read memory
            }
        }
        else {
            return fn; // Not a simple JMP we can resolve
        }

        return resolve_jump_thunk(reinterpret_cast<uint8_t*>(target), depth + 1);
    }

} // namespace decoder

.h

c++:
Expand Collapse Copy
namespace decoder {

    // Global array of 64-bit register names for easy lookup.
    static const char* reg64[16] = {
        "RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI",
        "R8",  "R9",  "R10", "R11", "R12", "R13", "R14", "R15"
    };

    // Defines the type of an operand (Register, Memory, or Immediate value).
    enum class OperandType {
        REG,
        MEM,
        IMM
    };

    // Represents a single operand for an instruction.
    struct Operand {
        OperandType type;
        uint8_t size;
        int64_t value = 0;
        std::string text; // Formatted text for the operand (e.g., "RAX", "[RIP+0x1234]").
    };

    // Represents the SIB byte, used for complex memory addressing.
    struct SIB {
        uint8_t scale, index, base;
    };

    struct Instruction {
        const uint8_t* address;
        uint8_t length;
        std::string mnemonic;

        uint8_t prefixes[4];
        uint8_t num_prefixes;
        uint8_t rex;
        uint8_t opcode;
        bool is_two_byte;
        bool is_three_byte; // For 0F 38/3A opcodes

        bool has_modrm;
        uint8_t modrm;
        bool has_sib;
        uint8_t sib;

        uint8_t disp_offset;
        int32_t displacement;
        bool is_rip_relative;

        uint8_t imm_offset;
        int64_t immediate;

        // VEX Prefix Info
        bool has_vex;
        uint8_t vex_prefix[3];
        uint8_t vex_L;
        uint8_t vex_pp;
        uint8_t vex_vvvv;
    };

    // Represents the ModR/M byte fields.
    struct ModRM {
        uint8_t mod;
        uint8_t reg;
        uint8_t rm;
    };


// Describes the properties of an opcode.
    enum OpcodeFlags : uint32_t {
        OF_NONE = 0,
        OF_MODRM = 1 << 0,  // Instruction has a ModR/M byte
        OF_IMM8 = 1 << 1,  // Instruction has an 8-bit immediate
        OF_IMM16 = 1 << 2,  // Instruction has a 16-bit immediate
        OF_IMM32 = 1 << 3,  // Instruction has a 32-bit immediate
        OF_IMM64 = 1 << 4,  // Instruction has a 64-bit immediate
        OF_RELATIVE = 1 << 5,  // Immediate is a relative offset (for JMP, CALL, Jcc)
        OF_TWOBYTE = 1 << 6,  // Indicates a two-byte opcode map (0F xx)
        OF_THREEBYTE_38 = 1 << 7, // Three-byte opcode map (0F 38 xx)
        OF_THREEBYTE_3A = 1 << 8, // Three-byte opcode map (0F 3A xx)
    };

    // Maps an opcode to its mnemonic and properties.
    struct OpcodeInfo {
        const char* mnemonic;
        uint32_t flags;
    };

    bool decode_instruction(const uint8_t* code, size_t max_len, Instruction& out_inst);;
    bool relocate_instruction(const Instruction& inst, uint8_t* trampoline_ptr, size_t& trampoline_len);
    uint8_t* resolve_jump_thunk(uint8_t* fn, int depth);
    void write_absolute_jump(uint8_t* buffer, void* destination);
    size_t length_disasm_until_min_bytes(uint8_t* code, size_t max_len, size_t min_total_len);
    size_t get_relocated_length(const Instruction& inst);
    uint8_t* resolve_jumps(uint8_t* func_ptr);
} // namespace decoder
 
Последнее редактирование:
Назад
Сверху Снизу