Coverage Report

Created: 2025-07-11 06:19

/src/zydis/tools/ZydisFuzzShared.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************************************
2
3
  Zyan Disassembler Library (Zydis)
4
5
  Original Author : Joel Hoener
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 an entry point and common functions used by fuzz target projects. To create
31
 * a new fuzz target add this file to your project and implement `ZydisFuzzTarget` in a separate
32
 * compilation unit.
33
 */
34
35
#include "ZydisFuzzShared.h"
36
37
#ifdef ZYAN_WINDOWS
38
#   include <fcntl.h>
39
#   include <io.h>
40
#endif
41
42
#ifdef ZYAN_POSIX
43
#   include <unistd.h>
44
#endif
45
46
/* ============================================================================================== */
47
/* Stream reading abstraction                                                                     */
48
/* ============================================================================================== */
49
50
ZyanUSize ZydisStdinRead(void *ctx, ZyanU8* buf, ZyanUSize max_len)
51
0
{
52
0
    ZYAN_UNUSED(ctx);
53
0
#ifdef ZYAN_POSIX
54
    // `fread` does internal buffering that can result in different code paths to be taken every
55
    // time we call it. This is detrimental for fuzzing stability in persistent mode. Use direct
56
    // syscall when possible.
57
0
    return read(0, buf, max_len);
58
#else
59
    return fread(buf, 1, max_len, ZYAN_STDIN);
60
#endif
61
0
}
62
63
#ifdef ZYDIS_LIBFUZZER
64
typedef struct
65
{
66
    ZyanU8 *buf;
67
    ZyanISize buf_len;
68
    ZyanISize read_offs;
69
} ZydisLibFuzzerContext;
70
71
ZyanUSize ZydisLibFuzzerRead(void* ctx, ZyanU8* buf, ZyanUSize max_len)
72
16.6k
{
73
16.6k
    ZydisLibFuzzerContext* c = (ZydisLibFuzzerContext*)ctx;
74
16.6k
    ZyanUSize len = ZYAN_MIN((ZyanUSize)(c->buf_len - c->read_offs), max_len);
75
    // printf("buf_len: %ld, read_offs: %ld, len: %ld, max_len: %ld, ptr: %p\n",
76
    //     c->buf_len, c->read_offs, len, max_len, c->buf + c->read_offs);
77
16.6k
    if (!len)
78
373
    {
79
373
        return 0;
80
373
    }
81
16.3k
    ZYAN_MEMCPY(buf, c->buf + c->read_offs, len);
82
16.3k
    c->read_offs += len;
83
16.3k
    return len;
84
16.6k
}
85
#endif // ZYDIS_LIBFUZZER
86
87
/* ============================================================================================== */
88
/* Shared utility functions                                                                       */
89
/* ============================================================================================== */
90
91
#if !defined(ZYDIS_FUZZ_AFL_FAST) && !defined(ZYDIS_LIBFUZZER)
92
93
void ZydisPrintInstruction(const ZydisDecodedInstruction* instruction,
94
    const ZydisDecodedOperand* operands, ZyanU8 operand_count, const ZyanU8* instruction_bytes)
95
{
96
    switch (instruction->machine_mode)
97
    {
98
    case ZYDIS_MACHINE_MODE_LONG_64:
99
        printf("-64 ");
100
        break;
101
    case ZYDIS_MACHINE_MODE_LONG_COMPAT_32:
102
    case ZYDIS_MACHINE_MODE_LEGACY_32:
103
        printf("-32 ");
104
        break;
105
    case ZYDIS_MACHINE_MODE_LONG_COMPAT_16:
106
    case ZYDIS_MACHINE_MODE_LEGACY_16:
107
    case ZYDIS_MACHINE_MODE_REAL_16:
108
        printf("-16 ");
109
        break;
110
    default:
111
        ZYAN_UNREACHABLE;
112
    }
113
    printf("-%u ", instruction->stack_width);
114
115
    for (ZyanU8 i = 0; i < instruction->length; ++i)
116
    {
117
        printf("%02X", instruction_bytes[i]);
118
    }
119
120
    ZydisFormatter formatter;
121
    if (!ZYAN_SUCCESS(ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL)) ||
122
        !ZYAN_SUCCESS(ZydisFormatterSetProperty(&formatter, ZYDIS_FORMATTER_PROP_FORCE_SEGMENT,
123
            ZYAN_TRUE)) ||
124
        !ZYAN_SUCCESS(ZydisFormatterSetProperty(&formatter, ZYDIS_FORMATTER_PROP_FORCE_SIZE,
125
            ZYAN_TRUE)))
