Coverage Report

Created: 2024-02-25 07:20

/src/libevtx/libevtx/libevtx_io_handle.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Input/Output (IO) handle 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 "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
 */
47
int libevtx_io_handle_initialize(
48
     libevtx_io_handle_t **io_handle,
49
     libcerror_error_t **error )
50
2.90k
{
51
2.90k
  static char *function = "libevtx_io_handle_initialize";
52
53
2.90k
  if( io_handle == NULL )
54
0
  {
55
0
    libcerror_error_set(
56
0
     error,
57
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
58
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
59
0
     "%s: invalid IO handle.",
60
0
     function );
61
62
0
    return( -1 );
63
0
  }
64
2.90k
  if( *io_handle != NULL )
65
0
  {
66
0
    libcerror_error_set(
67
0
     error,
68
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
69
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
70
0
     "%s: invalid IO handle value already set.",
71
0
     function );
72
73
0
    return( -1 );
74
0
  }
75
2.90k
  *io_handle = memory_allocate_structure(
76
2.90k
                libevtx_io_handle_t );
77
78
2.90k
  if( *io_handle == NULL )
79
0
  {
80
0
    libcerror_error_set(
81
0
     error,
82
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
83
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
84
0
     "%s: unable to create IO handle.",
85
0
     function );
86
87
0
    goto on_error;
88
0
  }
89
2.90k
  if( memory_set(
90
2.90k
       *io_handle,
91
2.90k
       0,
92
2.90k
       sizeof( libevtx_io_handle_t ) ) == NULL )
93
0
  {
94
0
    libcerror_error_set(
95
0
     error,
96
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
97
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
98
0
     "%s: unable to clear IO handle.",
99
0
     function );
100
101
0
    goto on_error;
102
0
  }
103
2.90k
  ( *io_handle )->chunk_size     = 0x00010000UL;
104
2.90k
  ( *io_handle )->ascii_codepage = LIBEVTX_CODEPAGE_WINDOWS_1252;
105
106
2.90k
  return( 1 );
107
108
0
on_error:
109
0
  if( *io_handle != NULL )
110
0
  {
111
0
    memory_free(
112
0
     *io_handle );
113
114
0
    *io_handle = NULL;
115
0
  }
116
0
  return( -1 );
117
2.90k
}
118
119
/* Frees an IO handle
120
 * Returns 1 if successful or -1 on error
121
 */
122
int libevtx_io_handle_free(
123
     libevtx_io_handle_t **io_handle,
124
     libcerror_error_t **error )
125
2.90k
{
126
2.90k
  static char *function = "libevtx_io_handle_free";
127
2.90k
  int result            = 1;
128
129
2.90k
  if( io_handle == NULL )
130
0
  {
131
0
    libcerror_error_set(
132
0
     error,
133
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
134
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
135
0
     "%s: invalid IO handle.",
136
0
     function );
137
138
0
    return( -1 );
139
0
  }
140
2.90k
  if( *io_handle != NULL )
141
2.90k
  {
142
2.90k
    memory_free(
143
2.90k
     *io_handle );
144
145
2.90k
    *io_handle = NULL;
146
2.90k
  }
147
2.90k
  return( result );
148
2.90k
}
149
150
/* Clears the IO handle
151
 * Returns 1 if successful or -1 on error
152
 */
153
int libevtx_io_handle_clear(
154
     libevtx_io_handle_t *io_handle,
155
     libcerror_error_t **error )
