Coverage Report

Created: 2026-04-10 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libregf/libregf/libregf_file_header.c
Line
Count
Source
1
/*
2
 * File header functions
3
 *
4
 * Copyright (C) 2009-2025, 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 "libregf_checksum.h"
28
#include "libregf_debug.h"
29
#include "libregf_file_header.h"
30
#include "libregf_io_handle.h"
31
#include "libregf_libcerror.h"
32
#include "libregf_libcnotify.h"
33
#include "libregf_libfdatetime.h"
34
35
#include "regf_file_header.h"
36
37
/* Creates a file header
38
 * Make sure the value file_header is referencing, is set to NULL
39
 * Returns 1 if successful or -1 on error
40
 */
41
int libregf_file_header_initialize(
42
     libregf_file_header_t **file_header,
43
     libcerror_error_t **error )
44
4.15k
{
45
4.15k
  static char *function = "libregf_file_header_initialize";
46
47
4.15k
  if( file_header == NULL )
48
0
  {
49
0
    libcerror_error_set(
50
0
     error,
51
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
52
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
53
0
     "%s: invalid file header.",
54
0
     function );
55
56
0
    return( -1 );
57
0
  }
58
4.15k
  if( *file_header != NULL )
59
0
  {
60
0
    libcerror_error_set(
61
0
     error,
62
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
63
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
64
0
     "%s: invalid file header value already set.",
65
0
     function );
66
67
0
    return( -1 );
68
0
  }
69
4.15k
  *file_header = memory_allocate_structure(
70
4.15k
                  libregf_file_header_t );
71
72
4.15k
  if( *file_header == NULL )
73
0
  {
74
0
    libcerror_error_set(
75
0
     error,
76
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
77
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
78
0
     "%s: unable to create file header.",
79
0
     function );
80
81
0
    goto on_error;
82
0
  }
83
4.15k
  if( memory_set(
84
4.15k
       *file_header,
85
4.15k
       0,
86
4.15k
       sizeof( libregf_file_header_t ) ) == NULL )
87
0
  {
88
0
    libcerror_error_set(
89
0
     error,
90
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
91
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
92
0
     "%s: unable to clear file header.",
93
0
     function );
94
95
0
    goto on_error;
96
0
  }
97
4.15k
  return( 1 );
98
99
0
on_error:
100
0
  if( *file_header != NULL )
101
0
  {
102
0
    memory_free(
103
0
     *file_header );
104
105
0
    *file_header = NULL;
106
0
  }
107
0
  return( -1 );
108
4.15k
}
109
110
/* Frees a file header
111
 * Returns 1 if successful or -1 on error
112
 */
113
int libregf_file_header_free(
114
     libregf_file_header_t **file_header,
115
     libcerror_error_t **error )
116
4.15k
{
117
4.15k
  static char *function = "libregf_file_header_free";
118
119
4.15k
  if( file_header == NULL )
120
0
  {
121
0
    libcerror_error_set(
122
0
     error,
123
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
124
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
125
0
     "%s: invalid file header.",
126
0
     function );
127
128
0
    return( -1 );
129
0
  }
130
4.15k
  if( *file_header != NULL )
131
4.15k
  {
132
4.15k
    memory_free(
133
4.15k
     *file_header );
134
135
4.15k
    *file_header = NULL;
136
4.15k
  }
137
4.15k
  return( 1 );
138
4.15k
}
139
140
/* Reads the file header data
141
 * Returns 1 if successful or -1 on error
142
 */
143
int libregf_file_header_read_data(
144
     libregf_file_header_t *file_header,
145
     const uint8_t *data,
146
     size_t data_size,
147
     libcerror_error_t **error )
