ZydisFuzzEncoder.c
1 /*************************************************************************************************** 2 3 Zyan Disassembler Library (Zydis) 4 5 Original Author : Mappa 6 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in all 15 * copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 25 ***************************************************************************************************/ 26 27 /** 28 * @file 29 * 30 * This file implements fuzz target for encoder. 31 */ 32 33 #include "ZydisFuzzShared.h" 34 35 /* ============================================================================================== */ 36 /* Fuzz target */ 37 /* ============================================================================================== */ 38 39 // TODO: This could check `EVEX`/`MVEX` stuff as well 40 void ZydisCompareRequestToInstruction(const ZydisEncoderRequest *request, 41 const ZydisDecodedInstruction *insn, const ZydisDecodedOperand* operands, const ZyanU8 *insn_bytes) 42 { 43 // Special case, `xchg rAX, rAX` is an alias for `NOP` 44 if ((request->mnemonic == ZYDIS_MNEMONIC_XCHG) && 45 (request->operand_count == 2) && 46 (request->operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER) && 47 (request->operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER) && 48 (request->operands[0].reg.value == request->operands[1].reg.value) && 49 (insn->mnemonic == ZYDIS_MNEMONIC_NOP)) 50 { 51 switch (request->operands[0].reg.value) 52 { 53 case ZYDIS_REGISTER_AX: 54 case ZYDIS_REGISTER_EAX: 55 case ZYDIS_REGISTER_RAX: 56 return; 57 default: 58 break; 59 } 60 } 61 62 // Handle possible KNC overlap 63 ZydisDecodedInstruction knc_insn; 64 ZydisDecodedOperand knc_operands[ZYDIS_MAX_OPERAND_COUNT]; 65 if (request->mnemonic != insn->mnemonic) 66 { 67 ZydisDecoder decoder; 68 ZydisStackWidth stack_width = (ZydisStackWidth)(insn->stack_width >> 5); 69 if (!ZYAN_SUCCESS(ZydisDecoderInit(&decoder, insn->machine_mode, stack_width))) 70 { 71 fputs("Failed to initialize decoder\n", ZYAN_STDERR); 72 abort(); 73 } 74 if (!ZYAN_SUCCESS(ZydisDecoderEnableMode(&decoder, ZYDIS_DECODER_MODE_KNC, ZYAN_TRUE))) 75 { 76 fputs("Failed to enable KNC mode\n", ZYAN_STDERR); 77 abort(); 78 } 79 if (!ZYAN_SUCCESS(ZydisDecoderDecodeFull(&decoder, insn_bytes, insn->length, &knc_insn, 80 knc_operands))) 81 { 82 fputs("Failed to decode instruction\n", ZYAN_STDERR); 83 abort(); 84 } 85 insn = &knc_insn; 86 operands = knc_operands; 87 } 88 89 ZyanBool prefixes_match = ((insn->attributes & request->prefixes) == request->prefixes); 90 if (!prefixes_match && 91 (request->machine_mode != ZYDIS_MACHINE_MODE_LONG_64) && 92 (request->prefixes & ZYDIS_ATTRIB_HAS_SEGMENT_DS)) 93 { 94 // Encoder allows specifying DS override even when it might be interpreted as NOTRACK 95 ZyanU64 acceptable_prefixes = (request->prefixes & (~ZYDIS_ATTRIB_HAS_SEGMENT_DS)) | 96 ZYDIS_ATTRIB_HAS_NOTRACK; 97 prefixes_match = ((insn->attributes & acceptable_prefixes) == acceptable_prefixes); 98 } 99 if ((request->machine_mode != insn->machine_mode) || 100 (request->mnemonic != insn->mnemonic) || 101 (request->operand_count != insn->operand_count_visible) || 102 !prefixes_match) 103 { 104 fputs("Basic instruction attributes mismatch\n", ZYAN_STDERR); 105 abort(); 106 } 107 108 for (ZyanU8 i = 0; i < insn->operand_count_visible; ++i) 109 { 110 const ZydisEncoderOperand *op1 = &request->operands[i]; 111 const ZydisDecodedOperand *op2 = &operands[i]; 112 if (op1->type != op2->type) 113 { 114 fprintf(ZYAN_STDERR, "Mismatch for operand %u\n", i); 115 abort(); 116 } 117 switch (op1->type) 118 { 119 case ZYDIS_OPERAND_TYPE_REGISTER: 120 if (op1->reg.value != op2->reg.value) 121 { 122 fprintf(ZYAN_STDERR, "Mismatch for register operand %u\n", i); 123 abort(); 124 } 125 break; 126 case ZYDIS_OPERAND_TYPE_MEMORY: 127 if ((op1->mem.base != op2->mem.base) || 128 (op1->mem.index != op2->mem.index) || 129 (op1->mem.scale != op2->mem.scale && op2->mem.type != ZYDIS_MEMOP_TYPE_MIB) || 130 (op1->mem.displacement != op2->mem.disp.value)) 131 { 132 ZyanBool acceptable_mismatch = ZYAN_FALSE; 133 if (op1->mem.displacement != op2->mem.disp.value) 134 { 135 if ((op2->mem.disp.has_displacement) && 136 (op1->mem.index == ZYDIS_REGISTER_NONE) && 137 ((op1->mem.base == ZYDIS_REGISTER_NONE) || 138 (op1->mem.base == ZYDIS_REGISTER_EIP) || 139 (op1->mem.base == ZYDIS_REGISTER_RIP))) 140 { 141 ZyanU64 addr; 142 ZydisCalcAbsoluteAddress(insn, op2, 0, &addr); 143 acceptable_mismatch = ((ZyanU64)op1->mem.displacement == addr); 144 } 145 if ((insn->machine_mode == ZYDIS_MACHINE_MODE_REAL_16) || 146 (insn->machine_mode == ZYDIS_MACHINE_MODE_LEGACY_16) || 147 (insn->machine_mode == ZYDIS_MACHINE_MODE_LONG_COMPAT_16) || 148 (insn->stack_width == 16) || 149 (insn->address_width == 16)) 150 { 151 acceptable_mismatch = ((op1->mem.displacement & 0xFFFF) == 152 (op2->mem.disp.value & 0xFFFF)); 153 } 154 } 155 if (!acceptable_mismatch) 156 { 157 fprintf(ZYAN_STDERR, "Mismatch for memory operand %u\n", i); 158 abort(); 159 } 160 } 161 break; 162 case ZYDIS_OPERAND_TYPE_POINTER: 163 if ((op1->ptr.segment != op2->ptr.segment) || 164 (op1->ptr.offset != op2->ptr.offset)) 165 { 166 fprintf(ZYAN_STDERR, "Mismatch for pointer operand %u\n", i); 167 abort(); 168 } 169 break; 170 case ZYDIS_OPERAND_TYPE_IMMEDIATE: 171 if (op1->imm.u != op2->imm.value.u) 172 { 173 ZyanBool acceptable_mismatch = ZYAN_FALSE; 174 if ((insn->meta.category == ZYDIS_CATEGORY_DATAXFER) || 175 (insn->meta.category == ZYDIS_CATEGORY_LOGICAL)) 176 { 177 if (op2->size < 64) 178 { 179 ZyanU64 mask = (1ULL << op2->size) - 1; 180 acceptable_mismatch = 181 (op1->imm.u & mask) == (op2->imm.value.u & mask); 182 } 183 else 184 { 185 acceptable_mismatch = op1->imm.u == op2->imm.value.u; 186 } 187 } 188 if (!acceptable_mismatch) 189 { 190 fprintf(ZYAN_STDERR, "Mismatch for immediate operand %u\n", i); 191 abort(); 192 } 193 } 194 break; 195 default: 196 fprintf(ZYAN_STDERR, "Invalid operand type for operand %u\n", i); 197 abort(); 198 } 199 } 200 } 201 202 ZYAN_NO_SANITIZE("enum") 203 int ZydisFuzzTarget(ZydisStreamRead read_fn, void *stream_ctx) 204 { 205 ZydisEncoderRequest request; 206 if (read_fn(stream_ctx, (ZyanU8 *)&request, sizeof(request)) != sizeof(request)) 207 { 208 ZYDIS_MAYBE_FPUTS("Not enough bytes to fuzz\n", ZYAN_STDERR); 209 return EXIT_SUCCESS; 210 } 211 212 // Sanitization greatly improves coverage, without it most inputs will fail at basic checks 213 // inside `ZydisEncoderCheckRequestSanity` 214 request.operand_count %= ZYDIS_ENCODER_MAX_OPERANDS + 1; 215 ZYDIS_SANITIZE_MASK32(request.allowed_encodings, ZydisEncodableEncoding, 216 ZYDIS_ENCODABLE_ENCODING_MAX_VALUE); 217 ZYDIS_SANITIZE_MASK64(request.prefixes, ZydisInstructionAttributes, ZYDIS_ENCODABLE_PREFIXES); 218 ZYDIS_SANITIZE_ENUM(request.machine_mode, ZydisMachineMode, ZYDIS_MACHINE_MODE_MAX_VALUE); 219 ZYDIS_SANITIZE_ENUM(request.mnemonic, ZydisMnemonic, ZYDIS_MNEMONIC_MAX_VALUE); 220 ZYDIS_SANITIZE_ENUM(request.branch_type, ZydisBranchType, ZYDIS_BRANCH_TYPE_MAX_VALUE); 221 ZYDIS_SANITIZE_ENUM(request.branch_width, ZydisBranchWidth, ZYDIS_BRANCH_WIDTH_MAX_VALUE); 222 ZYDIS_SANITIZE_ENUM(request.address_size_hint, ZydisAddressSizeHint, 223 ZYDIS_ADDRESS_SIZE_HINT_MAX_VALUE); 224 ZYDIS_SANITIZE_ENUM(request.operand_size_hint, ZydisOperandSizeHint, 225 ZYDIS_OPERAND_SIZE_HINT_MAX_VALUE); 226 ZYDIS_SANITIZE_ENUM(request.evex.broadcast, ZydisBroadcastMode, ZYDIS_BROADCAST_MODE_MAX_VALUE); 227 ZYDIS_SANITIZE_ENUM(request.evex.rounding, ZydisRoundingMode, ZYDIS_ROUNDING_MODE_MAX_VALUE); 228 ZYDIS_SANITIZE_ENUM(request.mvex.broadcast, ZydisBroadcastMode, ZYDIS_BROADCAST_MODE_MAX_VALUE); 229 ZYDIS_SANITIZE_ENUM(request.mvex.conversion, ZydisConversionMode, 230 ZYDIS_CONVERSION_MODE_MAX_VALUE); 231 ZYDIS_SANITIZE_ENUM(request.mvex.rounding, ZydisRoundingMode, ZYDIS_ROUNDING_MODE_MAX_VALUE); 232 ZYDIS_SANITIZE_ENUM(request.mvex.swizzle, ZydisSwizzleMode, ZYDIS_SWIZZLE_MODE_MAX_VALUE); 233 for (ZyanU8 i = 0; i < request.operand_count; ++i) 234 { 235 ZydisEncoderOperand *op = &request.operands[i]; 236 op->type = (ZydisOperandType)(ZYDIS_OPERAND_TYPE_REGISTER + 237 ((ZyanUSize)op->type % ZYDIS_OPERAND_TYPE_MAX_VALUE)); 238 switch (op->type) 239 { 240 case ZYDIS_OPERAND_TYPE_REGISTER: 241 ZYDIS_SANITIZE_ENUM(op->reg.value, ZydisRegister, ZYDIS_REGISTER_MAX_VALUE); 242 break; 243 case ZYDIS_OPERAND_TYPE_MEMORY: 244 ZYDIS_SANITIZE_ENUM(op->mem.base, ZydisRegister, ZYDIS_REGISTER_MAX_VALUE); 245 ZYDIS_SANITIZE_ENUM(op->mem.index, ZydisRegister, ZYDIS_REGISTER_MAX_VALUE); 246 break; 247 case ZYDIS_OPERAND_TYPE_POINTER: 248 case ZYDIS_OPERAND_TYPE_IMMEDIATE: 249 break; 250 default: 251 ZYAN_UNREACHABLE; 252 } 253 } 254 255 ZyanU8 encoded_instruction[ZYDIS_MAX_INSTRUCTION_LENGTH]; 256 ZyanUSize encoded_length = sizeof(encoded_instruction); 257 ZyanStatus status = ZydisEncoderEncodeInstruction(&request, encoded_instruction, 258 &encoded_length); 259 if (!ZYAN_SUCCESS(status)) 260 { 261 return EXIT_SUCCESS; 262 } 263 264 ZydisStackWidth stack_width; 265 switch (request.machine_mode) 266 { 267 case ZYDIS_MACHINE_MODE_LONG_64: 268 stack_width = ZYDIS_STACK_WIDTH_64; 269 break; 270 case ZYDIS_MACHINE_MODE_LONG_COMPAT_32: 271 case ZYDIS_MACHINE_MODE_LEGACY_32: 272 stack_width = ZYDIS_STACK_WIDTH_32; 273 break; 274 case ZYDIS_MACHINE_MODE_LONG_COMPAT_16: 275 case ZYDIS_MACHINE_MODE_LEGACY_16: 276 case ZYDIS_MACHINE_MODE_REAL_16: 277 stack_width = ZYDIS_STACK_WIDTH_16; 278 break; 279 default: 280 ZYAN_UNREACHABLE; 281 } 282 283 ZydisDecoder decoder; 284 if (!ZYAN_SUCCESS(ZydisDecoderInit(&decoder, request.machine_mode, stack_width))) 285 { 286 fputs("Failed to initialize decoder\n", ZYAN_STDERR); 287 abort(); 288 } 289 290 ZydisDecodedInstruction insn1; 291 ZydisDecodedOperand operands1[ZYDIS_MAX_OPERAND_COUNT]; 292 status = ZydisDecoderDecodeFull(&decoder, encoded_instruction, encoded_length, &insn1, 293 operands1); 294 if (!ZYAN_SUCCESS(status)) 295 { 296 fputs("Failed to decode instruction\n", ZYAN_STDERR); 297 abort(); 298 } 299 300 ZydisCompareRequestToInstruction(&request, &insn1, operands1, encoded_instruction); 301 ZydisReEncodeInstruction(&decoder, &insn1, operands1, insn1.operand_count, 302 encoded_instruction); 303 304 return EXIT_SUCCESS; 305 } 306 307 /* ============================================================================================== */