/ externals / zydis / tools / ZydisFuzzEncoder.c
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  /* ============================================================================================== */