Coverage Report

Created: 2026-03-05 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libexe/libexe/libexe_io_handle.c
Line
Count
Source
1
/*
2
 * Input/Output (IO) handle functions
3
 *
4
 * Copyright (C) 2011-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 <narrow_string.h>
26
#include <system_string.h>
27
#include <types.h>
28
29
#include "libexe_codepage.h"
30
#include "libexe_coff_header.h"
31
#include "libexe_coff_optional_header.h"
32
#include "libexe_data_directory_descriptor.h"
33
#include "libexe_debug.h"
34
#include "libexe_definitions.h"
35
#include "libexe_io_handle.h"
36
#include "libexe_le_header.h"
37
#include "libexe_libbfio.h"
38
#include "libexe_libcerror.h"
39
#include "libexe_libcdata.h"
40
#include "libexe_libcnotify.h"
41
#include "libexe_libfdatetime.h"
42
#include "libexe_mz_header.h"
43
#include "libexe_ne_header.h"
44
#include "libexe_section_descriptor.h"
45
#include "libexe_unused.h"
46
47
#include "exe_file_header.h"
48
#include "exe_mz_header.h"
49
#include "exe_pe_header.h"
50
#include "exe_section_table.h"
51
52
const char *exe_pe_signature = "PE\x0\x0";
53
54
/* Creates an IO handle
55
 * Make sure the value io_handle is referencing, is set to NULL
56
 * Returns 1 if successful or -1 on error
57
 */
58
int libexe_io_handle_initialize(
59
     libexe_io_handle_t **io_handle,
60
     libcerror_error_t **error )
61
871
{
62
871
  static char *function = "libexe_io_handle_initialize";
63
64
871
  if( io_handle == NULL )
65
0
  {
66
0
    libcerror_error_set(
67
0
     error,
68
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
69
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
70
0
     "%s: invalid IO handle.",
71
0
     function );
72
73
0
    return( -1 );
74
0
  }
75
871
  if( *io_handle != NULL )
76
0
  {
77
0
    libcerror_error_set(
78
0
     error,
79
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
80
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
81
0
     "%s: invalid IO handle value already set.",
82
0
     function );
83
84
0
    return( -1 );
85
0
  }
86
871
  *io_handle = memory_allocate_structure(
87
871
                libexe_io_handle_t );
88
89
871
  if( *io_handle == NULL )
90
0
  {
91
0
    libcerror_error_set(
92
0
     error,
93
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
94
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
95
0
     "%s: unable to create IO handle.",
96
0
     function );
97
98
0
    goto on_error;
99
0
  }
100
871
  if( memory_set(
101
871
       *io_handle,
102
871
       0,
103
871
       sizeof( libexe_io_handle_t ) ) == NULL )
104
0
  {
105
0
    libcerror_error_set(
106
0
     error,
107
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
108
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
109
0
     "%s: unable to clear file.",
110
0
     function );
111
112
0
    memory_free(
113
0
     *io_handle );
114
115
0
    *io_handle = NULL;
116
117
0
    return( -1 );
118
0
  }
119
871
  ( *io_handle )->executable_type = LIBEXE_EXECUTABLE_TYPE_MZ;
120
871
  ( *io_handle )->ascii_codepage  = LIBEXE_CODEPAGE_WINDOWS_1252;
121
122
871
  return( 1 );
123
124
0
on_error:
125
0
  if( *io_handle != NULL )
126
0
  {
127
0
    memory_free(
128
0
     *io_handle );
129
130
0
    *io_handle = NULL;
131
0
  }
132
0
  return( -1 );
133
871
}
134
135
/* Frees an IO handle
136
 * Returns 1 if successful or -1 on error
137
 */
138
int libexe_io_handle_free(
139
     libexe_io_handle_t **io_handle,
140
     libcerror_error_t **error )
141
871
{
142
871
  static char *function = "libexe_io_handle_free";
143
871
  int result            = 1;
144
145
871
  if( io_handle == NULL )
146
0
  {
147
0
    libcerror_error_set(
148
0
     error,
149
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
150
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
151
0
     "%s: invalid IO handle.",
152
0
     function );
153
154
0
    return( -1 );
155
0
  }
156
871
  if( *io_handle != NULL )
157
871
  {
158
871
    if( libexe_io_handle_clear(
159
871
         *io_handle,
160
871
         error ) != 1 )
161
0
    {
162
0
      libcerror_error_set(
163
0
       error,
164
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
165
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
166
0
       "%s: unable to clear IO handle.",
167
0
       function );
168
169
0
      result = -1;
170
0
    }
171
871
    if( ( *io_handle )->coff_header != NULL )
172
0
    {
173
0
      if( libexe_coff_header_free(
174
0
           &( ( *io_handle )->coff_header ),
175
0
           error ) != 1 )
176
0
      {
177
0
        libcerror_error_set(
178
0
         error,
179
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
180
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
181
0
         "%s: unable to free COFF header.",
182
0
         function );
183
184
0
        result = -1;
185
0
      }
186
0
    }
187
871
    if( ( *io_handle )->coff_optional_header != NULL )
188
0
    {
189
0
      if( libexe_coff_optional_header_free(
190
0
           &( ( *io_handle )->coff_optional_header ),
191
0
           error ) != 1 )
192
0
      {
193
0
        libcerror_error_set(
194
0
         error,
195
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
196
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
197
0
         "%s: unable to free COFF optional header.",
198
0
         function );
199
200
0
        result = -1;
201
0
      }
202
0
    }
203
871
    memory_free(
204
871
     *io_handle );
205
206
871
    *io_handle = NULL;
207
871
  }
208
871
  return( result );
209
871
}
210
211
/* Clears the IO handle
212
 * Returns 1 if successful or -1 on error
213
 */
