Files
BeneficialCode-WinArk/KernelLibrary/disasm.cpp
T

1308 lines
64 KiB
C++

#include "pch.h"
#include <limits.h>
#include "disasm.h"
#include "detours.h"
//////////////////////////////////////////////////////////////////////////////
//
// Detours Disassembler (disasm.cpp of detours.lib)
//
// Microsoft Research Detours Package, Version 4.0.1
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// thanks detours and pepsi :)
// These macros define common uses of nFixedSize, nFixedSize16, nModOffset, nRelOffset, nFlagBits, pfCopy.
#define ENTRY_DataIgnored 0, 0, 0, 0, 0,
#define ENTRY_CopyBytes1 { 1, 1, 0, 0, 0, &Disasm::CopyBytes }
#ifdef DETOURS_X64
#define ENTRY_CopyBytes1Address { 9, 5, 0, 0, FlagBits::Address, &Disasm::CopyBytes }
#else
#define ENTRY_CopyBytes1Address { 5, 3, 0, 0, FlagBits::Address, &Disasm::CopyBytes }
#endif
#define ENTRY_CopyBytes1Dynamic { 1, 1, 0, 0, FlagBits::Dynamic, &Disasm::CopyBytes }
#define ENTRY_CopyBytes2 { 2, 2, 0, 0, 0, &Disasm::CopyBytes }
#define ENTRY_CopyBytes2Jump { ENTRY_DataIgnored &Disasm::CopyBytesJump }
#define ENTRY_CopyBytes2CantJump { 2, 2, 0, 1, FlagBits::NoEnlarge, &Disasm::CopyBytes }
#define ENTRY_CopyBytes2Dynamic { 2, 2, 0, 0, FlagBits::Dynamic, &Disasm::CopyBytes }
#define ENTRY_CopyBytes3 { 3, 3, 0, 0, 0, &Disasm::CopyBytes }
#define ENTRY_CopyBytes3Dynamic { 3, 3, 0, 0, FlagBits::Dynamic, &Disasm::CopyBytes }
#define ENTRY_CopyBytes3Or5 { 5, 3, 0, 0, 0, &Disasm::CopyBytes }
#define ENTRY_CopyBytes3Or5Dynamic { 5, 3, 0, 0, FlagBits::Dynamic, &Disasm::CopyBytes }// x86 only
#ifdef DETOURS_X64
#define ENTRY_CopyBytes3Or5Rax { 5, 3, 0, 0, FlagBits::Rax, &Disasm::CopyBytes }
#define ENTRY_CopyBytes3Or5Target { 5, 5, 0, 1, 0, &Disasm::CopyBytes }
#else
#define ENTRY_CopyBytes3Or5Rax { 5, 3, 0, 0, 0, &Disasm::CopyBytes }
#define ENTRY_CopyBytes3Or5Target { 5, 3, 0, 1, 0, &Disasm::CopyBytes }
#endif
#define ENTRY_CopyBytes4 { 4, 4, 0, 0, 0, &Disasm::CopyBytes }
#define ENTRY_CopyBytes5 { 5, 5, 0, 0, 0, &Disasm::CopyBytes }
#define ENTRY_CopyBytes5Or7Dynamic { 7, 5, 0, 0, FlagBits::Dynamic, &Disasm::CopyBytes }
#define ENTRY_CopyBytes7 { 7, 7, 0, 0, 0, &Disasm::CopyBytes }
#define ENTRY_CopyBytes2Mod { 2, 2, 1, 0, 0, &Disasm::CopyBytes }
#define ENTRY_CopyBytes2ModDynamic { 2, 2, 1, 0, FlagBits::Dynamic, &Disasm::CopyBytes }
#define ENTRY_CopyBytes2Mod1 { 3, 3, 1, 0, 0, &Disasm::CopyBytes }
#define ENTRY_CopyBytes2ModOperand { 6, 4, 1, 0, 0, &Disasm::CopyBytes }
#define ENTRY_CopyBytes3Mod { 3, 3, 2, 0, 0, &Disasm::CopyBytes } // SSE3 0F 38 opcode modrm
#define ENTRY_CopyBytes3Mod1 { 4, 4, 2, 0, 0, &Disasm::CopyBytes } // SSE3 0F 3A opcode modrm .. imm8
#define ENTRY_CopyBytesPrefix { ENTRY_DataIgnored &Disasm::CopyBytesPrefix }
#define ENTRY_CopyBytesSegment { ENTRY_DataIgnored &Disasm::CopyBytesSegment }
#define ENTRY_CopyBytesRax { ENTRY_DataIgnored &Disasm::CopyBytesRax }
#define ENTRY_CopyF2 { ENTRY_DataIgnored &Disasm::CopyF2 }
#define ENTRY_CopyF3 { ENTRY_DataIgnored &Disasm::CopyF3 } // 32bit x86 only
#define ENTRY_Copy0F { ENTRY_DataIgnored &Disasm::Copy0F }
#define ENTRY_Copy0F78 { ENTRY_DataIgnored &Disasm::Copy0F78 }
#define ENTRY_Copy0F00 { ENTRY_DataIgnored &Disasm::Copy0F00 } // 32bit x86 only
#define ENTRY_Copy0FB8 { ENTRY_DataIgnored &Disasm::Copy0FB8 } // 32bit x86 only
#define ENTRY_Copy66 { ENTRY_DataIgnored &Disasm::Copy66 }
#define ENTRY_Copy67 { ENTRY_DataIgnored &Disasm::Copy67 }
#define ENTRY_CopyF6 { ENTRY_DataIgnored &Disasm::CopyF6 }
#define ENTRY_CopyF7 { ENTRY_DataIgnored &Disasm::CopyF7 }
#define ENTRY_CopyFF { ENTRY_DataIgnored &Disasm::CopyFF }
#define ENTRY_CopyVex2 { ENTRY_DataIgnored &Disasm::CopyVex2 }
#define ENTRY_CopyVex3 { ENTRY_DataIgnored &Disasm::CopyVex3 }
#define ENTRY_CopyEvex { ENTRY_DataIgnored &Disasm::CopyEvex } // 62, 3 byte payload, then normal with implied prefixes like vex
#define ENTRY_CopyXop { ENTRY_DataIgnored &Disasm::CopyXop } // 0x8F ... POP /0 or AMD XOP
#define ENTRY_CopyBytesXop { 5, 5, 4, 0, 0, &Disasm::CopyBytes } // 0x8F xop1 xop2 opcode modrm
#define ENTRY_CopyBytesXop1 { 6, 6, 4, 0, 0, &Disasm::CopyBytes } // 0x8F xop1 xop2 opcode modrm ... imm8
#define ENTRY_CopyBytesXop4 { 9, 9, 4, 0, 0, &Disasm::CopyBytes } // 0x8F xop1 xop2 opcode modrm ... imm32
#define ENTRY_Invalid { ENTRY_DataIgnored &Disasm::Invalid }
const Disasm::CopyEntry Disasm::s_CopyTable[] = {
/* 00 */ ENTRY_CopyBytes2Mod, // ADD /r
/* 01 */ ENTRY_CopyBytes2Mod, // ADD /r
/* 02 */ ENTRY_CopyBytes2Mod, // ADD /r
/* 03 */ ENTRY_CopyBytes2Mod, // ADD /r
/* 04 */ ENTRY_CopyBytes2, // ADD ib
/* 05 */ ENTRY_CopyBytes3Or5, // ADD iw
#ifdef DETOURS_X64
/* 06 */ ENTRY_Invalid, // Invalid
/* 07 */ ENTRY_Invalid, // Invalid
#else
/* 06 */ ENTRY_CopyBytes1, // PUSH
/* 07 */ ENTRY_CopyBytes1, // POP
#endif
/* 08 */ ENTRY_CopyBytes2Mod, // OR /r
/* 09 */ ENTRY_CopyBytes2Mod, // OR /r
/* 0A */ ENTRY_CopyBytes2Mod, // OR /r
/* 0B */ ENTRY_CopyBytes2Mod, // OR /r
/* 0C */ ENTRY_CopyBytes2, // OR ib
/* 0D */ ENTRY_CopyBytes3Or5, // OR iw
#ifdef DETOURS_X64
/* 0E */ ENTRY_Invalid, // Invalid
#else
/* 0E */ ENTRY_CopyBytes1, // PUSH
#endif
/* 0F */ ENTRY_Copy0F, // Extension Ops
/* 10 */ ENTRY_CopyBytes2Mod, // ADC /r
/* 11 */ ENTRY_CopyBytes2Mod, // ADC /r
/* 12 */ ENTRY_CopyBytes2Mod, // ADC /r
/* 13 */ ENTRY_CopyBytes2Mod, // ADC /r
/* 14 */ ENTRY_CopyBytes2, // ADC ib
/* 15 */ ENTRY_CopyBytes3Or5, // ADC id
#ifdef DETOURS_X64
/* 16 */ ENTRY_Invalid, // Invalid
/* 17 */ ENTRY_Invalid, // Invalid
#else
/* 16 */ ENTRY_CopyBytes1, // PUSH
/* 17 */ ENTRY_CopyBytes1, // POP
#endif
/* 18 */ ENTRY_CopyBytes2Mod, // SBB /r
/* 19 */ ENTRY_CopyBytes2Mod, // SBB /r
/* 1A */ ENTRY_CopyBytes2Mod, // SBB /r
/* 1B */ ENTRY_CopyBytes2Mod, // SBB /r
/* 1C */ ENTRY_CopyBytes2, // SBB ib
/* 1D */ ENTRY_CopyBytes3Or5, // SBB id
#ifdef DETOURS_X64
/* 1E */ ENTRY_Invalid, // Invalid
/* 1F */ ENTRY_Invalid, // Invalid
#else
/* 1E */ ENTRY_CopyBytes1, // PUSH
/* 1F */ ENTRY_CopyBytes1, // POP
#endif
/* 20 */ ENTRY_CopyBytes2Mod, // AND /r
/* 21 */ ENTRY_CopyBytes2Mod, // AND /r
/* 22 */ ENTRY_CopyBytes2Mod, // AND /r
/* 23 */ ENTRY_CopyBytes2Mod, // AND /r
/* 24 */ ENTRY_CopyBytes2, // AND ib
/* 25 */ ENTRY_CopyBytes3Or5, // AND id
/* 26 */ ENTRY_CopyBytesSegment, // ES prefix
#ifdef DETOURS_X64
/* 27 */ ENTRY_Invalid, // Invalid
#else
/* 27 */ ENTRY_CopyBytes1, // DAA
#endif
/* 28 */ ENTRY_CopyBytes2Mod, // SUB /r
/* 29 */ ENTRY_CopyBytes2Mod, // SUB /r
/* 2A */ ENTRY_CopyBytes2Mod, // SUB /r
/* 2B */ ENTRY_CopyBytes2Mod, // SUB /r
/* 2C */ ENTRY_CopyBytes2, // SUB ib
/* 2D */ ENTRY_CopyBytes3Or5, // SUB id
/* 2E */ ENTRY_CopyBytesSegment, // CS prefix
#ifdef DETOURS_X64
/* 2F */ ENTRY_Invalid, // Invalid
#else
/* 2F */ ENTRY_CopyBytes1, // DAS
#endif
/* 30 */ ENTRY_CopyBytes2Mod, // XOR /r
/* 31 */ ENTRY_CopyBytes2Mod, // XOR /r
/* 32 */ ENTRY_CopyBytes2Mod, // XOR /r
/* 33 */ ENTRY_CopyBytes2Mod, // XOR /r
/* 34 */ ENTRY_CopyBytes2, // XOR ib
/* 35 */ ENTRY_CopyBytes3Or5, // XOR id
/* 36 */ ENTRY_CopyBytesSegment, // SS prefix
#ifdef DETOURS_X64
/* 37 */ ENTRY_Invalid, // Invalid
#else
/* 37 */ ENTRY_CopyBytes1, // AAA
#endif
/* 38 */ ENTRY_CopyBytes2Mod, // CMP /r
/* 39 */ ENTRY_CopyBytes2Mod, // CMP /r
/* 3A */ ENTRY_CopyBytes2Mod, // CMP /r
/* 3B */ ENTRY_CopyBytes2Mod, // CMP /r
/* 3C */ ENTRY_CopyBytes2, // CMP ib
/* 3D */ ENTRY_CopyBytes3Or5, // CMP id
/* 3E */ ENTRY_CopyBytesSegment, // DS prefix
#ifdef DETOURS_X64
/* 3F */ ENTRY_Invalid, // Invalid
#else
/* 3F */ ENTRY_CopyBytes1, // AAS
#endif
#ifdef DETOURS_X64 // For Rax Prefix
/* 40 */ ENTRY_CopyBytesRax, // Rax
/* 41 */ ENTRY_CopyBytesRax, // Rax
/* 42 */ ENTRY_CopyBytesRax, // Rax
/* 43 */ ENTRY_CopyBytesRax, // Rax
/* 44 */ ENTRY_CopyBytesRax, // Rax
/* 45 */ ENTRY_CopyBytesRax, // Rax
/* 46 */ ENTRY_CopyBytesRax, // Rax
/* 47 */ ENTRY_CopyBytesRax, // Rax
/* 48 */ ENTRY_CopyBytesRax, // Rax
/* 49 */ ENTRY_CopyBytesRax, // Rax
/* 4A */ ENTRY_CopyBytesRax, // Rax
/* 4B */ ENTRY_CopyBytesRax, // Rax
/* 4C */ ENTRY_CopyBytesRax, // Rax
/* 4D */ ENTRY_CopyBytesRax, // Rax
/* 4E */ ENTRY_CopyBytesRax, // Rax
/* 4F */ ENTRY_CopyBytesRax, // Rax
#else
/* 40 */ ENTRY_CopyBytes1, // INC
/* 41 */ ENTRY_CopyBytes1, // INC
/* 42 */ ENTRY_CopyBytes1, // INC
/* 43 */ ENTRY_CopyBytes1, // INC
/* 44 */ ENTRY_CopyBytes1, // INC
/* 45 */ ENTRY_CopyBytes1, // INC
/* 46 */ ENTRY_CopyBytes1, // INC
/* 47 */ ENTRY_CopyBytes1, // INC
/* 48 */ ENTRY_CopyBytes1, // DEC
/* 49 */ ENTRY_CopyBytes1, // DEC
/* 4A */ ENTRY_CopyBytes1, // DEC
/* 4B */ ENTRY_CopyBytes1, // DEC
/* 4C */ ENTRY_CopyBytes1, // DEC
/* 4D */ ENTRY_CopyBytes1, // DEC
/* 4E */ ENTRY_CopyBytes1, // DEC
/* 4F */ ENTRY_CopyBytes1, // DEC
#endif
/* 50 */ ENTRY_CopyBytes1, // PUSH
/* 51 */ ENTRY_CopyBytes1, // PUSH
/* 52 */ ENTRY_CopyBytes1, // PUSH
/* 53 */ ENTRY_CopyBytes1, // PUSH
/* 54 */ ENTRY_CopyBytes1, // PUSH
/* 55 */ ENTRY_CopyBytes1, // PUSH
/* 56 */ ENTRY_CopyBytes1, // PUSH
/* 57 */ ENTRY_CopyBytes1, // PUSH
/* 58 */ ENTRY_CopyBytes1, // POP
/* 59 */ ENTRY_CopyBytes1, // POP
/* 5A */ ENTRY_CopyBytes1, // POP
/* 5B */ ENTRY_CopyBytes1, // POP
/* 5C */ ENTRY_CopyBytes1, // POP
/* 5D */ ENTRY_CopyBytes1, // POP
/* 5E */ ENTRY_CopyBytes1, // POP
/* 5F */ ENTRY_CopyBytes1, // POP
#ifdef DETOURS_X64
/* 60 */ ENTRY_Invalid, // Invalid
/* 61 */ ENTRY_Invalid, // Invalid
/* 62 */ ENTRY_CopyEvex, // EVEX / AVX512
#else
/* 60 */ ENTRY_CopyBytes1, // PUSHAD
/* 61 */ ENTRY_CopyBytes1, // POPAD
/* 62 */ ENTRY_CopyEvex, // BOUND /r and EVEX / AVX512
#endif
/* 63 */ ENTRY_CopyBytes2Mod, // 32bit ARPL /r, 64bit MOVSXD
/* 64 */ ENTRY_CopyBytesSegment, // FS prefix
/* 65 */ ENTRY_CopyBytesSegment, // GS prefix
/* 66 */ ENTRY_Copy66, // Operand Prefix
/* 67 */ ENTRY_Copy67, // Address Prefix
/* 68 */ ENTRY_CopyBytes3Or5, // PUSH
/* 69 */ ENTRY_CopyBytes2ModOperand, // IMUL /r iz
/* 6A */ ENTRY_CopyBytes2, // PUSH
/* 6B */ ENTRY_CopyBytes2Mod1, // IMUL /r ib
/* 6C */ ENTRY_CopyBytes1, // INS
/* 6D */ ENTRY_CopyBytes1, // INS
/* 6E */ ENTRY_CopyBytes1, // OUTS/OUTSB
/* 6F */ ENTRY_CopyBytes1, // OUTS/OUTSW
/* 70 */ ENTRY_CopyBytes2Jump, // JO // 0f80
/* 71 */ ENTRY_CopyBytes2Jump, // JNO // 0f81
/* 72 */ ENTRY_CopyBytes2Jump, // JB/JC/JNAE // 0f82
/* 73 */ ENTRY_CopyBytes2Jump, // JAE/JNB/JNC // 0f83
/* 74 */ ENTRY_CopyBytes2Jump, // JE/JZ // 0f84
/* 75 */ ENTRY_CopyBytes2Jump, // JNE/JNZ // 0f85
/* 76 */ ENTRY_CopyBytes2Jump, // JBE/JNA // 0f86
/* 77 */ ENTRY_CopyBytes2Jump, // JA/JNBE // 0f87
/* 78 */ ENTRY_CopyBytes2Jump, // JS // 0f88
/* 79 */ ENTRY_CopyBytes2Jump, // JNS // 0f89
/* 7A */ ENTRY_CopyBytes2Jump, // JP/JPE // 0f8a
/* 7B */ ENTRY_CopyBytes2Jump, // JNP/JPO // 0f8b
/* 7C */ ENTRY_CopyBytes2Jump, // JL/JNGE // 0f8c
/* 7D */ ENTRY_CopyBytes2Jump, // JGE/JNL // 0f8d
/* 7E */ ENTRY_CopyBytes2Jump, // JLE/JNG // 0f8e
/* 7F */ ENTRY_CopyBytes2Jump, // JG/JNLE // 0f8f
/* 80 */ ENTRY_CopyBytes2Mod1, // ADD/0 OR/1 ADC/2 SBB/3 AND/4 SUB/5 XOR/6 CMP/7 byte reg, immediate byte
/* 81 */ ENTRY_CopyBytes2ModOperand, // ADD/0 OR/1 ADC/2 SBB/3 AND/4 SUB/5 XOR/6 CMP/7 byte reg, immediate word or dword
#ifdef DETOURS_X64
/* 82 */ ENTRY_Invalid, // Invalid
#else
/* 82 */ ENTRY_CopyBytes2Mod1, // MOV al,x
#endif
/* 83 */ ENTRY_CopyBytes2Mod1, // ADD/0 OR/1 ADC/2 SBB/3 AND/4 SUB/5 XOR/6 CMP/7 reg, immediate byte
/* 84 */ ENTRY_CopyBytes2Mod, // TEST /r
/* 85 */ ENTRY_CopyBytes2Mod, // TEST /r
/* 86 */ ENTRY_CopyBytes2Mod, // XCHG /r @todo
/* 87 */ ENTRY_CopyBytes2Mod, // XCHG /r @todo
/* 88 */ ENTRY_CopyBytes2Mod, // MOV /r
/* 89 */ ENTRY_CopyBytes2Mod, // MOV /r
/* 8A */ ENTRY_CopyBytes2Mod, // MOV /r
/* 8B */ ENTRY_CopyBytes2Mod, // MOV /r
/* 8C */ ENTRY_CopyBytes2Mod, // MOV /r
/* 8D */ ENTRY_CopyBytes2Mod, // LEA /r
/* 8E */ ENTRY_CopyBytes2Mod, // MOV /r
/* 8F */ ENTRY_CopyXop, // POP /0 or AMD XOP
/* 90 */ ENTRY_CopyBytes1, // NOP
/* 91 */ ENTRY_CopyBytes1, // XCHG
/* 92 */ ENTRY_CopyBytes1, // XCHG
/* 93 */ ENTRY_CopyBytes1, // XCHG
/* 94 */ ENTRY_CopyBytes1, // XCHG
/* 95 */ ENTRY_CopyBytes1, // XCHG
/* 96 */ ENTRY_CopyBytes1, // XCHG
/* 97 */ ENTRY_CopyBytes1, // XCHG
/* 98 */ ENTRY_CopyBytes1, // CWDE
/* 99 */ ENTRY_CopyBytes1, // CDQ
#ifdef DETOURS_X64
/* 9A */ ENTRY_Invalid, // Invalid
#else
/* 9A */ ENTRY_CopyBytes5Or7Dynamic, // CALL cp
#endif
/* 9B */ ENTRY_CopyBytes1, // WAIT/FWAIT
/* 9C */ ENTRY_CopyBytes1, // PUSHFD
/* 9D */ ENTRY_CopyBytes1, // POPFD
/* 9E */ ENTRY_CopyBytes1, // SAHF
/* 9F */ ENTRY_CopyBytes1, // LAHF
/* A0 */ ENTRY_CopyBytes1Address, // MOV
/* A1 */ ENTRY_CopyBytes1Address, // MOV
/* A2 */ ENTRY_CopyBytes1Address, // MOV
/* A3 */ ENTRY_CopyBytes1Address, // MOV
/* A4 */ ENTRY_CopyBytes1, // MOVS
/* A5 */ ENTRY_CopyBytes1, // MOVS/MOVSD
/* A6 */ ENTRY_CopyBytes1, // CMPS/CMPSB
/* A7 */ ENTRY_CopyBytes1, // CMPS/CMPSW
/* A8 */ ENTRY_CopyBytes2, // TEST
/* A9 */ ENTRY_CopyBytes3Or5, // TEST
/* AA */ ENTRY_CopyBytes1, // STOS/STOSB
/* AB */ ENTRY_CopyBytes1, // STOS/STOSW
/* AC */ ENTRY_CopyBytes1, // LODS/LODSB
/* AD */ ENTRY_CopyBytes1, // LODS/LODSW
/* AE */ ENTRY_CopyBytes1, // SCAS/SCASB
/* AF */ ENTRY_CopyBytes1, // SCAS/SCASD
/* B0 */ ENTRY_CopyBytes2, // MOV B0+rb
/* B1 */ ENTRY_CopyBytes2, // MOV B0+rb
/* B2 */ ENTRY_CopyBytes2, // MOV B0+rb
/* B3 */ ENTRY_CopyBytes2, // MOV B0+rb
/* B4 */ ENTRY_CopyBytes2, // MOV B0+rb
/* B5 */ ENTRY_CopyBytes2, // MOV B0+rb
/* B6 */ ENTRY_CopyBytes2, // MOV B0+rb
/* B7 */ ENTRY_CopyBytes2, // MOV B0+rb
/* B8 */ ENTRY_CopyBytes3Or5Rax, // MOV B8+rb
/* B9 */ ENTRY_CopyBytes3Or5Rax, // MOV B8+rb
/* BA */ ENTRY_CopyBytes3Or5Rax, // MOV B8+rb
/* BB */ ENTRY_CopyBytes3Or5Rax, // MOV B8+rb
/* BC */ ENTRY_CopyBytes3Or5Rax, // MOV B8+rb
/* BD */ ENTRY_CopyBytes3Or5Rax, // MOV B8+rb
/* BE */ ENTRY_CopyBytes3Or5Rax, // MOV B8+rb
/* BF */ ENTRY_CopyBytes3Or5Rax, // MOV B8+rb
/* C0 */ ENTRY_CopyBytes2Mod1, // RCL/2 ib, etc.
/* C1 */ ENTRY_CopyBytes2Mod1, // RCL/2 ib, etc.
/* C2 */ ENTRY_CopyBytes3, // RET
/* C3 */ ENTRY_CopyBytes1, // RET
/* C4 */ ENTRY_CopyVex3, // LES, VEX 3-byte opcodes.
/* C5 */ ENTRY_CopyVex2, // LDS, VEX 2-byte opcodes.
/* C6 */ ENTRY_CopyBytes2Mod1, // MOV
/* C7 */ ENTRY_CopyBytes2ModOperand, // MOV/0 XBEGIN/7
/* C8 */ ENTRY_CopyBytes4, // ENTER
/* C9 */ ENTRY_CopyBytes1, // LEAVE
/* CA */ ENTRY_CopyBytes3Dynamic, // RET
/* CB */ ENTRY_CopyBytes1Dynamic, // RET
/* CC */ ENTRY_CopyBytes1Dynamic, // INT 3
/* CD */ ENTRY_CopyBytes2Dynamic, // INT ib
#ifdef DETOURS_X64
/* CE */ ENTRY_Invalid, // Invalid
#else
/* CE */ ENTRY_CopyBytes1Dynamic, // INTO
#endif
/* CF */ ENTRY_CopyBytes1Dynamic, // IRET
/* D0 */ ENTRY_CopyBytes2Mod, // RCL/2, etc.
/* D1 */ ENTRY_CopyBytes2Mod, // RCL/2, etc.
/* D2 */ ENTRY_CopyBytes2Mod, // RCL/2, etc.
/* D3 */ ENTRY_CopyBytes2Mod, // RCL/2, etc.
#ifdef DETOURS_X64
/* D4 */ ENTRY_Invalid, // Invalid
/* D5 */ ENTRY_Invalid, // Invalid
#else
/* D4 */ ENTRY_CopyBytes2, // AAM
/* D5 */ ENTRY_CopyBytes2, // AAD
#endif
/* D6 */ ENTRY_Invalid, // Invalid
/* D7 */ ENTRY_CopyBytes1, // XLAT/XLATB
/* D8 */ ENTRY_CopyBytes2Mod, // FADD, etc.
/* D9 */ ENTRY_CopyBytes2Mod, // F2XM1, etc.
/* DA */ ENTRY_CopyBytes2Mod, // FLADD, etc.
/* DB */ ENTRY_CopyBytes2Mod, // FCLEX, etc.
/* DC */ ENTRY_CopyBytes2Mod, // FADD/0, etc.
/* DD */ ENTRY_CopyBytes2Mod, // FFREE, etc.
/* DE */ ENTRY_CopyBytes2Mod, // FADDP, etc.
/* DF */ ENTRY_CopyBytes2Mod, // FBLD/4, etc.
/* E0 */ ENTRY_CopyBytes2CantJump, // LOOPNE cb
/* E1 */ ENTRY_CopyBytes2CantJump, // LOOPE cb
/* E2 */ ENTRY_CopyBytes2CantJump, // LOOP cb
/* E3 */ ENTRY_CopyBytes2CantJump, // JCXZ/JECXZ
/* E4 */ ENTRY_CopyBytes2, // IN ib
/* E5 */ ENTRY_CopyBytes2, // IN id
/* E6 */ ENTRY_CopyBytes2, // OUT ib
/* E7 */ ENTRY_CopyBytes2, // OUT ib
/* E8 */ ENTRY_CopyBytes3Or5Target, // CALL cd
/* E9 */ ENTRY_CopyBytes3Or5Target, // JMP cd
#ifdef DETOURS_X64
/* EA */ ENTRY_Invalid, // Invalid
#else
/* EA */ ENTRY_CopyBytes5Or7Dynamic, // JMP cp
#endif
/* EB */ ENTRY_CopyBytes2Jump, // JMP cb
/* EC */ ENTRY_CopyBytes1, // IN ib
/* ED */ ENTRY_CopyBytes1, // IN id
/* EE */ ENTRY_CopyBytes1, // OUT
/* EF */ ENTRY_CopyBytes1, // OUT
/* F0 */ ENTRY_CopyBytesPrefix, // LOCK prefix
/* F1 */ ENTRY_CopyBytes1Dynamic, // INT1 / ICEBP somewhat documented by AMD, not by Intel
/* F2 */ ENTRY_CopyF2, // REPNE prefix
//#ifdef DETOURS_X86
/* F3 */ ENTRY_CopyF3, // REPE prefix
//#else
// This does presently suffice for AMD64 but it requires tracing
// through a bunch of code to verify and seems not worth maintaining.
// /* F3 */ ENTRY_CopyBytesPrefix, // REPE prefix
//#endif
/* F4 */ ENTRY_CopyBytes1, // HLT
/* F5 */ ENTRY_CopyBytes1, // CMC
/* F6 */ ENTRY_CopyF6, // TEST/0, DIV/6
/* F7 */ ENTRY_CopyF7, // TEST/0, DIV/6
/* F8 */ ENTRY_CopyBytes1, // CLC
/* F9 */ ENTRY_CopyBytes1, // STC
/* FA */ ENTRY_CopyBytes1, // CLI
/* FB */ ENTRY_CopyBytes1, // STI
/* FC */ ENTRY_CopyBytes1, // CLD
/* FD */ ENTRY_CopyBytes1, // STD
/* FE */ ENTRY_CopyBytes2Mod, // DEC/1,INC/0
/* FF */ ENTRY_CopyFF, // CALL/2
};
///////////////////////////////////////////////////////// Disassembler Tables.
//
const UCHAR Disasm::s_ModRm[256] = {
0,0,0,0, static_cast<UCHAR>(ModRm::Sib) | 1,static_cast<UCHAR>(ModRm::Rip) | 4,0,0, 0,0,0,0, static_cast<UCHAR>(ModRm::Sib) | 1,static_cast<UCHAR>(ModRm::Sib) | 4,0,0, // 0x
0,0,0,0, static_cast<UCHAR>(ModRm::Sib) | 1,static_cast<UCHAR>(ModRm::Rip) | 4,0,0, 0,0,0,0, static_cast<UCHAR>(ModRm::Sib) | 1,static_cast<UCHAR>(ModRm::Sib) | 4,0,0, // 1x
0,0,0,0, static_cast<UCHAR>(ModRm::Sib) | 1,static_cast<UCHAR>(ModRm::Rip) | 4,0,0, 0,0,0,0, static_cast<UCHAR>(ModRm::Sib) | 1,static_cast<UCHAR>(ModRm::Sib) | 4,0,0, // 2x
0,0,0,0, static_cast<UCHAR>(ModRm::Sib) | 1,static_cast<UCHAR>(ModRm::Rip) | 4,0,0, 0,0,0,0, static_cast<UCHAR>(ModRm::Sib) | 1,static_cast<UCHAR>(ModRm::Sib) | 4,0,0, // 3x
1,1,1,1, 2,1,1,1, 1,1,1,1, 2,1,1,1, // 4x
1,1,1,1, 2,1,1,1, 1,1,1,1, 2,1,1,1, // 5x
1,1,1,1, 2,1,1,1, 1,1,1,1, 2,1,1,1, // 6x
1,1,1,1, 2,1,1,1, 1,1,1,1, 2,1,1,1, // 7x
4,4,4,4, 5,4,4,4, 4,4,4,4, 5,4,4,4, // 8x
4,4,4,4, 5,4,4,4, 4,4,4,4, 5,4,4,4, // 9x
4,4,4,4, 5,4,4,4, 4,4,4,4, 5,4,4,4, // Ax
4,4,4,4, 5,4,4,4, 4,4,4,4, 5,4,4,4, // Bx
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Cx
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Dx
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Ex
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 // Fx
};
const Disasm::CopyEntry Disasm::s_CopyTable0F[] = {
#ifdef DETOURS_X86
/* 00 */ ENTRY_Copy0F00, // sldt/0 str/1 lldt/2 ltr/3 err/4 verw/5 jmpe/6/dynamic invalid/7
#else
/* 00 */ ENTRY_CopyBytes2Mod, // sldt/0 str/1 lldt/2 ltr/3 err/4 verw/5 jmpe/6/dynamic invalid/7
#endif
/* 01 */ ENTRY_CopyBytes2Mod, // INVLPG/7, etc.
/* 02 */ ENTRY_CopyBytes2Mod, // LAR/r
/* 03 */ ENTRY_CopyBytes2Mod, // LSL/r
/* 04 */ ENTRY_Invalid, // _04
/* 05 */ ENTRY_CopyBytes1, // SYSCALL
/* 06 */ ENTRY_CopyBytes1, // CLTS
/* 07 */ ENTRY_CopyBytes1, // SYSRET
/* 08 */ ENTRY_CopyBytes1, // INVD
/* 09 */ ENTRY_CopyBytes1, // WBINVD
/* 0A */ ENTRY_Invalid, // _0A
/* 0B */ ENTRY_CopyBytes1, // UD2
/* 0C */ ENTRY_Invalid, // _0C
/* 0D */ ENTRY_CopyBytes2Mod, // PREFETCH
/* 0E */ ENTRY_CopyBytes1, // FEMMS (3DNow -- not in Intel documentation)
/* 0F */ ENTRY_CopyBytes2Mod1, // 3DNow Opcodes
/* 10 */ ENTRY_CopyBytes2Mod, // MOVSS MOVUPD MOVSD
/* 11 */ ENTRY_CopyBytes2Mod, // MOVSS MOVUPD MOVSD
/* 12 */ ENTRY_CopyBytes2Mod, // MOVLPD
/* 13 */ ENTRY_CopyBytes2Mod, // MOVLPD
/* 14 */ ENTRY_CopyBytes2Mod, // UNPCKLPD
/* 15 */ ENTRY_CopyBytes2Mod, // UNPCKHPD
/* 16 */ ENTRY_CopyBytes2Mod, // MOVHPD
/* 17 */ ENTRY_CopyBytes2Mod, // MOVHPD
/* 18 */ ENTRY_CopyBytes2Mod, // PREFETCHINTA...
/* 19 */ ENTRY_CopyBytes2Mod, // NOP/r multi byte nop, not documented by Intel, documented by AMD
/* 1A */ ENTRY_CopyBytes2Mod, // NOP/r multi byte nop, not documented by Intel, documented by AMD
/* 1B */ ENTRY_CopyBytes2Mod, // NOP/r multi byte nop, not documented by Intel, documented by AMD
/* 1C */ ENTRY_CopyBytes2Mod, // NOP/r multi byte nop, not documented by Intel, documented by AMD
/* 1D */ ENTRY_CopyBytes2Mod, // NOP/r multi byte nop, not documented by Intel, documented by AMD
/* 1E */ ENTRY_CopyBytes2Mod, // NOP/r multi byte nop, not documented by Intel, documented by AMD
/* 1F */ ENTRY_CopyBytes2Mod, // NOP/r multi byte nop
/* 20 */ ENTRY_CopyBytes2Mod, // MOV/r
/* 21 */ ENTRY_CopyBytes2Mod, // MOV/r
/* 22 */ ENTRY_CopyBytes2Mod, // MOV/r
/* 23 */ ENTRY_CopyBytes2Mod, // MOV/r
#ifdef DETOURS_X64
/* 24 */ ENTRY_Invalid, // _24
#else
/* 24 */ ENTRY_CopyBytes2Mod, // MOV/r,TR TR is test register on 80386 and 80486, removed in Pentium
#endif
/* 25 */ ENTRY_Invalid, // _25
#ifdef DETOURS_X64
/* 26 */ ENTRY_Invalid, // _26
#else
/* 26 */ ENTRY_CopyBytes2Mod, // MOV TR/r TR is test register on 80386 and 80486, removed in Pentium
#endif
/* 27 */ ENTRY_Invalid, // _27
/* 28 */ ENTRY_CopyBytes2Mod, // MOVAPS MOVAPD
/* 29 */ ENTRY_CopyBytes2Mod, // MOVAPS MOVAPD
/* 2A */ ENTRY_CopyBytes2Mod, // CVPI2PS &
/* 2B */ ENTRY_CopyBytes2Mod, // MOVNTPS MOVNTPD
/* 2C */ ENTRY_CopyBytes2Mod, // CVTTPS2PI &
/* 2D */ ENTRY_CopyBytes2Mod, // CVTPS2PI &
/* 2E */ ENTRY_CopyBytes2Mod, // UCOMISS UCOMISD
/* 2F */ ENTRY_CopyBytes2Mod, // COMISS COMISD
/* 30 */ ENTRY_CopyBytes1, // WRMSR
/* 31 */ ENTRY_CopyBytes1, // RDTSC
/* 32 */ ENTRY_CopyBytes1, // RDMSR
/* 33 */ ENTRY_CopyBytes1, // RDPMC
/* 34 */ ENTRY_CopyBytes1, // SYSENTER
/* 35 */ ENTRY_CopyBytes1, // SYSEXIT
/* 36 */ ENTRY_Invalid, // _36
/* 37 */ ENTRY_CopyBytes1, // GETSEC
/* 38 */ ENTRY_CopyBytes3Mod, // SSE3 Opcodes
/* 39 */ ENTRY_Invalid, // _39
/* 3A */ ENTRY_CopyBytes3Mod1, // SSE3 Opcodes
/* 3B */ ENTRY_Invalid, // _3B
/* 3C */ ENTRY_Invalid, // _3C
/* 3D */ ENTRY_Invalid, // _3D
/* 3E */ ENTRY_Invalid, // _3E
/* 3F */ ENTRY_Invalid, // _3F
/* 40 */ ENTRY_CopyBytes2Mod, // CMOVO (0F 40)
/* 41 */ ENTRY_CopyBytes2Mod, // CMOVNO (0F 41)
/* 42 */ ENTRY_CopyBytes2Mod, // CMOVB & CMOVNE (0F 42)
/* 43 */ ENTRY_CopyBytes2Mod, // CMOVAE & CMOVNB (0F 43)
/* 44 */ ENTRY_CopyBytes2Mod, // CMOVE & CMOVZ (0F 44)
/* 45 */ ENTRY_CopyBytes2Mod, // CMOVNE & CMOVNZ (0F 45)
/* 46 */ ENTRY_CopyBytes2Mod, // CMOVBE & CMOVNA (0F 46)
/* 47 */ ENTRY_CopyBytes2Mod, // CMOVA & CMOVNBE (0F 47)
/* 48 */ ENTRY_CopyBytes2Mod, // CMOVS (0F 48)
/* 49 */ ENTRY_CopyBytes2Mod, // CMOVNS (0F 49)
/* 4A */ ENTRY_CopyBytes2Mod, // CMOVP & CMOVPE (0F 4A)
/* 4B */ ENTRY_CopyBytes2Mod, // CMOVNP & CMOVPO (0F 4B)
/* 4C */ ENTRY_CopyBytes2Mod, // CMOVL & CMOVNGE (0F 4C)
/* 4D */ ENTRY_CopyBytes2Mod, // CMOVGE & CMOVNL (0F 4D)
/* 4E */ ENTRY_CopyBytes2Mod, // CMOVLE & CMOVNG (0F 4E)
/* 4F */ ENTRY_CopyBytes2Mod, // CMOVG & CMOVNLE (0F 4F)
/* 50 */ ENTRY_CopyBytes2Mod, // MOVMSKPD MOVMSKPD
/* 51 */ ENTRY_CopyBytes2Mod, // SQRTPS &
/* 52 */ ENTRY_CopyBytes2Mod, // RSQRTTS RSQRTPS
/* 53 */ ENTRY_CopyBytes2Mod, // RCPPS RCPSS
/* 54 */ ENTRY_CopyBytes2Mod, // ANDPS ANDPD
/* 55 */ ENTRY_CopyBytes2Mod, // ANDNPS ANDNPD
/* 56 */ ENTRY_CopyBytes2Mod, // ORPS ORPD
/* 57 */ ENTRY_CopyBytes2Mod, // XORPS XORPD
/* 58 */ ENTRY_CopyBytes2Mod, // ADDPS &
/* 59 */ ENTRY_CopyBytes2Mod, // MULPS &
/* 5A */ ENTRY_CopyBytes2Mod, // CVTPS2PD &
/* 5B */ ENTRY_CopyBytes2Mod, // CVTDQ2PS &
/* 5C */ ENTRY_CopyBytes2Mod, // SUBPS &
/* 5D */ ENTRY_CopyBytes2Mod, // MINPS &
/* 5E */ ENTRY_CopyBytes2Mod, // DIVPS &
/* 5F */ ENTRY_CopyBytes2Mod, // MASPS &
/* 60 */ ENTRY_CopyBytes2Mod, // PUNPCKLBW/r
/* 61 */ ENTRY_CopyBytes2Mod, // PUNPCKLWD/r
/* 62 */ ENTRY_CopyBytes2Mod, // PUNPCKLWD/r
/* 63 */ ENTRY_CopyBytes2Mod, // PACKSSWB/r
/* 64 */ ENTRY_CopyBytes2Mod, // PCMPGTB/r
/* 65 */ ENTRY_CopyBytes2Mod, // PCMPGTW/r
/* 66 */ ENTRY_CopyBytes2Mod, // PCMPGTD/r
/* 67 */ ENTRY_CopyBytes2Mod, // PACKUSWB/r
/* 68 */ ENTRY_CopyBytes2Mod, // PUNPCKHBW/r
/* 69 */ ENTRY_CopyBytes2Mod, // PUNPCKHWD/r
/* 6A */ ENTRY_CopyBytes2Mod, // PUNPCKHDQ/r
/* 6B */ ENTRY_CopyBytes2Mod, // PACKSSDW/r
/* 6C */ ENTRY_CopyBytes2Mod, // PUNPCKLQDQ
/* 6D */ ENTRY_CopyBytes2Mod, // PUNPCKHQDQ
/* 6E */ ENTRY_CopyBytes2Mod, // MOVD/r
/* 6F */ ENTRY_CopyBytes2Mod, // MOV/r
/* 70 */ ENTRY_CopyBytes2Mod1, // PSHUFW/r ib
/* 71 */ ENTRY_CopyBytes2Mod1, // PSLLW/6 ib,PSRAW/4 ib,PSRLW/2 ib
/* 72 */ ENTRY_CopyBytes2Mod1, // PSLLD/6 ib,PSRAD/4 ib,PSRLD/2 ib
/* 73 */ ENTRY_CopyBytes2Mod1, // PSLLQ/6 ib,PSRLQ/2 ib
/* 74 */ ENTRY_CopyBytes2Mod, // PCMPEQB/r
/* 75 */ ENTRY_CopyBytes2Mod, // PCMPEQW/r
/* 76 */ ENTRY_CopyBytes2Mod, // PCMPEQD/r
/* 77 */ ENTRY_CopyBytes1, // EMMS
// extrq/insertq require mode=3 and are followed by two immediate bytes
/* 78 */ ENTRY_Copy0F78, // VMREAD/r, 66/EXTRQ/r/ib/ib, F2/INSERTQ/r/ib/ib
// extrq/insertq require mod=3, therefore ENTRY_CopyBytes2, but it ends up the same
/* 79 */ ENTRY_CopyBytes2Mod, // VMWRITE/r, 66/EXTRQ/r, F2/INSERTQ/r
/* 7A */ ENTRY_Invalid, // _7A
/* 7B */ ENTRY_Invalid, // _7B
/* 7C */ ENTRY_CopyBytes2Mod, // HADDPS
/* 7D */ ENTRY_CopyBytes2Mod, // HSUBPS
/* 7E */ ENTRY_CopyBytes2Mod, // MOVD/r
/* 7F */ ENTRY_CopyBytes2Mod, // MOV/r
/* 80 */ ENTRY_CopyBytes3Or5Target, // JO
/* 81 */ ENTRY_CopyBytes3Or5Target, // JNO
/* 82 */ ENTRY_CopyBytes3Or5Target, // JB,JC,JNAE
/* 83 */ ENTRY_CopyBytes3Or5Target, // JAE,JNB,JNC
/* 84 */ ENTRY_CopyBytes3Or5Target, // JE,JZ,JZ
/* 85 */ ENTRY_CopyBytes3Or5Target, // JNE,JNZ
/* 86 */ ENTRY_CopyBytes3Or5Target, // JBE,JNA
/* 87 */ ENTRY_CopyBytes3Or5Target, // JA,JNBE
/* 88 */ ENTRY_CopyBytes3Or5Target, // JS
/* 89 */ ENTRY_CopyBytes3Or5Target, // JNS
/* 8A */ ENTRY_CopyBytes3Or5Target, // JP,JPE
/* 8B */ ENTRY_CopyBytes3Or5Target, // JNP,JPO
/* 8C */ ENTRY_CopyBytes3Or5Target, // JL,NGE
/* 8D */ ENTRY_CopyBytes3Or5Target, // JGE,JNL
/* 8E */ ENTRY_CopyBytes3Or5Target, // JLE,JNG
/* 8F */ ENTRY_CopyBytes3Or5Target, // JG,JNLE
/* 90 */ ENTRY_CopyBytes2Mod, // CMOVO (0F 40)
/* 91 */ ENTRY_CopyBytes2Mod, // CMOVNO (0F 41)
/* 92 */ ENTRY_CopyBytes2Mod, // CMOVB & CMOVC & CMOVNAE (0F 42)
/* 93 */ ENTRY_CopyBytes2Mod, // CMOVAE & CMOVNB & CMOVNC (0F 43)
/* 94 */ ENTRY_CopyBytes2Mod, // CMOVE & CMOVZ (0F 44)
/* 95 */ ENTRY_CopyBytes2Mod, // CMOVNE & CMOVNZ (0F 45)
/* 96 */ ENTRY_CopyBytes2Mod, // CMOVBE & CMOVNA (0F 46)
/* 97 */ ENTRY_CopyBytes2Mod, // CMOVA & CMOVNBE (0F 47)
/* 98 */ ENTRY_CopyBytes2Mod, // CMOVS (0F 48)
/* 99 */ ENTRY_CopyBytes2Mod, // CMOVNS (0F 49)
/* 9A */ ENTRY_CopyBytes2Mod, // CMOVP & CMOVPE (0F 4A)
/* 9B */ ENTRY_CopyBytes2Mod, // CMOVNP & CMOVPO (0F 4B)
/* 9C */ ENTRY_CopyBytes2Mod, // CMOVL & CMOVNGE (0F 4C)
/* 9D */ ENTRY_CopyBytes2Mod, // CMOVGE & CMOVNL (0F 4D)
/* 9E */ ENTRY_CopyBytes2Mod, // CMOVLE & CMOVNG (0F 4E)
/* 9F */ ENTRY_CopyBytes2Mod, // CMOVG & CMOVNLE (0F 4F)
/* A0 */ ENTRY_CopyBytes1, // PUSH
/* A1 */ ENTRY_CopyBytes1, // POP
/* A2 */ ENTRY_CopyBytes1, // CPUID
/* A3 */ ENTRY_CopyBytes2Mod, // BT (0F A3)
/* A4 */ ENTRY_CopyBytes2Mod1, // SHLD
/* A5 */ ENTRY_CopyBytes2Mod, // SHLD
/* A6 */ ENTRY_CopyBytes2Mod, // XBTS
/* A7 */ ENTRY_CopyBytes2Mod, // IBTS
/* A8 */ ENTRY_CopyBytes1, // PUSH
/* A9 */ ENTRY_CopyBytes1, // POP
/* AA */ ENTRY_CopyBytes1, // RSM
/* AB */ ENTRY_CopyBytes2Mod, // BTS (0F AB)
/* AC */ ENTRY_CopyBytes2Mod1, // SHRD
/* AD */ ENTRY_CopyBytes2Mod, // SHRD
// 0F AE mod76=mem mod543=0 fxsave
// 0F AE mod76=mem mod543=1 fxrstor
// 0F AE mod76=mem mod543=2 ldmxcsr
// 0F AE mod76=mem mod543=3 stmxcsr
// 0F AE mod76=mem mod543=4 xsave
// 0F AE mod76=mem mod543=5 xrstor
// 0F AE mod76=mem mod543=6 saveopt
// 0F AE mod76=mem mod543=7 clflush
// 0F AE mod76=11b mod543=5 lfence
// 0F AE mod76=11b mod543=6 mfence
// 0F AE mod76=11b mod543=7 sfence
// F3 0F AE mod76=11b mod543=0 rdfsbase
// F3 0F AE mod76=11b mod543=1 rdgsbase
// F3 0F AE mod76=11b mod543=2 wrfsbase
// F3 0F AE mod76=11b mod543=3 wrgsbase
/* AE */ ENTRY_CopyBytes2Mod, // fxsave fxrstor ldmxcsr stmxcsr xsave xrstor saveopt clflush lfence mfence sfence rdfsbase rdgsbase wrfsbase wrgsbase
/* AF */ ENTRY_CopyBytes2Mod, // IMUL (0F AF)
/* B0 */ ENTRY_CopyBytes2Mod, // CMPXCHG (0F B0)
/* B1 */ ENTRY_CopyBytes2Mod, // CMPXCHG (0F B1)
/* B2 */ ENTRY_CopyBytes2Mod, // LSS/r
/* B3 */ ENTRY_CopyBytes2Mod, // BTR (0F B3)
/* B4 */ ENTRY_CopyBytes2Mod, // LFS/r
/* B5 */ ENTRY_CopyBytes2Mod, // LGS/r
/* B6 */ ENTRY_CopyBytes2Mod, // MOVZX/r
/* B7 */ ENTRY_CopyBytes2Mod, // MOVZX/r
#ifdef DETOURS_X86
/* B8 */ ENTRY_Copy0FB8, // jmpe f3/popcnt
#else
/* B8 */ ENTRY_CopyBytes2Mod, // f3/popcnt
#endif
/* B9 */ ENTRY_Invalid, // _B9
/* BA */ ENTRY_CopyBytes2Mod1, // BT & BTC & BTR & BTS (0F BA)
/* BB */ ENTRY_CopyBytes2Mod, // BTC (0F BB)
/* BC */ ENTRY_CopyBytes2Mod, // BSF (0F BC)
/* BD */ ENTRY_CopyBytes2Mod, // BSR (0F BD)
/* BE */ ENTRY_CopyBytes2Mod, // MOVSX/r
/* BF */ ENTRY_CopyBytes2Mod, // MOVSX/r
/* C0 */ ENTRY_CopyBytes2Mod, // XADD/r
/* C1 */ ENTRY_CopyBytes2Mod, // XADD/r
/* C2 */ ENTRY_CopyBytes2Mod1, // CMPPS &
/* C3 */ ENTRY_CopyBytes2Mod, // MOVNTI
/* C4 */ ENTRY_CopyBytes2Mod1, // PINSRW /r ib
/* C5 */ ENTRY_CopyBytes2Mod1, // PEXTRW /r ib
/* C6 */ ENTRY_CopyBytes2Mod1, // SHUFPS & SHUFPD
/* C7 */ ENTRY_CopyBytes2Mod, // CMPXCHG8B (0F C7)
/* C8 */ ENTRY_CopyBytes1, // BSWAP 0F C8 + rd
/* C9 */ ENTRY_CopyBytes1, // BSWAP 0F C8 + rd
/* CA */ ENTRY_CopyBytes1, // BSWAP 0F C8 + rd
/* CB */ ENTRY_CopyBytes1, // CVTPD2PI BSWAP 0F C8 + rd
/* CC */ ENTRY_CopyBytes1, // BSWAP 0F C8 + rd
/* CD */ ENTRY_CopyBytes1, // BSWAP 0F C8 + rd
/* CE */ ENTRY_CopyBytes1, // BSWAP 0F C8 + rd
/* CF */ ENTRY_CopyBytes1, // BSWAP 0F C8 + rd
/* D0 */ ENTRY_CopyBytes2Mod, // ADDSUBPS (untestd)
/* D1 */ ENTRY_CopyBytes2Mod, // PSRLW/r
/* D2 */ ENTRY_CopyBytes2Mod, // PSRLD/r
/* D3 */ ENTRY_CopyBytes2Mod, // PSRLQ/r
/* D4 */ ENTRY_CopyBytes2Mod, // PADDQ
/* D5 */ ENTRY_CopyBytes2Mod, // PMULLW/r
/* D6 */ ENTRY_CopyBytes2Mod, // MOVDQ2Q / MOVQ2DQ
/* D7 */ ENTRY_CopyBytes2Mod, // PMOVMSKB/r
/* D8 */ ENTRY_CopyBytes2Mod, // PSUBUSB/r
/* D9 */ ENTRY_CopyBytes2Mod, // PSUBUSW/r
/* DA */ ENTRY_CopyBytes2Mod, // PMINUB/r
/* DB */ ENTRY_CopyBytes2Mod, // PAND/r
/* DC */ ENTRY_CopyBytes2Mod, // PADDUSB/r
/* DD */ ENTRY_CopyBytes2Mod, // PADDUSW/r
/* DE */ ENTRY_CopyBytes2Mod, // PMAXUB/r
/* DF */ ENTRY_CopyBytes2Mod, // PANDN/r
/* E0 */ ENTRY_CopyBytes2Mod , // PAVGB
/* E1 */ ENTRY_CopyBytes2Mod, // PSRAW/r
/* E2 */ ENTRY_CopyBytes2Mod, // PSRAD/r
/* E3 */ ENTRY_CopyBytes2Mod, // PAVGW
/* E4 */ ENTRY_CopyBytes2Mod, // PMULHUW/r
/* E5 */ ENTRY_CopyBytes2Mod, // PMULHW/r
/* E6 */ ENTRY_CopyBytes2Mod, // CTDQ2PD &
/* E7 */ ENTRY_CopyBytes2Mod, // MOVNTQ
/* E8 */ ENTRY_CopyBytes2Mod, // PSUBB/r
/* E9 */ ENTRY_CopyBytes2Mod, // PSUBW/r
/* EA */ ENTRY_CopyBytes2Mod, // PMINSW/r
/* EB */ ENTRY_CopyBytes2Mod, // POR/r
/* EC */ ENTRY_CopyBytes2Mod, // PADDSB/r
/* ED */ ENTRY_CopyBytes2Mod, // PADDSW/r
/* EE */ ENTRY_CopyBytes2Mod, // PMAXSW /r
/* EF */ ENTRY_CopyBytes2Mod, // PXOR/r
/* F0 */ ENTRY_CopyBytes2Mod, // LDDQU
/* F1 */ ENTRY_CopyBytes2Mod, // PSLLW/r
/* F2 */ ENTRY_CopyBytes2Mod, // PSLLD/r
/* F3 */ ENTRY_CopyBytes2Mod, // PSLLQ/r
/* F4 */ ENTRY_CopyBytes2Mod, // PMULUDQ/r
/* F5 */ ENTRY_CopyBytes2Mod, // PMADDWD/r
/* F6 */ ENTRY_CopyBytes2Mod, // PSADBW/r
/* F7 */ ENTRY_CopyBytes2Mod, // MASKMOVQ
/* F8 */ ENTRY_CopyBytes2Mod, // PSUBB/r
/* F9 */ ENTRY_CopyBytes2Mod, // PSUBW/r
/* FA */ ENTRY_CopyBytes2Mod, // PSUBD/r
/* FB */ ENTRY_CopyBytes2Mod, // FSUBQ/r
/* FC */ ENTRY_CopyBytes2Mod, // PADDB/r
/* FD */ ENTRY_CopyBytes2Mod, // PADDW/r
/* FE */ ENTRY_CopyBytes2Mod, // PADDD/r
/* FF */ ENTRY_Invalid, // _FF
};
_Use_decl_annotations_
PVOID DetourCopyInstruction(PVOID pDst,
PVOID* ppDstPool,
PVOID pSrc,
PVOID* ppTarget,
LONG* pExtra) {
UNREFERENCED_PARAMETER(ppDstPool);
Disasm disasm((PUCHAR*)ppTarget, pExtra);
return disasm.CopyInstruction((PUCHAR)pDst, (PUCHAR)pSrc);
}
Disasm::Disasm(PUCHAR* ppTarget, LONG* pExtra) {
m_ppTarget = ppTarget ? ppTarget : &m_pScratchTarget;
m_pExtra = pExtra ? pExtra : &m_ScratchExtra;
*m_ppTarget = nullptr;
*m_pExtra = 0;
}
PUCHAR Disasm::CopyInstruction(PUCHAR pDst, PUCHAR pSrc) {
// Configure scratch areas if real areas are not available.
if (nullptr == pDst) {
pDst = m_ScratchDst;
}
if (nullptr == pSrc) {
// We cannot copy a non-existent instruction
return nullptr;
}
// Figure out how big the instruction is, do the appropriate copy,
// and figure out what the target of the instruction is if any
//
RefCopyEntry pEntry = &s_CopyTable[pSrc[0]];
return (this->*pEntry->pfCopy)(pEntry, pDst, pSrc);
}
PUCHAR Disasm::CopyBytes(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
ULONG bytesFixed;
if (m_Vex || m_Evex) {
ASSERT(pEntry->FlagBits == FlagBits::None);
ASSERT(pEntry->FixedSize == pEntry->FixedSize16);
}
ULONG const modOffset = pEntry->ModOffset;
FlagBits flagBits = pEntry->FlagBits;
ULONG const fixedSize = pEntry->FixedSize;
ULONG const fixedSize16 = pEntry->FixedSize16;
bool address = (flagBits & FlagBits::Address) == FlagBits::Address;
if (address) {
bytesFixed = m_AddressOverride ? fixedSize16 : fixedSize;
}
#ifdef DETOURS_X64
// REX.W trumps 66
else if (m_RaxOverride) {
bool rax = (flagBits & FlagBits::Rax) == FlagBits::Rax;
bytesFixed = fixedSize + (rax ? 4 : 0);
}
#endif // DETOURS_X64
else {
bytesFixed = m_OperandOverride ? fixedSize16 : fixedSize;
}
ULONG bytes = bytesFixed;
ULONG relOffset = pEntry->RelOffset;
ULONG target = bytes - relOffset;
if (modOffset > 0) {
ASSERT(relOffset == 0);
UCHAR const modRm = pSrc[modOffset];
UCHAR const flags = s_ModRm[modRm];
bytes += flags & static_cast<UCHAR>(ModRm::NotSib);
if (flags & static_cast<UCHAR>(ModRm::Sib)) {
UCHAR const sib = pSrc[modOffset + 1];
if ((sib & 0x07) == 0x05) {
if ((modRm & 0xc0) == 0x00) {
bytes += 4;
}
else if ((modRm & 0xc0) == 0x40) {
bytes += 1;
}
else if ((modRm & 0xc0) == 0x80) {
bytes += 4;
}
}
target = bytes - relOffset;
}
#ifdef DETOURS_X64
else if (flags & static_cast<UCHAR>(ModRm::Rip)) {
relOffset = modOffset + 1;
target = 4;
}
#endif // DETOURS_X64
}
RtlCopyMemory(pDst, pSrc, bytes);
if (relOffset) {
*m_ppTarget = AdjustTarget(pDst, pSrc, bytes, relOffset, target);
#ifdef DETOURS_X64
if (pEntry->RelOffset == 0) {
// This is a data target, not a code target, so we shouldn't return it.
*m_ppTarget = nullptr;
}
#endif // DETOURS_X64
}
bool noEnlarge = (flagBits & FlagBits::NoEnlarge) == FlagBits::NoEnlarge;
if (noEnlarge) {
*m_pExtra = -*m_pExtra;
}
bool dynamic = (flagBits & FlagBits::Dynamic) == FlagBits::Dynamic;
if (dynamic) {
*m_ppTarget = (PUCHAR)DETOUR_INSTRUCTION_TARGET_DYNAMIC;
}
return pSrc + bytes;
}
PUCHAR Disasm::CopyBytesPrefix(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
pDst[0] = pSrc[0];
pEntry = &s_CopyTable[pSrc[1]];
return (this->*pEntry->pfCopy)(pEntry, pDst + 1, pSrc + 1);
}
PUCHAR Disasm::CopyBytesSegment(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
m_SegmentOverride = pSrc[0];
return CopyBytesPrefix(nullptr, pDst, pSrc);
}
PUCHAR Disasm::CopyBytesRax(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
// AMD64 only
if (pSrc[0] * 0x8) {
m_RaxOverride = true;
}
return CopyBytesPrefix(nullptr, pDst, pSrc);
}
PUCHAR Disasm::CopyBytesJump(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
UNREFERENCED_PARAMETER(pEntry);
PVOID pSrcAddr = &pSrc[1];
PVOID pDstAddr = nullptr;
LONG_PTR oldOffset = (LONG_PTR) * (signed char*&)pSrcAddr;
LONG_PTR newOffset = 0;
*m_ppTarget = pSrc + 2 + oldOffset;
if (pSrc[0] == 0xeb) {
pDst[0] = 0xe9;
pDstAddr = &pDst[1];
newOffset = oldOffset - ((pDst - pSrc) + 3);
*(UNALIGNED LONG*&)pDstAddr = (LONG)newOffset;
*m_pExtra = 3;
return pSrc + 2;
}
ASSERT(pSrc[0] >= 0x70 && pSrc[0] <= 0x7f);
pDst[0] = 0x0f;
pDst[1] = 0x80 | (pSrc[0] & 0xf);
pDstAddr = &pDst[2];
newOffset = oldOffset - ((pDst - pSrc) + 4);
*(UNALIGNED LONG*&)pDstAddr = (LONG)newOffset;
*m_pExtra = 4;
return pSrc + 2;
}
PUCHAR Disasm::AdjustTarget(PUCHAR pDst, PUCHAR pSrc, ULONG op, ULONG targetOffset,
ULONG targetSize) {
PUCHAR pTarget = nullptr;
#if 1 // fault injection to test code
#ifdef DETOURS_X64
typedef LONGLONG T;
#else
typedef LONG T;
#endif // DETOURS_X64
T oldOffset;
T newOffset;
PVOID pTargetAddr = &pDst[targetOffset];
switch (targetSize) {
case 1:
oldOffset = *(signed char*&)pTargetAddr;
break;
case 2:
oldOffset = *(UNALIGNED SHORT*&)pTargetAddr;
break;
case 4:
oldOffset = *(UNALIGNED LONG*&)pTargetAddr;
break;
#if defined(DETOURS_X64)
case 8:
oldOffset = *(UNALIGNED LONGLONG*&)pTargetAddr;
break;
#endif
default:
ASSERT(!"cbTargetSize is invalid.");
oldOffset = 0;
break;
}
pTarget = pSrc + op + oldOffset;
newOffset = oldOffset - (T)(pDst - pSrc);
switch (targetSize) {
case 1:
*(CHAR*&)pTargetAddr = (CHAR)newOffset;
if (newOffset < SCHAR_MIN || newOffset > SCHAR_MAX) {
*m_pExtra = sizeof(ULONG) - 1;
}
break;
case 2:
*(UNALIGNED SHORT*&)pTargetAddr = (SHORT)newOffset;
if (newOffset < SHRT_MIN || newOffset > SHRT_MAX) {
*m_pExtra = sizeof(ULONG) - 2;
}
break;
case 4:
*(UNALIGNED LONG*&)pTargetAddr = (LONG)newOffset;
if (newOffset < LONG_MIN || newOffset > LONG_MAX) {
*m_pExtra = sizeof(ULONG) - 4;
}
break;
#if defined(DETOURS_X64)
case 8:
*(UNALIGNED LONGLONG*&)pTargetAddr = newOffset;
break;
#endif
}
#ifdef DETOURS_X64
// When we are only computing size, source and dest can be
// far apart, distance not encodable in 32bits. Ok.
// At least still check the lower 32bits.
if (pDst >= m_ScratchDst && pDst < (sizeof(m_ScratchDst) + m_ScratchDst)) {
ASSERT((((size_t)pDst + op + newOffset) & 0xFFFFFFFF) == (((size_t)pTarget) & 0xFFFFFFFF));
}
else
#endif
{
ASSERT(pDst + op + newOffset == pTarget);
}
#endif
return pTarget;
}
PUCHAR Disasm::Invalid(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
UNREFERENCED_PARAMETER(pEntry);
UNREFERENCED_PARAMETER(pDst);
ASSERT(!"Invalid Instruction");
return pSrc + 1;
}
////////////////////////////////////////////////////// Individual Bytes Codes.
//
PUCHAR Disasm::Copy0F(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
pDst[0] = pSrc[0];
pEntry = &s_CopyTable0F[pSrc[1]];
return (this->*pEntry->pfCopy)(pEntry, pDst + 1, pSrc + 1);
}
// x86 only sldt/0 str/1 lldt/2 ltr/3 err/4 verw/5 jmpe/6/dynamic invalid/7
PUCHAR Disasm::Copy0F00(RefCopyEntry, PUCHAR pDst, PUCHAR pSrc) {
// jmpe is 32bit x86 only
// Notice that the size are the same either way, but jmpe is marked as "dynamic"
static const CopyEntry other = /* B8 */ ENTRY_CopyBytes2Mod; // sldt/0 str/1 lldt/2 ltr/3 err/4 verw/5 jmpe/6 invalid/7
static const CopyEntry jmpe = /* B8 */ ENTRY_CopyBytes2ModDynamic; // jmpe/6 x86-on-IA64 syscalls
RefCopyEntry const pEntry = (((6 << 3) == ((7 << 3) & pSrc[1])) ? &jmpe : &other);
return (this->*pEntry->pfCopy)(pEntry, pDst, pSrc);
}
// vmread, 66/extrq/ib/ib, F2/insertq/ib/ib
PUCHAR Disasm::Copy0F78(RefCopyEntry, PUCHAR pDst, PUCHAR pSrc) {
// vmread, 66/extrq, F2/insertq
static const CopyEntry vmread = /* 78 */ ENTRY_CopyBytes2Mod;
static const CopyEntry extrq_insertq = /* 78 */ ENTRY_CopyBytes4;
ASSERT(!(m_F2 && m_OperandOverride));
// For insertq and presumably despite documentation extrq, mode must be 11, not checked.
// insertq/extrq/78 are followed by two immediate bytes, and given mode == 11, mod/rm byte is always one byte,
// and the 0x78 makes 4 bytes (not counting the 66/F2/F which are accounted for elsewhere)
RefCopyEntry const pEntry = ((m_F2 || m_OperandOverride) ? &extrq_insertq : &vmread);
return (this->*pEntry->pfCopy)(pEntry, pDst, pSrc);
}
// jmpe or F3/popcnt
PUCHAR Disasm::Copy0FB8(RefCopyEntry, PUCHAR pDst, PUCHAR pSrc) {
// jmpe is 32bit x86 only
static const CopyEntry popcnt = /* B8 */ ENTRY_CopyBytes2Mod;
static const CopyEntry jmpe = /* B8 */ ENTRY_CopyBytes3Or5Dynamic; // jmpe x86-on-IA64 syscalls
RefCopyEntry const pEntry = m_F3 ? &popcnt : &jmpe;
return (this->*pEntry->pfCopy)(pEntry, pDst, pSrc);
}
PUCHAR Disasm::Copy66(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
// Operand-size override prefix
m_OperandOverride = TRUE;
return CopyBytesPrefix(pEntry, pDst, pSrc);
}
PUCHAR Disasm::Copy67(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
m_AddressOverride = true;
return CopyBytesPrefix(pEntry, pDst, pSrc);
}
PUCHAR Disasm::CopyF2(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
m_F2 = true;
return CopyBytesPrefix(pEntry, pDst, pSrc);
}
PUCHAR Disasm::CopyF3(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
// x86 only
m_F3 = TRUE;
return CopyBytesPrefix(pEntry, pDst, pSrc);
}
PUCHAR Disasm::CopyF6(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
UNREFERENCED_PARAMETER(pEntry);
// TEST BYTE /0
if (0x00 == (0x38 & pSrc[1])) { // reg(bits 543) of ModR/M == 0
static const CopyEntry ce = /* f6 */ ENTRY_CopyBytes2Mod1;
return (this->*ce.pfCopy)(&ce, pDst, pSrc);
}
// DIV /6
// IDIV /7
// IMUL /5
// MUL /4
// NEG /3
// NOT /2
static const CopyEntry ce = /* f6 */ ENTRY_CopyBytes2Mod;
return (this->*ce.pfCopy)(&ce, pDst, pSrc);
}
PUCHAR Disasm::CopyF7(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
UNREFERENCED_PARAMETER(pEntry);
// TEST WORD /0
if (0x00 == (0x38 & pSrc[1])) { // reg(bits 543) of ModR/M == 0
static const CopyEntry ce = /* f7 */ ENTRY_CopyBytes2ModOperand;
return (this->*ce.pfCopy)(&ce, pDst, pSrc);
}
// DIV /6
// IDIV /7
// IMUL /5
// MUL /4
// NEG /3
// NOT /2
static const CopyEntry ce = /* f7 */ ENTRY_CopyBytes2Mod;
return (this->*ce.pfCopy)(&ce, pDst, pSrc);
}
PUCHAR Disasm::CopyFF(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
// INC /0
// DEC /1
// CALL /2
// CALL /3
// JMP /4
// JMP /5
// PUSH /6
// invalid/7
UNREFERENCED_PARAMETER(pEntry);
static const CopyEntry ce = /* ff */ ENTRY_CopyBytes2Mod;
PUCHAR pOut = (this->*ce.pfCopy)(&ce, pDst, pSrc);
UCHAR const b1 = pSrc[1];
if (0x15 == b1 || 0x25 == b1) { // CALL [], JMP []
#ifdef DETOURS_X64
// All segments but FS and GS are equivalent.
if (m_SegmentOverride != 0x64 && m_SegmentOverride != 0x65)
#else
if (m_SegmentOverride == 0 || m_SegmentOverride == 0x2E)
#endif
{
#ifdef DETOURS_X64
INT32 offset = *(UNALIGNED INT32*) & pSrc[2];
PUCHAR* ppTarget = (PUCHAR*)(pSrc + 6 + offset);
#else
PUCHAR* ppTarget = (PUCHAR*)(SIZE_T) * (UNALIGNED ULONG*) & pSrc[2];
#endif
if (s_fLimitReferencesToModule &&
(ppTarget < (PVOID)s_pModuleBeg || ppTarget >= (PVOID)s_pModuleEnd)) {
*m_ppTarget = (PUCHAR)DETOUR_INSTRUCTION_TARGET_DYNAMIC;
}
else {
// This can access violate on random bytes. Use DetourSetCodeModule.
*m_ppTarget = *ppTarget;
}
}
else {
*m_ppTarget = (PUCHAR)DETOUR_INSTRUCTION_TARGET_DYNAMIC;
}
}
else if (0x10 == (0x30 & b1) || // CALL /2 or /3 --> reg(bits 543) of ModR/M == 010 or 011
0x20 == (0x30 & b1)) { // JMP /4 or /5 --> reg(bits 543) of ModR/M == 100 or 101
*m_ppTarget = (PUCHAR)DETOUR_INSTRUCTION_TARGET_DYNAMIC;
}
return pOut;
}
PUCHAR Disasm::CopyVex2(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
// 2 byte VEX prefix 0xC5
#ifdef DETOURS_X86
const static CopyEntry ceLDS = /* C5 */ ENTRY_CopyBytes2Mod;
if ((pSrc[1] & 0xC0) != 0xC0) {
RefCopyEntry pEntry = &ceLDS;
return (this->*pEntry->pfCopy)(pEntry, pDst, pSrc);
}
#endif
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
return CopyVexCommon(1, pDst + 2, pSrc + 2);
}
PUCHAR Disasm::CopyVex3(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
// 3 byte VEX prefix 0xc4
#ifdef DETOURS_X86
const static CopyEntry ceLES = /* C4 */ ENTRY_CopyBytes2Mod;
if ((pSrc[1] & 0xC0) != 0xC0) {
RefCopyEntry pEntry = &ceLES;
return (this->*pEntry->pfCopy)(pEntry, pDst, pSrc);
}
#endif
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
pDst[2] = pSrc[2];
#ifdef DETOURS_X64
m_RaxOverride |= !!(pSrc[2] & 0x80); // w in last byte, see CopyBytesRax
#else
//
// TODO
//
// Usually the VEX.W bit changes the size of a general purpose register and is ignored for 32bit.
// Sometimes it is an opcode extension.
// Look in the Intel manual, in the instruction-by-instruction reference, for ".W1",
// without nearby wording saying it is ignored for 32bit.
// For example: "VFMADD132PD/VFMADD213PD/VFMADD231PD Fused Multiply-Add of Packed Double-Precision Floating-Point Values".
//
// Then, go through each such case and determine if W0 vs. W1 affect the size of the instruction. Probably not.
// Look for the same encoding but with "W1" changed to "W0".
// Here is one such pairing:
// VFMADD132PD/VFMADD213PD/VFMADD231PD Fused Multiply-Add of Packed Double-Precision Floating-Point Values
//
// VEX.DDS.128.66.0F38.W1 98 /r A V/V FMA Multiply packed double-precision floating-point values
// from xmm0 and xmm2/mem, add to xmm1 and
// put result in xmm0.
// VFMADD132PD xmm0, xmm1, xmm2/m128
//
// VFMADD132PS/VFMADD213PS/VFMADD231PS Fused Multiply-Add of Packed Single-Precision Floating-Point Values
// VEX.DDS.128.66.0F38.W0 98 /r A V/V FMA Multiply packed single-precision floating-point values
// from xmm0 and xmm2/mem, add to xmm1 and put
// result in xmm0.
// VFMADD132PS xmm0, xmm1, xmm2/m128
//
#endif
return CopyVexCommon(pSrc[1] & 0x1F, pDst + 3, pSrc + 3);
}
PUCHAR Disasm::CopyVexEvexCommon(UCHAR m, PUCHAR pDst, PUCHAR pSrc,UCHAR p,UCHAR fp16) {
// m is first instead of last in the hopes of pbDst/pbSrc being
// passed along efficiently in the registers they were already in.
static const CopyEntry ceF38 = /* 38 */ ENTRY_CopyBytes2Mod;
static const CopyEntry ceF3A = /* 3A */ ENTRY_CopyBytes2Mod1;
static const CopyEntry ceInvalid = /* C4 */ ENTRY_Invalid;
switch (p & 3) {
case 0: break;
case 1: m_OperandOverride = TRUE; break;
case 2: m_F3 = TRUE; break;
case 3: m_F2 = TRUE; break;
}
RefCopyEntry pEntry;
// see https://software.intel.com/content/www/us/en/develop/download/intel-avx512-fp16-architecture-specification.html
switch (m | fp16) {
default: return Invalid(&ceInvalid, pDst, pSrc);
case 1: pEntry = &s_CopyTable0F[pSrc[0]];
return (this->*pEntry->pfCopy)(pEntry, pDst, pSrc);
case 5: // fallthrough
case 6: // fallthrough
case 2: return CopyBytes(&ceF38, pDst, pSrc);
case 3: return CopyBytes(&ceF3A, pDst, pSrc);
}
}
PUCHAR Disasm::CopyVexCommon(UCHAR m, PUCHAR pDst, PUCHAR pSrc) {
// m is first instead of last in the hopes of pDst/pSrc being
// passed along efficiently in the registers they were already in.
m_Vex = TRUE;
UCHAR const p = (UCHAR)(pSrc[-1] & 3); // p in last byte
return CopyVexEvexCommon(m, pDst, pSrc, p);
}
PUCHAR Disasm::CopyEvex(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
// 62, 3 byte payload, x86 with implied prefixes like Vex
// for 32bit, mode 0xC0 else fallback to bound /r
// NOTE: Intel and Wikipedia number these differently.
// Intel says 0-2, Wikipedia says 1-3.
UCHAR const p0 = pSrc[1];
#ifdef DETOURS_X86
const static CopyEntry ceBound = /* 62 */ ENTRY_CopyBytes2Mod;
if ((p0 & 0xC0) != 0xC0) {
return CopyBytes(&ceBound, pDst, pSrc);
}
#endif
static const CopyEntry ceInvalid = /* 62 */ ENTRY_Invalid;
// This could also be handled by default in CopyVexEvexCommon
// if 4u changed to 4|8.
if (p0 & 8u)
return Invalid(&ceInvalid, pDst, pSrc);
UCHAR const p1 = pSrc[2];
if ((p1 & 0x04) != 0x04)
return Invalid(&ceInvalid, pDst, pSrc);
// Copy 4 byte prefix.
*(UNALIGNED ULONG*)pDst = *(UNALIGNED ULONG*)pSrc;
m_Evex = TRUE;
#ifdef DETOURS_X64
m_RaxOverride |= !!(p1 & 0x80); // w
#endif
return CopyVexEvexCommon(p0 & 3u, pDst + 4, pSrc + 4, p1 & 3u, p0 & 4u);
}
PUCHAR Disasm::CopyXop(RefCopyEntry pEntry, PUCHAR pDst, PUCHAR pSrc) {
/* 3 byte AMD XOP prefix 0x8F
byte0: 0x8F
byte1: RXBmmmmm
byte2: WvvvvLpp
byte3: opcode
mmmmm >= 8, else pop
mmmmm only otherwise defined for 8, 9, A.
pp is like VEX but only instructions with 0 are defined
*/
const static CopyEntry cePop = /* 8F */ ENTRY_CopyBytes2Mod;
const static CopyEntry ceXop = /* 8F */ ENTRY_CopyBytesXop;
const static CopyEntry ceXop1 = /* 8F */ ENTRY_CopyBytesXop1;
const static CopyEntry ceXop4 = /* 8F */ ENTRY_CopyBytesXop4;
UCHAR const m = (UCHAR)(pSrc[1] & 0x1F);
ASSERT(m <= 10);
switch (m)
{
default:
return CopyBytes(&cePop, pDst, pSrc);
case 8: // modrm with 8bit immediate
return CopyBytes(&ceXop1, pDst, pSrc);
case 9: // modrm with no immediate
return CopyBytes(&ceXop, pDst, pSrc);
case 10: // modrm with 32bit immediate
return CopyBytes(&ceXop4, pDst, pSrc);
}
}