156
2.43k
{
157
2.43k
  static char *function = "libevtx_io_handle_clear";
158
159
2.43k
  if( io_handle == NULL )
160
0
  {
161
0
    libcerror_error_set(
162
0
     error,
163
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
164
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
165
0
     "%s: invalid IO handle.",
166
0
     function );
167
168
0
    return( -1 );
169
0
  }
170
2.43k
  if( memory_set(
171
2.43k
       io_handle,
172
2.43k
       0,
173
2.43k
       sizeof( libevtx_io_handle_t ) ) == NULL )
174
0
  {
175
0
    libcerror_error_set(
176
0
     error,
177
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
178
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
179
0
     "%s: unable to clear IO handle.",
180
0
     function );
181
182
0
    return( -1 );
183
0
  }
184
2.43k
  io_handle->chunk_size     = 0x00010000UL;
185
2.43k
  io_handle->ascii_codepage = LIBEVTX_CODEPAGE_WINDOWS_1252;
186
187
2.43k
  return( 1 );
188
2.43k
}
189
190
/* Reads the file (or database) header
191
 * Returns 1 if successful or -1 on error
192
 */
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
2.90k
{
199
2.90k
  uint8_t *file_header_data    = NULL;
200
2.90k
  static char *function        = "libevtx_io_handle_read_file_header";
201
2.90k
  size_t read_size             = 4096;
202
2.90k
  ssize_t read_count           = 0;
203
2.90k
  uint32_t calculated_checksum = 0;
204
2.90k
  uint32_t stored_checksum     = 0;
205
2.90k
  uint16_t first_chunk_number  = 0;
206
2.90k
  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
2.90k
  if( io_handle == NULL )
214
0
  {
215
0
    libcerror_error_set(
216
0
     error,
217
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
218
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
219
0
     "%s: invalid IO handle.",
220
0
     function );
221
222
0
    return( -1 );
223
0
  }
224
2.90k
  file_header_data = (uint8_t *) memory_allocate(
225
2.90k
                                  sizeof( uint8_t ) * read_size );
226
227
2.90k
  if( file_header_data == NULL )
228
0
  {
229
0
    libcerror_error_set(
230
0
     error,
231
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
232
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
233
0
     "%s: unable to create file header data.",
234
0
     function );
235
236
0
    return( -1 );
237
0
  }
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
2.90k
  read_count = libbfio_handle_read_buffer_at_offset(
249
2.90k
                file_io_handle,
250
2.90k
                file_header_data,
251
2.90k
                read_size,
252
2.90k
                file_offset,
253
2.90k
                error );
254
255
2.90k
  if( read_count != (ssize_t) read_size )
256
68
  {
257
68
    libcerror_error_set(
258
68
     error,
259
68
     LIBCERROR_ERROR_DOMAIN_IO,
260
68
     LIBCERROR_IO_ERROR_READ_FAILED,
261
68
     "%s: unable to read file header at offset: %" PRIi64 " (0x%08" PRIx64 ").",
262
68
     function,
263
68
     file_offset,
264
68
     file_offset );
265
266
68
    goto on_error;
267
68
  }
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
2.83k
  if( memory_compare(
281
2.83k
       ( (evtx_file_header_t *) file_header_data )->signature,
282
2.83k
       evtx_file_signature,
283
2.83k
       8 ) != 0 )
284
148
  {
285
148
    libcerror_error_set(
286
148
     error,
287
148
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
288
148
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
289
148
     "%s: unsupported file signature.",
290
148
     function );
291
292
148
    goto on_error;
293
148
  }
294
2.68k
  byte_stream_copy_to_uint64_little_endian(
295
2.68k
   ( (evtx_file_header_t *) file_header_data )->first_chunk_number,
296
2.68k
   first_chunk_number );
297
298
2.68k
  byte_stream_copy_to_uint64_little_endian(
299
2.68k
   ( (evtx_file_header_t *) file_header_data )->last_chunk_number,
300
2.68k
   last_chunk_number );
301
302
2.68k
  byte_stream_copy_to_uint16_little_endian(
303
2.68k
   ( (evtx_file_header_t *) file_header_data )->minor_version,
304
2.68k
   io_handle->minor_version );
305
306
2.68k
  byte_stream_copy_to_uint16_little_endian(
307
2.68k
   ( (evtx_file_header_t *) file_header_data )->major_version,
308
2.68k
   io_handle->major_version );
309
310
2.68k
  byte_stream_copy_to_uint16_little_endian(
311
2.68k
   ( (evtx_file_header_t *) file_header_data )->header_block_size,
312
2.68k
   io_handle->chunks_data_offset );
313
314
2.68k
  byte_stream_copy_to_uint16_little_endian(
315
2.68k
   ( (evtx_file_header_t *) file_header_data )->number_of_chunks,
316
2.68k
   io_handle->number_of_chunks );
317
318
2.68k
  byte_stream_copy_to_uint32_little_endian(
319
2.68k
   ( (evtx_file_header_t *) file_header_data )->file_flags,
320
2.68k
   io_handle->file_flags );
321
322
2.68k
  byte_stream_copy_to_uint32_little_endian(
323
2.68k
   ( (evtx_file_header_t *) file_header_data )->checksum,
324
2.68k
   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
2.68k
  if( libevtx_checksum_calculate_little_endian_crc32(
415
2.68k
       &calculated_checksum,
416
2.68k
       file_header_data,
417
2.68k
       120,
418
2.68k
       0,
419
2.68k
       error ) != 1 )
420
0
  {
421
0
    libcerror_error_set(
422
0
     error,
423
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
424
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
425
0
     "%s: unable to calculate CRC-32 checksum.",
426
0
     function );
427
428
0
    goto on_error;
429
0
  }
430
2.68k
  if( stored_checksum != calculated_checksum )
431
2.65k
  {
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
2.65k
    io_handle->flags |= LIBEVTX_IO_HANDLE_FLAG_IS_CORRUPTED;
443
2.65k
  }
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
2.68k
  if( first_chunk_number > last_chunk_number )
457
1.11k
  {
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
1.11k
    io_handle->flags |= LIBEVTX_IO_HANDLE_FLAG_IS_CORRUPTED;
469
1.11k
  }
470
1.56k
  else if( io_handle->number_of_chunks != ( last_chunk_number - first_chunk_number + 1 ) )
471
1.14k
  {
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
1.14k
    io_handle->flags |= LIBEVTX_IO_HANDLE_FLAG_IS_CORRUPTED;
483
1.14k
  }
484
2.68k
  memory_free(
485
2.68k
   file_header_data );
486
487
2.68k
  file_header_data = NULL;
488
489
2.68k
  return( 1 );
490
491
216
on_error:
492
216
  if( file_header_data != NULL )
493
216
  {
494
216
    memory_free(
495
216
     file_header_data );
496
216
  }
497
216
  return( -1 );
498
2.68k
}
499
500
/* Reads a chunk
501
 * Callback function for the chunk vector
502
 * Returns 1 if successful or -1 on error
503
 */
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
1.54k
{
517
1.54k
  libevtx_chunk_t *chunk = NULL;
518
1.54k
  static char *function  = "libevtx_io_handle_read_chunk";
519
520
1.54k
  LIBEVTX_UNREFERENCED_PARAMETER( element_data_file_index );
521
1.54k
  LIBEVTX_UNREFERENCED_PARAMETER( element_data_size );
522
1.54k
  LIBEVTX_UNREFERENCED_PARAMETER( element_data_flags );
523
1.54k
  LIBEVTX_UNREFERENCED_PARAMETER( read_flags );
524
525
1.54k
  if( libevtx_chunk_initialize(
526
1.54k
       &chunk,
527
1.54k
       error ) != 1 )
528
0
  {
529
0
    libcerror_error_set(
530
0
     error,
531
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
532
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
533
0
     "%s: unable to create chunk.",
534
0
     function );
535
536
0
    goto on_error;
537
0
  }
538
1.54k
  if( libevtx_chunk_read(
539
1.54k
       chunk,
540
1.54k
       io_handle,
541
1.54k
       file_io_handle,
542
1.54k
       element_data_offset,
543
1.54k
       error ) != 1 )
544
0
  {
545
0
    libcerror_error_set(
546
0
     error,
547
0
     LIBCERROR_ERROR_DOMAIN_IO,
548
0
     LIBCERROR_IO_ERROR_READ_FAILED,
549
0
     "%s: unable to read chunk.",
550
0
     function );
551
552
0
    goto on_error;
553
0
  }
554
1.54k
  if( libfdata_vector_set_element_value_by_index(
555
1.54k
       vector,
556
1.54k
       (intptr_t *) file_io_handle,
557
1.54k
       cache,
558
1.54k
       element_index,
559
1.54k
       (intptr_t *) chunk,
560
1.54k
       (int (*)(intptr_t **, libcerror_error_t **)) &libevtx_chunk_free,
561
1.54k
       LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
562
1.54k
       error ) != 1 )
563
0
  {
564
0
    libcerror_error_set(
565
0
     error,
566
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
567
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
568
0
     "%s: unable to set chunk as element value.",
569
0
     function );
570
571
0
    goto on_error;
572
0
  }
573
1.54k
  return( 1 );
574
575
0
on_error:
576
0
  if( chunk != NULL )
577
0
  {
578
0
    libevtx_chunk_free(
579
0
     &chunk,
580
0
     NULL );
581
0
  }
582
0
  return( -1 );
583
1.54k
}
584