126
    {
127
        fputs("Failed to initialize instruction formatter\n", ZYAN_STDERR);
128
        abort();
129
    }
130
131
    char buffer[256];
132
    ZydisFormatterFormatInstruction(&formatter, instruction, operands, operand_count, buffer,
133
        sizeof(buffer), 0, ZYAN_NULL);
134
    printf(" %s\n", buffer);
135
}
136
137
#endif
138
139
void ZydisValidateImmediateSize(ZyanU64 value) 
140
9.33k
{
141
9.33k
    if ((value != 0) &&
142
9.33k
        (value != 8) &&
143
9.33k
        (value != 16) &&
144
9.33k
        (value != 32) &&
145
9.33k
        (value != 64)) 
146
0
    {
147
0
        fprintf(stderr, "Value 0x%016" PRIX64 " does not match any of the expected "
148
0
            "values (0, 8, 16, 32, 64).\n", value);
149
0
        abort();
150
0
    }
151
9.33k
}
152
153
// NOTE: This function doesn't validate flag values, yet.
154
void ZydisValidateEnumRanges(const ZydisDecodedInstruction* insn,
155
    const ZydisDecodedOperand* operands, ZyanU8 operand_count)
156
10.0k
{
157
10.0k
#   define ZYDIS_CHECK_ENUM(value, max)                                                            \
158
538k
    if ((ZyanU64)(value) > (ZyanU64)(max))                                                         \
159
538k
    {                                                                                              \
160
0
        fprintf(stderr, "Value " #value " = 0x%016" PRIX64 " is above expected max " #max          \
161
0
            " = 0x%016" PRIX64 "\n", (ZyanU64)(value), (ZyanU64)(max));                            \
162
0
        abort();                                                                                   \
163
0
    }
164
10.0k
#   define ZYDIS_CHECK_MAX ZYDIS_CHECK_ENUM
165
166
10.0k
    ZYDIS_CHECK_ENUM(insn->length, ZYDIS_MAX_INSTRUCTION_LENGTH);
167
168
10.0k
    ZYDIS_CHECK_ENUM(insn->machine_mode, ZYDIS_MACHINE_MODE_MAX_VALUE);
169
10.0k
    ZYDIS_CHECK_ENUM(insn->mnemonic, ZYDIS_MNEMONIC_MAX_VALUE);
170
10.0k
    ZYDIS_CHECK_ENUM(insn->encoding, ZYDIS_INSTRUCTION_ENCODING_MAX_VALUE);
171
10.0k
    ZYDIS_CHECK_ENUM(insn->opcode_map, ZYDIS_OPCODE_MAP_MAX_VALUE);
172
10.0k
    ZYDIS_CHECK_ENUM(insn->opcode_map, ZYDIS_OPCODE_MAP_MAX_VALUE);
173
174
    // Operands.
175
33.4k
    for (ZyanU32 i = 0; i < operand_count; ++i)
176
23.3k
    {
177
23.3k
        const ZydisDecodedOperand* op = &operands[i];
178
23.3k
        ZYDIS_CHECK_ENUM(op->type, ZYDIS_OPERAND_TYPE_MAX_VALUE);
179
23.3k
        ZYDIS_CHECK_ENUM(op->visibility, ZYDIS_OPERAND_VISIBILITY_MAX_VALUE);
180
23.3k
        ZYDIS_CHECK_ENUM(op->encoding, ZYDIS_OPERAND_ENCODING_MAX_VALUE);
181
23.3k
        ZYDIS_CHECK_ENUM(op->element_type, ZYDIS_ELEMENT_TYPE_MAX_VALUE);
182
183
23.3k
        switch (op->type)
184
23.3k
        {
185
13.8k
        case ZYDIS_OPERAND_TYPE_REGISTER:
186
13.8k
            ZYDIS_CHECK_ENUM(op->reg.value, ZYDIS_REGISTER_MAX_VALUE);
187
13.8k
            break;
188
5.88k
        case ZYDIS_OPERAND_TYPE_MEMORY:
189
5.88k
            ZYDIS_CHECK_ENUM(op->mem.type, ZYDIS_MEMOP_TYPE_MAX_VALUE);
190
5.88k
            ZYDIS_CHECK_ENUM(op->mem.segment, ZYDIS_REGISTER_MAX_VALUE);
191
5.88k
            ZYDIS_CHECK_ENUM(op->mem.base, ZYDIS_REGISTER_MAX_VALUE);
192
5.88k
            ZYDIS_CHECK_ENUM(op->mem.index, ZYDIS_REGISTER_MAX_VALUE);
193
5.88k
            ZydisValidateImmediateSize(op->mem.disp.size);
194
5.88k
            ZYDIS_CHECK_MAX(op->mem.disp.offset + (op->mem.disp.size / 8), insn->length);
195
5.88k
            break;
196
3.45k
        case ZYDIS_OPERAND_TYPE_IMMEDIATE:
197
3.45k
            ZYDIS_CHECK_ENUM(op->imm.is_signed, ZYAN_TRUE);
198
3.45k
            ZYDIS_CHECK_ENUM(op->imm.is_relative, ZYAN_TRUE);
199
3.45k
            ZydisValidateImmediateSize(op->imm.size);
200
3.45k
            ZYDIS_CHECK_MAX(op->imm.offset + (op->imm.size / 8), insn->length);
201
3.45k
            break;
202
232
        default:
203
232
            break;
204
23.3k
        }
205
23.3k
    }
206
207
    // AVX.
208
10.0k
    ZYDIS_CHECK_ENUM(insn->avx.mask.mode, ZYDIS_MASK_MODE_MAX_VALUE);
209
10.0k
    ZYDIS_CHECK_ENUM(insn->avx.mask.reg, ZYDIS_REGISTER_MAX_VALUE);
210
10.0k
    ZYDIS_CHECK_ENUM(insn->avx.broadcast.is_static, ZYAN_TRUE);
211
10.0k
    ZYDIS_CHECK_ENUM(insn->avx.broadcast.mode, ZYDIS_BROADCAST_MODE_MAX_VALUE);
212
10.0k
    ZYDIS_CHECK_ENUM(insn->avx.rounding.mode, ZYDIS_ROUNDING_MODE_MAX_VALUE);
213
10.0k
    ZYDIS_CHECK_ENUM(insn->avx.swizzle.mode, ZYDIS_SWIZZLE_MODE_MAX_VALUE);
214
10.0k
    ZYDIS_CHECK_ENUM(insn->avx.conversion.mode, ZYDIS_CONVERSION_MODE_MAX_VALUE);
215
10.0k
    ZYDIS_CHECK_ENUM(insn->avx.has_sae, ZYAN_TRUE);
216
10.0k
    ZYDIS_CHECK_ENUM(insn->avx.has_eviction_hint, ZYAN_TRUE);
217
218
    // Meta.
219
10.0k
    ZYDIS_CHECK_ENUM(insn->meta.category, ZYDIS_CATEGORY_MAX_VALUE);
220
10.0k
    ZYDIS_CHECK_ENUM(insn->meta.isa_set, ZYDIS_ISA_SET_MAX_VALUE);
221
10.0k
    ZYDIS_CHECK_ENUM(insn->meta.isa_ext, ZYDIS_ISA_SET_MAX_VALUE);
222
10.0k
    ZYDIS_CHECK_ENUM(insn->meta.branch_type, ZYDIS_BRANCH_TYPE_MAX_VALUE);
223
10.0k
    ZYDIS_CHECK_ENUM(insn->meta.exception_class, ZYDIS_EXCEPTION_CLASS_MAX_VALUE);
224
225
    // Raw.
226
160k
    for (ZyanU32 i = 0; i < ZYAN_ARRAY_LENGTH(insn->raw.prefixes); ++i)
227
150k
    {
228
150k
        ZYDIS_CHECK_ENUM(insn->raw.prefixes[i].type, ZYDIS_PREFIX_TYPE_MAX_VALUE);
229
150k
    }
230
30.1k
    for (ZyanU32 i = 0; i < ZYAN_ARRAY_LENGTH(insn->raw.imm); ++i)
231
20.0k
    {
232
20.0k
        ZYDIS_CHECK_ENUM(insn->raw.imm[i].is_signed, ZYAN_TRUE);
233
20.0k
        ZYDIS_CHECK_ENUM(insn->raw.imm[i].is_relative, ZYAN_TRUE);
234
20.0k
    }
235
236
10.0k
#   undef ZYDIS_CHECK_ENUM
237
10.0k
#   undef ZYDIS_CHECK_MAX
238
10.0k
}
239
240
void ZydisValidateInstructionIdentity(const ZydisDecodedInstruction* insn1,
241
    const ZydisDecodedOperand* operands1, const ZydisDecodedInstruction* insn2,
242
    const ZydisDecodedOperand* operands2)