214
int libexe_io_handle_clear(
215
     libexe_io_handle_t *io_handle,
216
     libcerror_error_t **error )
217
951
{
218
951
  static char *function = "libexe_io_handle_clear";
219
220
951
  if( io_handle == NULL )
221
0
  {
222
0
    libcerror_error_set(
223
0
     error,
224
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
225
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
226
0
     "%s: invalid IO handle.",
227
0
     function );
228
229
0
    return( -1 );
230
0
  }
231
/* TODO refactor
232
  if( memory_set(
233
       io_handle,
234
       0,
235
       sizeof( libexe_io_handle_t ) ) == NULL )
236
  {
237
    libcerror_error_set(
238
     error,
239
     LIBCERROR_ERROR_DOMAIN_MEMORY,
240
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
241
     "%s: unable to clear IO handle.",
242
     function );
243
244
    return( -1 );
245
  }
246
*/
247
951
  if( io_handle->coff_header != NULL )
248
586
  {
249
586
    if( libexe_coff_header_free(
250
586
         &( io_handle->coff_header ),
251
586
         error ) != 1 )
252
0
    {
253
0
      libcerror_error_set(
254
0
       error,
255
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
256
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
257
0
       "%s: unable to free COFF header.",
258
0
       function );
259
260
0
      return( -1 );
261
0
    }
262
586
  }
263
951
  if( io_handle->coff_optional_header != NULL )
264
506
  {
265
506
    if( libexe_coff_optional_header_free(
266
506
         &( io_handle->coff_optional_header ),
267
506
         error ) != 1 )
268
0
    {
269
0
      libcerror_error_set(
270
0
       error,
271
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
272
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
273
0
       "%s: unable to free COFF optional header.",
274
0
       function );
275
276
0
      return( -1 );
277
0
    }
278
506
  }
279
951
  io_handle->executable_type = LIBEXE_EXECUTABLE_TYPE_MZ;
280
951
  io_handle->ascii_codepage  = LIBEXE_CODEPAGE_WINDOWS_1252;
281
282
951
  return( 1 );
283
951
}
284
285
/* Reads the file header
286
 * Returns 1 if successful or -1 on error
287
 */
288
int libexe_io_handle_read_file_header(
289
     libexe_io_handle_t *io_handle,
290
     libbfio_handle_t *file_io_handle,
291
     uint16_t *number_of_sections,
292
     libcerror_error_t **error )
293
871
{
294
871
  libexe_mz_header_t *mz_header   = NULL;
295
871
  static char *function           = "libexe_io_handle_read_file_header";
296
297
871
  if( libexe_mz_header_initialize(
298
871
       &mz_header,
299
871
       error ) != 1 )
300
0
  {
301
0
    libcerror_error_set(
302
0
     error,
303
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
304
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
305
0
     "%s: unable to create MZ header.",
306
0
     function );
307
308
0
    goto on_error;
309
0
  }
310
871
  if( libexe_mz_header_read_file_io_handle(
311
871
       mz_header,
312
871
       file_io_handle,
313
871
       0,
314
871
       error ) != 1 )
315
58
  {
316
58
    libcerror_error_set(
317
58
     error,
318
58
     LIBCERROR_ERROR_DOMAIN_IO,
319
58
     LIBCERROR_IO_ERROR_READ_FAILED,
320
58
     "%s: unable to read MZ header.",
321
58
     function );
322
323
58
    goto on_error;
324
58
  }
325
/* TODO check if value is sane */
326
813
  if( mz_header->extended_header_offset != 0 )
327
806
  {
328
/* TODO print data between current offset and extended_header_offset */
329
330
806
    if( libexe_io_handle_read_extended_header(
331
806
         io_handle,
332
806
         file_io_handle,
333
806
         mz_header->extended_header_offset,
334
806
         number_of_sections,
335
806
         error ) != 1 )
336
220
    {
337
220
      libcerror_error_set(
338
220
       error,
339
220
       LIBCERROR_ERROR_DOMAIN_IO,
340
220
       LIBCERROR_IO_ERROR_READ_FAILED,
341
220
       "%s: unable to read extended header.",
342
220
       function );
343
344
220
      goto on_error;
345
220
    }
346
806
  }
347
593
  if( libexe_mz_header_free(
348
593
       &mz_header,
349
593
       error ) != 1 )
350
0
  {
351
0
    libcerror_error_set(
352
0
     error,
353
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
354
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
355
0
     "%s: unable to free MZ header.",
356
0
     function );
357
358
0
    goto on_error;
359
0
  }
360
593
  return( 1 );
361
362
278
on_error:
363
278
  if( mz_header != NULL )
364
278
  {
365
278
    libexe_mz_header_free(
366
278
     &mz_header,
367
278
     NULL );
368
278
  }
369
278
  return( -1 );
370
593
}
371
372
/* Reads the extended header
373
 * Returns 1 if successful or -1 on error
374
 */
