1 /*
2 * Chunk 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 <memory.h>
24 #include <types.h>
25
26 #include "libevtx_byte_stream.h"
27 #include "libevtx_checksum.h"
28 #include "libevtx_chunk.h"
29 #include "libevtx_definitions.h"
30 #include "libevtx_io_handle.h"
31 #include "libevtx_libbfio.h"
32 #include "libevtx_libcdata.h"
33 #include "libevtx_libcerror.h"
34 #include "libevtx_libcnotify.h"
35 #include "libevtx_record_values.h"
36
37 #include "evtx_chunk.h"
38 #include "evtx_event_record.h"
39
40 const uint8_t *evtx_chunk_signature = (uint8_t *) "ElfChnk";
41
42 /* Creates a chunk
43 * Make sure the value chunk is referencing, is set to NULL
44 * Returns 1 if successful or -1 on error
45 */
libevtx_chunk_initialize(libevtx_chunk_t ** chunk,libcerror_error_t ** error)46 int libevtx_chunk_initialize(
47 libevtx_chunk_t **chunk,
48 libcerror_error_t **error )
49 {
50 static char *function = "libevtx_chunk_initialize";
51
52 if( chunk == NULL )
53 {
54 libcerror_error_set(
55 error,
56 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
57 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
58 "%s: invalid chunk.",
59 function );
60
61 return( -1 );
62 }
63 if( *chunk != NULL )
64 {
65 libcerror_error_set(
66 error,
67 LIBCERROR_ERROR_DOMAIN_RUNTIME,
68 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
69 "%s: invalid chunk value already set.",
70 function );
71
72 return( -1 );
73 }
74 *chunk = memory_allocate_structure(
75 libevtx_chunk_t );
76
77 if( *chunk == NULL )
78 {
79 libcerror_error_set(
80 error,
81 LIBCERROR_ERROR_DOMAIN_MEMORY,
82 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
83 "%s: unable to create chunk.",
84 function );
85
86 goto on_error;
87 }
88 if( memory_set(
89 *chunk,
90 0,
91 sizeof( libevtx_chunk_t ) ) == NULL )
92 {
93 libcerror_error_set(
94 error,
95 LIBCERROR_ERROR_DOMAIN_MEMORY,
96 LIBCERROR_MEMORY_ERROR_SET_FAILED,
97 "%s: unable to clear chunk.",
98 function );
99
100 memory_free(
101 *chunk );
102
103 *chunk = NULL;
104
105 return( -1 );
106 }
107 if( libcdata_array_initialize(
108 &( ( *chunk )->records_array ),
109 0,
110 error ) != 1 )
111 {
112 libcerror_error_set(
113 error,
114 LIBCERROR_ERROR_DOMAIN_RUNTIME,
115 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
116 "%s: unable to create chunk records array.",
117 function );
118
119 goto on_error;
120 }
121 if( libcdata_array_initialize(
122 &( ( *chunk )->recovered_records_array ),
123 0,
124 error ) != 1 )
125 {
126 libcerror_error_set(
127 error,
128 LIBCERROR_ERROR_DOMAIN_RUNTIME,
129 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
130 "%s: unable to create chunk recovered records array.",
131 function );
132
133 goto on_error;
134 }
135 return( 1 );
136
137 on_error:
138 if( *chunk != NULL )
139 {
140 if( ( *chunk )->records_array != NULL )
141 {
142 libcdata_array_free(
143 &( ( *chunk )->records_array ),
144 NULL,
145 NULL );
146 }
147 memory_free(
148 *chunk );
149
150 *chunk = NULL;
151 }
152 return( -1 );
153 }
154
155 /* Frees a chunk
156 * Returns 1 if successful or -1 on error
157 */
libevtx_chunk_free(libevtx_chunk_t ** chunk,libcerror_error_t ** error)158 int libevtx_chunk_free(
159 libevtx_chunk_t **chunk,
160 libcerror_error_t **error )
161 {
162 static char *function = "libevtx_chunk_free";
163 int result = 1;
164
165 if( chunk == NULL )
166 {
167 libcerror_error_set(
168 error,
169 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
170 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
171 "%s: invalid chunk.",
172 function );
173
174 return( -1 );
175 }
176 if( *chunk != NULL )
177 {
178 if( libcdata_array_free(
179 &( ( *chunk )->recovered_records_array ),
180 (int (*)(intptr_t **, libcerror_error_t **)) &libevtx_record_values_free,
181 error ) != 1 )
182 {
183 libcerror_error_set(
184 error,
185 LIBCERROR_ERROR_DOMAIN_RUNTIME,
186 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
187 "%s: unable to free the chunk recovered records array.",
188 function );
189
190 result = -1;
191 }
192 if( libcdata_array_free(
193 &( ( *chunk )->records_array ),
194 (int (*)(intptr_t **, libcerror_error_t **)) &libevtx_record_values_free,
195 error ) != 1 )
196 {
197 libcerror_error_set(
198 error,
199 LIBCERROR_ERROR_DOMAIN_RUNTIME,
200 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
201 "%s: unable to free the chunk records array.",
202 function );
203
204 result = -1;
205 }
206 if( ( *chunk )->data != NULL )
207 {
208 memory_free(
209 ( *chunk )->data );
210 }
211 memory_free(
212 *chunk );
213
214 *chunk = NULL;
215 }
216 return( result );
217 }
218
219 /* Reads the chunk
220 * Returns 1 if successful, 0 if the chunk is 0-byte filled or -1 on error
221 */
libevtx_chunk_read(libevtx_chunk_t * chunk,libevtx_io_handle_t * io_handle,libbfio_handle_t * file_io_handle,off64_t file_offset,libcerror_error_t ** error)222 int libevtx_chunk_read(
223 libevtx_chunk_t *chunk,
224 libevtx_io_handle_t *io_handle,
225 libbfio_handle_t *file_io_handle,
226 off64_t file_offset,
227 libcerror_error_t **error )
228 {
229 libevtx_record_values_t *record_values = NULL;
230 uint8_t *chunk_data = NULL;
231 static char *function = "libevtx_chunk_read";
232 size_t chunk_data_offset = 0;
233 size_t chunk_data_size = 0;
234 size_t xml_data_offset = 0;
235 size_t xml_data_size = 0;
236 ssize_t read_count = 0;
237 uint64_t calculated_number_of_event_records = 0;
238 uint64_t first_event_record_identifier = 0;
239 uint64_t first_event_record_number = 0;
240 uint64_t last_event_record_identifier = 0;
241 uint64_t last_event_record_number = 0;
242 uint64_t number_of_event_records = 0;
243 uint32_t calculated_checksum = 0;
244 uint32_t event_records_checksum = 0;
245 uint32_t free_space_offset = 0;
246 uint32_t header_size = 0;
247 uint32_t last_event_record_offset = 0;
248 uint32_t stored_checksum = 0;
249 int entry_index = 0;
250 int result = 0;
251
252 #if defined( HAVE_DEBUG_OUTPUT ) || defined( HAVE_VERBOSE_OUTPUT )
253 uint64_t calculated_chunk_number = 0;
254 #endif
255 #if defined( HAVE_DEBUG_OUTPUT )
256 ssize_t free_space_size = 0;
257 uint32_t value_32bit = 0;
258 #endif
259
260 if( chunk == NULL )
261 {
262 libcerror_error_set(
263 error,
264 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
265 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
266 "%s: invalid chunk.",
267 function );
268
269 return( -1 );
270 }
271 if( chunk->data != NULL )
272 {
273 libcerror_error_set(
274 error,
275 LIBCERROR_ERROR_DOMAIN_RUNTIME,
276 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
277 "%s: invalid chunk data already set.",
278 function );
279
280 return( -1 );
281 }
282 if( io_handle == NULL )
283 {
284 libcerror_error_set(
285 error,
286 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
287 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
288 "%s: invalid IO handle.",
289 function );
290
291 return( -1 );
292 }
293 if( ( io_handle->chunk_size < 4 )
294 || ( io_handle->chunk_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
295 {
296 libcerror_error_set(
297 error,
298 LIBCERROR_ERROR_DOMAIN_RUNTIME,
299 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
300 "%s: invalid IO handle - invalid chunk size value out of bounds.",
301 function );
302
303 goto on_error;
304 }
305 #if defined( HAVE_DEBUG_OUTPUT ) || defined( HAVE_VERBOSE_OUTPUT )
306 calculated_chunk_number = (uint64_t) ( ( file_offset - io_handle->chunk_size ) / io_handle->chunk_size );
307 #endif
308 chunk->file_offset = file_offset;
309
310 chunk->data = (uint8_t *) memory_allocate(
311 (size_t) io_handle->chunk_size );
312
313 if( chunk->data == NULL )
314 {
315 libcerror_error_set(
316 error,
317 LIBCERROR_ERROR_DOMAIN_MEMORY,
318 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
319 "%s: unable to create chunk data.",
320 function );
321
322 goto on_error;
323 }
324 chunk->data_size = (size_t) io_handle->chunk_size;
325
326 #if defined( HAVE_DEBUG_OUTPUT )
327 if( libcnotify_verbose != 0 )
328 {
329 libcnotify_printf(
330 "%s: reading chunk: %" PRIu64 " at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
331 function,
332 calculated_chunk_number,
333 file_offset,
334 file_offset );
335 }
336 #endif
337 read_count = libbfio_handle_read_buffer_at_offset(
338 file_io_handle,
339 chunk->data,
340 chunk->data_size,
341 file_offset,
342 error );
343
344 if( read_count != (ssize_t) chunk->data_size )
345 {
346 libcerror_error_set(
347 error,
348 LIBCERROR_ERROR_DOMAIN_IO,
349 LIBCERROR_IO_ERROR_READ_FAILED,
350 "%s: unable to read chunk data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
351 function,
352 file_offset,
353 file_offset );
354
355 goto on_error;
356 }
357 chunk_data = chunk->data;
358 chunk_data_size = chunk->data_size;
359
360 #if defined( HAVE_DEBUG_OUTPUT )
361 if( libcnotify_verbose != 0 )
362 {
363 libcnotify_printf(
364 "%s: chunk header data:\n",
365 function );
366 libcnotify_print_data(
367 chunk_data,
368 sizeof( evtx_chunk_header_t ),
369 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
370 }
371 #endif
372 result = libevtx_byte_stream_check_for_zero_byte_fill(
373 chunk_data,
374 chunk_data_size,
375 error );
376
377 if( result == -1 )
378 {
379 libcerror_error_set(
380 error,
381 LIBCERROR_ERROR_DOMAIN_RUNTIME,
382 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
383 "%s: unable to determine of chunk is 0-byte filled.",
384 function );
385
386 goto on_error;
387 }
388 else if( result != 0 )
389 {
390 return( 0 );
391 }
392 if( memory_compare(
393 ( (evtx_chunk_header_t *) chunk_data )->signature,
394 evtx_chunk_signature,
395 8 ) != 0 )
396 {
397 #if defined( HAVE_VERBOSE_OUTPUT )
398 if( libcnotify_verbose != 0 )
399 {
400 libcnotify_printf(
401 "%s: unsupported chunk signature.\n",
402 function );
403 }
404 #endif
405 chunk->flags |= LIBEVTX_CHUNK_FLAG_IS_CORRUPTED;
406 }
407 else
408 {
409 byte_stream_copy_to_uint64_little_endian(
410 ( (evtx_chunk_header_t *) chunk_data )->first_event_record_number,
411 first_event_record_number );
412
413 byte_stream_copy_to_uint64_little_endian(
414 ( (evtx_chunk_header_t *) chunk_data )->last_event_record_number,
415 last_event_record_number );
416
417 byte_stream_copy_to_uint64_little_endian(
418 ( (evtx_chunk_header_t *) chunk_data )->first_event_record_identifier,
419 first_event_record_identifier );
420
421 byte_stream_copy_to_uint64_little_endian(
422 ( (evtx_chunk_header_t *) chunk_data )->last_event_record_identifier,
423 last_event_record_identifier );
424
425 byte_stream_copy_to_uint32_little_endian(
426 ( (evtx_chunk_header_t *) chunk_data )->header_size,
427 header_size );
428
429 byte_stream_copy_to_uint32_little_endian(
430 ( (evtx_chunk_header_t *) chunk_data )->last_event_record_offset,
431 last_event_record_offset );
432
433 byte_stream_copy_to_uint32_little_endian(
434 ( (evtx_chunk_header_t *) chunk_data )->free_space_offset,
435 free_space_offset );
436
437 byte_stream_copy_to_uint32_little_endian(
438 ( (evtx_chunk_header_t *) chunk_data )->event_records_checksum,
439 event_records_checksum );
440
441 byte_stream_copy_to_uint32_little_endian(
442 ( (evtx_chunk_header_t *) chunk_data )->checksum,
443 stored_checksum );
444
445 #if defined( HAVE_DEBUG_OUTPUT )
446 if( libcnotify_verbose != 0 )
447 {
448 libcnotify_printf(
449 "%s: signature\t\t\t\t\t\t: %c%c%c%c%c%c%c\\x%02x\n",
450 function,
451 ( (evtx_chunk_header_t *) chunk_data )->signature[ 0 ],
452 ( (evtx_chunk_header_t *) chunk_data )->signature[ 1 ],
453 ( (evtx_chunk_header_t *) chunk_data )->signature[ 2 ],
454 ( (evtx_chunk_header_t *) chunk_data )->signature[ 3 ],
455 ( (evtx_chunk_header_t *) chunk_data )->signature[ 4 ],
456 ( (evtx_chunk_header_t *) chunk_data )->signature[ 5 ] ,
457 ( (evtx_chunk_header_t *) chunk_data )->signature[ 6 ],
458 ( (evtx_chunk_header_t *) chunk_data )->signature[ 7 ] );
459
460 libcnotify_printf(
461 "%s: first event record number\t\t\t\t: %" PRIu64 "\n",
462 function,
463 first_event_record_number );
464
465 libcnotify_printf(
466 "%s: last event record number\t\t\t\t: %" PRIu64 "\n",
467 function,
468 last_event_record_number );
469
470 libcnotify_printf(
471 "%s: first event record identifier\t\t\t: %" PRIu64 "\n",
472 function,
473 first_event_record_identifier );
474
475 libcnotify_printf(
476 "%s: last event record identifier\t\t\t: %" PRIu64 "\n",
477 function,
478 last_event_record_identifier );
479
480 libcnotify_printf(
481 "%s: header size\t\t\t\t\t\t: %" PRIu32 "\n",
482 function,
483 header_size );
484
485 libcnotify_printf(
486 "%s: last event record offset\t\t\t\t: 0x%08" PRIx32 "\n",
487 function,
488 last_event_record_offset );
489
490 libcnotify_printf(
491 "%s: free space offset\t\t\t\t\t: 0x%08" PRIx32 "\n",
492 function,
493 free_space_offset );
494
495 libcnotify_printf(
496 "%s: event records checksum\t\t\t\t: 0x%08" PRIx32 "\n",
497 function,
498 event_records_checksum );
499
500 libcnotify_printf(
501 "%s: unknown1:\n",
502 function );
503 libcnotify_print_data(
504 ( (evtx_chunk_header_t *) chunk_data )->unknown1,
505 64,
506 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
507
508 byte_stream_copy_to_uint32_little_endian(
509 ( (evtx_chunk_header_t *) chunk_data )->unknown2,
510 value_32bit );
511 libcnotify_printf(
512 "%s: unknown2\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
513 function,
514 value_32bit );
515
516 libcnotify_printf(
517 "%s: checksum\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
518 function,
519 stored_checksum );
520
521 libcnotify_printf(
522 "\n" );
523 }
524 #endif /* defined( HAVE_DEBUG_OUTPUT ) */
525
526 if( header_size != 128 )
527 {
528 libcerror_error_set(
529 error,
530 LIBCERROR_ERROR_DOMAIN_RUNTIME,
531 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
532 "%s: unsupported header size: %" PRIu32 ".",
533 function,
534 header_size );
535
536 goto on_error;
537 }
538 if( libevtx_checksum_calculate_little_endian_crc32(
539 &calculated_checksum,
540 chunk_data,
541 120,
542 0,
543 error ) != 1 )
544 {
545 libcerror_error_set(
546 error,
547 LIBCERROR_ERROR_DOMAIN_RUNTIME,
548 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
549 "%s: unable to calculate CRC-32 checksum.",
550 function );
551
552 goto on_error;
553 }
554 if( libevtx_checksum_calculate_little_endian_crc32(
555 &calculated_checksum,
556 &( chunk_data[ 128 ] ),
557 384,
558 calculated_checksum,
559 error ) != 1 )
560 {
561 libcerror_error_set(
562 error,
563 LIBCERROR_ERROR_DOMAIN_RUNTIME,
564 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
565 "%s: unable to calculate CRC-32 checksum.",
566 function );
567
568 goto on_error;
569 }
570 if( stored_checksum != calculated_checksum )
571 {
572 #if defined( HAVE_VERBOSE_OUTPUT )
573 if( libcnotify_verbose != 0 )
574 {
575 libcnotify_printf(
576 "%s: mismatch in chunk: %" PRIu64 " header CRC-32 checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).\n",
577 function,
578 calculated_chunk_number,
579 stored_checksum,
580 calculated_checksum );
581 }
582 #endif
583 chunk->flags |= LIBEVTX_CHUNK_FLAG_IS_CORRUPTED;
584 }
585 chunk_data_offset = sizeof( evtx_chunk_header_t );
586
587 #if defined( HAVE_DEBUG_OUTPUT )
588 if( libcnotify_verbose != 0 )
589 {
590 libcnotify_printf(
591 "%s: chunk table data:\n",
592 function );
593 libcnotify_print_data(
594 &( chunk_data[ chunk_data_offset ] ),
595 384,
596 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
597 }
598 #endif
599 chunk_data_offset += 384;
600 /* TODO can free_space_offset be 0 ? */
601
602 if( ( free_space_offset < chunk_data_offset )
603 || ( free_space_offset > chunk_data_size ) )
604 {
605 libcerror_error_set(
606 error,
607 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
608 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
609 "%s: invalid free space offset value out of bounds.",
610 function );
611
612 goto on_error;
613 }
614 if( libevtx_checksum_calculate_little_endian_crc32(
615 &calculated_checksum,
616 &( chunk_data[ 512 ] ),
617 free_space_offset - chunk_data_offset,
618 0,
619 error ) != 1 )
620 {
621 libcerror_error_set(
622 error,
623 LIBCERROR_ERROR_DOMAIN_RUNTIME,
624 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
625 "%s: unable to calculate CRC-32 checksum.",
626 function );
627
628 goto on_error;
629 }
630 if( event_records_checksum != calculated_checksum )
631 {
632 #if defined( HAVE_VERBOSE_OUTPUT )
633 if( libcnotify_verbose != 0 )
634 {
635 libcnotify_printf(
636 "%s: mismatch in chunk: %" PRIu64 " event records CRC-32 checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).\n",
637 function,
638 calculated_chunk_number,
639 event_records_checksum,
640 calculated_checksum );
641 }
642 #endif
643 chunk->flags |= LIBEVTX_CHUNK_FLAG_IS_CORRUPTED;
644 }
645 while( chunk_data_offset <= last_event_record_offset )
646 {
647 if( libevtx_record_values_initialize(
648 &record_values,
649 error ) != 1 )
650 {
651 libcerror_error_set(
652 error,
653 LIBCERROR_ERROR_DOMAIN_RUNTIME,
654 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
655 "%s: unable to create record values.",
656 function );
657
658 goto on_error;
659 }
660 #if defined( HAVE_DEBUG_OUTPUT )
661 if( libcnotify_verbose != 0 )
662 {
663 libcnotify_printf(
664 "%s: reading record at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
665 function,
666 file_offset + chunk_data_offset,
667 file_offset + chunk_data_offset );
668 }
669 #endif
670 result = libevtx_record_values_read_header(
671 record_values,
672 io_handle,
673 chunk_data,
674 chunk_data_size,
675 chunk_data_offset,
676 error );
677
678 if( result == -1 )
679 {
680 libcerror_error_set(
681 error,
682 LIBCERROR_ERROR_DOMAIN_IO,
683 LIBCERROR_IO_ERROR_READ_FAILED,
684 "%s: unable to read record values header at offset: %" PRIi64 ".",
685 function,
686 file_offset + chunk_data_offset );
687
688 #if defined( HAVE_DEBUG_OUTPUT )
689 if( libcnotify_verbose != 0 )
690 {
691 if( ( error != NULL )
692 && ( *error != NULL ) )
693 {
694 libcnotify_print_error_backtrace(
695 *error );
696 }
697 }
698 #endif
699 libcerror_error_free(
700 error );
701 }
702 if( result != 1 )
703 {
704 break;
705 }
706 chunk_data_offset += record_values->data_size;
707
708 if( libcdata_array_append_entry(
709 chunk->records_array,
710 &entry_index,
711 (intptr_t *) record_values,
712 error ) != 1 )
713 {
714 libcerror_error_set(
715 error,
716 LIBCERROR_ERROR_DOMAIN_RUNTIME,
717 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
718 "%s: unable to append record values to records array.",
719 function );
720
721 goto on_error;
722 }
723 record_values = NULL;
724
725 number_of_event_records++;
726 }
727 if( first_event_record_number > last_event_record_number )
728 {
729 #if defined( HAVE_VERBOSE_OUTPUT )
730 if( libcnotify_verbose != 0 )
731 {
732 libcnotify_printf(
733 "%s: invalid chunk: %" PRIu64 " first event record number: %" PRIu64 " exceeds last event record number: %" PRIu64 ".\n",
734 function,
735 calculated_chunk_number,
736 first_event_record_number,
737 last_event_record_number );
738 }
739 #endif
740 chunk->flags |= LIBEVTX_CHUNK_FLAG_IS_CORRUPTED;
741 }
742 else if( result == 1 )
743 {
744 calculated_number_of_event_records = last_event_record_number - first_event_record_number + 1;
745
746 #if defined( HAVE_DEBUG_OUTPUT )
747 if( libcnotify_verbose != 0 )
748 {
749 libcnotify_printf(
750 "%s: calculated number of records\t\t\t: %" PRIu64 "\n",
751 function,
752 calculated_number_of_event_records );
753 }
754 #endif
755 if( number_of_event_records != calculated_number_of_event_records )
756 {
757 #if defined( HAVE_VERBOSE_OUTPUT )
758 if( libcnotify_verbose != 0 )
759 {
760 libcnotify_printf(
761 "%s: mismatch in chunk: %" PRIu64 " number of event records ( %" PRIu64 " != %" PRIu64 " ).\n",
762 function,
763 calculated_chunk_number,
764 number_of_event_records,
765 calculated_number_of_event_records );
766 }
767 #endif
768 chunk->flags |= LIBEVTX_CHUNK_FLAG_IS_CORRUPTED;
769 }
770 }
771 if( first_event_record_identifier > last_event_record_identifier )
772 {
773 #if defined( HAVE_VERBOSE_OUTPUT )
774 if( libcnotify_verbose != 0 )
775 {
776 libcnotify_printf(
777 "%s: in chunk: %" PRIu64 " first event record identifier: %" PRIu64 " exceeds last event record identifier: %" PRIu64 ".\n",
778 function,
779 calculated_chunk_number,
780 first_event_record_identifier,
781 last_event_record_identifier );
782 }
783 #endif
784 /* TODO mark this as corruption ? */
785 }
786 }
787 if( chunk_data_offset < chunk_data_size )
788 {
789 #if defined( HAVE_DEBUG_OUTPUT )
790 free_space_size = chunk_data_size - chunk_data_offset;
791
792 if( libcnotify_verbose != 0 )
793 {
794 libcnotify_printf(
795 "%s: free space data:\n",
796 function );
797 libcnotify_print_data(
798 &( chunk_data[ chunk_data_offset ] ),
799 free_space_size,
800 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
801 }
802 #endif
803 while( chunk_data_offset < ( chunk_data_size - 4 ) )
804 {
805 /* TODO optimize scan ? */
806 if( memory_compare(
807 &( chunk_data[ chunk_data_offset ] ),
808 evtx_event_record_signature,
809 4 ) == 0 )
810 {
811 if( record_values == NULL )
812 {
813 if( libevtx_record_values_initialize(
814 &record_values,
815 error ) != 1 )
816 {
817 libcerror_error_set(
818 error,
819 LIBCERROR_ERROR_DOMAIN_RUNTIME,
820 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
821 "%s: unable to create record values.",
822 function );
823
824 goto on_error;
825 }
826 }
827 #if defined( HAVE_DEBUG_OUTPUT )
828 if( libcnotify_verbose != 0 )
829 {
830 libcnotify_printf(
831 "%s: reading recovered record at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
832 function,
833 file_offset + chunk_data_offset,
834 file_offset + chunk_data_offset );
835 }
836 #endif
837 if( libevtx_record_values_read_header(
838 record_values,
839 io_handle,
840 chunk_data,
841 chunk_data_size,
842 chunk_data_offset,
843 error ) != 1 )
844 {
845 libcerror_error_set(
846 error,
847 LIBCERROR_ERROR_DOMAIN_IO,
848 LIBCERROR_IO_ERROR_READ_FAILED,
849 "%s: unable to read record values header at offset: %" PRIi64 ".",
850 function,
851 file_offset + chunk_data_offset );
852
853 #if defined( HAVE_DEBUG_OUTPUT )
854 if( libcnotify_verbose != 0 )
855 {
856 if( ( error != NULL )
857 && ( *error != NULL ) )
858 {
859 libcnotify_print_error_backtrace(
860 *error );
861 }
862 }
863 #endif
864 libcerror_error_free(
865 error );
866 }
867 else
868 {
869 xml_data_offset = chunk_data_offset + sizeof( evtx_event_record_header_t );
870 xml_data_size = 0;
871
872 if( record_values->data_size > ( sizeof( evtx_event_record_header_t ) + 4 ) )
873 {
874 xml_data_size = record_values->data_size - ( sizeof( evtx_event_record_header_t ) + 4 );
875 }
876 result = 0;
877
878 if( xml_data_size > 0 )
879 {
880 if( ( xml_data_size >= 5 )
881 && ( chunk_data[ xml_data_offset ] == 0x0a ) )
882 {
883 result = 1;
884 }
885 else if( ( xml_data_size >= 4 )
886 && ( chunk_data[ xml_data_offset ] == 0x0f )
887 && ( chunk_data[ xml_data_offset + 1 ] == 0x01 )
888 && ( chunk_data[ xml_data_offset + 2 ] == 0x01 )
889 && ( chunk_data[ xml_data_offset + 3 ] == 0x00 ) )
890 {
891 result = 1;
892 }
893 /* TODO what about 0x00 allow it ? */
894 }
895 if( result != 0 )
896 {
897 chunk_data_offset += record_values->data_size - 4;
898
899 if( libcdata_array_append_entry(
900 chunk->recovered_records_array,
901 &entry_index,
902 (intptr_t *) record_values,
903 error ) != 1 )
904 {
905 libcerror_error_set(
906 error,
907 LIBCERROR_ERROR_DOMAIN_RUNTIME,
908 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
909 "%s: unable to append record values to recovered records array.",
910 function );
911
912 goto on_error;
913 }
914 record_values = NULL;
915 }
916 }
917 }
918 chunk_data_offset += 4;
919 }
920 if( record_values != NULL )
921 {
922 if( libevtx_record_values_free(
923 &record_values,
924 error ) != 1 )
925 {
926 libcerror_error_set(
927 error,
928 LIBCERROR_ERROR_DOMAIN_RUNTIME,
929 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
930 "%s: unable to free record values.",
931 function );
932
933 goto on_error;
934 }
935 }
936 }
937 return( 1 );
938
939 on_error:
940 if( record_values != NULL )
941 {
942 libevtx_record_values_free(
943 &record_values,
944 NULL );
945 }
946 if( chunk->data != NULL )
947 {
948 memory_free(
949 chunk->data );
950
951 chunk->data = NULL;
952 }
953 return( -1 );
954 }
955
956 /* Retrieves the number of records
957 * Returns 1 if successful or -1 on error
958 */
libevtx_chunk_get_number_of_records(libevtx_chunk_t * chunk,uint16_t * number_of_records,libcerror_error_t ** error)959 int libevtx_chunk_get_number_of_records(
960 libevtx_chunk_t *chunk,
961 uint16_t *number_of_records,
962 libcerror_error_t **error )
963 {
964 static char *function = "libevtx_chunk_get_number_of_records";
965 int chunk_number_of_records = 0;
966
967 if( chunk == NULL )
968 {
969 libcerror_error_set(
970 error,
971 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
972 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
973 "%s: invalid chunk.",
974 function );
975
976 return( -1 );
977 }
978 if( number_of_records == NULL )
979 {
980 libcerror_error_set(
981 error,
982 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
983 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
984 "%s: invalid number of records.",
985 function );
986
987 return( -1 );
988 }
989 if( libcdata_array_get_number_of_entries(
990 chunk->records_array,
991 &chunk_number_of_records,
992 error ) != 1 )
993 {
994 libcerror_error_set(
995 error,
996 LIBCERROR_ERROR_DOMAIN_RUNTIME,
997 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
998 "%s: unable to retrieve number of records.",
999 function );
1000
1001 return( -1 );
1002 }
1003 if( chunk_number_of_records > (int) UINT16_MAX )
1004 {
1005 libcerror_error_set(
1006 error,
1007 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1008 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1009 "%s: invalid number of chunk records value exceeds maximum.",
1010 function );
1011
1012 return( -1 );
1013 }
1014 *number_of_records = (uint16_t) chunk_number_of_records;
1015
1016 return( 1 );
1017 }
1018
1019 /* Retrieves the record at the index
1020 * Returns 1 if successful or -1 on error
1021 */
libevtx_chunk_get_record(libevtx_chunk_t * chunk,uint16_t record_index,libevtx_record_values_t ** record_values,libcerror_error_t ** error)1022 int libevtx_chunk_get_record(
1023 libevtx_chunk_t *chunk,
1024 uint16_t record_index,
1025 libevtx_record_values_t **record_values,
1026 libcerror_error_t **error )
1027 {
1028 static char *function = "libevtx_chunk_get_record";
1029
1030 if( chunk == NULL )
1031 {
1032 libcerror_error_set(
1033 error,
1034 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1035 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1036 "%s: invalid chunk.",
1037 function );
1038
1039 return( -1 );
1040 }
1041 if( libcdata_array_get_entry_by_index(
1042 chunk->records_array,
1043 (int) record_index,
1044 (intptr_t **) record_values,
1045 error ) != 1 )
1046 {
1047 libcerror_error_set(
1048 error,
1049 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1050 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1051 "%s: unable to retrieve record: %" PRIu16 ".",
1052 function,
1053 record_index );
1054
1055 return( -1 );
1056 }
1057 return( 1 );
1058 }
1059
1060 /* Retrieves the number of recovered records
1061 * Returns 1 if successful or -1 on error
1062 */
libevtx_chunk_get_number_of_recovered_records(libevtx_chunk_t * chunk,uint16_t * number_of_records,libcerror_error_t ** error)1063 int libevtx_chunk_get_number_of_recovered_records(
1064 libevtx_chunk_t *chunk,
1065 uint16_t *number_of_records,
1066 libcerror_error_t **error )
1067 {
1068 static char *function = "libevtx_chunk_get_number_of_recovered_records";
1069 int chunk_number_of_records = 0;
1070
1071 if( chunk == NULL )
1072 {
1073 libcerror_error_set(
1074 error,
1075 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1076 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1077 "%s: invalid chunk.",
1078 function );
1079
1080 return( -1 );
1081 }
1082 if( number_of_records == NULL )
1083 {
1084 libcerror_error_set(
1085 error,
1086 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1087 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1088 "%s: invalid number of records.",
1089 function );
1090
1091 return( -1 );
1092 }
1093 if( libcdata_array_get_number_of_entries(
1094 chunk->recovered_records_array,
1095 &chunk_number_of_records,
1096 error ) != 1 )
1097 {
1098 libcerror_error_set(
1099 error,
1100 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1101 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1102 "%s: unable to retrieve number of records.",
1103 function );
1104
1105 return( -1 );
1106 }
1107 if( chunk_number_of_records > (int) UINT16_MAX )
1108 {
1109 libcerror_error_set(
1110 error,
1111 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1112 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1113 "%s: invalid number of chunk records value exceeds maximum.",
1114 function );
1115
1116 return( -1 );
1117 }
1118 *number_of_records = (uint16_t) chunk_number_of_records;
1119
1120 return( 1 );
1121 }
1122
1123 /* Retrieves the recovered record at the index
1124 * Returns 1 if successful or -1 on error
1125 */
libevtx_chunk_get_recovered_record(libevtx_chunk_t * chunk,uint16_t record_index,libevtx_record_values_t ** record_values,libcerror_error_t ** error)1126 int libevtx_chunk_get_recovered_record(
1127 libevtx_chunk_t *chunk,
1128 uint16_t record_index,
1129 libevtx_record_values_t **record_values,
1130 libcerror_error_t **error )
1131 {
1132 static char *function = "libevtx_chunk_get_recovered_record";
1133
1134 if( chunk == NULL )
1135 {
1136 libcerror_error_set(
1137 error,
1138 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1139 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1140 "%s: invalid chunk.",
1141 function );
1142
1143 return( -1 );
1144 }
1145 if( libcdata_array_get_entry_by_index(
1146 chunk->recovered_records_array,
1147 (int) record_index,
1148 (intptr_t **) record_values,
1149 error ) != 1 )
1150 {
1151 libcerror_error_set(
1152 error,
1153 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1154 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
1155 "%s: unable to retrieve record: %" PRIu16 ".",
1156 function,
1157 record_index );
1158
1159 return( -1 );
1160 }
1161 return( 1 );
1162 }
1163
1164