/src/zydis/tools/ZydisFuzzDecoder.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 fuzz target for decoder, formatter and various utility functions. |
31 | | */ |
32 | | |
33 | | #include "ZydisFuzzShared.h" |
34 | | |
35 | | /* ============================================================================================== */ |
36 | | /* Enums and types */ |
37 | | /* ============================================================================================== */ |
38 | | |
39 | | /** |
40 | | * Main fuzzer control block data structure. |
41 | | */ |
42 | | typedef struct ZydisFuzzControlBlock_ |
43 | | { |
44 | | ZydisMachineMode machine_mode; |
45 | | ZydisStackWidth stack_width; |
46 | | ZyanBool decoder_mode[ZYDIS_DECODER_MODE_MAX_VALUE + 1]; |
47 | | ZydisFormatterStyle formatter_style; |
48 | | ZyanU64 u64; // u64 used for all kind of non-overlapping purposes |
49 | | ZyanUPointer formatter_properties[ZYDIS_FORMATTER_PROP_MAX_VALUE + 1]; |
50 | | char string[16]; |
51 | | ZyanU16 formatter_max_len; |
52 | | } ZydisFuzzControlBlock; |
53 | | |
54 | | /* ============================================================================================== */ |
55 | | /* Fuzz target */ |
56 | | /* ============================================================================================== */ |
57 | | |
58 | | // We disable enum sanitization here because we actually want Zydis to be tested with |
59 | | // possibly invalid enum values in mind, thus need to be able to create them here. |
60 | | ZYAN_NO_SANITIZE("enum") |
61 | | int ZydisFuzzTarget(ZydisStreamRead read_fn, void* stream_ctx) |
62 | 1.73k | { |
63 | 1.73k | ZydisFuzzControlBlock control_block; |
64 | 1.73k | if (read_fn( |
65 | 1.73k | stream_ctx, (ZyanU8*)&control_block, sizeof(control_block)) != sizeof(control_block)) |
66 | 23 | { |
67 | 23 | ZYDIS_MAYBE_FPUTS("Not enough bytes to fuzz\n", ZYAN_STDERR); |
68 | 23 | return EXIT_SUCCESS; |
69 | 23 | } |
70 | 1.70k | control_block.string[ZYAN_ARRAY_LENGTH(control_block.string) - 1] = 0; |
71 | | |
72 | 1.70k | ZydisDecoder decoder; |
73 | 1.70k | if (!ZYAN_SUCCESS(ZydisDecoderInit(&decoder, control_block.machine_mode, |
74 | 1.70k | control_block.stack_width))) |
75 | 108 | { |
76 | 108 | ZYDIS_MAYBE_FPUTS("Failed to initialize decoder\n", ZYAN_STDERR); |
77 | 108 | return EXIT_FAILURE; |
78 | 108 | } |
79 | 20.7k | for (int mode = 0; mode <= ZYDIS_DECODER_MODE_MAX_VALUE; ++mode) |
80 | 19.1k | { |
81 | 19.1k | if (!ZYAN_SUCCESS(ZydisDecoderEnableMode(&decoder, (ZydisDecoderMode)mode, |
82 | 19.1k | control_block.decoder_mode[mode] ? 1 : 0))) |
83 | 0 | { |
84 | 0 | ZYDIS_MAYBE_FPUTS("Failed to adjust decoder-mode\n", ZYAN_STDERR); |
85 | 0 | return EXIT_FAILURE; |
86 | 0 | } |
87 | 19.1k | } |
88 | | |
89 | 1.59k | ZydisFormatter formatter; |
90 | 1.59k | if (!ZYAN_SUCCESS(ZydisFormatterInit(&formatter, control_block.formatter_style))) |
91 | 49 | { |
92 | 49 | ZYDIS_MAYBE_FPUTS("Failed to initialize formatter\n", ZYAN_STDERR); |
93 | 49 | return EXIT_FAILURE; |
94 | 49 | } |
95 | 25.8k | for (int prop = 0; prop <= ZYDIS_FORMATTER_PROP_MAX_VALUE; ++prop) |
96 | 25.8k | { |
97 | 25.8k | switch (prop) |
98 | 25.8k | { |
99 | 433 | case ZYDIS_FORMATTER_PROP_DEC_PREFIX: |
100 | 852 | case ZYDIS_FORMATTER_PROP_DEC_SUFFIX: |
101 | 1.26k | case ZYDIS_FORMATTER_PROP_HEX_PREFIX: |
102 | 1.67k | case ZYDIS_FORMATTER_PROP_HEX_SUFFIX: |
103 | 1.67k | control_block.formatter_properties[prop] = |
104 | 1.67k | control_block.formatter_properties[prop] ? (ZyanUPointer)&control_block.string : 0; |
105 | 1.67k | break; |
106 | 24.1k | default: |
107 | 24.1k | break; |
108 | 25.8k | } |
109 | 25.8k | if (!ZYAN_SUCCESS(ZydisFormatterSetProperty(&formatter, (ZydisFormatterProperty)prop, |
110 | 25.8k | control_block.formatter_properties[prop]))) |
111 | 1.55k | { |
112 | 1.55k | ZYDIS_MAYBE_FPUTS("Failed to set formatter-attribute\n", ZYAN_STDERR); |
113 | 1.55k | return EXIT_FAILURE; |
114 | 1.55k | } |
115 | 25.8k | } |
116 | | |
117 | 0 | ZyanU8 buffer[32]; |
118 | 0 | ZyanUSize input_len = read_fn(stream_ctx, buffer, sizeof(buffer)); |
119 | 0 | ZydisDecodedInstruction instruction; |
120 | 0 | ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]; |
121 | | |
122 | | // Fuzz decoder. |
123 | 0 | ZyanStatus status = ZydisDecoderDecodeFull(&decoder, buffer, input_len, &instruction, operands); |
124 | 0 | if (!ZYAN_SUCCESS(status)) |
125 | 0 | { |
126 | 0 | return EXIT_FAILURE; |
127 | 0 | } |
128 | | |
129 | 0 | ZydisValidateEnumRanges(&instruction, operands, instruction.operand_count); |
130 | | |
131 | | // Fuzz formatter. |
132 | 0 | char format_buffer[256]; |
133 | | // Allow the control block to artificially restrict the buffer size. |
134 | 0 | ZyanUSize output_len = ZYAN_MIN(sizeof(format_buffer), control_block.formatter_max_len); |
135 | 0 | ZydisFormatterFormatInstruction(&formatter, &instruction, operands, |
136 | 0 | instruction.operand_count_visible, format_buffer, output_len, control_block.u64, ZYAN_NULL); |
137 | | |
138 | | // Fuzz tokenizer. |
139 | 0 | const ZydisFormatterToken* token; |
140 | 0 | status = ZydisFormatterTokenizeInstruction(&formatter, &instruction, operands, |
141 | 0 | instruction.operand_count_visible, format_buffer, output_len, control_block.u64, &token, |
142 | 0 | ZYAN_NULL); |
143 | | |
144 | | // Walk tokens. |
145 | 0 | while (ZYAN_SUCCESS(status)) |
146 | 0 | { |
147 | 0 | ZydisTokenType type; |
148 | 0 | ZyanConstCharPointer value; |
149 | 0 | if (!ZYAN_SUCCESS(status = ZydisFormatterTokenGetValue(token, &type, &value))) |
150 | 0 | { |
151 | 0 | ZYDIS_MAYBE_FPUTS("Failed to get token value\n", ZYAN_STDERR); |
152 | 0 | break; |
153 | 0 | } |
154 | | |
155 | 0 | status = ZydisFormatterTokenNext(&token); |
156 | 0 | } |
157 | |
|
158 | 0 | if (instruction.operand_count_visible > 0) |
159 | 0 | { |
160 | | // Fuzz single operand formatting. We reuse rt-address for operand selection. |
161 | | // It's casted to u8 because modulo is way cheaper on that. |
162 | 0 | ZyanU8 op_idx = (ZyanU8)control_block.u64 % instruction.operand_count_visible; |
163 | 0 | const ZydisDecodedOperand* op = &operands[op_idx]; |
164 | |
|
165 | 0 | ZydisFormatterFormatOperand(&formatter, &instruction, op, format_buffer, output_len, |
166 | 0 | control_block.u64, ZYAN_NULL); |
167 | | |
168 | | // Fuzz single operand tokenization. |
169 | 0 | ZydisFormatterTokenizeOperand(&formatter, &instruction, op, format_buffer, output_len, |
170 | 0 | control_block.u64, &token, ZYAN_NULL); |
171 | | |
172 | | // Address translation helper. |
173 | 0 | ZyanU64 abs_addr; |
174 | 0 | ZydisCalcAbsoluteAddress(&instruction, op, control_block.u64, &abs_addr); |
175 | 0 | } |
176 | | |
177 | | // Mnemonic helpers. |
178 | 0 | ZydisMnemonicGetString((ZydisMnemonic)control_block.u64); |
179 | 0 | ZydisMnemonicGetStringWrapped((ZydisMnemonic)control_block.u64); |
180 | | |
181 | | // Instruction segment helper. |
182 | 0 | # ifndef ZYDIS_DISABLE_SEGMENT |
183 | 0 | ZydisInstructionSegments segments; |
184 | 0 | ZydisGetInstructionSegments(&instruction, &segments); |
185 | 0 | # endif |
186 | | |
187 | | // Feature enable check helper. |
188 | 0 | ZydisIsFeatureEnabled((ZydisFeature)control_block.u64); |
189 | | |
190 | | // Register helpers. |
191 | 0 | ZydisRegisterEncode((ZydisRegisterClass)(control_block.u64 >> 8), (ZyanU8)control_block.u64); |
192 | 0 | ZydisRegisterGetId((ZydisRegister)control_block.u64); |
193 | 0 | ZydisRegisterGetClass((ZydisRegister)control_block.u64); |
194 | 0 | ZydisRegisterGetWidth(control_block.machine_mode, (ZydisRegister)control_block.u64); |
195 | 0 | ZydisRegisterGetLargestEnclosing(control_block.machine_mode, (ZydisRegister)control_block.u64); |
196 | 0 | ZydisRegisterGetString((ZydisRegister)control_block.u64); |
197 | 0 | ZydisRegisterGetStringWrapped((ZydisRegister)control_block.u64); |
198 | 0 | ZydisRegisterClassGetWidth(control_block.machine_mode, (ZydisRegisterClass)control_block.u64); |
199 | |
|
200 | 0 | return EXIT_SUCCESS; |
201 | 0 | } |
202 | | |
203 | | /* ============================================================================================== */ |