1 /*
2 * MZ header functions
3 *
4 * Copyright (C) 2011-2021, Joachim Metz <joachim.metz@gmail.com>
5 *
6 * Refer to AUTHORS for acknowledgements.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 #include <common.h>
23 #include <byte_stream.h>
24 #include <memory.h>
25 #include <types.h>
26
27 #include "libexe_libcerror.h"
28 #include "libexe_libcnotify.h"
29 #include "libexe_mz_header.h"
30
31 #include "exe_mz_header.h"
32
33 /* Creates a MZ header
34 * Make sure the value mz_header is referencing, is set to NULL
35 * Returns 1 if successful or -1 on error
36 */
libexe_mz_header_initialize(libexe_mz_header_t ** mz_header,libcerror_error_t ** error)37 int libexe_mz_header_initialize(
38 libexe_mz_header_t **mz_header,
39 libcerror_error_t **error )
40 {
41 static char *function = "libexe_mz_header_initialize";
42
43 if( mz_header == NULL )
44 {
45 libcerror_error_set(
46 error,
47 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
48 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
49 "%s: invalid MZ header.",
50 function );
51
52 return( -1 );
53 }
54 if( *mz_header != NULL )
55 {
56 libcerror_error_set(
57 error,
58 LIBCERROR_ERROR_DOMAIN_RUNTIME,
59 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
60 "%s: invalid MZ header value already set.",
61 function );
62
63 return( -1 );
64 }
65 *mz_header = memory_allocate_structure(
66 libexe_mz_header_t );
67
68 if( *mz_header == NULL )
69 {
70 libcerror_error_set(
71 error,
72 LIBCERROR_ERROR_DOMAIN_MEMORY,
73 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
74 "%s: unable to create MZ header.",
75 function );
76
77 goto on_error;
78 }
79 if( memory_set(
80 *mz_header,
81 0,
82 sizeof( libexe_mz_header_t ) ) == NULL )
83 {
84 libcerror_error_set(
85 error,
86 LIBCERROR_ERROR_DOMAIN_MEMORY,
87 LIBCERROR_MEMORY_ERROR_SET_FAILED,
88 "%s: unable to clear file.",
89 function );
90
91 goto on_error;
92 }
93 return( 1 );
94
95 on_error:
96 if( *mz_header != NULL )
97 {
98 memory_free(
99 *mz_header );
100
101 *mz_header = NULL;
102 }
103 return( -1 );
104 }
105
106 /* Frees a MZ header
107 * Returns 1 if successful or -1 on error
108 */
libexe_mz_header_free(libexe_mz_header_t ** mz_header,libcerror_error_t ** error)109 int libexe_mz_header_free(
110 libexe_mz_header_t **mz_header,
111 libcerror_error_t **error )
112 {
113 static char *function = "libexe_mz_header_free";
114
115 if( mz_header == NULL )
116 {
117 libcerror_error_set(
118 error,
119 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
120 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
121 "%s: invalid MZ header.",
122 function );
123
124 return( -1 );
125 }
126 if( *mz_header != NULL )
127 {
128 memory_free(
129 *mz_header );
130
131 *mz_header = NULL;
132 }
133 return( 1 );
134 }
135
136 /* Reads the MZ header
137 * Returns 1 if successful or -1 on error
138 */
libexe_mz_header_read_data(libexe_mz_header_t * mz_header,const uint8_t * data,size_t data_size,libcerror_error_t ** error)139 int libexe_mz_header_read_data(
140 libexe_mz_header_t *mz_header,
141 const uint8_t *data,
142 size_t data_size,
143 libcerror_error_t **error )
144 {
145 static char *function = "libexe_mz_header_read_data";
146 uint16_t number_of_relocation_entries = 0;
147 uint16_t relocation_table_offset = 0;
148
149 #if defined( HAVE_DEBUG_OUTPUT )
150 uint32_t value_32bit = 0;
151 uint16_t value_16bit = 0;
152 #endif
153
154 if( mz_header == NULL )
155 {
156 libcerror_error_set(
157 error,
158 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
159 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
160 "%s: invalid MZ header.",
161 function );
162
163 return( -1 );
164 }
165 if( data == NULL )
166 {
167 libcerror_error_set(
168 error,
169 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
170 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
171 "%s: invalid data.",
172 function );
173
174 return( -1 );
175 }
176 if( data_size < sizeof( exe_mz_header_t ) )
177 {
178 libcerror_error_set(
179 error,
180 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
181 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
182 "%s: invalid data size value too small.",
183 function );
184
185 return( -1 );
186 }
187 if( data_size > (size_t) SSIZE_MAX )
188 {
189 libcerror_error_set(
190 error,
191 LIBCERROR_ERROR_DOMAIN_RUNTIME,
192 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
193 "%s: invalid data size value exceeds maximum.",
194 function );
195
196 return( -1 );
197 }
198 #if defined( HAVE_DEBUG_OUTPUT )
199 if( libcnotify_verbose != 0 )
200 {
201 libcnotify_printf(
202 "%s: MZ header:\n",
203 function );
204 libcnotify_print_data(
205 data,
206 sizeof( exe_mz_header_t ),
207 0 );
208 }
209 #endif
210 if( memory_compare(
211 ( (exe_mz_header_t *) data )->signature,
212 EXE_MZ_SIGNATURE,
213 2 ) != 0 )
214 {
215 libcerror_error_set(
216 error,
217 LIBCERROR_ERROR_DOMAIN_RUNTIME,
218 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
219 "%s: invalid signature.",
220 function );
221
222 return( -1 );
223 }
224 byte_stream_copy_to_uint16_little_endian(
225 ( (exe_mz_header_t *) data )->number_of_relocation_entries,
226 number_of_relocation_entries );
227
228 byte_stream_copy_to_uint16_little_endian(
229 ( (exe_mz_header_t *) data )->relocation_table_offset,
230 relocation_table_offset );
231
232 #if defined( HAVE_DEBUG_OUTPUT )
233 if( libcnotify_verbose != 0 )
234 {
235 libcnotify_printf(
236 "%s: signature\t\t\t\t\t: %c%c\n",
237 function,
238 ( (exe_mz_header_t *) data )->signature[ 0 ],
239 ( (exe_mz_header_t *) data )->signature[ 1 ] );
240
241 byte_stream_copy_to_uint16_little_endian(
242 ( (exe_mz_header_t *) data )->last_page_size,
243 value_16bit );
244 libcnotify_printf(
245 "%s: last page size\t\t\t\t: %" PRIu16 "\n",
246 function,
247 value_16bit );
248
249 byte_stream_copy_to_uint16_little_endian(
250 ( (exe_mz_header_t *) data )->number_of_pages,
251 value_16bit );
252 libcnotify_printf(
253 "%s: number of pages\t\t\t\t: %" PRIu16 "\n",
254 function,
255 value_16bit );
256
257 libcnotify_printf(
258 "%s: number of relocation entries\t\t: %" PRIu16 "\n",
259 function,
260 number_of_relocation_entries );
261
262 byte_stream_copy_to_uint16_little_endian(
263 ( (exe_mz_header_t *) data )->number_of_header_paragraphs,
264 value_16bit );
265 libcnotify_printf(
266 "%s: number of header paragraphs\t\t\t: %" PRIu16 "\n",
267 function,
268 value_16bit );
269
270 byte_stream_copy_to_uint16_little_endian(
271 ( (exe_mz_header_t *) data )->minimum_allocated_paragraphs,
272 value_16bit );
273 libcnotify_printf(
274 "%s: minimum allocated paragraphs\t\t: %" PRIu16 "\n",
275 function,
276 value_16bit );
277
278 byte_stream_copy_to_uint16_little_endian(
279 ( (exe_mz_header_t *) data )->maximum_allocated_paragraphs,
280 value_16bit );
281 libcnotify_printf(
282 "%s: maximum allocated paragraphs\t\t: %" PRIu16 "\n",
283 function,
284 value_16bit );
285
286 byte_stream_copy_to_uint16_little_endian(
287 ( (exe_mz_header_t *) data )->initial_stack_segment,
288 value_16bit );
289 libcnotify_printf(
290 "%s: initial stack segment\t\t\t: 0x%04" PRIx16 "\n",
291 function,
292 value_16bit );
293
294 byte_stream_copy_to_uint16_little_endian(
295 ( (exe_mz_header_t *) data )->initial_stack_pointer,
296 value_16bit );
297 libcnotify_printf(
298 "%s: initial stack pointer\t\t\t: 0x%04" PRIx16 "\n",
299 function,
300 value_16bit );
301
302 byte_stream_copy_to_uint16_little_endian(
303 ( (exe_mz_header_t *) data )->checksum,
304 value_16bit );
305 libcnotify_printf(
306 "%s: checksum\t\t\t\t\t: 0x%04" PRIx16 "\n",
307 function,
308 value_16bit );
309
310 byte_stream_copy_to_uint32_little_endian(
311 ( (exe_mz_header_t *) data )->entry_point,
312 value_32bit );
313 libcnotify_printf(
314 "%s: entry point\t\t\t\t\t: 0x%08" PRIx32 "\n",
315 function,
316 value_32bit );
317
318 libcnotify_printf(
319 "%s: relocation table offset\t\t\t: 0x%04" PRIx16 "\n",
320 function,
321 relocation_table_offset );
322
323 byte_stream_copy_to_uint16_little_endian(
324 ( (exe_mz_header_t *) data )->overlay_number,
325 value_16bit );
326 libcnotify_printf(
327 "%s: overlay number\t\t\t\t: %" PRIu16 "\n",
328 function,
329 value_16bit );
330
331 libcnotify_printf(
332 "\n" );
333 }
334 #endif /* defined( HAVE_DEBUG_OUTPUT ) */
335
336 if( relocation_table_offset >= 0x40 )
337 {
338 /* TODO read data */
339 byte_stream_copy_to_uint32_little_endian(
340 ( (exe_mz_header_t *) data )->extended_header_offset,
341 mz_header->extended_header_offset );
342
343 #if defined( HAVE_DEBUG_OUTPUT )
344 if( libcnotify_verbose != 0 )
345 {
346 libcnotify_printf(
347 "%s: unknown1:\n",
348 function );
349 libcnotify_print_data(
350 ( (exe_mz_header_t *) data )->unknown1,
351 32,
352 0 );
353
354 libcnotify_printf(
355 "%s: extended header offset\t\t\t: 0x%08" PRIx32 "\n",
356 function,
357 mz_header->extended_header_offset );
358
359 libcnotify_printf(
360 "%s: unknown2:\n",
361 function );
362 libcnotify_print_data(
363 ( (exe_mz_header_t *) data )->unknown2,
364 112,
365 0 );
366 }
367 #endif /* defined( HAVE_DEBUG_OUTPUT ) */
368 }
369 /* TODO print data between realloc and current offset */
370 if( number_of_relocation_entries > 0 )
371 {
372 /* TODO print relation table entries */
373 }
374 return( 1 );
375 }
376
377 /* Reads the MZ header from a Basic File IO (bfio) handle
378 * Returns 1 if successful or -1 on error
379 */
libexe_mz_header_read_file_io_handle(libexe_mz_header_t * mz_header,libbfio_handle_t * file_io_handle,off64_t file_offset,libcerror_error_t ** error)380 int libexe_mz_header_read_file_io_handle(
381 libexe_mz_header_t *mz_header,
382 libbfio_handle_t *file_io_handle,
383 off64_t file_offset,
384 libcerror_error_t **error )
385 {
386 uint8_t data[ sizeof( exe_mz_header_t ) ];
387
388 static char *function = "libexe_mz_header_read_file_io_handle";
389 ssize_t read_count = 0;
390
391 #if defined( HAVE_DEBUG_OUTPUT )
392 if( libcnotify_verbose != 0 )
393 {
394 libcnotify_printf(
395 "%s: reading MZ header at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
396 function,
397 file_offset,
398 file_offset );
399 }
400 #endif
401 read_count = libbfio_handle_read_buffer_at_offset(
402 file_io_handle,
403 data,
404 sizeof( exe_mz_header_t ),
405 file_offset,
406 error );
407
408 if( read_count != (ssize_t) sizeof( exe_mz_header_t ) )
409 {
410 libcerror_error_set(
411 error,
412 LIBCERROR_ERROR_DOMAIN_IO,
413 LIBCERROR_IO_ERROR_READ_FAILED,
414 "%s: unable to read MZ header data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
415 function,
416 file_offset,
417 file_offset );
418
419 return( -1 );
420 }
421 if( libexe_mz_header_read_data(
422 mz_header,
423 data,
424 sizeof( exe_mz_header_t ),
425 error ) != 1 )
426 {
427 libcerror_error_set(
428 error,
429 LIBCERROR_ERROR_DOMAIN_IO,
430 LIBCERROR_IO_ERROR_READ_FAILED,
431 "%s: unable to read MZ header at offset: %" PRIi64 " (0x%08" PRIx64 ").",
432 function,
433 file_offset,
434 file_offset );
435
436 return( -1 );
437 }
438 return( 1 );
439 }
440
441