1 /*
2 * Input/Output (IO) handle 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 "libevtx_checksum.h"
28 #include "libevtx_chunk.h"
29 #include "libevtx_codepage.h"
30 #include "libevtx_debug.h"
31 #include "libevtx_definitions.h"
32 #include "libevtx_io_handle.h"
33 #include "libevtx_libbfio.h"
34 #include "libevtx_libcerror.h"
35 #include "libevtx_libcnotify.h"
36 #include "libevtx_libfdata.h"
37 #include "libevtx_unused.h"
38
39 #include "evtx_file_header.h"
40
41 const uint8_t *evtx_file_signature = (uint8_t *) "ElfFile";
42
43 /* Creates an IO handle
44 * Make sure the value io_handle is referencing, is set to NULL
45 * Returns 1 if successful or -1 on error
46 */
libevtx_io_handle_initialize(libevtx_io_handle_t ** io_handle,libcerror_error_t ** error)47 int libevtx_io_handle_initialize(
48 libevtx_io_handle_t **io_handle,
49 libcerror_error_t **error )
50 {
51 static char *function = "libevtx_io_handle_initialize";
52
53 if( io_handle == NULL )
54 {
55 libcerror_error_set(
56 error,
57 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
58 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
59 "%s: invalid IO handle.",
60 function );
61
62 return( -1 );
63 }
64 if( *io_handle != NULL )
65 {
66 libcerror_error_set(
67 error,
68 LIBCERROR_ERROR_DOMAIN_RUNTIME,
69 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
70 "%s: invalid IO handle value already set.",
71 function );
72
73 return( -1 );
74 }
75 *io_handle = memory_allocate_structure(
76 libevtx_io_handle_t );
77
78 if( *io_handle == NULL )
79 {
80 libcerror_error_set(
81 error,
82 LIBCERROR_ERROR_DOMAIN_MEMORY,
83 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
84 "%s: unable to create IO handle.",
85 function );
86
87 goto on_error;
88 }
89 if( memory_set(
90 *io_handle,
91 0,
92 sizeof( libevtx_io_handle_t ) ) == NULL )
93 {
94 libcerror_error_set(
95 error,
96 LIBCERROR_ERROR_DOMAIN_MEMORY,
97 LIBCERROR_MEMORY_ERROR_SET_FAILED,
98 "%s: unable to clear IO handle.",
99 function );
100
101 goto on_error;
102 }
103 ( *io_handle )->chunk_size = 0x00010000UL;
104 ( *io_handle )->ascii_codepage = LIBEVTX_CODEPAGE_WINDOWS_1252;
105
106 return( 1 );
107
108 on_error:
109 if( *io_handle != NULL )
110 {
111 memory_free(
112 *io_handle );
113
114 *io_handle = NULL;
115 }
116 return( -1 );
117 }
118
119 /* Frees an IO handle
120 * Returns 1 if successful or -1 on error
121 */
libevtx_io_handle_free(libevtx_io_handle_t ** io_handle,libcerror_error_t ** error)122 int libevtx_io_handle_free(
123 libevtx_io_handle_t **io_handle,
124 libcerror_error_t **error )
125 {
126 static char *function = "libevtx_io_handle_free";
127 int result = 1;
128
129 if( io_handle == NULL )
130 {
131 libcerror_error_set(
132 error,
133 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
134 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
135 "%s: invalid IO handle.",
136 function );
137
138 return( -1 );
139 }
140 if( *io_handle != NULL )
141 {
142 memory_free(
143 *io_handle );
144
145 *io_handle = NULL;
146 }
147 return( result );
148 }
149
150 /* Clears the IO handle
151 * Returns 1 if successful or -1 on error
152 */
libevtx_io_handle_clear(libevtx_io_handle_t * io_handle,libcerror_error_t ** error)153 int libevtx_io_handle_clear(
154 libevtx_io_handle_t *io_handle,
155 libcerror_error_t **error )
156 {
157 static char *function = "libevtx_io_handle_clear";
158
159 if( io_handle == NULL )
160 {
161 libcerror_error_set(
162 error,
163 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
164 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
165 "%s: invalid IO handle.",
166 function );
167
168 return( -1 );
169 }
170 if( memory_set(
171 io_handle,
172 0,
173 sizeof( libevtx_io_handle_t ) ) == NULL )
174 {
175 libcerror_error_set(
176 error,
177 LIBCERROR_ERROR_DOMAIN_MEMORY,
178 LIBCERROR_MEMORY_ERROR_SET_FAILED,
179 "%s: unable to clear IO handle.",
180 function );
181
182 return( -1 );
183 }
184 io_handle->chunk_size = 0x00010000UL;
185 io_handle->ascii_codepage = LIBEVTX_CODEPAGE_WINDOWS_1252;
186
187 return( 1 );
188 }
189
190 /* Reads the file (or database) header
191 * Returns 1 if successful or -1 on error
192 */
libevtx_io_handle_read_file_header(libevtx_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,off64_t file_offset,libcerror_error_t ** error)193 int libevtx_io_handle_read_file_header(
194 libevtx_io_handle_t *io_handle,
195 libbfio_handle_t *file_io_handle,
196 off64_t file_offset,
197 libcerror_error_t **error )
198 {
199 uint8_t *file_header_data = NULL;
200 static char *function = "libevtx_io_handle_read_file_header";
201 size_t read_size = 4096;
202 ssize_t read_count = 0;
203 uint32_t calculated_checksum = 0;
204 uint32_t stored_checksum = 0;
205 uint16_t first_chunk_number = 0;
206 uint16_t last_chunk_number = 0;
207
208 #if defined( HAVE_DEBUG_OUTPUT )
209 uint64_t value_64bit = 0;
210 uint32_t value_32bit = 0;
211 #endif
212
213 if( io_handle == NULL )
214 {
215 libcerror_error_set(
216 error,
217 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
218 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
219 "%s: invalid IO handle.",
220 function );
221
222 return( -1 );
223 }
224 file_header_data = (uint8_t *) memory_allocate(
225 sizeof( uint8_t ) * read_size );
226
227 if( file_header_data == NULL )
228 {
229 libcerror_error_set(
230 error,
231 LIBCERROR_ERROR_DOMAIN_MEMORY,
232 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
233 "%s: unable to create file header data.",
234 function );
235
236 return( -1 );
237 }
238 #if defined( HAVE_DEBUG_OUTPUT )
239 if( libcnotify_verbose != 0 )
240 {
241 libcnotify_printf(
242 "%s: reading file header at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
243 function,
244 file_offset,
245 file_offset );
246 }
247 #endif
248 read_count = libbfio_handle_read_buffer_at_offset(
249 file_io_handle,
250 file_header_data,
251 read_size,
252 file_offset,
253 error );
254
255 if( read_count != (ssize_t) read_size )
256 {
257 libcerror_error_set(
258 error,
259 LIBCERROR_ERROR_DOMAIN_IO,
260 LIBCERROR_IO_ERROR_READ_FAILED,
261 "%s: unable to read file header at offset: %" PRIi64 " (0x%08" PRIx64 ").",
262 function,
263 file_offset,
264 file_offset );
265
266 goto on_error;
267 }
268 #if defined( HAVE_DEBUG_OUTPUT )
269 if( libcnotify_verbose != 0 )
270 {
271 libcnotify_printf(
272 "%s: file header data:\n",
273 function );
274 libcnotify_print_data(
275 file_header_data,
276 sizeof( evtx_file_header_t ),
277 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
278 }
279 #endif
280 if( memory_compare(
281 ( (evtx_file_header_t *) file_header_data )->signature,
282 evtx_file_signature,
283 8 ) != 0 )
284 {
285 libcerror_error_set(
286 error,
287 LIBCERROR_ERROR_DOMAIN_RUNTIME,
288 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
289 "%s: unsupported file signature.",
290 function );
291
292 goto on_error;
293 }
294 byte_stream_copy_to_uint64_little_endian(
295 ( (evtx_file_header_t *) file_header_data )->first_chunk_number,
296 first_chunk_number );
297
298 byte_stream_copy_to_uint64_little_endian(
299 ( (evtx_file_header_t *) file_header_data )->last_chunk_number,
300 last_chunk_number );
301
302 byte_stream_copy_to_uint16_little_endian(
303 ( (evtx_file_header_t *) file_header_data )->minor_version,
304 io_handle->minor_version );
305
306 byte_stream_copy_to_uint16_little_endian(
307 ( (evtx_file_header_t *) file_header_data )->major_version,
308 io_handle->major_version );
309
310 byte_stream_copy_to_uint16_little_endian(
311 ( (evtx_file_header_t *) file_header_data )->header_block_size,
312 io_handle->chunks_data_offset );
313
314 byte_stream_copy_to_uint16_little_endian(
315 ( (evtx_file_header_t *) file_header_data )->number_of_chunks,
316 io_handle->number_of_chunks );
317
318 byte_stream_copy_to_uint32_little_endian(
319 ( (evtx_file_header_t *) file_header_data )->file_flags,
320 io_handle->file_flags );
321
322 byte_stream_copy_to_uint32_little_endian(
323 ( (evtx_file_header_t *) file_header_data )->checksum,
324 stored_checksum );
325
326 #if defined( HAVE_DEBUG_OUTPUT )
327 if( libcnotify_verbose != 0 )
328 {
329 libcnotify_printf(
330 "%s: signature\t\t\t\t: %c%c%c%c%c%c%c\\x%02x\n",
331 function,
332 ( (evtx_file_header_t *) file_header_data )->signature[ 0 ],
333 ( (evtx_file_header_t *) file_header_data )->signature[ 1 ],
334 ( (evtx_file_header_t *) file_header_data )->signature[ 2 ],
335 ( (evtx_file_header_t *) file_header_data )->signature[ 3 ],
336 ( (evtx_file_header_t *) file_header_data )->signature[ 4 ],
337 ( (evtx_file_header_t *) file_header_data )->signature[ 5 ] ,
338 ( (evtx_file_header_t *) file_header_data )->signature[ 6 ] ,
339 ( (evtx_file_header_t *) file_header_data )->signature[ 7 ] );
340
341 libcnotify_printf(
342 "%s: first chunk number\t\t\t: %" PRIu64 "\n",
343 function,
344 first_chunk_number );
345
346 libcnotify_printf(
347 "%s: last chunk number\t\t\t: %" PRIu64 "\n",
348 function,
349 last_chunk_number );
350
351 byte_stream_copy_to_uint64_little_endian(
352 ( (evtx_file_header_t *) file_header_data )->next_record_identifier,
353 value_64bit );
354 libcnotify_printf(
355 "%s: next record identifier\t\t: %" PRIu64 "\n",
356 function,
357 value_64bit );
358
359 byte_stream_copy_to_uint32_little_endian(
360 ( (evtx_file_header_t *) file_header_data )->header_size,
361 value_32bit );
362 libcnotify_printf(
363 "%s: header size\t\t\t\t: %" PRIu32 "\n",
364 function,
365 value_32bit );
366
367 libcnotify_printf(
368 "%s: minor version\t\t\t: %" PRIu16 "\n",
369 function,
370 io_handle->minor_version );
371
372 libcnotify_printf(
373 "%s: major version\t\t\t: %" PRIu16 "\n",
374 function,
375 io_handle->major_version );
376
377 libcnotify_printf(
378 "%s: header block size\t\t\t: %" PRIi64 "\n",
379 function,
380 io_handle->chunks_data_offset );
381
382 libcnotify_printf(
383 "%s: number of chunks\t\t\t: %" PRIu16 "\n",
384 function,
385 io_handle->number_of_chunks );
386
387 libcnotify_printf(
388 "%s: unknown1:\n",
389 function );
390 libcnotify_print_data(
391 ( (evtx_file_header_t *) file_header_data )->unknown1,
392 76,
393 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
394
395 libcnotify_printf(
396 "%s: file flags\t\t\t\t: 0x%08" PRIx32 "\n",
397 function,
398 io_handle->file_flags );
399 libevtx_debug_print_file_flags(
400 io_handle->file_flags );
401 libcnotify_printf(
402 "\n" );
403
404 libcnotify_printf(
405 "%s: checksum\t\t\t\t: 0x%08" PRIx32 "\n",
406 function,
407 stored_checksum );
408
409 libcnotify_printf(
410 "\n" );
411 }
412 #endif /* defined( HAVE_DEBUG_OUTPUT ) */
413
414 if( libevtx_checksum_calculate_little_endian_crc32(
415 &calculated_checksum,
416 file_header_data,
417 120,
418 0,
419 error ) != 1 )
420 {
421 libcerror_error_set(
422 error,
423 LIBCERROR_ERROR_DOMAIN_RUNTIME,
424 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
425 "%s: unable to calculate CRC-32 checksum.",
426 function );
427
428 goto on_error;
429 }
430 if( stored_checksum != calculated_checksum )
431 {
432 #if defined( HAVE_VERBOSE_OUTPUT )
433 if( libcnotify_verbose != 0 )
434 {
435 libcnotify_printf(
436 "%s: mismatch in file header CRC-32 checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).\n",
437 function,
438 stored_checksum,
439 calculated_checksum );
440 }
441 #endif
442 io_handle->flags |= LIBEVTX_IO_HANDLE_FLAG_IS_CORRUPTED;
443 }
444 #if defined( HAVE_DEBUG_OUTPUT )
445 if( libcnotify_verbose != 0 )
446 {
447 libcnotify_printf(
448 "%s: trailing data:\n",
449 function );
450 libcnotify_print_data(
451 &( file_header_data[ sizeof( evtx_file_header_t ) ] ),
452 read_size - sizeof( evtx_file_header_t ),
453 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
454 }
455 #endif
456 if( first_chunk_number > last_chunk_number )
457 {
458 #if defined( HAVE_VERBOSE_OUTPUT )
459 if( libcnotify_verbose != 0 )
460 {
461 libcnotify_printf(
462 "%s: first chunk number: %" PRIu16 " exceeds last chunk number: %" PRIu16 ".\n",
463 function,
464 first_chunk_number,
465 last_chunk_number );
466 }
467 #endif
468 io_handle->flags |= LIBEVTX_IO_HANDLE_FLAG_IS_CORRUPTED;
469 }
470 else if( io_handle->number_of_chunks != ( last_chunk_number - first_chunk_number + 1 ) )
471 {
472 #if defined( HAVE_VERBOSE_OUTPUT )
473 if( libcnotify_verbose != 0 )
474 {
475 libcnotify_printf(
476 "%s: mismatch in number of chunks ( %" PRIu16 " != %" PRIu16 " ).\n",
477 function,
478 io_handle->number_of_chunks,
479 last_chunk_number - first_chunk_number + 1 );
480 }
481 #endif
482 io_handle->flags |= LIBEVTX_IO_HANDLE_FLAG_IS_CORRUPTED;
483 }
484 memory_free(
485 file_header_data );
486
487 file_header_data = NULL;
488
489 return( 1 );
490
491 on_error:
492 if( file_header_data != NULL )
493 {
494 memory_free(
495 file_header_data );
496 }
497 return( -1 );
498 }
499
500 /* Reads a chunk
501 * Callback function for the chunk vector
502 * Returns 1 if successful or -1 on error
503 */
libevtx_io_handle_read_chunk(libevtx_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,libfdata_vector_t * vector,libfdata_cache_t * cache,int element_index,int element_data_file_index LIBEVTX_ATTRIBUTE_UNUSED,off64_t element_data_offset,size64_t element_data_size LIBEVTX_ATTRIBUTE_UNUSED,uint32_t element_data_flags LIBEVTX_ATTRIBUTE_UNUSED,uint8_t read_flags LIBEVTX_ATTRIBUTE_UNUSED,libcerror_error_t ** error)504 int libevtx_io_handle_read_chunk(
505 libevtx_io_handle_t *io_handle,
506 libbfio_handle_t *file_io_handle,
507 libfdata_vector_t *vector,
508 libfdata_cache_t *cache,
509 int element_index,
510 int element_data_file_index LIBEVTX_ATTRIBUTE_UNUSED,
511 off64_t element_data_offset,
512 size64_t element_data_size LIBEVTX_ATTRIBUTE_UNUSED,
513 uint32_t element_data_flags LIBEVTX_ATTRIBUTE_UNUSED,
514 uint8_t read_flags LIBEVTX_ATTRIBUTE_UNUSED,
515 libcerror_error_t **error )
516 {
517 libevtx_chunk_t *chunk = NULL;
518 static char *function = "libevtx_io_handle_read_chunk";
519
520 LIBEVTX_UNREFERENCED_PARAMETER( element_data_file_index );
521 LIBEVTX_UNREFERENCED_PARAMETER( element_data_size );
522 LIBEVTX_UNREFERENCED_PARAMETER( element_data_flags );
523 LIBEVTX_UNREFERENCED_PARAMETER( read_flags );
524
525 if( libevtx_chunk_initialize(
526 &chunk,
527 error ) != 1 )
528 {
529 libcerror_error_set(
530 error,
531 LIBCERROR_ERROR_DOMAIN_RUNTIME,
532 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
533 "%s: unable to create chunk.",
534 function );
535
536 goto on_error;
537 }
538 if( libevtx_chunk_read(
539 chunk,
540 io_handle,
541 file_io_handle,
542 element_data_offset,
543 error ) != 1 )
544 {
545 libcerror_error_set(
546 error,
547 LIBCERROR_ERROR_DOMAIN_IO,
548 LIBCERROR_IO_ERROR_READ_FAILED,
549 "%s: unable to read chunk.",
550 function );
551
552 goto on_error;
553 }
554 if( libfdata_vector_set_element_value_by_index(
555 vector,
556 (intptr_t *) file_io_handle,
557 cache,
558 element_index,
559 (intptr_t *) chunk,
560 (int (*)(intptr_t **, libcerror_error_t **)) &libevtx_chunk_free,
561 LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
562 error ) != 1 )
563 {
564 libcerror_error_set(
565 error,
566 LIBCERROR_ERROR_DOMAIN_RUNTIME,
567 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
568 "%s: unable to set chunk as element value.",
569 function );
570
571 goto on_error;
572 }
573 return( 1 );
574
575 on_error:
576 if( chunk != NULL )
577 {
578 libevtx_chunk_free(
579 &chunk,
580 NULL );
581 }
582 return( -1 );
583 }
584
585