243
3.59k
{
244
    // TODO: Probably a good idea to input validate operand_counts to this function
245
    // TODO: I don't like accessing buffers without having their actual sizes available...
246
247
    // Special case, `xchg rAX, rAX` is an alias for `NOP` except `xchg eax, eax` in 64-bit mode
248
3.59k
    if ((insn1->mnemonic == ZYDIS_MNEMONIC_XCHG) &&
249
3.59k
        (insn1->operand_count == 2) &&
250
3.59k
        (operands1[0].type == ZYDIS_OPERAND_TYPE_REGISTER) &&
251
3.59k
        (operands1[1].type == ZYDIS_OPERAND_TYPE_REGISTER) &&
252
3.59k
        (operands1[0].reg.value == operands1[1].reg.value) &&
253
3.59k
        (insn2->mnemonic == ZYDIS_MNEMONIC_NOP))
254
4
    {
255
4
        switch (operands1[0].reg.value)
256
4
        {
257
1
        case ZYDIS_REGISTER_AX:
258
2
        case ZYDIS_REGISTER_RAX:
259
2
            return;
260
2
        case ZYDIS_REGISTER_EAX:
261
2
            if (insn1->machine_mode != ZYDIS_MACHINE_MODE_LONG_64)
262
2
                return;
263
0
            break;
264
0
        default:
265
0
            break;
266
4
        }
267
4
    }
268
269
3.58k
    ZydisSwizzleMode swizzle1 = insn1->avx.swizzle.mode == ZYDIS_SWIZZLE_MODE_DCBA ?
270
3.58k
        ZYDIS_SWIZZLE_MODE_INVALID : insn1->avx.swizzle.mode;
271
3.58k
    ZydisSwizzleMode swizzle2 = insn2->avx.swizzle.mode == ZYDIS_SWIZZLE_MODE_DCBA ?
272
3.58k
        ZYDIS_SWIZZLE_MODE_INVALID : insn2->avx.swizzle.mode;
273
3.58k
    if ((insn1->machine_mode != insn2->machine_mode) ||
274
3.58k
        (insn1->mnemonic != insn2->mnemonic) ||
275
3.58k
        (insn1->stack_width != insn2->stack_width) ||
276
3.58k
        (insn1->operand_count != insn2->operand_count) ||
277
3.58k
        (insn1->avx.mask.mode != insn2->avx.mask.mode) ||
278
3.58k
        (insn1->avx.broadcast.is_static != insn2->avx.broadcast.is_static) ||
279
3.58k
        (insn1->avx.broadcast.mode != insn2->avx.broadcast.mode) ||
280
3.58k
        (insn1->avx.conversion.mode != insn2->avx.conversion.mode) ||
281
3.58k
        (insn1->avx.rounding.mode != insn2->avx.rounding.mode) ||
282
3.58k
        (insn1->avx.has_sae != insn2->avx.has_sae) ||
283
3.58k
        (insn1->avx.has_eviction_hint != insn2->avx.has_eviction_hint) ||
284
3.58k
        (swizzle1 != swizzle2))
285
0
    {
286
0
        fputs("Basic instruction attributes mismatch\n", ZYAN_STDERR);
287
0
        abort();
288
0
    }
289
290
13.2k
    for (ZyanU8 i = 0; i < insn1->operand_count; ++i)
291
9.65k
    {
292
9.65k
        const ZydisDecodedOperand *op1 = &operands1[i];
293
9.65k
        const ZydisDecodedOperand *op2 = &operands2[i];
294
9.65k
        if ((op1->type != op2->type) ||
295
9.65k
            (op1->size != op2->size && op1->type != ZYDIS_OPERAND_TYPE_IMMEDIATE))
296
0
        {
297
0
            fprintf(ZYAN_STDERR, "Mismatch for operand %u\n", i);
298
0
            abort();
299
0
        }
300
9.65k
        switch (op1->type)
301
9.65k
        {
302
5.97k
        case ZYDIS_OPERAND_TYPE_REGISTER:
303
5.97k
            if (op1->reg.value != op2->reg.value)
304
0
            {
305
0
                fprintf(ZYAN_STDERR, "Mismatch for register operand %u\n", i);
306
0
                abort();
307
0
            }
308
5.97k
            break;
309
5.97k
        case ZYDIS_OPERAND_TYPE_MEMORY:
310
2.30k
        {
311
            // Usually this check is done after verifying instruction identity but in this case
312
            // we have to fail early
313
2.30k
            if (insn1->length < insn2->length)
314
0
            {
315
0
                fputs("Suboptimal output size detected\n", ZYAN_STDERR);
316
0
                abort();
317
0
            }
318
2.30k
            ZyanU64 addr1, addr2;
319
2.30k
            ZyanStatus status1 = ZydisCalcAbsoluteAddress(insn1, op1, 0, &addr1);
320
2.30k
            ZyanStatus status2 = ZydisCalcAbsoluteAddress(insn2, op2,
321
2.30k
                insn1->length - insn2->length, &addr2);
322
2.30k
            ZyanBool addresses_match = ZYAN_FALSE;
323
2.30k
            if (ZYAN_SUCCESS(status1) && ZYAN_SUCCESS(status2))
324
1.24k
            {
325
1.24k
                if (addr1 != addr2)
326
0
                {
327
0
                    fprintf(ZYAN_STDERR, "Mismatch for memory operand %u (absolute address)\n", i);
328
0
                    abort();
329
0
                }
330
1.24k
                addresses_match = ZYAN_TRUE;
331
1.24k
            }
332
2.30k
            if ((op1->mem.type != op2->mem.type) ||
333
2.30k
                (op1->mem.segment != op2->mem.segment) ||
334
2.30k
                (op1->mem.base != op2->mem.base) ||
335
2.30k
                (op1->mem.index != op2->mem.index) ||
336
2.30k
                ((op1->mem.scale != op2->mem.scale) && (op1->mem.type != ZYDIS_MEMOP_TYPE_MIB)) ||
337
2.30k
                ((op1->mem.disp.value != op2->mem.disp.value) && !addresses_match))
338
0
            {
339
0
                fprintf(ZYAN_STDERR, "Mismatch for memory operand %u\n", i);
340
0
                abort();
341
0
            }
342
2.30k
            break;
343
2.30k
        }
344
2.30k
        case ZYDIS_OPERAND_TYPE_POINTER:
345
96
            if ((op1->ptr.segment != op2->ptr.segment) ||
346
96
                (op1->ptr.offset != op2->ptr.offset))
347
0
            {
348
0
                fprintf(ZYAN_STDERR, "Mismatch for pointer operand %u\n", i);
349
0
                abort();
350
0
            }
351
96
            break;
352
1.27k
        case ZYDIS_OPERAND_TYPE_IMMEDIATE:
353
1.27k
            if ((op1->imm.is_relative != op2->imm.is_relative) ||
354
1.27k
                (op1->imm.is_signed != op2->imm.is_signed) ||
355
1.27k
                (op1->imm.value.u != op2->imm.value.u))
356
0
            {
357
0
                ZyanBool acceptable_mismatch = ZYAN_FALSE;
358
0
                if ((insn1->meta.category == ZYDIS_CATEGORY_DATAXFER) ||
359
0
                    (insn1->meta.category == ZYDIS_CATEGORY_LOGICAL))
360
0
                {
361
0
                    const ZyanU16 size = ZYAN_MAX(op1->size, op2->size);
362
0
                    if (size < 64)
363
0
                    {
364
0
                        const ZyanU64 mask = (1ULL << size) - 1;
365
0
                        acceptable_mismatch =
366
0
                            (op1->imm.value.u & mask) == (op2->imm.value.u & mask);
367
0
                    }
368
0
                    else
369
0
                    {
370
0
                        acceptable_mismatch = op1->imm.value.u == op2->imm.value.u;
371
0
                    }
372
0
                }
373
0
                if (!acceptable_mismatch)
374
0
                {
375
0
                    fprintf(ZYAN_STDERR, "Mismatch for immediate operand %u\n", i);
376
0
                    abort();
377
0
                }
378
0
            }
379
1.27k
            break;
380
1.27k
        default:
381
0
            fprintf(ZYAN_STDERR, "Invalid operand type for operand %u\n", i);
382
0
            abort();
383
9.65k
        }
384
9.65k
    }
385
3.58k
}
386
387
#if !defined(ZYDIS_DISABLE_ENCODER)
388
389
static void ZydisReEncodeInstructionAbsolute(ZydisEncoderRequest* req,
390
    const ZydisDecodedInstruction* insn2, const ZydisDecodedOperand* insn2_operands,
391
    const ZyanU8* insn2_bytes)
