/src/libexe/libexe/libexe_mz_header.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * MZ header functions |
3 | | * |
4 | | * Copyright (C) 2011-2024, 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 | | */ |
37 | | int libexe_mz_header_initialize( |
38 | | libexe_mz_header_t **mz_header, |
39 | | libcerror_error_t **error ) |
40 | 917 | { |
41 | 917 | static char *function = "libexe_mz_header_initialize"; |
42 | | |
43 | 917 | if( mz_header == NULL ) |
44 | 0 | { |
45 | 0 | libcerror_error_set( |
46 | 0 | error, |
47 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
48 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
49 | 0 | "%s: invalid MZ header.", |
50 | 0 | function ); |
51 | |
|
52 | 0 | return( -1 ); |
53 | 0 | } |
54 | 917 | if( *mz_header != NULL ) |
55 | 0 | { |
56 | 0 | libcerror_error_set( |
57 | 0 | error, |
58 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
59 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, |
60 | 0 | "%s: invalid MZ header value already set.", |
61 | 0 | function ); |
62 | |
|
63 | 0 | return( -1 ); |
64 | 0 | } |
65 | 917 | *mz_header = memory_allocate_structure( |
66 | 917 | libexe_mz_header_t ); |
67 | | |
68 | 917 | if( *mz_header == NULL ) |
69 | 0 | { |
70 | 0 | libcerror_error_set( |
71 | 0 | error, |
72 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
73 | 0 | LIBCERROR_MEMORY_ERROR_INSUFFICIENT, |
74 | 0 | "%s: unable to create MZ header.", |
75 | 0 | function ); |
76 | |
|
77 | 0 | goto on_error; |
78 | 0 | } |
79 | 917 | if( memory_set( |
80 | 917 | *mz_header, |
81 | 917 | 0, |
82 | 917 | sizeof( libexe_mz_header_t ) ) == NULL ) |
83 | 0 | { |
84 | 0 | libcerror_error_set( |
85 | 0 | error, |
86 | 0 | LIBCERROR_ERROR_DOMAIN_MEMORY, |
87 | 0 | LIBCERROR_MEMORY_ERROR_SET_FAILED, |
88 | 0 | "%s: unable to clear file.", |
89 | 0 | function ); |
90 | |
|
91 | 0 | goto on_error; |
92 | 0 | } |
93 | 917 | return( 1 ); |
94 | | |
95 | 0 | on_error: |
96 | 0 | if( *mz_header != NULL ) |
97 | 0 | { |
98 | 0 | memory_free( |
99 | 0 | *mz_header ); |
100 | |
|
101 | 0 | *mz_header = NULL; |
102 | 0 | } |
103 | 0 | return( -1 ); |
104 | 917 | } |
105 | | |
106 | | /* Frees a MZ header |
107 | | * Returns 1 if successful or -1 on error |
108 | | */ |
109 | | int libexe_mz_header_free( |
110 | | libexe_mz_header_t **mz_header, |
111 | | libcerror_error_t **error ) |
112 | 917 | { |
113 | 917 | static char *function = "libexe_mz_header_free"; |
114 | | |
115 | 917 | if( mz_header == NULL ) |
116 | 0 | { |
117 | 0 | libcerror_error_set( |
118 | 0 | error, |
119 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
120 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
121 | 0 | "%s: invalid MZ header.", |
122 | 0 | function ); |
123 | |
|
124 | 0 | return( -1 ); |
125 | 0 | } |
126 | 917 | if( *mz_header != NULL ) |
127 | 917 | { |
128 | 917 | memory_free( |
129 | 917 | *mz_header ); |
130 | | |
131 | 917 | *mz_header = NULL; |
132 | 917 | } |
133 | 917 | return( 1 ); |
134 | 917 | } |
135 | | |
136 | | /* Reads the MZ header |
137 | | * Returns 1 if successful or -1 on error |
138 | | */ |
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 | 899 | { |
145 | 899 | static char *function = "libexe_mz_header_read_data"; |
146 | 899 | uint16_t number_of_relocation_entries = 0; |
147 | 899 | 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 | 899 | if( mz_header == NULL ) |
155 | 0 | { |
156 | 0 | libcerror_error_set( |
157 | 0 | error, |
158 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
159 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
160 | 0 | "%s: invalid MZ header.", |
161 | 0 | function ); |
162 | |
|
163 | 0 | return( -1 ); |
164 | 0 | } |
165 | 899 | if( data == NULL ) |
166 | 0 | { |
167 | 0 | libcerror_error_set( |
168 | 0 | error, |
169 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
170 | 0 | LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, |
171 | 0 | "%s: invalid data.", |
172 | 0 | function ); |
173 | |
|
174 | 0 | return( -1 ); |
175 | 0 | } |
176 | 899 | if( data_size < sizeof( exe_mz_header_t ) ) |
177 | 0 | { |
178 | 0 | libcerror_error_set( |
179 | 0 | error, |
180 | 0 | LIBCERROR_ERROR_DOMAIN_ARGUMENTS, |
181 | 0 | LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL, |
182 | 0 | "%s: invalid data size value too small.", |
183 | 0 | function ); |
184 | |
|
185 | 0 | return( -1 ); |
186 | 0 | } |
187 | 899 | if( data_size > (size_t) SSIZE_MAX ) |
188 | 0 | { |
189 | 0 | libcerror_error_set( |
190 | 0 | error, |
191 | 0 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
192 | 0 | LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM, |
193 | 0 | "%s: invalid data size value exceeds maximum.", |
194 | 0 | function ); |
195 | |
|
196 | 0 | return( -1 ); |
197 | 0 | } |
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 | 899 | if( memory_compare( |
211 | 899 | ( (exe_mz_header_t *) data )->signature, |
212 | 899 | EXE_MZ_SIGNATURE, |
213 | 899 | 2 ) != 0 ) |
214 | 40 | { |
215 | 40 | libcerror_error_set( |
216 | 40 | error, |
217 | 40 | LIBCERROR_ERROR_DOMAIN_RUNTIME, |
218 | 40 | LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, |
219 | 40 | "%s: invalid signature.", |
220 | 40 | function ); |
221 | | |
222 | 40 | return( -1 ); |
223 | 40 | } |
224 | 859 | byte_stream_copy_to_uint16_little_endian( |
225 | 859 | ( (exe_mz_header_t *) data )->number_of_relocation_entries, |
226 | 859 | number_of_relocation_entries ); |
227 | | |
228 | 859 | byte_stream_copy_to_uint16_little_endian( |
229 | 859 | ( (exe_mz_header_t *) data )->relocation_table_offset, |
230 | 859 | 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 | 859 | if( relocation_table_offset >= 0x40 ) |
337 | 853 | { |
338 | | /* TODO read data */ |
339 | 853 | byte_stream_copy_to_uint32_little_endian( |
340 | 853 | ( (exe_mz_header_t *) data )->extended_header_offset, |
341 | 853 | 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 | 853 | } |
369 | | /* TODO print data between realloc and current offset */ |
370 | 859 | if( number_of_relocation_entries > 0 ) |
371 | 718 | { |
372 | | /* TODO print relation table entries */ |
373 | 718 | } |
374 | 859 | return( 1 ); |
375 | 899 | } |
376 | | |
377 | | /* Reads the MZ header from a Basic File IO (bfio) handle |
378 | | * Returns 1 if successful or -1 on error |
379 | | */ |
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 | 917 | { |
386 | 917 | uint8_t data[ sizeof( exe_mz_header_t ) ]; |
387 | | |
388 | 917 | static char *function = "libexe_mz_header_read_file_io_handle"; |
389 | 917 | 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 | 917 | read_count = libbfio_handle_read_buffer_at_offset( |
402 | 917 | file_io_handle, |
403 | 917 | data, |
404 | 917 | sizeof( exe_mz_header_t ), |
405 | 917 | file_offset, |
406 | 917 | error ); |
407 | | |
408 | 917 | if( read_count != (ssize_t) sizeof( exe_mz_header_t ) ) |
409 | 18 | { |
410 | 18 | libcerror_error_set( |
411 | 18 | error, |
412 | 18 | LIBCERROR_ERROR_DOMAIN_IO, |
413 | 18 | LIBCERROR_IO_ERROR_READ_FAILED, |
414 | 18 | "%s: unable to read MZ header data at offset: %" PRIi64 " (0x%08" PRIx64 ").", |
415 | 18 | function, |
416 | 18 | file_offset, |
417 | 18 | file_offset ); |
418 | | |
419 | 18 | return( -1 ); |
420 | 18 | } |
421 | 899 | if( libexe_mz_header_read_data( |
422 | 899 | mz_header, |
423 | 899 | data, |
424 | 899 | sizeof( exe_mz_header_t ), |
425 | 899 | error ) != 1 ) |
426 | 40 | { |
427 | 40 | libcerror_error_set( |
428 | 40 | error, |
429 | 40 | LIBCERROR_ERROR_DOMAIN_IO, |
430 | 40 | LIBCERROR_IO_ERROR_READ_FAILED, |
431 | 40 | "%s: unable to read MZ header at offset: %" PRIi64 " (0x%08" PRIx64 ").", |
432 | 40 | function, |
433 | 40 | file_offset, |
434 | 40 | file_offset ); |
435 | | |
436 | 40 | return( -1 ); |
437 | 40 | } |
438 | 859 | return( 1 ); |
439 | 899 | } |
440 | | |