From f828c908e40f8ee04c8449ddf6d994a65d5c0c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20H=C3=B6ner?= Date: Sun, 12 Dec 2021 22:58:54 +0100 Subject: [PATCH 1/3] Add unions in decoded instruction and operands --- README.md | 4 +- assets/porting-guide-v3-v4.md | 6 +- include/Zydis/DecoderTypes.h | 580 +++++++++++++++++----------------- tools/ZydisFuzzShared.c | 28 +- 4 files changed, 318 insertions(+), 300 deletions(-) diff --git a/README.md b/README.md index f25203a4..2b59d568 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ - Very small file-size overhead compared to other common disassembler libraries - [Complete doxygen documentation](https://zydis.re/doc/3/) - Absolutely no third party dependencies — not even libc - - Should compile on any platform with a working C99 compiler + - Should compile on any platform with a working C11 compiler - Tested on Windows, macOS, FreeBSD, Linux and UEFI, both user and kernel mode ## Decoder Example @@ -140,7 +140,7 @@ The above example program generates the following output: ### Unix -Zydis builds cleanly on most platforms without any external dependencies. You can use CMake to generate project files for your favorite C99 compiler. +Zydis builds cleanly on most platforms without any external dependencies. You can use CMake to generate project files for your favorite C11 compiler. ```bash git clone --recursive 'https://github.com/zyantific/zydis.git' diff --git a/assets/porting-guide-v3-v4.md b/assets/porting-guide-v3-v4.md index c840d4da..36cb77cc 100644 --- a/assets/porting-guide-v3-v4.md +++ b/assets/porting-guide-v3-v4.md @@ -1,5 +1,7 @@ # Porting Guide v3 -> v4 +- Zydis now requires a C11 capable compiler + ## API changes ### ZydisDecodedInstruction @@ -9,7 +11,7 @@ 2. Added field `operand_count_visible` - Contains the number of visible (explicit and implicit) operands -### ZydisDecoder +### Decoder #### 1 @@ -63,3 +65,5 @@ ZYDIS_EXPORT ZyanStatus ZydisDecoderDecodeOperands(const ZydisDecoder* decoder, - The `ZYDIS_ATTRIB_` defines were rebased (underlying bits were changed) - New type: `ZydisDecodingFlags` - New type: `ZydisDecoderContext` +- `ZydisDecodedOperand::type` was moved to a different location in the struct +- Unions were added around fields in `ZydisDecodedOperand` and `ZydisDecodedInstruction` diff --git a/include/Zydis/DecoderTypes.h b/include/Zydis/DecoderTypes.h index 5cd5c77f..a90c840f 100644 --- a/include/Zydis/DecoderTypes.h +++ b/include/Zydis/DecoderTypes.h @@ -117,10 +117,6 @@ typedef struct ZydisDecodedOperand_ * The operand-id. */ ZyanU8 id; - /** - * The type of the operand. - */ - ZydisOperandType type; /** * The visibility of the operand. */ @@ -154,86 +150,91 @@ typedef struct ZydisDecodedOperand_ */ ZydisOperandAttributes attributes; /** - * Extended info for register-operands. + * The type of the operand. */ - struct ZydisDecodedOperandReg_ - { - /** - * The register value. - */ - ZydisRegister value; - } reg; - /** - * Extended info for memory-operands. + ZydisOperandType type; + /* + * Operand type specific information. + * + * The enabled union variant is determined by the `type` field. */ - struct ZydisDecodedOperandMem_ - { - /** - * The type of the memory operand. - */ - ZydisMemoryOperandType type; - /** - * The segment register. - */ - ZydisRegister segment; - /** - * The base register. - */ - ZydisRegister base; - /** - * The index register. - */ - ZydisRegister index; + union { /** - * The scale factor. + * Extended info for register-operands. */ - ZyanU8 scale; + struct ZydisDecodedOperandReg_ { + /** + * The register value. + */ + ZydisRegister value; + } reg; /** - * Extended info for memory-operands with displacement. + * Extended info for memory-operands. */ - struct ZydisDecodedOperandMemDisp_ - { + struct ZydisDecodedOperandMem_ { /** - * Signals, if the displacement value is used. + * The type of the memory operand. */ - ZyanBool has_displacement; + ZydisMemoryOperandType type; /** - * The displacement value + * The segment register. */ - ZyanI64 value; - } disp; - } mem; - /** - * Extended info for pointer-operands. - */ - struct ZydisDecodedOperandPtr_ - { - ZyanU16 segment; - ZyanU32 offset; - } ptr; - /** - * Extended info for immediate-operands. - */ - struct ZydisDecodedOperandImm_ - { - /** - * Signals, if the immediate value is signed. - */ - ZyanBool is_signed; + ZydisRegister segment; + /** + * The base register. + */ + ZydisRegister base; + /** + * The index register. + */ + ZydisRegister index; + /** + * The scale factor. + */ + ZyanU8 scale; + /** + * Extended info for memory-operands with displacement. + */ + struct ZydisDecodedOperandMemDisp_ { + /** + * Signals, if the displacement value is used. + */ + ZyanBool has_displacement; + /** + * The displacement value + */ + ZyanI64 value; + } disp; + } mem; /** - * Signals, if the immediate value contains a relative offset. You can use - * `ZydisCalcAbsoluteAddress` to determine the absolute address value. + * Extended info for pointer-operands. */ - ZyanBool is_relative; + struct ZydisDecodedOperandPtr_ { + ZyanU16 segment; + ZyanU32 offset; + } ptr; /** - * The immediate value. + * Extended info for immediate-operands. */ - union ZydisDecodedOperandImmValue_ - { - ZyanU64 u; - ZyanI64 s; - } value; - } imm; + struct ZydisDecodedOperandImm_ { + /** + * Signals, if the immediate value is signed. + */ + ZyanBool is_signed; + /** + * Signals, if the immediate value contains a relative offset. You can use + * `ZydisCalcAbsoluteAddress` to determine the absolute address value. + */ + ZyanBool is_relative; + /** + * The immediate value. + */ + union ZydisDecodedOperandImmValue_ { + ZyanU64 u; + ZyanI64 s; + } value; + } imm; + }; } ZydisDecodedOperand; /* ---------------------------------------------------------------------------------------------- */ @@ -913,226 +914,227 @@ typedef struct ZydisDecodedInstruction_ */ ZyanU8 offset; } rex; - /** - * Detailed info about the `XOP` prefix. + /* + * Union for things from various mutually exclusive vector extensions. */ - struct ZydisDecodedInstructionRawXop_ - { - /** - * Extension of the `ModRM.reg` field (inverted). - */ - ZyanU8 R; - /** - * Extension of the `SIB.index` field (inverted). - */ - ZyanU8 X; - /** - * Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted). - */ - ZyanU8 B; - /** - * Opcode-map specifier. - */ - ZyanU8 m_mmmm; - /** - * 64-bit operand-size promotion or opcode-extension. - */ - ZyanU8 W; - /** - * `NDS`/`NDD` (non-destructive-source/destination) register - * specifier (inverted). - */ - ZyanU8 vvvv; - /** - * Vector-length specifier. - */ - ZyanU8 L; - /** - * Compressed legacy prefix. - */ - ZyanU8 pp; - /** - * The offset of the first xop byte, relative to the beginning of - * the instruction, in bytes. - */ - ZyanU8 offset; - } xop; - /** - * Detailed info about the `VEX` prefix. - */ - struct ZydisDecodedInstructionRawVex_ - { - /** - * Extension of the `ModRM.reg` field (inverted). - */ - ZyanU8 R; - /** - * Extension of the `SIB.index` field (inverted). - */ - ZyanU8 X; - /** - * Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted). - */ - ZyanU8 B; - /** - * Opcode-map specifier. - */ - ZyanU8 m_mmmm; - /** - * 64-bit operand-size promotion or opcode-extension. - */ - ZyanU8 W; - /** - * `NDS`/`NDD` (non-destructive-source/destination) register specifier - * (inverted). - */ - ZyanU8 vvvv; - /** - * Vector-length specifier. - */ - ZyanU8 L; - /** - * Compressed legacy prefix. - */ - ZyanU8 pp; - /** - * The offset of the first `VEX` byte, relative to the beginning of the instruction, in - * bytes. - */ - ZyanU8 offset; - /** - * The size of the `VEX` prefix, in bytes. - */ - ZyanU8 size; - } vex; - /** - * Detailed info about the `EVEX` prefix. - */ - struct ZydisDecodedInstructionRawEvex_ - { - /** - * Extension of the `ModRM.reg` field (inverted). - */ - ZyanU8 R; - /** - * Extension of the `SIB.index/vidx` field (inverted). - */ - ZyanU8 X; - /** - * Extension of the `ModRM.rm` or `SIB.base` field (inverted). - */ - ZyanU8 B; - /** - * High-16 register specifier modifier (inverted). - */ - ZyanU8 R2; - /** - * Opcode-map specifier. - */ - ZyanU8 mmm; - /** - * 64-bit operand-size promotion or opcode-extension. - */ - ZyanU8 W; - /** - * `NDS`/`NDD` (non-destructive-source/destination) register specifier - * (inverted). - */ - ZyanU8 vvvv; - /** - * Compressed legacy prefix. - */ - ZyanU8 pp; - /** - * Zeroing/Merging. - */ - ZyanU8 z; - /** - * Vector-length specifier or rounding-control (most significant bit). - */ - ZyanU8 L2; - /** - * Vector-length specifier or rounding-control (least significant bit). - */ - ZyanU8 L; - /** - * Broadcast/RC/SAE context. - */ - ZyanU8 b; - /** - * High-16 `NDS`/`VIDX` register specifier. - */ - ZyanU8 V2; - /** - * Embedded opmask register specifier. - */ - ZyanU8 aaa; - /** - * The offset of the first evex byte, relative to the beginning of the - * instruction, in bytes. - */ - ZyanU8 offset; - } evex; - /** - * Detailed info about the `MVEX` prefix. - */ - struct ZydisDecodedInstructionRawMvex_ - { - /** - * Extension of the `ModRM.reg` field (inverted). - */ - ZyanU8 R; - /** - * Extension of the `SIB.index/vidx` field (inverted). - */ - ZyanU8 X; - /** - * Extension of the `ModRM.rm` or `SIB.base` field (inverted). - */ - ZyanU8 B; - /** - * High-16 register specifier modifier (inverted). - */ - ZyanU8 R2; - /** - * Opcode-map specifier. - */ - ZyanU8 mmmm; - /** - * 64-bit operand-size promotion or opcode-extension. - */ - ZyanU8 W; - /** - * `NDS`/`NDD` (non-destructive-source/destination) register specifier - * (inverted). - */ - ZyanU8 vvvv; - /** - * Compressed legacy prefix. - */ - ZyanU8 pp; - /** - * Non-temporal/eviction hint. - */ - ZyanU8 E; - /** - * Swizzle/broadcast/up-convert/down-convert/static-rounding controls. - */ - ZyanU8 SSS; - /** - * High-16 `NDS`/`VIDX` register specifier. - */ - ZyanU8 V2; - /** - * Embedded opmask register specifier. - */ - ZyanU8 kkk; - /** - * The offset of the first mvex byte, relative to the beginning of the - * instruction, in bytes. - */ - ZyanU8 offset; - } mvex; + union { + /** + * Detailed info about the `XOP` prefix. + */ + struct ZydisDecodedInstructionRawXop_ { + /** + * Extension of the `ModRM.reg` field (inverted). + */ + ZyanU8 R; + /** + * Extension of the `SIB.index` field (inverted). + */ + ZyanU8 X; + /** + * Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted). + */ + ZyanU8 B; + /** + * Opcode-map specifier. + */ + ZyanU8 m_mmmm; + /** + * 64-bit operand-size promotion or opcode-extension. + */ + ZyanU8 W; + /** + * `NDS`/`NDD` (non-destructive-source/destination) register + * specifier (inverted). + */ + ZyanU8 vvvv; + /** + * Vector-length specifier. + */ + ZyanU8 L; + /** + * Compressed legacy prefix. + */ + ZyanU8 pp; + /** + * The offset of the first xop byte, relative to the beginning of + * the instruction, in bytes. + */ + ZyanU8 offset; + } xop; + /** + * Detailed info about the `VEX` prefix. + */ + struct ZydisDecodedInstructionRawVex_ { + /** + * Extension of the `ModRM.reg` field (inverted). + */ + ZyanU8 R; + /** + * Extension of the `SIB.index` field (inverted). + */ + ZyanU8 X; + /** + * Extension of the `ModRM.rm`, `SIB.base`, or `opcode.reg` field (inverted). + */ + ZyanU8 B; + /** + * Opcode-map specifier. + */ + ZyanU8 m_mmmm; + /** + * 64-bit operand-size promotion or opcode-extension. + */ + ZyanU8 W; + /** + * `NDS`/`NDD` (non-destructive-source/destination) register specifier + * (inverted). + */ + ZyanU8 vvvv; + /** + * Vector-length specifier. + */ + ZyanU8 L; + /** + * Compressed legacy prefix. + */ + ZyanU8 pp; + /** + * The offset of the first `VEX` byte, relative to the beginning of the instruction, in + * bytes. + */ + ZyanU8 offset; + /** + * The size of the `VEX` prefix, in bytes. + */ + ZyanU8 size; + } vex; + /** + * Detailed info about the `EVEX` prefix. + */ + struct ZydisDecodedInstructionRawEvex_ { + /** + * Extension of the `ModRM.reg` field (inverted). + */ + ZyanU8 R; + /** + * Extension of the `SIB.index/vidx` field (inverted). + */ + ZyanU8 X; + /** + * Extension of the `ModRM.rm` or `SIB.base` field (inverted). + */ + ZyanU8 B; + /** + * High-16 register specifier modifier (inverted). + */ + ZyanU8 R2; + /** + * Opcode-map specifier. + */ + ZyanU8 mmm; + /** + * 64-bit operand-size promotion or opcode-extension. + */ + ZyanU8 W; + /** + * `NDS`/`NDD` (non-destructive-source/destination) register specifier + * (inverted). + */ + ZyanU8 vvvv; + /** + * Compressed legacy prefix. + */ + ZyanU8 pp; + /** + * Zeroing/Merging. + */ + ZyanU8 z; + /** + * Vector-length specifier or rounding-control (most significant bit). + */ + ZyanU8 L2; + /** + * Vector-length specifier or rounding-control (least significant bit). + */ + ZyanU8 L; + /** + * Broadcast/RC/SAE context. + */ + ZyanU8 b; + /** + * High-16 `NDS`/`VIDX` register specifier. + */ + ZyanU8 V2; + /** + * Embedded opmask register specifier. + */ + ZyanU8 aaa; + /** + * The offset of the first evex byte, relative to the beginning of the + * instruction, in bytes. + */ + ZyanU8 offset; + } evex; + /** + * Detailed info about the `MVEX` prefix. + */ + struct ZydisDecodedInstructionRawMvex_ { + /** + * Extension of the `ModRM.reg` field (inverted). + */ + ZyanU8 R; + /** + * Extension of the `SIB.index/vidx` field (inverted). + */ + ZyanU8 X; + /** + * Extension of the `ModRM.rm` or `SIB.base` field (inverted). + */ + ZyanU8 B; + /** + * High-16 register specifier modifier (inverted). + */ + ZyanU8 R2; + /** + * Opcode-map specifier. + */ + ZyanU8 mmmm; + /** + * 64-bit operand-size promotion or opcode-extension. + */ + ZyanU8 W; + /** + * `NDS`/`NDD` (non-destructive-source/destination) register specifier + * (inverted). + */ + ZyanU8 vvvv; + /** + * Compressed legacy prefix. + */ + ZyanU8 pp; + /** + * Non-temporal/eviction hint. + */ + ZyanU8 E; + /** + * Swizzle/broadcast/up-convert/down-convert/static-rounding controls. + */ + ZyanU8 SSS; + /** + * High-16 `NDS`/`VIDX` register specifier. + */ + ZyanU8 V2; + /** + * Embedded opmask register specifier. + */ + ZyanU8 kkk; + /** + * The offset of the first mvex byte, relative to the beginning of the + * instruction, in bytes. + */ + ZyanU8 offset; + } mvex; + }; /** * Detailed info about the `ModRM` byte. */ diff --git a/tools/ZydisFuzzShared.c b/tools/ZydisFuzzShared.c index bcbb5c45..8a86b50a 100644 --- a/tools/ZydisFuzzShared.c +++ b/tools/ZydisFuzzShared.c @@ -153,14 +153,26 @@ void ZydisValidateEnumRanges(const ZydisDecodedInstruction* insn, ZYDIS_CHECK_ENUM(op->visibility, ZYDIS_OPERAND_VISIBILITY_MAX_VALUE); ZYDIS_CHECK_ENUM(op->encoding, ZYDIS_OPERAND_ENCODING_MAX_VALUE); ZYDIS_CHECK_ENUM(op->element_type, ZYDIS_ELEMENT_TYPE_MAX_VALUE); - ZYDIS_CHECK_ENUM(op->reg.value, ZYDIS_REGISTER_MAX_VALUE); - ZYDIS_CHECK_ENUM(op->mem.type, ZYDIS_MEMOP_TYPE_MAX_VALUE); - ZYDIS_CHECK_ENUM(op->mem.segment, ZYDIS_REGISTER_MAX_VALUE); - ZYDIS_CHECK_ENUM(op->mem.base, ZYDIS_REGISTER_MAX_VALUE); - ZYDIS_CHECK_ENUM(op->mem.index, ZYDIS_REGISTER_MAX_VALUE); - ZYDIS_CHECK_ENUM(op->mem.disp.has_displacement, ZYAN_TRUE); - ZYDIS_CHECK_ENUM(op->imm.is_signed, ZYAN_TRUE); - ZYDIS_CHECK_ENUM(op->imm.is_relative, ZYAN_TRUE); + + switch (op->type) + { + case ZYDIS_OPERAND_TYPE_REGISTER: + ZYDIS_CHECK_ENUM(op->reg.value, ZYDIS_REGISTER_MAX_VALUE); + break; + case ZYDIS_OPERAND_TYPE_MEMORY: + ZYDIS_CHECK_ENUM(op->mem.type, ZYDIS_MEMOP_TYPE_MAX_VALUE); + ZYDIS_CHECK_ENUM(op->mem.segment, ZYDIS_REGISTER_MAX_VALUE); + ZYDIS_CHECK_ENUM(op->mem.base, ZYDIS_REGISTER_MAX_VALUE); + ZYDIS_CHECK_ENUM(op->mem.index, ZYDIS_REGISTER_MAX_VALUE); + ZYDIS_CHECK_ENUM(op->mem.disp.has_displacement, ZYAN_TRUE); + break; + case ZYDIS_OPERAND_TYPE_IMMEDIATE: + ZYDIS_CHECK_ENUM(op->imm.is_signed, ZYAN_TRUE); + ZYDIS_CHECK_ENUM(op->imm.is_relative, ZYAN_TRUE); + break; + default: + break; + } } // AVX. From 54ffedeab2646848a5a6cf108b18b38456e050a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20H=C3=B6ner?= Date: Thu, 21 Apr 2022 11:19:43 +0200 Subject: [PATCH 2/3] Update Zycore submodule --- dependencies/zycore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/zycore b/dependencies/zycore index dd2211a0..c58d7fb5 160000 --- a/dependencies/zycore +++ b/dependencies/zycore @@ -1 +1 @@ -Subproject commit dd2211a023c2e6d383709fcb401a92943cb5e6b1 +Subproject commit c58d7fb524a7e0ef6cf30f594e4746441a4a2acf From 6474ac75da82288e3ee449fe78992182deff9c44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20H=C3=B6ner?= Date: Thu, 21 Apr 2022 11:15:02 +0200 Subject: [PATCH 3/3] Disable C11 feature warnings in Windows kernel example Because Windows still has trouble with compiling C11 code 11 years after the standard was released, we instead rely on the non-standard extension of anonymous unions being supported by MSVC since basically forever. Doing so produces a warning in kernel builds, so we need to shut that up. --- msvc/dependencies/zycore/Zycore.vcxproj | 4 ++++ msvc/examples/ZydisWinKernel.vcxproj | 4 ++++ msvc/zydis/Zydis.vcxproj | 6 +++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/msvc/dependencies/zycore/Zycore.vcxproj b/msvc/dependencies/zycore/Zycore.vcxproj index fc941189..3803b3fa 100644 --- a/msvc/dependencies/zycore/Zycore.vcxproj +++ b/msvc/dependencies/zycore/Zycore.vcxproj @@ -423,6 +423,7 @@ Disabled true true + 4201;4748;%(DisableSpecificWarnings) Native @@ -550,6 +551,7 @@ true true MaxSpeed + 4201;4603;4627;4986;4987;%(DisableSpecificWarnings) Native @@ -676,6 +678,7 @@ Disabled true true + 4201;4748;%(DisableSpecificWarnings) Native @@ -804,6 +807,7 @@ true true MaxSpeed + 4201;4603;4627;4986;4987;%(DisableSpecificWarnings) Native diff --git a/msvc/examples/ZydisWinKernel.vcxproj b/msvc/examples/ZydisWinKernel.vcxproj index f5ae1908..20669b87 100644 --- a/msvc/examples/ZydisWinKernel.vcxproj +++ b/msvc/examples/ZydisWinKernel.vcxproj @@ -130,6 +130,7 @@ true false false + 4201;4748;%(DisableSpecificWarnings) /NOVCFEATURE /NOCOFFGRPINFO %(AdditionalOptions) @@ -156,6 +157,7 @@ true false MaxSpeed + 4201;4603;4627;4986;4987;%(DisableSpecificWarnings) UseLinkTimeCodeGeneration @@ -180,6 +182,7 @@ true false false + 4201;4748;%(DisableSpecificWarnings) /NOVCFEATURE /NOCOFFGRPINFO %(AdditionalOptions) @@ -206,6 +209,7 @@ true false MaxSpeed + 4201;4603;4627;4986;4987;%(DisableSpecificWarnings) UseLinkTimeCodeGeneration diff --git a/msvc/zydis/Zydis.vcxproj b/msvc/zydis/Zydis.vcxproj index c3460895..06929d76 100644 --- a/msvc/zydis/Zydis.vcxproj +++ b/msvc/zydis/Zydis.vcxproj @@ -424,6 +424,7 @@ Disabled true true + 4201;4748;%(DisableSpecificWarnings) Native @@ -551,6 +552,7 @@ true true MaxSpeed + 4201;4603;4627;4986;4987;%(DisableSpecificWarnings) Native @@ -677,6 +679,7 @@ Disabled true true + 4201;4748;%(DisableSpecificWarnings) Native @@ -802,6 +805,7 @@ true true MaxSpeed + 4201;4603;4627;4986;4987;%(DisableSpecificWarnings) Native @@ -938,4 +942,4 @@ - + \ No newline at end of file