392
3.59k
{
393
3.59k
    ZyanU64 runtime_address;
394
3.59k
    switch (insn2->address_width)
395
3.59k
    {
396
687
    case 16:
397
687
        runtime_address = (ZyanU64)(ZyanU16)ZYAN_INT16_MIN;
398
687
        break;
399
752
    case 32:
400
752
        runtime_address = (ZyanU64)(ZyanU32)ZYAN_INT32_MIN;
401
752
        break;
402
2.15k
    case 64:
403
2.15k
        runtime_address = (ZyanU64)ZYAN_INT64_MIN;
404
2.15k
        break;
405
0
    default:
406
0
        ZYAN_UNREACHABLE;
407
3.59k
    }
408
3.59k
    if ((insn2->machine_mode != ZYDIS_MACHINE_MODE_LONG_64) && (insn2->operand_width == 16))
409
520
    {
410
520
        runtime_address = (ZyanU64)(ZyanU16)ZYAN_INT16_MIN;
411
520
    }
412
3.59k
    runtime_address -= insn2->length;
413
414
3.59k
    ZyanBool has_relative = ZYAN_FALSE;
415
10.7k
    for (ZyanU8 i = 0; i < req->operand_count; ++i)
416
7.16k
    {
417
7.16k
        const ZydisDecodedOperand *decoded_op = &insn2_operands[i];
418
7.16k
        ZydisEncoderOperand *op = &req->operands[i];
419
7.16k
        ZyanU64 *dst_address = ZYAN_NULL;
420
7.16k
        switch (op->type)
421
7.16k
        {
422
1.27k
        case ZYDIS_OPERAND_TYPE_IMMEDIATE:
423
1.27k
            if (decoded_op->imm.is_relative)
424
408
            {
425
408
                dst_address = &op->imm.u;
426
408
            }
427
1.27k
            break;
428
1.93k
        case ZYDIS_OPERAND_TYPE_MEMORY:
429
1.93k
            if ((decoded_op->mem.base == ZYDIS_REGISTER_EIP) ||
430
1.93k
                (decoded_op->mem.base == ZYDIS_REGISTER_RIP))
431
552
            {
432
552
                dst_address = (ZyanU64 *)&op->mem.displacement;
433
552
            }
434
1.93k
            break;
435
3.95k
        default:
436
3.95k
            break;
437
7.16k
        }
438
7.16k
        if (!dst_address)
439
6.20k
        {
440
6.20k
            continue;
441
6.20k
        }
442
960
        has_relative = ZYAN_TRUE;
443
960
        if (!ZYAN_SUCCESS(ZydisCalcAbsoluteAddress(insn2, decoded_op, runtime_address,
444
960
            dst_address)))
445
0
        {
446
0
            fputs("ZydisCalcAbsoluteAddress has failed\n", ZYAN_STDERR);
447
0
            abort();
448
0
        }
449
960
    }
450
3.59k
    if (!has_relative)
451
2.63k
    {
452
2.63k
        return;
453
2.63k
    }
454
455
960
    ZyanU8 insn1_bytes[ZYDIS_MAX_INSTRUCTION_LENGTH];
456
960
    ZyanUSize insn1_length = sizeof(insn1_bytes);
457
960
    ZyanStatus status = ZydisEncoderEncodeInstructionAbsolute(req, insn1_bytes, &insn1_length,
458
960
        runtime_address);
459
960
    if (!ZYAN_SUCCESS(status))
460
0
    {
461
0
        fputs("Failed to re-encode instruction (absolute)\n", ZYAN_STDERR);
462
0
        abort();
463
0
    }
464
960
    if (insn1_length != insn2->length || ZYAN_MEMCMP(insn1_bytes, insn2_bytes, insn2->length))
465
0
    {
466
0
        fputs("Instruction mismatch (absolute)\n", ZYAN_STDERR);
467
0
        abort();
468
0
    }
469
960
}
470
471
void ZydisReEncodeInstruction(const ZydisDecoder *decoder, const ZydisDecodedInstruction *insn1,
472
    const ZydisDecodedOperand* operands1, ZyanU8 operand_count, const ZyanU8 *insn1_bytes)