148
4.10k
{
149
4.10k
  static char *function              = "libregf_file_header_read_data";
150
4.10k
  uint32_t calculated_xor32_checksum = 0;
151
4.10k
  uint32_t stored_xor32_checksum     = 0;
152
153
#if defined( HAVE_DEBUG_OUTPUT )
154
  uint32_t value_32bit               = 0;
155
#endif
156
157
4.10k
  if( file_header == NULL )
158
0
  {
159
0
    libcerror_error_set(
160
0
     error,
161
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
162
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
163
0
     "%s: invalid file header.",
164
0
     function );
165
166
0
    return( -1 );
167
0
  }
168
4.10k
  if( data == NULL )
169
0
  {
170
0
    libcerror_error_set(
171
0
     error,
172
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
173
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
174
0
     "%s: invalid data.",
175
0
     function );
176
177
0
    return( -1 );
178
0
  }
179
4.10k
  if( ( data_size < sizeof( regf_file_header_t ) )
180
4.10k
   || ( data_size > (size_t) SSIZE_MAX ) )
181
0
  {
182
0
    libcerror_error_set(
183
0
     error,
184
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
185
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
186
0
     "%s: invalid data size value out of bounds.",
187
0
     function );
188
189
0
    return( -1 );
190
0
  }
191
#if defined( HAVE_DEBUG_OUTPUT )
192
  if( libcnotify_verbose != 0 )
193
  {
194
    libcnotify_printf(
195
     "%s: file header data:\n",
196
     function );
197
    libcnotify_print_data(
198
     data,
199
     sizeof( regf_file_header_t ),
200
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
201
  }
202
#endif
203
4.10k
  if( memory_compare(
204
4.10k
       ( (regf_file_header_t *) data )->signature,
205
4.10k
       regf_file_signature,
206
4.10k
       4 ) != 0 )
207
115
  {
208
115
    libcerror_error_set(
209
115
     error,
210
115
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
211
115
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
212
115
     "%s: invalid file signature.",
213
115
     function );
214
215
115
    return( -1 );
216
115
  }
217
3.99k
  if( libregf_checksum_calculate_little_endian_xor32(
218
3.99k
       &calculated_xor32_checksum,
219
3.99k
       data,
220
3.99k
       508,
221
3.99k
       0,
222
3.99k
       error ) != 1 )
223
0
  {
224
0
    libcerror_error_set(
225
0
     error,
226
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
227
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
228
0
     "%s: unable to calculate XOR-32 checksum.",
229
0
     function );
230
231
0
    return( -1 );
232
0
  }
233
3.99k
  byte_stream_copy_to_uint32_little_endian(
234
3.99k
   ( (regf_file_header_t *) data )->checksum,
235
3.99k
   stored_xor32_checksum );
236
237
3.99k
  if( stored_xor32_checksum != calculated_xor32_checksum )
238
156
  {
239
156
    libcerror_error_set(
240
156
     error,
241
156
     LIBCERROR_ERROR_DOMAIN_INPUT,
242
156
     LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH,
243
156
     "%s: mismatch in file header checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).",
244
156
     function,
245
156
     stored_xor32_checksum,
246
156
     calculated_xor32_checksum );
247
248
156
    return( -1 );
249
156
  }
250
3.83k
  byte_stream_copy_to_uint32_little_endian(
251
3.83k
   ( (regf_file_header_t *) data )->major_format_version,
252
3.83k
   file_header->major_format_version );
253
254
3.83k
  byte_stream_copy_to_uint32_little_endian(
255
3.83k
   ( (regf_file_header_t *) data )->minor_format_version,
256
3.83k
   file_header->minor_format_version );
257
258
3.83k
  byte_stream_copy_to_uint32_little_endian(
259
3.83k
   ( (regf_file_header_t *) data )->file_type,
260
3.83k
   file_header->file_type );
261
262
3.83k
  byte_stream_copy_to_uint32_little_endian(
263
3.83k
   ( (regf_file_header_t *) data )->root_key_offset,
264
3.83k
   file_header->root_key_offset );
265
266
3.83k
  byte_stream_copy_to_uint32_little_endian(
267
3.83k
   ( (regf_file_header_t *) data )->hive_bins_size,
268
3.83k
   file_header->hive_bins_size );
269
270
#if defined( HAVE_DEBUG_OUTPUT )
271
  if( libcnotify_verbose != 0 )
272
  {
273
    libcnotify_printf(
274
     "%s: signature\t\t\t\t: %c%c%c%c\n",
275
     function,
276
     ( (regf_file_header_t *) data )->signature[ 0 ],
277
     ( (regf_file_header_t *) data )->signature[ 1 ],
278
     ( (regf_file_header_t *) data )->signature[ 2 ],
279
     ( (regf_file_header_t *) data )->signature[ 3 ] );
280
281
    byte_stream_copy_to_uint32_little_endian(
282
     ( (regf_file_header_t *) data )->primary_sequence_number,
283
     value_32bit );
284
    libcnotify_printf(
285
     "%s: primary sequence number\t\t\t: %" PRIu32 "\n",
286
     function,
287
     value_32bit );
288
    byte_stream_copy_to_uint32_little_endian(
289
     ( (regf_file_header_t *) data )->secondary_sequence_number,
290
     value_32bit );
291
    libcnotify_printf(
292
     "%s: secondary sequence number\t\t: %" PRIu32 "\n",
293
     function,
294
     value_32bit );
295
296
    if( libregf_debug_print_filetime_value(
297
         function,
298
         "modification time\t\t\t",
299
         ( (regf_file_header_t *) data )->modification_time,
300
         8,
301
         LIBFDATETIME_ENDIAN_LITTLE,
302
         LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
303
         error ) != 1 )
304
    {
305
      libcerror_error_set(
306
       error,
307
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
308
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
309
       "%s: unable to print FILETIME value.",
310
       function );
311
312
      return( -1 );
313
    }
314
    libcnotify_printf(
315
     "%s: major format version\t\t\t: %" PRIu32 "\n",
316
     function,
317
     file_header->major_format_version );
318
319
    libcnotify_printf(
320
     "%s: minor format version\t\t\t: %" PRIu32 "\n",
321
     function,
322
     file_header->minor_format_version );
323
324
    libcnotify_printf(
325
     "%s: file type\t\t\t\t: %" PRIu32 "\n",
326
     function,
327
     file_header->file_type );
328
329
    byte_stream_copy_to_uint32_little_endian(
330
     ( (regf_file_header_t *) data )->unknown1,
331
     value_32bit );
332
    libcnotify_printf(
333
     "%s: unknown1\t\t\t\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n",
334
     function,
335
     value_32bit,
336
     value_32bit );
337
338
    libcnotify_printf(
339
     "%s: root key offset\t\t\t\t: 0x%08" PRIx32 "\n",
340
     function,
341
     file_header->root_key_offset );
342
343
    libcnotify_printf(
344
     "%s: hive bins size\t\t\t\t: %" PRIu32 " bytes\n",
345
     function,
346
     file_header->hive_bins_size );
347
348
    byte_stream_copy_to_uint32_little_endian(
349
     ( (regf_file_header_t *) data )->unknown2,
350
     value_32bit );
351
    libcnotify_printf(
352
     "%s: unknown2\t\t\t\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n",
353
     function,
354
     value_32bit,
355
     value_32bit );
356
357
    libcnotify_printf(
358
     "%s: unknown3:\n",
359
     function );
360
    libcnotify_print_data(
361
     ( (regf_file_header_t *) data )->unknown3,
362
     64,
363
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
364
365
    libcnotify_printf(
366
     "%s: unknown4:\n",
367
     function );
368
    libcnotify_print_data(
369
     ( (regf_file_header_t *) data )->unknown4,
370
     396,
371
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
372
373
    libcnotify_printf(
374
     "%s: checksum\t\t\t\t\t: 0x%08" PRIx32 "\n",
375
     function,
376
     stored_xor32_checksum );
377
378
    libcnotify_printf(
379
     "\n" );
380
  }
381
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
382
383
3.83k
  return( 1 );
384
3.99k
}
385
386
/* Reads the file header
387
 * Returns 1 if successful or -1 on error
388
 */
389
int libregf_file_header_read_file_io_handle(
390
     libregf_file_header_t *file_header,
391
     libbfio_handle_t *file_io_handle,
392
     libcerror_error_t **error )
393
4.15k
{
394
4.15k
  uint8_t file_header_data[ sizeof( regf_file_header_t ) ];
395
396
4.15k
  static char *function = "libregf_file_header_read_file_io_handle";
397
4.15k
  ssize_t read_count    = 0;
398
399
4.15k
  if( file_header == NULL )
400
0
  {
401
0
    libcerror_error_set(
402
0
     error,
403
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
404
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
405
0
     "%s: invalid file header.",
406
0
     function );
407
408
0
    return( -1 );
409
0
  }
410
#if defined( HAVE_DEBUG_OUTPUT )
411
  if( libcnotify_verbose != 0 )
412
  {
413
    libcnotify_printf(
414
     "%s: reading file header at offset: 0 (0x00000000)\n",
415
     function );
416
  }
417
#endif
418
4.15k
  read_count = libbfio_handle_read_buffer_at_offset(
419
4.15k
                file_io_handle,
420
4.15k
                file_header_data,
421
4.15k
                sizeof( regf_file_header_t ),
422
4.15k
                0,
423
4.15k
                error );
424
425
4.15k
  if( read_count != (ssize_t) sizeof( regf_file_header_t ) )
426
48
  {
427
48
    libcerror_error_set(
428
48
     error,
429
48
     LIBCERROR_ERROR_DOMAIN_IO,
430
48
     LIBCERROR_IO_ERROR_READ_FAILED,
431
48
     "%s: unable to read file header data at offset: 0 (0x00000000).",
432
48
     function );
433
434
48
    return( -1 );
435
48
  }
436
4.10k
  if( libregf_file_header_read_data(
437
4.10k
       file_header,
438
4.10k
       file_header_data,
439
4.10k
       sizeof( regf_file_header_t ),
440
4.10k
       error ) != 1 )
441
271
  {
442
271
    libcerror_error_set(
443
271
     error,
444
271
     LIBCERROR_ERROR_DOMAIN_IO,
445
271
     LIBCERROR_IO_ERROR_READ_FAILED,
446
271
     "%s: unable to read file header.",
447
271
     function );
448
449
271
    return( -1 );
450
271
  }
451
3.83k
  return( 1 );
452
4.10k
}
453