375
int libexe_io_handle_read_extended_header(
376
     libexe_io_handle_t *io_handle,
377
     libbfio_handle_t *file_io_handle,
378
     uint32_t extended_header_offset,
379
     uint16_t *number_of_sections,
380
     libcerror_error_t **error )
381
806
{
382
806
  uint8_t extended_header_data[ 2 ];
383
384
806
  static char *function = "libexe_io_handle_read_extended_header";
385
806
  ssize_t read_count    = 0;
386
387
806
  if( io_handle == NULL )
388
0
  {
389
0
    libcerror_error_set(
390
0
     error,
391
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
392
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
393
0
     "%s: invalid IO handle.",
394
0
     function );
395
396
0
    return( -1 );
397
0
  }
398
#if defined( HAVE_DEBUG_OUTPUT )
399
  if( libcnotify_verbose != 0 )
400
  {
401
    libcnotify_printf(
402
     "%s: reading extended header at offset: %" PRIu32 " (0x%08" PRIx32 ")\n",
403
     function,
404
     extended_header_offset,
405
     extended_header_offset );
406
  }
407
#endif
408
806
  read_count = libbfio_handle_read_buffer_at_offset(
409
806
                file_io_handle,
410
806
                extended_header_data,
411
806
                2,
412
806
                (off64_t) extended_header_offset,
413
806
                error );
414
415
806
  if( read_count != 2 )
416
52
  {
417
52
    libcerror_error_set(
418
52
     error,
419
52
     LIBCERROR_ERROR_DOMAIN_IO,
420
52
     LIBCERROR_IO_ERROR_READ_FAILED,
421
52
     "%s: unable to read first 2 bytes of extended header data at offset: %" PRIu32 " (0x%08" PRIx32 ").",
422
52
     function,
423
52
     extended_header_offset,
424
52
     extended_header_offset );
425
426
52
    return( -1 );
427
52
  }
428
#if defined( HAVE_DEBUG_OUTPUT )
429
  if( libcnotify_verbose != 0 )
430
  {
431
    libcnotify_printf(
432
     "%s: extended header data:\n",
433
     function );
434
    libcnotify_print_data(
435
     extended_header_data,
436
     2,
437
     0 );
438
  }
439
#endif
440
/* TODO pass extended header, so it is read once */
441
754
  if( ( extended_header_data[ 0 ] == (uint8_t) 'L' )
442
11
   && ( extended_header_data[ 1 ] == (uint8_t) 'E' ) )
443
1
  {
444
1
    if( libexe_io_handle_read_le_header(
445
1
         io_handle,
446
1
         file_io_handle,
447
1
         extended_header_offset,
448
1
         number_of_sections,
449
1
         error ) != 1 )
450
1
    {
451
1
      libcerror_error_set(
452
1
       error,
453
1
       LIBCERROR_ERROR_DOMAIN_IO,
454
1
       LIBCERROR_IO_ERROR_READ_FAILED,
455
1
       "%s: unable to read LE header.",
456
1
       function );
457
458
1
      return( -1 );
459
1
    }
460
1
  }
461
753
  else if( ( extended_header_data[ 0 ] == (uint8_t) 'N' )
462
9
        && ( extended_header_data[ 1 ] == (uint8_t) 'E' ) )
463
1
  {
464
1
    if( libexe_io_handle_read_ne_header(
465
1
         io_handle,
466
1
         file_io_handle,
467
1
         extended_header_offset,
468
1
         number_of_sections,
469
1
         error ) != 1 )
470
1
    {
471
1
      libcerror_error_set(
472
1
       error,
473
1
       LIBCERROR_ERROR_DOMAIN_IO,
474
1
       LIBCERROR_IO_ERROR_READ_FAILED,
475
1
       "%s: unable to read NE header.",
476
1
       function );
477
478
1
      return( -1 );
479
1
    }
480
1
  }
481
752
  else if( ( extended_header_data[ 0 ] == (uint8_t) 'P' )
482
718
        && ( extended_header_data[ 1 ] == (uint8_t) 'E' ) )
483
709
  {
484
709
    if( libexe_io_handle_read_pe_header(
485
709
         io_handle,
486
709
         file_io_handle,
487
709
         extended_header_offset,
488
709
         number_of_sections,
489
709
         error ) != 1 )
490
123
    {
491
123
      libcerror_error_set(
492
123
       error,
493
123
       LIBCERROR_ERROR_DOMAIN_IO,
494
123
       LIBCERROR_IO_ERROR_READ_FAILED,
495
123
       "%s: unable to read PE/COFF header.",
496
123
       function );
497
498
123
      return( -1 );
499
123
    }
500
709
  }
501
43
  else
502
43
  {
503
43
    libcerror_error_set(
504
43
     error,
505
43
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
506
43
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
507
43
     "%s: unsupported extended header.",
508
43
     function );
509
510
43
    return( -1 );
511
43
  }
512
586
  return( 1 );
513
754
}
514
515
/* Reads the LE header
516
 * Returns 1 if successful or -1 on error
517
 */