473
3.59k
{
474
3.59k
    ZydisPrintInstruction(insn1, operands1, operand_count, insn1_bytes);
475
3.59k
    ZydisValidateEnumRanges(insn1, operands1, operand_count);
476
477
3.59k
    ZYAN_ASSERT(operand_count >= insn1->operand_count_visible);
478
479
3.59k
    ZydisEncoderRequest request;
480
3.59k
    ZyanStatus status = ZydisEncoderDecodedInstructionToEncoderRequest(insn1, operands1,
481
3.59k
        insn1->operand_count_visible, &request);
482
3.59k
    if (!ZYAN_SUCCESS(status))
483
0
    {
484
0
        fputs("ZydisEncoderDecodedInstructionToEncoderRequest failed\n", ZYAN_STDERR);
485
0
        abort();
486
0
    }
487
488
3.59k
    ZyanU8 encoded_instruction[ZYDIS_MAX_INSTRUCTION_LENGTH];
489
3.59k
    ZyanUSize encoded_length = sizeof(encoded_instruction);
490
3.59k
    status = ZydisEncoderEncodeInstruction(&request, encoded_instruction, &encoded_length);
491
3.59k
    if (!ZYAN_SUCCESS(status))
492
0
    {
493
0
        fputs("Failed to re-encode instruction\n", ZYAN_STDERR);
494
0
        abort();
495
0
    }
496
497
3.59k
    ZydisDecodedInstruction insn2;
498
3.59k
    ZydisDecodedOperand operands2[ZYDIS_MAX_OPERAND_COUNT];
499
3.59k
    status = ZydisDecoderDecodeFull(decoder, encoded_instruction, encoded_length, &insn2,
500
3.59k
        operands2);
501
3.59k
    if (!ZYAN_SUCCESS(status))
502
0
    {
503
0
        fputs("Failed to decode re-encoded instruction\n", ZYAN_STDERR);
504
0
        abort();
505
0
    }
506
507
3.59k
    ZydisPrintInstruction(&insn2, operands2, insn2.operand_count_visible, encoded_instruction);
508
3.59k
    ZydisValidateEnumRanges(&insn2, operands2, insn2.operand_count_visible);
509
3.59k
    ZydisValidateInstructionIdentity(insn1, operands1, &insn2, operands2);
510
511
3.59k
    if (insn2.length > insn1->length)
512
0
    {
513
0
        fputs("Suboptimal output size detected\n", ZYAN_STDERR);
514
0
        abort();
515
0
    }
516
517
3.59k
    ZydisReEncodeInstructionAbsolute(&request, &insn2, operands2, encoded_instruction);
518
3.59k
}
519
520
#endif
521
522
/* ============================================================================================== */
523
/* Entry point                                                                                    */
524
/* ============================================================================================== */
525
526
int ZydisFuzzerInit(void)
527
6
{
528
6
    if (ZydisGetVersion() != ZYDIS_VERSION)
529
0
    {
530
0
        fputs("Invalid Zydis version\n", ZYAN_STDERR);
531
0
        return EXIT_FAILURE;
532
0
    }
533
534
#ifdef ZYAN_WINDOWS
535
    // The `stdin` pipe uses text-mode on Windows platforms by default. We need it to be opened in
536
    // binary mode
537
    (void)_setmode(_fileno(ZYAN_STDIN), _O_BINARY);
538
#endif
539
540
6
    return EXIT_SUCCESS;
541
6
}
542
543
#ifdef ZYDIS_LIBFUZZER
544
545
#ifdef __cplusplus
546
extern "C" {
547
#endif
548
549
int LLVMFuzzerInitialize(int *argc, char ***argv)
550
6
{
551
6
    ZYAN_UNUSED(argc);
552
6
    ZYAN_UNUSED(argv);
553
554
6
    return ZydisFuzzerInit();
555
6
}
556
557
int LLVMFuzzerTestOneInput(ZyanU8 *buf, ZyanUSize len)
558
10.4k
{
559
10.4k
    ZydisLibFuzzerContext ctx;
560
10.4k
    ctx.buf = buf;
561
10.4k
    ctx.buf_len = len;
562
10.4k
    ctx.read_offs = 0;
563
564
10.4k
    ZydisFuzzTarget(&ZydisLibFuzzerRead, &ctx);
565
10.4k
    return 0;
566
10.4k
}
567
568
#ifdef __cplusplus
569
} // extern "C"
570
#endif
571
572
#else // !ZYDIS_LIBFUZZER
573
574
int main(void)
575
{
576
    if (ZydisFuzzerInit() != EXIT_SUCCESS)
577
    {
578
        return EXIT_FAILURE;
579
    }
580
581
#ifdef ZYDIS_FUZZ_AFL_FAST
582
    while (__AFL_LOOP(1000))
583
    {
584
        ZydisFuzzTarget(&ZydisStdinRead, ZYAN_NULL);
585
    }
586
    return EXIT_SUCCESS;
587
#else
588
    return ZydisFuzzTarget(&ZydisStdinRead, ZYAN_NULL);
589
#endif
590
}
591
592
#endif // ZYDIS_LIBFUZZER
593
594
/* ============================================================================================== */