Coverage Report

Created: 2026-07-25 07:30

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-2026, 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
876
{
62
876
  static char *function = "libexe_io_handle_initialize";
63
64
876
  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
876
  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
876
  *io_handle = memory_allocate_structure(
87
876
                libexe_io_handle_t );
88
89
876
  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
876
  if( memory_set(
101
876
       *io_handle,
102
876
       0,
103
876
       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
876
  ( *io_handle )->executable_type = LIBEXE_EXECUTABLE_TYPE_MZ;
120
876
  ( *io_handle )->ascii_codepage  = LIBEXE_CODEPAGE_WINDOWS_1252;
121
122
876
  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
876
}
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
876
{
142
876
  static char *function = "libexe_io_handle_free";
143
876
  int result            = 1;
144
145
876
  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
876
  if( *io_handle != NULL )
157
876
  {
158
876
    if( libexe_io_handle_clear(
159
876
         *io_handle,
160
876
         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
876
    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
876
    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
876
    memory_free(
204
876
     *io_handle );
205
206
876
    *io_handle = NULL;
207
876
  }
208
876
  return( result );
209
876
}
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
958
{
218
958
  static char *function = "libexe_io_handle_clear";
219
220
958
  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
958
  if( io_handle->coff_header != NULL )
248
588
  {
249
588
    if( libexe_coff_header_free(
250
588
         &( io_handle->coff_header ),
251
588
         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
588
  }
263
958
  if( io_handle->coff_optional_header != NULL )
264
509
  {
265
509
    if( libexe_coff_optional_header_free(
266
509
         &( io_handle->coff_optional_header ),
267
509
         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
509
  }
279
958
  io_handle->executable_type = LIBEXE_EXECUTABLE_TYPE_MZ;
280
958
  io_handle->ascii_codepage  = LIBEXE_CODEPAGE_WINDOWS_1252;
281
282
958
  return( 1 );
283
958
}
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
876
{
294
876
  libexe_mz_header_t *mz_header   = NULL;
295
876
  static char *function           = "libexe_io_handle_read_file_header";
296
297
876
  if( libexe_mz_header_initialize(
298
876
       &mz_header,
299
876
       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
876
  if( libexe_mz_header_read_file_io_handle(
311
876
       mz_header,
312
876
       file_io_handle,
313
876
       0,
314
876
       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
818
  if( mz_header->extended_header_offset != 0 )
327
811
  {
328
/* TODO print data between current offset and extended_header_offset */
329
330
811
    if( libexe_io_handle_read_extended_header(
331
811
         io_handle,
332
811
         file_io_handle,
333
811
         mz_header->extended_header_offset,
334
811
         number_of_sections,
335
811
         error ) != 1 )
336
223
    {
337
223
      libcerror_error_set(
338
223
       error,
339
223
       LIBCERROR_ERROR_DOMAIN_IO,
340
223
       LIBCERROR_IO_ERROR_READ_FAILED,
341
223
       "%s: unable to read extended header.",
342
223
       function );
343
344
223
      goto on_error;
345
223
    }
346
811
  }
347
595
  if( libexe_mz_header_free(
348
595
       &mz_header,
349
595
       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
595
  return( 1 );
361
362
281
on_error:
363
281
  if( mz_header != NULL )
364
281
  {
365
281
    libexe_mz_header_free(
366
281
     &mz_header,
367
281
     NULL );
368
281
  }
369
281
  return( -1 );
370
595
}
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
811
{
382
811
  uint8_t extended_header_data[ 2 ];
383
384
811
  static char *function = "libexe_io_handle_read_extended_header";
385
811
  ssize_t read_count    = 0;
386
387
811
  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
811
  read_count = libbfio_handle_read_buffer_at_offset(
409
811
                file_io_handle,
410
811
                extended_header_data,
411
811
                2,
412
811
                (off64_t) extended_header_offset,
413
811
                error );
414
415
811
  if( read_count != 2 )
416
60
  {
417
60
    libcerror_error_set(
418
60
     error,
419
60
     LIBCERROR_ERROR_DOMAIN_IO,
420
60
     LIBCERROR_IO_ERROR_READ_FAILED,
421
60
     "%s: unable to read first 2 bytes of extended header data at offset: %" PRIu32 " (0x%08" PRIx32 ").",
422
60
     function,
423
60
     extended_header_offset,
424
60
     extended_header_offset );
425
426
60
    return( -1 );
427
60
  }
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
751
  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
750
  else if( ( extended_header_data[ 0 ] == (uint8_t) 'N' )
462
8
        && ( 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
749
  else if( ( extended_header_data[ 0 ] == (uint8_t) 'P' )
482
719
        && ( extended_header_data[ 1 ] == (uint8_t) 'E' ) )
483
710
  {
484
710
    if( libexe_io_handle_read_pe_header(
485
710
         io_handle,
486
710
         file_io_handle,
487
710
         extended_header_offset,
488
710
         number_of_sections,
489
710
         error ) != 1 )
490
122
    {
491
122
      libcerror_error_set(
492
122
       error,
493
122
       LIBCERROR_ERROR_DOMAIN_IO,
494
122
       LIBCERROR_IO_ERROR_READ_FAILED,
495
122
       "%s: unable to read PE/COFF header.",
496
122
       function );
497
498
122
      return( -1 );
499
122
    }
500
710
  }
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
588
  return( 1 );
513
751
}
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 LIBEXE_ATTRIBUTE_UNUSED,
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
  LIBEXE_UNREFERENCED_PARAMETER( le_header_offset )
529
530
1
  if( io_handle == NULL )
531
0
  {
532
0
    libcerror_error_set(
533
0
     error,
534
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
535
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
536
0
     "%s: invalid IO handle.",
537
0
     function );
538
539
0
    return( -1 );
540
0
  }
541
1
  if( number_of_sections == NULL )
542
0
  {
543
0
    libcerror_error_set(
544
0
     error,
545
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
546
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
547
0
     "%s: invalid number of sections.",
548
0
     function );
549
550
0
    return( -1 );
551
0
  }
552
1
  if( libexe_le_header_initialize(
553
1
       &le_header,
554
1
       error ) != 1 )
555
0
  {
556
0
    libcerror_error_set(
557
0
     error,
558
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
559
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
560
0
     "%s: unable to create LE header.",
561
0
     function );
562
563
0
    goto on_error;
564
0
  }
565
1
  if( libexe_le_header_read_file_io_handle(
566
1
       le_header,
567
1
       file_io_handle,
568
1
       0,
569
1
       error ) != 1 )
570
1
  {
571
1
    libcerror_error_set(
572
1
     error,
573
1
     LIBCERROR_ERROR_DOMAIN_IO,
574
1
     LIBCERROR_IO_ERROR_READ_FAILED,
575
1
     "%s: unable to read LE header.",
576
1
     function );
577
578
1
    goto on_error;
579
1
  }
580
0
  io_handle->executable_type = LIBEXE_EXECUTABLE_TYPE_LE;
581
582
0
  *number_of_sections = 0;
583
584
0
  if( libexe_le_header_free(
585
0
       &le_header,
586
0
       error ) != 1 )
587
0
  {
588
0
    libcerror_error_set(
589
0
     error,
590
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
591
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
592
0
     "%s: unable to free LE header.",
593
0
     function );
594
595
0
    goto on_error;
596
0
  }
597
0
  return( 1 );
598
599
1
on_error:
600
1
  if( le_header != NULL )
601
1
  {
602
1
    libexe_le_header_free(
603
1
     &le_header,
604
1
     NULL );
605
1
  }
606
1
  return( -1 );
607
0
}
608
609
/* Reads the NE header
610
 * Returns 1 if successful or -1 on error
611
 */
612
int libexe_io_handle_read_ne_header(
613
     libexe_io_handle_t *io_handle,
614
     libbfio_handle_t *file_io_handle,
615
     uint32_t ne_header_offset LIBEXE_ATTRIBUTE_UNUSED,
616
     uint16_t *number_of_sections,
617
     libcerror_error_t **error )
618
1
{
619
1
  libexe_ne_header_t *ne_header = NULL;
620
1
  static char *function         = "libexe_io_handle_read_ne_header";
621
622
1
  LIBEXE_UNREFERENCED_PARAMETER( ne_header_offset )
623
624
1
  if( io_handle == NULL )
625
0
  {
626
0
    libcerror_error_set(
627
0
     error,
628
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
629
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
630
0
     "%s: invalid IO handle.",
631
0
     function );
632
633
0
    return( -1 );
634
0
  }
635
1
  if( number_of_sections == NULL )
636
0
  {
637
0
    libcerror_error_set(
638
0
     error,
639
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
640
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
641
0
     "%s: invalid number of sections.",
642
0
     function );
643
644
0
    return( -1 );
645
0
  }
646
1
  if( libexe_ne_header_initialize(
647
1
       &ne_header,
648
1
       error ) != 1 )
649
0
  {
650
0
    libcerror_error_set(
651
0
     error,
652
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
653
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
654
0
     "%s: unable to create NE header.",
655
0
     function );
656
657
0
    goto on_error;
658
0
  }
659
1
  if( libexe_ne_header_read_file_io_handle(
660
1
       ne_header,
661
1
       file_io_handle,
662
1
       0,
663
1
       error ) != 1 )
664
1
  {
665
1
    libcerror_error_set(
666
1
     error,
667
1
     LIBCERROR_ERROR_DOMAIN_IO,
668
1
     LIBCERROR_IO_ERROR_READ_FAILED,
669
1
     "%s: unable to read NE header.",
670
1
     function );
671
672
1
    goto on_error;
673
1
  }
674
0
  io_handle->executable_type = LIBEXE_EXECUTABLE_TYPE_NE;
675
676
0
  *number_of_sections = 0;
677
678
0
  if( libexe_ne_header_free(
679
0
       &ne_header,
680
0
       error ) != 1 )
681
0
  {
682
0
    libcerror_error_set(
683
0
     error,
684
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
685
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
686
0
     "%s: unable to free NE header.",
687
0
     function );
688
689
0
    goto on_error;
690
0
  }
691
0
  return( 1 );
692
693
1
on_error:
694
1
  if( ne_header != NULL )
695
1
  {
696
1
    libexe_ne_header_free(
697
1
     &ne_header,
698
1
     NULL );
699
1
  }
700
1
  return( -1 );
701
0
}
702
703
/* Reads the PE/COFF header
704
 * Returns 1 if successful or -1 on error
705
 */
706
int libexe_io_handle_read_pe_header(
707
     libexe_io_handle_t *io_handle,
708
     libbfio_handle_t *file_io_handle,
709
     uint32_t pe_header_offset,
710
     uint16_t *number_of_sections,
711
     libcerror_error_t **error )
712
710
{
713
710
  exe_pe_header_t pe_header;
714
715
710
  static char *function = "libexe_io_handle_read_pe_header";
716
710
  ssize_t read_count    = 0;
717
710
  off64_t file_offset   = 0;
718
719
710
  if( io_handle == NULL )
720
0
  {
721
0
    libcerror_error_set(
722
0
     error,
723
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
724
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
725
0
     "%s: invalid IO handle.",
726
0
     function );
727
728
0
    return( -1 );
729
0
  }
730
710
  if( number_of_sections == NULL )
731
0
  {
732
0
    libcerror_error_set(
733
0
     error,
734
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
735
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
736
0
     "%s: invalid number of sections.",
737
0
     function );
738
739
0
    return( -1 );
740
0
  }
741
#if defined( HAVE_DEBUG_OUTPUT )
742
  if( libcnotify_verbose != 0 )
743
  {
744
    libcnotify_printf(
745
     "%s: reading PE header at offset: %" PRIu32 " (0x%08" PRIx32 ")\n",
746
     function,
747
     pe_header_offset,
748
     pe_header_offset );
749
  }
750
#endif
751
710
  read_count = libbfio_handle_read_buffer_at_offset(
752
710
                file_io_handle,
753
710
                (uint8_t *) &pe_header,
754
710
                sizeof( exe_pe_header_t ),
755
710
                (off64_t) pe_header_offset,
756
710
                error );
757
758
710
  if( read_count != (ssize_t) sizeof( exe_pe_header_t ) )
759
2
  {
760
2
    libcerror_error_set(
761
2
     error,
762
2
     LIBCERROR_ERROR_DOMAIN_IO,
763
2
     LIBCERROR_IO_ERROR_READ_FAILED,
764
2
     "%s: unable to read PE header data at offset: %" PRIu32 " (0x%08" PRIx32 ").",
765
2
     function,
766
2
     pe_header_offset,
767
2
     pe_header_offset );
768
769
2
    return( -1 );
770
2
  }
771
#if defined( HAVE_DEBUG_OUTPUT )
772
  if( libcnotify_verbose != 0 )
773
  {
774
    libcnotify_printf(
775
     "%s: PE header:\n",
776
     function );
777
    libcnotify_print_data(
778
     (uint8_t *) &pe_header,
779
     sizeof( exe_pe_header_t ),
780
     0 );
781
  }
782
#endif
783
708
  if( memory_compare(
784
708
       pe_header.signature,
785
708
       exe_pe_signature,
786
708
       4 ) != 0 )
787
13
  {
788
13
    libcerror_error_set(
789
13
     error,
790
13
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
791
13
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
792
13
     "%s: invalid signature.",
793
13
     function );
794
795
13
    return( -1 );
796
13
  }
797
#if defined( HAVE_DEBUG_OUTPUT )
798
  if( libcnotify_verbose != 0 )
799
  {
800
    libcnotify_printf(
801
     "%s: signature\t\t\t\t: %c%c\\x%" PRIx8 "\\x%" PRIx8 "\n",
802
     function,
803
     pe_header.signature[ 0 ],
804
     pe_header.signature[ 1 ],
805
     pe_header.signature[ 2 ],
806
     pe_header.signature[ 3 ] );
807
808
    libcnotify_printf(
809
     "\n" );
810
  }
811
#endif
812
695
  if( libexe_coff_header_initialize(
813
695
       &( io_handle->coff_header ),
814
695
       error ) != 1 )
815
0
  {
816
0
    libcerror_error_set(
817
0
     error,
818
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
819
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
820
0
     "%s: unable to create COFF header.",
821
0
     function );
822
823
0
    goto on_error;
824
0
  }
825
695
  file_offset = pe_header_offset + sizeof( exe_pe_header_t );
826
827
695
  if( libexe_coff_header_read_file_io_handle(
828
695
       io_handle->coff_header,
829
695
       file_io_handle,
830
695
       file_offset,
831
695
       error ) != 1 )
832
7
  {
833
7
    libcerror_error_set(
834
7
     error,
835
7
     LIBCERROR_ERROR_DOMAIN_IO,
836
7
     LIBCERROR_IO_ERROR_READ_FAILED,
837
7
     "%s: unable to read COFF header.",
838
7
     function );
839
840
7
    goto on_error;
841
7
  }
842
688
  file_offset += sizeof( exe_coff_header_t );
843
844
688
  *number_of_sections = io_handle->coff_header->number_of_sections;
845
846
688
  if( io_handle->coff_header->optional_header_size > 0 )
847
609
  {
848
609
    if( libexe_coff_optional_header_initialize(
849
609
         &( io_handle->coff_optional_header ),
850
609
         error ) != 1 )
851
0
    {
852
0
      libcerror_error_set(
853
0
       error,
854
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
855
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
856
0
       "%s: unable to create COFF optional header.",
857
0
       function );
858
859
0
      goto on_error;
860
0
    }
861
609
    if( libexe_coff_optional_header_read_file_io_handle(
862
609
         io_handle->coff_optional_header,
863
609
         file_io_handle,
864
609
         file_offset,
865
609
         io_handle->coff_header->optional_header_size,
866
609
         error ) != 1 )
867
100
    {
868
100
      libcerror_error_set(
869
100
       error,
870
100
       LIBCERROR_ERROR_DOMAIN_IO,
871
100
       LIBCERROR_IO_ERROR_READ_FAILED,
872
100
       "%s: unable to read COFF optional header.",
873
100
       function );
874
875
100
      goto on_error;
876
100
    }
877
609
  }
878
588
  io_handle->executable_type = LIBEXE_EXECUTABLE_TYPE_PE_COFF;
879
880
588
  return( 1 );
881
882
107
on_error:
883
107
  if( io_handle->coff_optional_header != NULL )
884
100
  {
885
100
    libexe_coff_optional_header_free(
886
100
     &( io_handle->coff_optional_header ),
887
100
     NULL );
888
100
  }
889
107
  if( io_handle->coff_header != NULL )
890
107
  {
891
107
    libexe_coff_header_free(
892
107
     &( io_handle->coff_header ),
893
107
     NULL );
894
107
  }
895
107
  return( -1 );
896
688
}
897
898
/* Reads the section table
899
 * Returns 1 if successful or -1 on error
900
 */
901
int libexe_io_handle_read_section_table(
902
     libexe_io_handle_t *io_handle,
903
     libbfio_handle_t *file_io_handle,
904
     uint16_t number_of_sections,
905
     libcdata_array_t *sections_array,
906
     libcerror_error_t **error )
907
505
{
908
505
  libexe_section_descriptor_t *section_descriptor = NULL;
909
505
  uint8_t *section_table                          = NULL;
910
505
  uint8_t *section_table_data                     = NULL;
911
505
  static char *function                           = "libexe_io_handle_read_section_table";
912
505
  size_t section_table_size                       = 0;
913
505
  ssize_t read_count                              = 0;
914
505
  uint32_t section_data_offset                    = 0;
915
505
  uint32_t section_data_size                      = 0;
916
505
  int entry_index                                 = 0;
917
918
#if defined( HAVE_DEBUG_OUTPUT )
919
  uint32_t value_32bit                            = 0;
920
  uint16_t value_16bit                            = 0;
921
  uint16_t section_index                          = 0;
922
#endif
923
924
505
  if( io_handle == NULL )
925
0
  {
926
0
    libcerror_error_set(
927
0
     error,
928
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
929
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
930
0
     "%s: invalid IO handle.",
931
0
     function );
932
933
0
    return( -1 );
934
0
  }
935
505
  section_table_size = sizeof( exe_section_table_entry_t )
936
505
                     * number_of_sections;
937
938
505
  if( ( section_table_size == 0 )
939
505
   || ( section_table_size > MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
940
0
  {
941
0
    libcerror_error_set(
942
0
     error,
943
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
944
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
945
0
     "%s: invalid section table size value out of bounds.",
946
0
     function );
947
948
0
    return( -1 );
949
0
  }
950
505
  section_table = (uint8_t *) memory_allocate(
951
505
                               sizeof( uint8_t ) * section_table_size );
952
953
505
  if( section_table == NULL )
954
0
  {
955
0
    libcerror_error_set(
956
0
     error,
957
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
958
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
959
0
     "%s: unable to create section table.",
960
0
     function );
961
962
0
    goto on_error;
963
0
  }
964
505
  read_count = libbfio_handle_read_buffer(
965
505
                file_io_handle,
966
505
                section_table,
967
505
                section_table_size,
968
505
                error );
969
970
505
  if( read_count != (ssize_t) section_table_size )
971
78
  {
972
78
    libcerror_error_set(
973
78
     error,
974
78
     LIBCERROR_ERROR_DOMAIN_IO,
975
78
     LIBCERROR_IO_ERROR_READ_FAILED,
976
78
     "%s: unable to read section table.",
977
78
     function );
978
979
78
    goto on_error;
980
78
  }
981
#if defined( HAVE_DEBUG_OUTPUT )
982
  if( libcnotify_verbose != 0 )
983
  {
984
    libcnotify_printf(
985
     "%s: section table data:\n",
986
     function );
987
    libcnotify_print_data(
988
     section_table,
989
     section_table_size,
990
     0 );
991
  }
992
#endif
993
427
  section_table_data = section_table;
994
995
206k
  while( section_table_size >= sizeof( exe_section_table_entry_t ) )
996
205k
  {
997
205k
    if( libexe_section_descriptor_initialize(
998
205k
         &section_descriptor,
999
205k
         error ) != 1 )
1000
0
    {
1001
0
      libcerror_error_set(
1002
0
       error,
1003
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1004
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1005
0
       "%s: unable to create section descriptor.",
1006
0
       function );
1007
1008
0
      goto on_error;
1009
0
    }
1010
205k
    if( memory_copy(
1011
205k
         section_descriptor->name,
1012
205k
         ( (exe_section_table_entry_t *) section_table_data )->name,
1013
205k
         8 ) == NULL )
1014
0
    {
1015
0
      libcerror_error_set(
1016
0
       error,
1017
0
       LIBCERROR_ERROR_DOMAIN_MEMORY,
1018
0
       LIBCERROR_MEMORY_ERROR_COPY_FAILED,
1019
0
       "%s: unable to copy name.",
1020
0
       function );
1021
1022
0
      goto on_error;
1023
0
    }
1024
205k
    section_descriptor->name[ 8 ] = 0;
1025
1026
205k
    section_descriptor->name_size = narrow_string_length(
1027
205k
                                     section_descriptor->name );
1028
1029
205k
    if( section_descriptor->name_size > 0 )
1030
125k
    {
1031
125k
      section_descriptor->name_size += 1;
1032
125k
    }
1033
205k
    byte_stream_copy_to_uint32_little_endian(
1034
205k
     ( (exe_section_table_entry_t *) section_table_data )->virtual_address,
1035
205k
     section_descriptor->virtual_address );
1036
1037
205k
    byte_stream_copy_to_uint32_little_endian(
1038
205k
     ( (exe_section_table_entry_t *) section_table_data )->data_size,
1039
205k
     section_data_size );
1040
1041
205k
    byte_stream_copy_to_uint32_little_endian(
1042
205k
     ( (exe_section_table_entry_t *) section_table_data )->data_offset,
1043
205k
     section_data_offset );
1044
1045
#if defined( HAVE_DEBUG_OUTPUT )
1046
    if( libcnotify_verbose != 0 )
1047
    {
1048
      libcnotify_printf(
1049
       "%s: entry: %02" PRIu16 " name\t\t\t\t: %s\n",
1050
       function,
1051
       section_index,
1052
       section_descriptor->name );
1053
1054
      byte_stream_copy_to_uint32_little_endian(
1055
       ( (exe_section_table_entry_t *) section_table_data )->virtual_size,
1056
       value_32bit );
1057
      libcnotify_printf(
1058
       "%s: entry: %02" PRIu16 " virtual size\t\t\t: %" PRIu32 "\n",
1059
       function,
1060
       section_index,
1061
       value_32bit );
1062
1063
      libcnotify_printf(
1064
       "%s: entry: %02" PRIu16 " virtual address\t\t\t: 0x%08" PRIx32 "\n",
1065
       function,
1066
       section_index,
1067
       section_descriptor->virtual_address );
1068
1069
      libcnotify_printf(
1070
       "%s: entry: %02" PRIu16 " data size\t\t\t: %" PRIu32 "\n",
1071
       function,
1072
       section_index,
1073
       section_data_size );
1074
1075
      libcnotify_printf(
1076
       "%s: entry: %02" PRIu16 " data offset\t\t\t: 0x%08" PRIx32 "\n",
1077
       function,
1078
       section_index,
1079
       section_data_offset );
1080
1081
      byte_stream_copy_to_uint32_little_endian(
1082
       ( (exe_section_table_entry_t *) section_table_data )->relocations_offset,
1083
       value_32bit );
1084
      libcnotify_printf(
1085
       "%s: entry: %02" PRIu16 " relocations offset\t\t: 0x%08" PRIx32 "\n",
1086
       function,
1087
       section_index,
1088
       value_32bit );
1089
1090
      byte_stream_copy_to_uint32_little_endian(
1091
       ( (exe_section_table_entry_t *) section_table_data )->line_numbers_offset,
1092
       value_32bit );
1093
      libcnotify_printf(
1094
       "%s: entry: %02" PRIu16 " line numbers offset\t\t: 0x%08" PRIx32 "\n",
1095
       function,
1096
       section_index,
1097
       value_32bit );
1098
1099
      byte_stream_copy_to_uint16_little_endian(
1100
       ( (exe_section_table_entry_t *) section_table_data )->relocations_offset,
1101
       value_16bit );
1102
      libcnotify_printf(
1103
       "%s: entry: %02" PRIu16 " number of relocations\t\t: %" PRIu16 "\n",
1104
       function,
1105
       section_index,
1106
       value_16bit );
1107
1108
      byte_stream_copy_to_uint16_little_endian(
1109
       ( (exe_section_table_entry_t *) section_table_data )->line_numbers_offset,
1110
       value_16bit );
1111
      libcnotify_printf(
1112
       "%s: entry: %02" PRIu16 " number of line numbers\t\t: %" PRIu16 "\n",
1113
       function,
1114
       section_index,
1115
       value_16bit );
1116
1117
      byte_stream_copy_to_uint32_little_endian(
1118
       ( (exe_section_table_entry_t *) section_table_data )->section_characteristic_flags,
1119
       value_32bit );
1120
      libcnotify_printf(
1121
       "%s: entry: %02" PRIu16 " section characteristic flags\t: 0x%08" PRIx32 "\n",
1122
       function,
1123
       section_index,
1124
       value_32bit );
1125
      libexe_debug_print_section_characteristic_flags(
1126
       value_32bit );
1127
      libcnotify_printf(
1128
       "\n" );
1129
    }
1130
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
1131
1132
205k
    section_table_data += sizeof( exe_section_table_entry_t );
1133
205k
    section_table_size -= sizeof( exe_section_table_entry_t );
1134
1135
205k
    if( libexe_section_descriptor_set_data_range(
1136
205k
         section_descriptor,
1137
205k
         (off64_t) section_data_offset,
1138
205k
         (size64_t) section_data_size,
1139
205k
         error ) != 1 )
1140
0
    {
1141
0
      libcerror_error_set(
1142
0
       error,
1143
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1144
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1145
0
       "%s: unable to set data range in section descriptor.",
1146
0
       function );
1147
1148
0
      goto on_error;
1149
0
    }
1150
205k
    if( libcdata_array_append_entry(
1151
205k
         sections_array,
1152
205k
         &entry_index,
1153
205k
         (intptr_t *) section_descriptor,
1154
205k
         error ) != 1 )
1155
0
    {
1156
0
      libcerror_error_set(
1157
0
       error,
1158
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1159
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
1160
0
       "%s: unable to append section descriptor to sections array.",
1161
0
       function );
1162
1163
0
      goto on_error;
1164
0
    }
1165
205k
    section_descriptor = NULL;
1166
1167
#if defined( HAVE_DEBUG_OUTPUT )
1168
    section_index++;
1169
#endif
1170
205k
  }
1171
427
  memory_free(
1172
427
   section_table );
1173
1174
427
  return( 1 );
1175
1176
78
on_error:
1177
78
  if( section_descriptor != NULL )
1178
0
  {
1179
0
    libexe_section_descriptor_free(
1180
0
     &section_descriptor,
1181
0
     NULL );
1182
0
  }
1183
78
  if( section_table != NULL )
1184
78
  {
1185
78
    memory_free(
1186
78
     section_table );
1187
78
  }
1188
78
  return( -1 );
1189
427
}
1190
1191
/* Reads the segment data into the buffer
1192
 * Callback function for the section stream
1193
 * Returns the number of bytes read or -1 on error
1194
 */
1195
ssize_t libexe_io_handle_read_segment_data(
1196
         intptr_t *data_handle LIBEXE_ATTRIBUTE_UNUSED,
1197
         libbfio_handle_t *file_io_handle,
1198
         int segment_index LIBEXE_ATTRIBUTE_UNUSED,
1199
         int segment_file_index LIBEXE_ATTRIBUTE_UNUSED,
1200
         uint8_t *segment_data,
1201
         size_t segment_data_size,
1202
         uint32_t segment_flags LIBEXE_ATTRIBUTE_UNUSED,
1203
         uint8_t read_flags LIBEXE_ATTRIBUTE_UNUSED,
1204
         libcerror_error_t **error )
1205
0
{
1206
0
  static char *function = "libexe_io_handle_read_segment_data";
1207
0
  ssize_t read_count    = 0;
1208
1209
0
  LIBEXE_UNREFERENCED_PARAMETER( data_handle )
1210
0
  LIBEXE_UNREFERENCED_PARAMETER( segment_index )
1211
0
  LIBEXE_UNREFERENCED_PARAMETER( segment_file_index )
1212
0
  LIBEXE_UNREFERENCED_PARAMETER( segment_flags )
1213
0
  LIBEXE_UNREFERENCED_PARAMETER( read_flags )
1214
1215
0
  read_count = libbfio_handle_read_buffer(
1216
0
          file_io_handle,
1217
0
          segment_data,
1218
0
          segment_data_size,
1219
0
          error );
1220
1221
0
  if( read_count != (ssize_t) segment_data_size )
1222
0
  {
1223
0
    libcerror_error_set(
1224
0
     error,
1225
0
     LIBCERROR_ERROR_DOMAIN_IO,
1226
0
     LIBCERROR_IO_ERROR_READ_FAILED,
1227
0
     "%s: unable to read segment data.",
1228
0
     function );
1229
1230
0
    return( -1 );
1231
0
  }
1232
0
  return( read_count );
1233
0
}
1234
1235
/* Seeks a certain segment offset
1236
 * Callback function for the section stream
1237
 * Returns the offset or -1 on error
1238
 */
1239
off64_t libexe_io_handle_seek_segment_offset(
1240
         intptr_t *data_handle LIBEXE_ATTRIBUTE_UNUSED,
1241
         libbfio_handle_t *file_io_handle,
1242
         int segment_index LIBEXE_ATTRIBUTE_UNUSED,
1243
         int segment_file_index LIBEXE_ATTRIBUTE_UNUSED,
1244
         off64_t segment_offset,
1245
         libcerror_error_t **error )
1246
0
{
1247
0
  static char *function = "libexe_io_handle_seek_segment_offset";
1248
1249
0
  LIBEXE_UNREFERENCED_PARAMETER( data_handle )
1250
0
  LIBEXE_UNREFERENCED_PARAMETER( segment_index )
1251
0
  LIBEXE_UNREFERENCED_PARAMETER( segment_file_index )
1252
1253
0
  segment_offset = libbfio_handle_seek_offset(
1254
0
                    file_io_handle,
1255
0
                    segment_offset,
1256
0
                    SEEK_SET,
1257
0
                    error );
1258
1259
0
  if( segment_offset == -1 )
1260
0
  {
1261
0
    libcerror_error_set(
1262
0
     error,
1263
0
     LIBCERROR_ERROR_DOMAIN_IO,
1264
0
     LIBCERROR_IO_ERROR_READ_FAILED,
1265
0
     "%s: unable to seek segment offset.",
1266
0
     function );
1267
1268
0
    return( -1 );
1269
0
  }
1270
0
  return( segment_offset );
1271
0
}
1272