518
int libexe_io_handle_read_le_header(
519
     libexe_io_handle_t *io_handle,
520
     libbfio_handle_t *file_io_handle,
521
     uint32_t le_header_offset,
522
     uint16_t *number_of_sections,
523
     libcerror_error_t **error )
524
1
{
525
1
  libexe_le_header_t *le_header = NULL;
526
1
  static char *function         = "libexe_io_handle_read_le_header";
527
528
1
  if( io_handle == NULL )
529
0
  {
530
0
    libcerror_error_set(
531
0
     error,
532
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
533
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
534
0
     "%s: invalid IO handle.",
535
0
     function );
536
537
0
    return( -1 );
538
0
  }
539
1
  if( number_of_sections == NULL )
540
0
  {
541
0
    libcerror_error_set(
542
0
     error,
543
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
544
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
545
0
     "%s: invalid number of sections.",
546
0
     function );
547
548
0
    return( -1 );
549
0
  }
550
1
  if( libexe_le_header_initialize(
551
1
       &le_header,
552
1
       error ) != 1 )
553
0
  {
554
0
    libcerror_error_set(
555
0
     error,
556
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
557
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
558
0
     "%s: unable to create LE header.",
559
0
     function );
560
561
0
    goto on_error;
562
0
  }
563
1
  if( libexe_le_header_read_file_io_handle(
564
1
       le_header,
565
1
       file_io_handle,
566
1
       0,
567
1
       error ) != 1 )
568
1
  {
569
1
    libcerror_error_set(
570
1
     error,
571
1
     LIBCERROR_ERROR_DOMAIN_IO,
572
1
     LIBCERROR_IO_ERROR_READ_FAILED,
573
1
     "%s: unable to read LE header.",
574
1
     function );
575
576
1
    goto on_error;
577
1
  }
578
0
  io_handle->executable_type = LIBEXE_EXECUTABLE_TYPE_LE;
579
580
0
  *number_of_sections = 0;
581
582
0
  if( libexe_le_header_free(
583
0
       &le_header,
584
0
       error ) != 1 )
585
0
  {
586
0
    libcerror_error_set(
587
0
     error,
588
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
589
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
590
0
     "%s: unable to free LE header.",
591
0
     function );
592
593
0
    goto on_error;
594
0
  }
595
0
  return( 1 );
596
597
1
on_error:
598
1
  if( le_header != NULL )
599
1
  {
600
1
    libexe_le_header_free(
601
1
     &le_header,
602
1
     NULL );
603
1
  }
604
1
  return( -1 );
605
0
}
606
607
/* Reads the NE header
608
 * Returns 1 if successful or -1 on error
609
 */
610
int libexe_io_handle_read_ne_header(
611
     libexe_io_handle_t *io_handle,
612
     libbfio_handle_t *file_io_handle,
613
     uint32_t ne_header_offset,
614
     uint16_t *number_of_sections,
615
     libcerror_error_t **error )
616
1
{
617
1
  libexe_ne_header_t *ne_header = NULL;
618
1
  static char *function         = "libexe_io_handle_read_ne_header";
619
620
1
  if( io_handle == NULL )
621
0
  {
622
0
    libcerror_error_set(
623
0
     error,
624
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
625
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
626
0
     "%s: invalid IO handle.",
627
0
     function );
628
629
0
    return( -1 );
630
0
  }
631
1
  if( number_of_sections == NULL )
632
0
  {
633
0
    libcerror_error_set(
634
0
     error,
635
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
636
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
637
0
     "%s: invalid number of sections.",
638
0
     function );
639
640
0
    return( -1 );
641
0
  }
642
1
  if( libexe_ne_header_initialize(
643
1
       &ne_header,
644
1
       error ) != 1 )
645
0
  {
646
0
    libcerror_error_set(
647
0
     error,
648
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
649
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
650
0
     "%s: unable to create NE header.",
651
0
     function );
652
653
0
    goto on_error;
654
0
  }
655
1
  if( libexe_ne_header_read_file_io_handle(
656
1
       ne_header,
657
1
       file_io_handle,
658
1
       0,
659
1
       error ) != 1 )
660
1
  {
661
1
    libcerror_error_set(
662
1
     error,
663
1
     LIBCERROR_ERROR_DOMAIN_IO,
664
1
     LIBCERROR_IO_ERROR_READ_FAILED,
665
1
     "%s: unable to read NE header.",
666
1
     function );
667
668
1
    goto on_error;
669
1
  }
670
0
  io_handle->executable_type = LIBEXE_EXECUTABLE_TYPE_NE;
671
672
0
  *number_of_sections = 0;
673
674
0
  if( libexe_ne_header_free(
675
0
       &ne_header,
676
0
       error ) != 1 )
677
0
  {
678
0
    libcerror_error_set(
679
0
     error,
680
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
681
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
682
0
     "%s: unable to free NE header.",
683
0
     function );
684
685
0
    goto on_error;
686
0
  }
687
0
  return( 1 );
688
689
1
on_error:
690
1
  if( ne_header != NULL )
691
1
  {
692
1
    libexe_ne_header_free(
693
1
     &ne_header,
694
1
     NULL );
695
1
  }
696
1
  return( -1 );
697
0
}
698
699
/* Reads the PE/COFF header
700
 * Returns 1 if successful or -1 on error
701
 */
