/src/zydis/tools/ZydisFuzzDecoder.c
Line | Count | Source |
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 | 4.92k | { |
63 | 4.92k | ZydisFuzzControlBlock control_block; |
64 | 4.92k | if (read_fn( |
65 | 4.92k | 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 | 4.90k | control_block.string[ZYAN_ARRAY_LENGTH(control_block.string) - 1] = 0; |
71 | | |
72 | 4.90k | ZydisDecoder decoder; |
73 | 4.90k | if (!ZYAN_SUCCESS(ZydisDecoderInit(&decoder, control_block.machine_mode, |
74 | 4.90k | control_block.stack_width))) |
75 | 106 | { |
76 | 106 | ZYDIS_MAYBE_FPUTS("Failed to initialize decoder\n", ZYAN_STDERR); |
77 | 106 | return EXIT_FAILURE; |
78 | 106 | } |
79 | 62.3k | for (int mode = 0; mode <= ZYDIS_DECODER_MODE_MAX_VALUE; ++mode) |
80 | 57.5k | { |
81 | 57.5k | if (!ZYAN_SUCCESS(ZydisDecoderEnableMode(&decoder, (ZydisDecoderMode)mode, |
82 | 57.5k | 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 | 57.5k | } |
88 | | |
89 | 4.79k | ZyanU8 buffer[32]; |
90 | 4.79k | ZyanUSize input_len = read_fn(stream_ctx, buffer, sizeof(buffer)); |
91 | 4.79k | ZydisDecodedInstruction instruction; |
92 | 4.79k | ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]; |
93 | | |
94 | | // Fuzz decoder. |
95 | 4.79k | ZyanStatus status = ZydisDecoderDecodeFull(&decoder, buffer, input_len, &instruction, operands); |
96 | 4.79k | if (!ZYAN_SUCCESS(status)) |
97 | 335 | { |
98 | 335 | return EXIT_FAILURE; |
99 | 335 | } |
100 | | |
101 | 4.46k | ZydisValidateEnumRanges(&instruction, operands, instruction.operand_count); |
102 | | |
103 | | // Fuzz formatter. |
104 | 4.46k | ZydisFormatter formatter; |
105 | 4.46k | if (!ZYAN_SUCCESS(ZydisFormatterInit(&formatter, control_block.formatter_style))) |
106 | 64 | { |
107 | 64 | ZYDIS_MAYBE_FPUTS("Failed to initialize formatter\n", ZYAN_STDERR); |
108 | 64 | return EXIT_FAILURE; |
109 | 64 | } |
110 | 113k | for (int prop = 0; prop <= ZYDIS_FORMATTER_PROP_MAX_VALUE; ++prop) |
111 | 110k | { |
112 | 110k | switch (prop) |
113 | 110k | { |
114 | 3.22k | case ZYDIS_FORMATTER_PROP_DEC_PREFIX: |
115 | 6.42k | case ZYDIS_FORMATTER_PROP_DEC_SUFFIX: |
116 | 9.62k | case ZYDIS_FORMATTER_PROP_HEX_PREFIX: |
117 | 12.8k | case ZYDIS_FORMATTER_PROP_HEX_SUFFIX: |
118 | 12.8k | control_block.formatter_properties[prop] = |
119 | 12.8k | control_block.formatter_properties[prop] ? (ZyanUPointer)&control_block.string : 0; |
120 | 12.8k | break; |
121 | | // TODO: Remove cases below after implementing APX properties |
122 | 3.19k | case ZYDIS_FORMATTER_PROP_DECO_APX_NF_USE_SUFFIX: |
123 | 6.39k | case ZYDIS_FORMATTER_PROP_DECO_APX_DFV_USE_IMMEDIATE: |
124 | 6.39k | continue; |
125 | 90.8k | default: |
126 | 90.8k | break; |
127 | 110k | } |
128 | 103k | if (!ZYAN_SUCCESS(ZydisFormatterSetProperty(&formatter, (ZydisFormatterProperty)prop, |
129 | 103k | control_block.formatter_properties[prop]))) |
130 | 1.19k | { |
131 | 1.19k | ZYDIS_MAYBE_FPUTS("Failed to set formatter-attribute\n", ZYAN_STDERR); |
132 | 1.19k | return EXIT_FAILURE; |
133 | 1.19k | } |
134 | 103k | } |
135 | | |
136 | 3.19k | char format_buffer[256]; |
137 | | // Allow the control block to artificially restrict the buffer size. |
138 | 3.19k | ZyanUSize output_len = ZYAN_MIN(sizeof(format_buffer), control_block.formatter_max_len); |
139 | 3.19k | ZydisFormatterFormatInstruction(&formatter, &instruction, operands, |
140 | 3.19k | instruction.operand_count_visible, format_buffer, output_len, control_block.u64, ZYAN_NULL); |
141 | | |
142 | | // Fuzz tokenizer. |
143 | 3.19k | const ZydisFormatterToken* token; |
144 | 3.19k | status = ZydisFormatterTokenizeInstruction(&formatter, &instruction, operands, |
145 | 3.19k | instruction.operand_count_visible, format_buffer, output_len, control_block.u64, &token, |
146 | 3.19k | ZYAN_NULL); |
147 | | |
148 | | // Walk tokens. |
149 | 16.3k | while (ZYAN_SUCCESS(status)) |
150 | 13.1k | { |
151 | 13.1k | ZydisTokenType type; |
152 | 13.1k | ZyanConstCharPointer value; |
153 | 13.1k | if (!ZYAN_SUCCESS(status = ZydisFormatterTokenGetValue(token, &type, &value))) |
154 | 0 | { |
155 | 0 | ZYDIS_MAYBE_FPUTS("Failed to get token value\n", ZYAN_STDERR); |
156 | 0 | break; |
157 | 0 | } |
158 | | |
159 | 13.1k | status = ZydisFormatterTokenNext(&token); |
160 | 13.1k | } |
161 | | |
162 | 3.19k | if (instruction.operand_count_visible > 0) |
163 | 2.73k | { |
164 | | // Fuzz single operand formatting. We reuse rt-address for operand selection. |
165 | | // It's casted to u8 because modulo is way cheaper on that. |
166 | 2.73k | ZyanU8 op_idx = (ZyanU8)control_block.u64 % instruction.operand_count_visible; |
167 | 2.73k | const ZydisDecodedOperand* op = &operands[op_idx]; |
168 | | |
169 | 2.73k | ZydisFormatterFormatOperand(&formatter, &instruction, op, format_buffer, output_len, |
170 | 2.73k | control_block.u64, ZYAN_NULL); |
171 | | |
172 | | // Fuzz single operand tokenization. |
173 | 2.73k | ZydisFormatterTokenizeOperand(&formatter, &instruction, op, format_buffer, output_len, |
174 | 2.73k | control_block.u64, &token, ZYAN_NULL); |
175 | | |
176 | | // Address translation helper. |
177 | 2.73k | ZyanU64 abs_addr; |
178 | 2.73k | ZydisCalcAbsoluteAddress(&instruction, op, control_block.u64, &abs_addr); |
179 | 2.73k | } |
180 | | |
181 | | // Mnemonic helpers. |
182 | 3.19k | ZydisMnemonicGetString((ZydisMnemonic)control_block.u64); |
183 | 3.19k | ZydisMnemonicGetStringWrapped((ZydisMnemonic)control_block.u64); |
184 | | |
185 | | // Instruction segment helper. |
186 | 3.19k | # ifndef ZYDIS_DISABLE_SEGMENT |
187 | 3.19k | ZydisInstructionSegments segments; |
188 | 3.19k | ZydisGetInstructionSegments(&instruction, &segments); |
189 | 3.19k | # endif |
190 | | |
191 | | // Feature enable check helper. |
192 | 3.19k | ZydisIsFeatureEnabled((ZydisFeature)control_block.u64); |
193 | | |
194 | | // Register helpers. |
195 | 3.19k | ZydisRegisterEncode((ZydisRegisterClass)(control_block.u64 >> 8), (ZyanU8)control_block.u64); |
196 | 3.19k | ZydisRegisterGetId((ZydisRegister)control_block.u64); |
197 | 3.19k | ZydisRegisterGetClass((ZydisRegister)control_block.u64); |
198 | 3.19k | ZydisRegisterGetWidth(control_block.machine_mode, (ZydisRegister)control_block.u64); |
199 | 3.19k | ZydisRegisterGetLargestEnclosing(control_block.machine_mode, (ZydisRegister)control_block.u64); |
200 | 3.19k | ZydisRegisterGetString((ZydisRegister)control_block.u64); |
201 | 3.19k | ZydisRegisterGetStringWrapped((ZydisRegister)control_block.u64); |
202 | 3.19k | ZydisRegisterClassGetWidth(control_block.machine_mode, (ZydisRegisterClass)control_block.u64); |
203 | | |
204 | | return EXIT_SUCCESS; |
205 | 4.39k | } |
206 | | |
207 | | /* ============================================================================================== */ |