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