702
int libexe_io_handle_read_pe_header(
703
     libexe_io_handle_t *io_handle,
704
     libbfio_handle_t *file_io_handle,
705
     uint32_t pe_header_offset,
706
     uint16_t *number_of_sections,
707
     libcerror_error_t **error )
708
709
{
709
709
  exe_pe_header_t pe_header;
710
711
709
  static char *function = "libexe_io_handle_read_pe_header";
712
709
  ssize_t read_count    = 0;
713
709
  off64_t file_offset   = 0;
714
715
709
  if( io_handle == NULL )
716
0
  {
717
0
    libcerror_error_set(
718
0
     error,
719
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
720
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
721
0
     "%s: invalid IO handle.",
722
0
     function );
723
724
0
    return( -1 );
725
0
  }
726
709
  if( number_of_sections == NULL )
727
0
  {
728
0
    libcerror_error_set(
729
0
     error,
730
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
731
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
732
0
     "%s: invalid number of sections.",
733
0
     function );
734
735
0
    return( -1 );
736
0
  }
737
#if defined( HAVE_DEBUG_OUTPUT )
738
  if( libcnotify_verbose != 0 )
739
  {
740
    libcnotify_printf(
741
     "%s: reading PE header at offset: %" PRIu32 " (0x%08" PRIx32 ")\n",
742
     function,
743
     pe_header_offset,
744
     pe_header_offset );
745
  }
746
#endif
747
709
  read_count = libbfio_handle_read_buffer_at_offset(
748
709
                file_io_handle,
749
709
                (uint8_t *) &pe_header,
750
709
                sizeof( exe_pe_header_t ),
751
709
                (off64_t) pe_header_offset,
752
709
                error );
753
754
709
  if( read_count != (ssize_t) sizeof( exe_pe_header_t ) )
755
2
  {
756
2
    libcerror_error_set(
757
2
     error,
758
2
     LIBCERROR_ERROR_DOMAIN_IO,
759
2
     LIBCERROR_IO_ERROR_READ_FAILED,
760
2
     "%s: unable to read PE header data at offset: %" PRIu32 " (0x%08" PRIx32 ").",
761
2
     function,
762
2
     pe_header_offset,
763
2
     pe_header_offset );
764
765
2
    return( -1 );
766
2
  }
767
#if defined( HAVE_DEBUG_OUTPUT )
768
  if( libcnotify_verbose != 0 )
769
  {
770
    libcnotify_printf(
771
     "%s: PE header:\n",
772
     function );
773
    libcnotify_print_data(
774
     (uint8_t *) &pe_header,
775
     sizeof( exe_pe_header_t ),
776
     0 );
777
  }
778
#endif
779
707
  if( memory_compare(
780
707
       pe_header.signature,
781
707
       exe_pe_signature,
782
707
       4 ) != 0 )
783
12
  {
784
12
    libcerror_error_set(
785
12
     error,
786
12
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
787
12
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
788
12
     "%s: invalid signature.",
789
12
     function );
790
791
12
    return( -1 );
792
12
  }
793
#if defined( HAVE_DEBUG_OUTPUT )
794
  if( libcnotify_verbose != 0 )
795
  {
796
    libcnotify_printf(
797
     "%s: signature\t\t\t\t: %c%c\\x%" PRIx8 "\\x%" PRIx8 "\n",
798
     function,
799
     pe_header.signature[ 0 ],
800
     pe_header.signature[ 1 ],
801
     pe_header.signature[ 2 ],
802
     pe_header.signature[ 3 ] );
803
804
    libcnotify_printf(
805
     "\n" );
806
  }
807
#endif
808
695
  if( libexe_coff_header_initialize(
809
695
       &( io_handle->coff_header ),
810
695
       error ) != 1 )
811
0
  {
812
0
    libcerror_error_set(
813
0
     error,
814
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
815
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
816
0
     "%s: unable to create COFF header.",
817
0
     function );
818
819
0
    goto on_error;
820
0
  }
821
695
  file_offset = pe_header_offset + sizeof( exe_pe_header_t );
822
823
695
  if( libexe_coff_header_read_file_io_handle(
824
695
       io_handle->coff_header,
825
695
       file_io_handle,
826
695
       file_offset,
827
695
       error ) != 1 )
828
7
  {
829
7
    libcerror_error_set(
830
7
     error,
831
7
     LIBCERROR_ERROR_DOMAIN_IO,
832
7
     LIBCERROR_IO_ERROR_READ_FAILED,
833
7
     "%s: unable to read COFF header.",
834
7
     function );
835
836
7
    goto on_error;
837
7
  }
838
688
  file_offset += sizeof( exe_coff_header_t );
839
840
688
  *number_of_sections = io_handle->coff_header->number_of_sections;
841
842
688
  if( io_handle->coff_header->optional_header_size > 0 )
843
608
  {
844
608
    if( libexe_coff_optional_header_initialize(
845
608
         &( io_handle->coff_optional_header ),
846
608
         error ) != 1 )
847
0
    {
848
0
      libcerror_error_set(
849
0
       error,
850
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
851
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
852
0
       "%s: unable to create COFF optional header.",
853
0
       function );
854
855
0
      goto on_error;
856
0
    }
857
608
    if( libexe_coff_optional_header_read_file_io_handle(
858
608
         io_handle->coff_optional_header,
859
608
         file_io_handle,
860
608
         file_offset,
861
608
         io_handle->coff_header->optional_header_size,
862
608
         error ) != 1 )
863
102
    {
864
102
      libcerror_error_set(
865
102
       error,
866
102
       LIBCERROR_ERROR_DOMAIN_IO,
867
102
       LIBCERROR_IO_ERROR_READ_FAILED,
868
102
       "%s: unable to read COFF optional header.",
869
102
       function );
870
871
102
      goto on_error;
872
102
    }
873
608
  }
874
586
  io_handle->executable_type = LIBEXE_EXECUTABLE_TYPE_PE_COFF;
875
876
586
  return( 1 );
877
878
109
on_error:
879
109
  if( io_handle->coff_optional_header != NULL )
880
102
  {
881
102
    libexe_coff_optional_header_free(
882
102
     &( io_handle->coff_optional_header ),
883
102
     NULL );
884
102
  }
885
109
  if( io_handle->coff_header != NULL )
886
109
  {
887
109
    libexe_coff_header_free(
888
109
     &( io_handle->coff_header ),
889
109
     NULL );
890
109
  }
891
109
  return( -1 );
892
688
}
893
894
/* Reads the section table
895
 * Returns 1 if successful or -1 on error
896
 */
