Coverage Report

Created: 2025-08-28 07:10

/src/libexe/libexe/libexe_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 <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
905
{
62
905
  static char *function = "libexe_io_handle_initialize";
63
64
905
  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
905
  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
905
  *io_handle = memory_allocate_structure(
87
905
                libexe_io_handle_t );
88
89
905
  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
905
  if( memory_set(
101
905
       *io_handle,
102
905
       0,
103
905
       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
905
  ( *io_handle )->executable_type = LIBEXE_EXECUTABLE_TYPE_MZ;
120
905
  ( *io_handle )->ascii_codepage  = LIBEXE_CODEPAGE_WINDOWS_1252;
121
122
905
  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
905
}
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
905
{
142
905
  static char *function = "libexe_io_handle_free";
143
905
  int result            = 1;
144
145
905
  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
905
  if( *io_handle != NULL )
157
905
  {
158
905
    if( libexe_io_handle_clear(
159
905
         *io_handle,
160
905
         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
905
    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
905
    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
905
    memory_free(
204
905
     *io_handle );
205
206
905
    *io_handle = NULL;
207
905
  }
208
905
  return( result );
209
905
}
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
991
{
218
991
  static char *function = "libexe_io_handle_clear";
219
220
991
  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
991
  if( io_handle->coff_header != NULL )
248
616
  {
249
616
    if( libexe_coff_header_free(
250
616
         &( io_handle->coff_header ),
251
616
         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
616
  }
263
991
  if( io_handle->coff_optional_header != NULL )
264
530
  {
265
530
    if( libexe_coff_optional_header_free(
266
530
         &( io_handle->coff_optional_header ),
267
530
         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
530
  }
279
991
  io_handle->executable_type = LIBEXE_EXECUTABLE_TYPE_MZ;
280
991
  io_handle->ascii_codepage  = LIBEXE_CODEPAGE_WINDOWS_1252;
281
282
991
  return( 1 );
283
991
}
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
905
{
294
905
  libexe_mz_header_t *mz_header   = NULL;
295
905
  static char *function           = "libexe_io_handle_read_file_header";
296
297
905
  if( libexe_mz_header_initialize(
298
905
       &mz_header,
299
905
       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
905
  if( libexe_mz_header_read_file_io_handle(
311
905
       mz_header,
312
905
       file_io_handle,
313
905
       0,
314
905
       error ) != 1 )
315
55
  {
316
55
    libcerror_error_set(
317
55
     error,
318
55
     LIBCERROR_ERROR_DOMAIN_IO,
319
55
     LIBCERROR_IO_ERROR_READ_FAILED,
320
55
     "%s: unable to read MZ header.",
321
55
     function );
322
323
55
    goto on_error;
324
55
  }
325
/* TODO check if value is sane */
326
850
  if( mz_header->extended_header_offset != 0 )
327
844
  {
328
/* TODO print data between current offset and extended_header_offset */
329
330
844
    if( libexe_io_handle_read_extended_header(
331
844
         io_handle,
332
844
         file_io_handle,
333
844
         mz_header->extended_header_offset,
334
844
         number_of_sections,
335
844
         error ) != 1 )
336
228
    {
337
228
      libcerror_error_set(
338
228
       error,
339
228
       LIBCERROR_ERROR_DOMAIN_IO,
340
228
       LIBCERROR_IO_ERROR_READ_FAILED,
341
228
       "%s: unable to read extended header.",
342
228
       function );
343
344
228
      goto on_error;
345
228
    }
346
844
  }
347
622
  if( libexe_mz_header_free(
348
622
       &mz_header,
349
622
       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
622
  return( 1 );
361
362
283
on_error:
363
283
  if( mz_header != NULL )
364
283
  {
365
283
    libexe_mz_header_free(
366
283
     &mz_header,
367
283
     NULL );
368
283
  }
369
283
  return( -1 );
370
622
}
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
844
{
382
844
  uint8_t extended_header_data[ 2 ];
383
384
844
  static char *function = "libexe_io_handle_read_extended_header";
385
844
  ssize_t read_count    = 0;
386
387
844
  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
844
  read_count = libbfio_handle_read_buffer_at_offset(
409
844
                file_io_handle,
410
844
                extended_header_data,
411
844
                2,
412
844
                (off64_t) extended_header_offset,
413
844
                error );
414
415
844
  if( read_count != 2 )
416
59
  {
417
59
    libcerror_error_set(
418
59
     error,
419
59
     LIBCERROR_ERROR_DOMAIN_IO,
420
59
     LIBCERROR_IO_ERROR_READ_FAILED,
421
59
     "%s: unable to read first 2 bytes of extended header data at offset: %" PRIu32 " (0x%08" PRIx32 ").",
422
59
     function,
423
59
     extended_header_offset,
424
59
     extended_header_offset );
425
426
59
    return( -1 );
427
59
  }
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
785
  if( ( extended_header_data[ 0 ] == (uint8_t) 'L' )
442
785
   && ( 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
784
  else if( ( extended_header_data[ 0 ] == (uint8_t) 'N' )
462
784
        && ( 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
783
  else if( ( extended_header_data[ 0 ] == (uint8_t) 'P' )
482
783
        && ( extended_header_data[ 1 ] == (uint8_t) 'E' ) )
483
744
  {
484
744
    if( libexe_io_handle_read_pe_header(
485
744
         io_handle,
486
744
         file_io_handle,
487
744
         extended_header_offset,
488
744
         number_of_sections,
489
744
         error ) != 1 )
490
128
    {
491
128
      libcerror_error_set(
492
128
       error,
493
128
       LIBCERROR_ERROR_DOMAIN_IO,
494
128
       LIBCERROR_IO_ERROR_READ_FAILED,
495
128
       "%s: unable to read PE/COFF header.",
496
128
       function );
497
498
128
      return( -1 );
499
128
    }
500
744
  }
501
39
  else
502
39
  {
503
39
    libcerror_error_set(
504
39
     error,
505
39
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
506
39
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
507
39
     "%s: unsupported extended header.",
508
39
     function );
509
510
39
    return( -1 );
511
39
  }
512
616
  return( 1 );
513
785
}
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
744
{
709
744
  exe_pe_header_t pe_header;
710
711
744
  static char *function = "libexe_io_handle_read_pe_header";
712
744
  ssize_t read_count    = 0;
713
744
  off64_t file_offset   = 0;
714
715
744
  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
744
  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
744
  read_count = libbfio_handle_read_buffer_at_offset(
748
744
                file_io_handle,
749
744
                (uint8_t *) &pe_header,
750
744
                sizeof( exe_pe_header_t ),
751
744
                (off64_t) pe_header_offset,
752
744
                error );
753
754
744
  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
742
  if( memory_compare(
780
742
       pe_header.signature,
781
742
       exe_pe_signature,
782
742
       4 ) != 0 )
783
16
  {
784
16
    libcerror_error_set(
785
16
     error,
786
16
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
787
16
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
788
16
     "%s: invalid signature.",
789
16
     function );
790
791
16
    return( -1 );
792
16
  }
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
726
  if( libexe_coff_header_initialize(
809
726
       &( io_handle->coff_header ),
810
726
       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
726
  file_offset = pe_header_offset + sizeof( exe_pe_header_t );
822
823
726
  if( libexe_coff_header_read_file_io_handle(
824
726
       io_handle->coff_header,
825
726
       file_io_handle,
826
726
       file_offset,
827
726
       error ) != 1 )
828
8
  {
829
8
    libcerror_error_set(
830
8
     error,
831
8
     LIBCERROR_ERROR_DOMAIN_IO,
832
8
     LIBCERROR_IO_ERROR_READ_FAILED,
833
8
     "%s: unable to read COFF header.",
834
8
     function );
835
836
8
    goto on_error;
837
8
  }
838
718
  file_offset += sizeof( exe_coff_header_t );
839
840
718
  *number_of_sections = io_handle->coff_header->number_of_sections;
841
842
718
  if( io_handle->coff_header->optional_header_size > 0 )
843
632
  {
844
632
    if( libexe_coff_optional_header_initialize(
845
632
         &( io_handle->coff_optional_header ),
846
632
         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
632
    if( libexe_coff_optional_header_read_file_io_handle(
858
632
         io_handle->coff_optional_header,
859
632
         file_io_handle,
860
632
         file_offset,
861
632
         io_handle->coff_header->optional_header_size,
862
632
         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
632
  }
874
616
  io_handle->executable_type = LIBEXE_EXECUTABLE_TYPE_PE_COFF;
875
876
616
  return( 1 );
877
878
110
on_error:
879
110
  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
110
  if( io_handle->coff_header != NULL )
886
110
  {
887
110
    libexe_coff_header_free(
888
110
     &( io_handle->coff_header ),
889
110
     NULL );
890
110
  }
891
110
  return( -1 );
892
718
}
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
536
{
904
536
  libexe_section_descriptor_t *section_descriptor = NULL;
905
536
  uint8_t *section_table                          = NULL;
906
536
  uint8_t *section_table_data                     = NULL;
907
536
  static char *function                           = "libexe_io_handle_read_section_table";
908
536
  size_t section_table_size                       = 0;
909
536
  ssize_t read_count                              = 0;
910
536
  uint32_t section_data_offset                    = 0;
911
536
  uint32_t section_data_size                      = 0;
912
536
  uint16_t section_index                          = 0;
913
536
  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
536
  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
536
  section_table_size = sizeof( exe_section_table_entry_t )
932
536
                     * number_of_sections;
933
934
536
  if( ( section_table_size == 0 )
935
536
   || ( 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
536
  section_table = (uint8_t *) memory_allocate(
947
536
                               sizeof( uint8_t ) * section_table_size );
948
949
536
  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
536
  read_count = libbfio_handle_read_buffer(
961
536
                file_io_handle,
962
536
                section_table,
963
536
                section_table_size,
964
536
                error );
965
966
536
  if( read_count != (ssize_t) section_table_size )
967
75
  {
968
75
    libcerror_error_set(
969
75
     error,
970
75
     LIBCERROR_ERROR_DOMAIN_IO,
971
75
     LIBCERROR_IO_ERROR_READ_FAILED,
972
75
     "%s: unable to read section table.",
973
75
     function );
974
975
75
    goto on_error;
976
75
  }
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
461
  section_table_data = section_table;
990
991
234k
  while( section_table_size >= sizeof( exe_section_table_entry_t ) )
992
234k
  {
993
234k
    if( libexe_section_descriptor_initialize(
994
234k
         &section_descriptor,
995
234k
         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
234k
    if( memory_copy(
1007
234k
         section_descriptor->name,
1008
234k
         ( (exe_section_table_entry_t *) section_table_data )->name,
1009
234k
         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
234k
    section_descriptor->name[ 8 ] = 0;
1021
1022
234k
    section_descriptor->name_size = narrow_string_length(
1023
234k
                                     section_descriptor->name );
1024
1025
234k
    if( section_descriptor->name_size > 0 )
1026
133k
    {
1027
133k
      section_descriptor->name_size += 1;
1028
133k
    }
1029
234k
    byte_stream_copy_to_uint32_little_endian(
1030
234k
     ( (exe_section_table_entry_t *) section_table_data )->virtual_address,
1031
234k
     section_descriptor->virtual_address );
1032
1033
234k
    byte_stream_copy_to_uint32_little_endian(
1034
234k
     ( (exe_section_table_entry_t *) section_table_data )->data_size,
1035
234k
     section_data_size );
1036
1037
234k
    byte_stream_copy_to_uint32_little_endian(
1038
234k
     ( (exe_section_table_entry_t *) section_table_data )->data_offset,
1039
234k
     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
234k
    section_table_data += sizeof( exe_section_table_entry_t );
1128
234k
    section_table_size -= sizeof( exe_section_table_entry_t );
1129
1130
234k
    if( libexe_section_descriptor_set_data_range(
1131
234k
         section_descriptor,
1132
234k
         (off64_t) section_data_offset,
1133
234k
         (size64_t) section_data_size,
1134
234k
         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
234k
    if( libcdata_array_append_entry(
1146
234k
         sections_array,
1147
234k
         &entry_index,
1148
234k
         (intptr_t *) section_descriptor,
1149
234k
         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
234k
    section_descriptor = NULL;
1161
1162
234k
    section_index++;
1163
234k
  }
1164
461
  memory_free(
1165
461
   section_table );
1166
1167
461
  return( 1 );
1168
1169
75
on_error:
1170
75
  if( section_descriptor != NULL )
1171
0
  {
1172
0
    libexe_section_descriptor_free(
1173
0
     &section_descriptor,
1174
0
     NULL );
1175
0
  }
1176
75
  if( section_table != NULL )
1177
75
  {
1178
75
    memory_free(
1179
75
     section_table );
1180
75
  }
1181
75
  return( -1 );
1182
461
}
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