897
int libexe_io_handle_read_section_table(
898
     libexe_io_handle_t *io_handle,
899
     libbfio_handle_t *file_io_handle,
900
     uint16_t number_of_sections,
901
     libcdata_array_t *sections_array,
902
     libcerror_error_t **error )
903
505
{
904
505
  libexe_section_descriptor_t *section_descriptor = NULL;
905
505
  uint8_t *section_table                          = NULL;
906
505
  uint8_t *section_table_data                     = NULL;
907
505
  static char *function                           = "libexe_io_handle_read_section_table";
908
505
  size_t section_table_size                       = 0;
909
505
  ssize_t read_count                              = 0;
910
505
  uint32_t section_data_offset                    = 0;
911
505
  uint32_t section_data_size                      = 0;
912
505
  uint16_t section_index                          = 0;
913
505
  int entry_index                                 = 0;
914
915
#if defined( HAVE_DEBUG_OUTPUT )
916
  uint32_t value_32bit                            = 0;
917
  uint16_t value_16bit                            = 0;
918
#endif
919
920
505
  if( io_handle == NULL )
921
0
  {
922
0
    libcerror_error_set(
923
0
     error,
924
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
925
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
926
0
     "%s: invalid IO handle.",
927
0
     function );
928
929
0
    return( -1 );
930
0
  }
931
505
  section_table_size = sizeof( exe_section_table_entry_t )
932
505
                     * number_of_sections;
933
934
505
  if( ( section_table_size == 0 )
935
505
   || ( section_table_size > MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
936
0
  {
937
0
    libcerror_error_set(
938
0
     error,
939
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
940
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
941
0
     "%s: invalid section table size value out of bounds.",
942
0
     function );
943
944
0
    return( -1 );
945
0
  }
946
505
  section_table = (uint8_t *) memory_allocate(
947
505
                               sizeof( uint8_t ) * section_table_size );
948
949
505
  if( section_table == NULL )
950
0
  {
951
0
    libcerror_error_set(
952
0
     error,
953
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
954
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
955
0
     "%s: unable to create section table.",
956
0
     function );
957
958
0
    goto on_error;
959
0
  }
960
505
  read_count = libbfio_handle_read_buffer(
961
505
                file_io_handle,
962
505
                section_table,
963
505
                section_table_size,
964
505
                error );
965
966
505
  if( read_count != (ssize_t) section_table_size )
967
79
  {
968
79
    libcerror_error_set(
969
79
     error,
970
79
     LIBCERROR_ERROR_DOMAIN_IO,
971
79
     LIBCERROR_IO_ERROR_READ_FAILED,
972
79
     "%s: unable to read section table.",
973
79
     function );
974
975
79
    goto on_error;
976
79
  }
977
#if defined( HAVE_DEBUG_OUTPUT )
978
  if( libcnotify_verbose != 0 )
979
  {
980
    libcnotify_printf(
981
     "%s: section table data:\n",
982
     function );
983
    libcnotify_print_data(
984
     section_table,
985
     section_table_size,
986
     0 );
987
  }
988
#endif
989
426
  section_table_data = section_table;
990
991
206k
  while( section_table_size >= sizeof( exe_section_table_entry_t ) )
992
205k
  {
993
205k
    if( libexe_section_descriptor_initialize(
994
205k
         &section_descriptor,
995
205k
         error ) != 1 )
996
0
    {
997
0
      libcerror_error_set(
998
0
       error,
999
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1000
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1001
0
       "%s: unable to create section descriptor.",
1002
0
       function );
1003
1004
0
      goto on_error;
1005
0
    }
1006
205k
    if( memory_copy(
1007
205k
         section_descriptor->name,
1008
205k
         ( (exe_section_table_entry_t *) section_table_data )->name,
1009
205k
         8 ) == NULL )
1010
0
    {
1011
0
      libcerror_error_set(
1012
0
       error,
1013
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
1014
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
1015
0
       "%s: unable to copy name.",
1016
0
       function );
1017
1018
0
      goto on_error;
1019
0
    }
1020
205k
    section_descriptor->name[ 8 ] = 0;
1021
1022
205k
    section_descriptor->name_size = narrow_string_length(
1023
205k
                                     section_descriptor->name );
1024
1025
205k
    if( section_descriptor->name_size > 0 )
1026
125k
    {
1027
125k
      section_descriptor->name_size += 1;
1028
125k
    }
1029
205k
    byte_stream_copy_to_uint32_little_endian(
1030
205k
     ( (exe_section_table_entry_t *) section_table_data )->virtual_address,
1031
205k
     section_descriptor->virtual_address );
1032
1033
205k
    byte_stream_copy_to_uint32_little_endian(
1034
205k
     ( (exe_section_table_entry_t *) section_table_data )->data_size,
1035
205k
     section_data_size );
1036
1037
205k
    byte_stream_copy_to_uint32_little_endian(
1038
205k
     ( (exe_section_table_entry_t *) section_table_data )->data_offset,
1039
205k
     section_data_offset );
1040
1041
#if defined( HAVE_DEBUG_OUTPUT )
1042
    if( libcnotify_verbose != 0 )
1043
    {
1044
      libcnotify_printf(
1045
       "%s: entry: %02" PRIu16 " name\t\t\t\t: %s\n",
1046
       function,
1047
       section_index,
1048
       section_descriptor->name );
1049
1050
      byte_stream_copy_to_uint32_little_endian(
1051
       ( (exe_section_table_entry_t *) section_table_data )->virtual_size,
1052
       value_32bit );
1053
      libcnotify_printf(
1054
       "%s: entry: %02" PRIu16 " virtual size\t\t\t: %" PRIu32 "\n",
1055
       function,
1056
       section_index,
1057
       value_32bit );
1058
1059
      libcnotify_printf(
1060
       "%s: entry: %02" PRIu16 " virtual address\t\t\t: 0x%08" PRIx32 "\n",
1061
       function,
1062
       section_index,
1063
       section_descriptor->virtual_address );
1064
1065
      libcnotify_printf(
1066
       "%s: entry: %02" PRIu16 " data size\t\t\t: %" PRIu32 "\n",
1067
       function,
1068
       section_index,
1069
       section_data_size );
1070
1071
      libcnotify_printf(
1072
       "%s: entry: %02" PRIu16 " data offset\t\t\t: 0x%08" PRIx32 "\n",
1073
       function,
1074
       section_index,
1075
       section_data_offset );
1076
1077
      byte_stream_copy_to_uint32_little_endian(
1078
       ( (exe_section_table_entry_t *) section_table_data )->relocations_offset,
1079
       value_32bit );
1080
      libcnotify_printf(
1081
       "%s: entry: %02" PRIu16 " relocations offset\t\t: 0x%08" PRIx32 "\n",
1082
       function,
1083
       section_index,
1084
       value_32bit );
1085
1086
      byte_stream_copy_to_uint32_little_endian(
1087
       ( (exe_section_table_entry_t *) section_table_data )->line_numbers_offset,
1088
       value_32bit );
1089
      libcnotify_printf(
1090
       "%s: entry: %02" PRIu16 " line numbers offset\t\t: 0x%08" PRIx32 "\n",
1091
       function,
1092
       section_index,
1093
       value_32bit );
1094
1095
      byte_stream_copy_to_uint16_little_endian(
1096
       ( (exe_section_table_entry_t *) section_table_data )->relocations_offset,
1097
       value_16bit );
1098
      libcnotify_printf(
1099
       "%s: entry: %02" PRIu16 " number of relocations\t\t: %" PRIu16 "\n",
1100
       function,
1101
       section_index,
1102
       value_16bit );
1103
1104
      byte_stream_copy_to_uint16_little_endian(
1105
       ( (exe_section_table_entry_t *) section_table_data )->line_numbers_offset,
1106
       value_16bit );
1107
      libcnotify_printf(
1108
       "%s: entry: %02" PRIu16 " number of line numbers\t\t: %" PRIu16 "\n",
1109
       function,
1110
       section_index,
1111
       value_16bit );
1112
1113
      byte_stream_copy_to_uint32_little_endian(
1114
       ( (exe_section_table_entry_t *) section_table_data )->section_characteristic_flags,
1115
       value_32bit );
1116
      libcnotify_printf(
1117
       "%s: entry: %02" PRIu16 " section characteristic flags\t: 0x%08" PRIx32 "\n",
1118
       function,
1119
       section_index,
1120
       value_32bit );
1121
      libexe_debug_print_section_characteristic_flags(
1122
       value_32bit );
1123
      libcnotify_printf(
1124
       "\n" );
1125
    }
1126
#endif
1127
205k
    section_table_data += sizeof( exe_section_table_entry_t );
1128
205k
    section_table_size -= sizeof( exe_section_table_entry_t );
1129
1130
205k
    if( libexe_section_descriptor_set_data_range(
1131
205k
         section_descriptor,
1132
205k
         (off64_t) section_data_offset,
1133
205k
         (size64_t) section_data_size,
1134
205k
         error ) != 1 )
1135
0
    {
1136
0
      libcerror_error_set(
1137
0
       error,
1138
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1139
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1140
0
       "%s: unable to set data range in section descriptor.",
1141
0
       function );
1142
1143
0
      goto on_error;
1144
0
    }
1145
205k
    if( libcdata_array_append_entry(
1146
205k
         sections_array,
1147
205k
         &entry_index,
1148
205k
         (intptr_t *) section_descriptor,
1149
205k
         error ) != 1 )
1150
0
    {
1151
0
      libcerror_error_set(
1152
0
       error,
1153
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1154
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1155
0
       "%s: unable to append section descriptor to sections array.",
1156
0
       function );
1157
1158
0
      goto on_error;
1159
0
    }
1160
205k
    section_descriptor = NULL;
1161
1162
205k
    section_index++;
1163
205k
  }
1164
426
  memory_free(
1165
426
   section_table );
1166
1167
426
  return( 1 );
1168
1169
79
on_error:
1170
79
  if( section_descriptor != NULL )
1171
0
  {
1172
0
    libexe_section_descriptor_free(
1173
0
     &section_descriptor,
1174
0
     NULL );
1175
0
  }
1176
79
  if( section_table != NULL )
1177
79
  {
1178
79
    memory_free(
1179
79
     section_table );
1180
79
  }
1181
79
  return( -1 );
1182
426
}
1183
1184
/* Reads the segment data into the buffer
1185
 * Callback function for the section stream
1186
 * Returns the number of bytes read or -1 on error
1187
 */
1188
ssize_t libexe_io_handle_read_segment_data(
1189
         intptr_t *data_handle LIBEXE_ATTRIBUTE_UNUSED,
1190
         libbfio_handle_t *file_io_handle,
1191
         int segment_index LIBEXE_ATTRIBUTE_UNUSED,
1192
         int segment_file_index LIBEXE_ATTRIBUTE_UNUSED,
1193
         uint8_t *segment_data,
1194
         size_t segment_data_size,
1195
         uint32_t segment_flags LIBEXE_ATTRIBUTE_UNUSED,
1196
         uint8_t read_flags LIBEXE_ATTRIBUTE_UNUSED,
1197
         libcerror_error_t **error )
1198
0
{
1199
0
  static char *function = "libexe_io_handle_read_segment_data";
1200
0
  ssize_t read_count    = 0;
1201
1202
0
  LIBEXE_UNREFERENCED_PARAMETER( data_handle )
1203
0
  LIBEXE_UNREFERENCED_PARAMETER( segment_index )
1204
0
  LIBEXE_UNREFERENCED_PARAMETER( segment_file_index )
1205
0
  LIBEXE_UNREFERENCED_PARAMETER( segment_flags )
1206
0
  LIBEXE_UNREFERENCED_PARAMETER( read_flags )
1207
1208
0
  read_count = libbfio_handle_read_buffer(
1209
0
          file_io_handle,
1210
0
          segment_data,
1211
0
          segment_data_size,
1212
0
          error );
1213
1214
0
  if( read_count != (ssize_t) segment_data_size )
1215
0
  {
1216
0
    libcerror_error_set(
1217
0
     error,
1218
0
     LIBCERROR_ERROR_DOMAIN_IO,
1219
0
     LIBCERROR_IO_ERROR_READ_FAILED,
1220
0
     "%s: unable to read segment data.",
1221
0
     function );
1222
1223
0
    return( -1 );
1224
0
  }
1225
0
  return( read_count );
1226
0
}
1227
1228
/* Seeks a certain segment offset
1229
 * Callback function for the section stream
1230
 * Returns the offset or -1 on error
1231
 */
1232
off64_t libexe_io_handle_seek_segment_offset(
1233
         intptr_t *data_handle LIBEXE_ATTRIBUTE_UNUSED,
1234
         libbfio_handle_t *file_io_handle,
1235
         int segment_index LIBEXE_ATTRIBUTE_UNUSED,
1236
         int segment_file_index LIBEXE_ATTRIBUTE_UNUSED,
1237
         off64_t segment_offset,
1238
         libcerror_error_t **error )
1239
0
{
1240
0
  static char *function = "libexe_io_handle_seek_segment_offset";
1241
1242
0
  LIBEXE_UNREFERENCED_PARAMETER( data_handle )
1243
0
  LIBEXE_UNREFERENCED_PARAMETER( segment_index )
1244
0
  LIBEXE_UNREFERENCED_PARAMETER( segment_file_index )
1245
1246
0
  segment_offset = libbfio_handle_seek_offset(
1247
0
                    file_io_handle,
1248
0
                    segment_offset,
1249
0
                    SEEK_SET,
1250
0
                    error );
1251
1252
0
  if( segment_offset == -1 )
1253
0
  {
1254
0
    libcerror_error_set(
1255
0
     error,
1256
0
     LIBCERROR_ERROR_DOMAIN_IO,
1257
0
     LIBCERROR_IO_ERROR_READ_FAILED,
1258
0
     "%s: unable to seek segment offset.",
1259
0
     function );
1260
1261
0
    return( -1 );
1262
0
  }
1263
0
  return( segment_offset );
1264
0
}
1265