github.com/saferwall/pe@v1.5.2/loadconfig.go (about)

     1  // Copyright 2018 Saferwall. All rights reserved.
     2  // Use of this source code is governed by Apache v2 license
     3  // license that can be found in the LICENSE file.
     4  
     5  // References:
     6  // https://www.virtualbox.org/svn/vbox/trunk/include/iprt/formats/pecoff.h
     7  // https://github.com/hdoc/llvm-project/blob/release/15.x/llvm/include/llvm/Object/COFF.h
     8  // https://ffri.github.io/ProjectChameleon/new_reloc_chpev2/
     9  // https://blogs.blackberry.com/en/2019/09/teardown-windows-10-on-arm-x86-emulation
    10  // DVRT: https://www.alex-ionescu.com/?p=323
    11  // https://xlab.tencent.com/en/2016/11/02/return-flow-guard/
    12  // https://denuvosoftwaresolutions.github.io/DVRT/dvrt.html
    13  // BlueHat v18 || Retpoline: The Anti sectre type 2 mitigation in windows: https://www.youtube.com/watch?v=ZfxXjDQRpsU
    14  
    15  package pe
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/binary"
    20  	"fmt"
    21  	"reflect"
    22  )
    23  
    24  // ImageGuardFlagType represents the type for load configuration image guard flags.
    25  type ImageGuardFlagType uint8
    26  
    27  // GFIDS table entry flags.
    28  const (
    29  	// ImageGuardFlagFIDSuppressed indicates that the call target is explicitly
    30  	// suppressed (do not treat it as valid for purposes of CFG).
    31  	ImageGuardFlagFIDSuppressed = 0x1
    32  
    33  	// ImageGuardFlagExportSuppressed indicates that the call target is export
    34  	// suppressed. See Export suppression for more details.
    35  	ImageGuardFlagExportSuppressed = 0x2
    36  )
    37  
    38  // The GuardFlags field contains a combination of one or more of the
    39  // following flags and subfields:
    40  const (
    41  	// ImageGuardCfInstrumented indicates that the module performs control flow
    42  	// integrity checks using system-supplied support.
    43  	ImageGuardCfInstrumented = 0x00000100
    44  
    45  	// ImageGuardCfWInstrumented indicates that the module performs control
    46  	// flow and write integrity checks.
    47  	ImageGuardCfWInstrumented = 0x00000200
    48  
    49  	// ImageGuardCfFunctionTablePresent indicates that the module contains
    50  	// valid control flow target metadata.
    51  	ImageGuardCfFunctionTablePresent = 0x00000400
    52  
    53  	// ImageGuardSecurityCookieUnused indicates that the module does not make
    54  	// use of the /GS security cookie.
    55  	ImageGuardSecurityCookieUnused = 0x00000800
    56  
    57  	// ImageGuardProtectDelayLoadIAT indicates that the module supports read
    58  	// only delay load IAT.
    59  	ImageGuardProtectDelayLoadIAT = 0x00001000
    60  
    61  	// ImageGuardDelayLoadIATInItsOwnSection indicates that the Delayload
    62  	// import table in its own .didat section (with nothing else in it) that
    63  	// can be freely reprotected.
    64  	ImageGuardDelayLoadIATInItsOwnSection = 0x00002000
    65  
    66  	// ImageGuardCfExportSuppressionInfoPresent indicates that the module
    67  	// contains suppressed export information. This also infers that the
    68  	// address taken IAT table is also present in the load config.
    69  	ImageGuardCfExportSuppressionInfoPresent = 0x00004000
    70  
    71  	// ImageGuardCfEnableExportSuppression indicates that the module enables
    72  	// suppression of exports.
    73  	ImageGuardCfEnableExportSuppression = 0x00008000
    74  
    75  	// ImageGuardCfLongJumpTablePresent indicates that the module contains
    76  	// long jmp target information.
    77  	ImageGuardCfLongJumpTablePresent = 0x00010000
    78  )
    79  
    80  const (
    81  	// ImageGuardCfFunctionTableSizeMask indicates that the mask for the
    82  	// subfield that contains the stride of Control Flow Guard function table
    83  	// entries (that is, the additional count of bytes per table entry).
    84  	ImageGuardCfFunctionTableSizeMask = 0xF0000000
    85  
    86  	// ImageGuardCfFunctionTableSizeShift indicates the shift to right-justify
    87  	// Guard CF function table stride.
    88  	ImageGuardCfFunctionTableSizeShift = 28
    89  )
    90  
    91  const (
    92  	ImageDynamicRelocationGuardRfPrologue = 0x00000001
    93  	ImageDynamicRelocationGuardREpilogue  = 0x00000002
    94  )
    95  
    96  // Software enclave information.
    97  const (
    98  	ImageEnclaveLongIDLength  = 32
    99  	ImageEnclaveShortIDLength = 16
   100  )
   101  
   102  const (
   103  	// ImageEnclaveImportMatchNone indicates that none of the identifiers of the
   104  	// image need to match the value in the import record.
   105  	ImageEnclaveImportMatchNone = 0x00000000
   106  
   107  	// ImageEnclaveImportMatchUniqueId indicates that the value of the enclave
   108  	// unique identifier of the image must match the value in the import record.
   109  	// Otherwise, loading of the image fails.
   110  	ImageEnclaveImportMatchUniqueID = 0x00000001
   111  
   112  	// ImageEnclaveImportMatchAuthorId indicates that the value of the enclave
   113  	// author identifier of the image must match the value in the import record.
   114  	// Otherwise, loading of the image fails. If this flag is set and the import
   115  	// record indicates an author identifier of all zeros, the imported image
   116  	// must be part of the Windows installation.
   117  	ImageEnclaveImportMatchAuthorID = 0x00000002
   118  
   119  	// ImageEnclaveImportMatchFamilyId indicates that the value of the enclave
   120  	// family identifier of the image must match the value in the import record.
   121  	// Otherwise, loading of the image fails.
   122  	ImageEnclaveImportMatchFamilyID = 0x00000003
   123  
   124  	// ImageEnclaveImportMatchImageId indicates that the value of the enclave
   125  	// image identifier must match the value in the import record. Otherwise,
   126  	// loading of the image fails.
   127  	ImageEnclaveImportMatchImageID = 0x00000004
   128  )
   129  
   130  // ImageLoadConfigDirectory32 Contains the load configuration data of an image for x86 binaries.
   131  type ImageLoadConfigDirectory32 struct {
   132  	// The actual size of the structure inclusive. May differ from the size
   133  	// given in the data directory for Windows XP and earlier compatibility.
   134  	Size uint32 `json:"size"`
   135  
   136  	// Date and time stamp value.
   137  	TimeDateStamp uint32 `json:"time_date_stamp"`
   138  
   139  	// Major version number.
   140  	MajorVersion uint16 `json:"major_version"`
   141  
   142  	// Minor version number.
   143  	MinorVersion uint16 `json:"minor_version"`
   144  
   145  	// The global loader flags to clear for this process as the loader starts
   146  	// the process.
   147  	GlobalFlagsClear uint32 `json:"global_flags_clear"`
   148  
   149  	// The global loader flags to set for this process as the loader starts the
   150  	// process.
   151  	GlobalFlagsSet uint32 `json:"global_flags_set"`
   152  
   153  	// The default timeout value to use for this process's critical sections
   154  	// that are abandoned.
   155  	CriticalSectionDefaultTimeout uint32 `json:"critical_section_default_timeout"`
   156  
   157  	// Memory that must be freed before it is returned to the system, in bytes.
   158  	DeCommitFreeBlockThreshold uint32 `json:"de_commit_free_block_threshold"`
   159  
   160  	// Total amount of free memory, in bytes.
   161  	DeCommitTotalFreeThreshold uint32 `json:"de_commit_total_free_threshold"`
   162  
   163  	// [x86 only] The VA of a list of addresses where the LOCK prefix is used so
   164  	// that they can be replaced with NOP on single processor machines.
   165  	LockPrefixTable uint32 `json:"lock_prefix_table"`
   166  
   167  	// Maximum allocation size, in bytes.
   168  	MaximumAllocationSize uint32 `json:"maximum_allocation_size"`
   169  
   170  	// Maximum virtual memory size, in bytes.
   171  	VirtualMemoryThreshold uint32 `json:"virtual_memory_threshold"`
   172  
   173  	// Process heap flags that correspond to the first argument of the HeapCreate
   174  	// function. These flags apply to the process heap that is created during
   175  	// process startup.
   176  	ProcessHeapFlags uint32 `json:"process_heap_flags"`
   177  
   178  	// Setting this field to a non-zero value is equivalent to calling
   179  	// SetProcessAffinityMask with this value during process startup (.exe only)
   180  	ProcessAffinityMask uint32 `json:"process_affinity_mask"`
   181  
   182  	// The service pack version identifier.
   183  	CSDVersion uint16 `json:"csd_version"`
   184  
   185  	// Must be zero.
   186  	DependentLoadFlags uint16 `json:"dependent_load_flags"`
   187  
   188  	// Reserved for use by the system.
   189  	EditList uint32 `json:"edit_list"`
   190  
   191  	// A pointer to a cookie that is used by Visual C++ or GS implementation.
   192  	SecurityCookie uint32 `json:"security_cookie"`
   193  
   194  	// [x86 only] The VA of the sorted table of RVAs of each valid, unique SE
   195  	// handler in the image.
   196  	SEHandlerTable uint32 `json:"se_handler_table"`
   197  
   198  	// [x86 only] The count of unique handlers in the table.
   199  	SEHandlerCount uint32 `json:"se_handler_count"`
   200  
   201  	// The VA where Control Flow Guard check-function pointer is stored.
   202  	GuardCFCheckFunctionPointer uint32 `json:"guard_cf_check_function_pointer"`
   203  
   204  	// The VA where Control Flow Guard dispatch-function pointer is stored.
   205  	GuardCFDispatchFunctionPointer uint32 `json:"guard_cf_dispatch_function_pointer"`
   206  
   207  	// The VA of the sorted table of RVAs of each Control Flow Guard function in
   208  	// the image.
   209  	GuardCFFunctionTable uint32 `json:"guard_cf_function_table"`
   210  
   211  	// The count of unique RVAs in the above table.
   212  	GuardCFFunctionCount uint32 `json:"guard_cf_function_count"`
   213  
   214  	// Control Flow Guard related flags.
   215  	GuardFlags uint32 `json:"guard_flags"`
   216  
   217  	// Code integrity information.
   218  	CodeIntegrity ImageLoadConfigCodeIntegrity `json:"code_integrity"`
   219  
   220  	// The VA where Control Flow Guard address taken IAT table is stored.
   221  	GuardAddressTakenIATEntryTable uint32 `json:"guard_address_taken_iat_entry_table"`
   222  
   223  	// The count of unique RVAs in the above table.
   224  	GuardAddressTakenIATEntryCount uint32 `json:"guard_address_taken_iat_entry_count"`
   225  
   226  	// The VA where Control Flow Guard long jump target table is stored.
   227  	GuardLongJumpTargetTable uint32 `json:"guard_long_jump_target_table"`
   228  
   229  	// The count of unique RVAs in the above table.
   230  	GuardLongJumpTargetCount uint32 `json:"guard_long_jump_target_count"`
   231  
   232  	DynamicValueRelocTable uint32 `json:"dynamic_value_reloc_table"`
   233  
   234  	// Not sure when this was renamed from HybridMetadataPointer.
   235  	CHPEMetadataPointer uint32 `json:"chpe_metadata_pointer"`
   236  
   237  	GuardRFFailureRoutine                    uint32 `json:"guard_rf_failure_routine"`
   238  	GuardRFFailureRoutineFunctionPointer     uint32 `json:"guard_rf_failure_routine_function_pointer"`
   239  	DynamicValueRelocTableOffset             uint32 `json:"dynamic_value_reloc_table_offset"`
   240  	DynamicValueRelocTableSection            uint16 `json:"dynamic_value_reloc_table_section"`
   241  	Reserved2                                uint16 `json:"reserved_2"`
   242  	GuardRFVerifyStackPointerFunctionPointer uint32 `json:"guard_rf_verify_stack_pointer_function_pointer"`
   243  	HotPatchTableOffset                      uint32 `json:"hot_patch_table_offset"`
   244  	Reserved3                                uint32 `json:"reserved_3"`
   245  	EnclaveConfigurationPointer              uint32 `json:"enclave_configuration_pointer"`
   246  	VolatileMetadataPointer                  uint32 `json:"volatile_metadata_pointer"`
   247  	GuardEHContinuationTable                 uint32 `json:"guard_eh_continuation_table"`
   248  	GuardEHContinuationCount                 uint32 `json:"guard_eh_continuation_count"`
   249  	GuardXFGCheckFunctionPointer             uint32 `json:"guard_xfg_check_function_pointer"`
   250  	GuardXFGDispatchFunctionPointer          uint32 `json:"guard_xfg_dispatch_function_pointer"`
   251  	GuardXFGTableDispatchFunctionPointer     uint32 `json:"guard_xfg_table_dispatch_function_pointer"`
   252  	CastGuardOSDeterminedFailureMode         uint32 `json:"cast_guard_os_determined_failure_mode"`
   253  	GuardMemcpyFunctionPointer               uint32 `json:"guard_memcpy_function_pointer"`
   254  }
   255  
   256  // ImageLoadConfigDirectory64 Contains the load configuration data of an image for x64 binaries.
   257  type ImageLoadConfigDirectory64 struct {
   258  	// The actual size of the structure inclusive. May differ from the size
   259  	// given in the data directory for Windows XP and earlier compatibility.
   260  	Size uint32 `json:"size"`
   261  
   262  	// Date and time stamp value.
   263  	TimeDateStamp uint32 `json:"time_date_stamp"`
   264  
   265  	// Major version number.
   266  	MajorVersion uint16 `json:"major_version"`
   267  
   268  	// Minor version number.
   269  	MinorVersion uint16 `json:"minor_version"`
   270  
   271  	// The global loader flags to clear for this process as the loader starts
   272  	// the process.
   273  	GlobalFlagsClear uint32 `json:"global_flags_clear"`
   274  
   275  	// The global loader flags to set for this process as the loader starts the
   276  	// process.
   277  	GlobalFlagsSet uint32 `json:"global_flags_set"`
   278  
   279  	// The default timeout value to use for this process's critical sections
   280  	// that are abandoned.
   281  	CriticalSectionDefaultTimeout uint32 `json:"critical_section_default_timeout"`
   282  
   283  	// Memory that must be freed before it is returned to the system, in bytes.
   284  	DeCommitFreeBlockThreshold uint64 `json:"de_commit_free_block_threshold"`
   285  
   286  	// Total amount of free memory, in bytes.
   287  	DeCommitTotalFreeThreshold uint64 `json:"de_commit_total_free_threshold"`
   288  
   289  	// [x86 only] The VA of a list of addresses where the LOCK prefix is used so
   290  	// that they can be replaced with NOP on single processor machines.
   291  	LockPrefixTable uint64 `json:"lock_prefix_table"`
   292  
   293  	// Maximum allocation size, in bytes.
   294  	MaximumAllocationSize uint64 `json:"maximum_allocation_size"`
   295  
   296  	// Maximum virtual memory size, in bytes.
   297  	VirtualMemoryThreshold uint64 `json:"virtual_memory_threshold"`
   298  
   299  	// Setting this field to a non-zero value is equivalent to calling
   300  	// SetProcessAffinityMask with this value during process startup (.exe only)
   301  	ProcessAffinityMask uint64 `json:"process_affinity_mask"`
   302  
   303  	// Process heap flags that correspond to the first argument of the HeapCreate
   304  	// function. These flags apply to the process heap that is created during
   305  	// process startup.
   306  	ProcessHeapFlags uint32 `json:"process_heap_flags"`
   307  
   308  	// The service pack version identifier.
   309  	CSDVersion uint16 `json:"csd_version"`
   310  
   311  	// Must be zero.
   312  	DependentLoadFlags uint16 `json:"dependent_load_flags"`
   313  
   314  	// Reserved for use by the system.
   315  	EditList uint64 `json:"edit_list"`
   316  
   317  	// A pointer to a cookie that is used by Visual C++ or GS implementation.
   318  	SecurityCookie uint64 `json:"security_cookie"`
   319  
   320  	// [x86 only] The VA of the sorted table of RVAs of each valid, unique SE
   321  	// handler in the image.
   322  	SEHandlerTable uint64 `json:"se_handler_table"`
   323  
   324  	// [x86 only] The count of unique handlers in the table.
   325  	SEHandlerCount uint64 `json:"se_handler_count"`
   326  
   327  	// The VA where Control Flow Guard check-function pointer is stored.
   328  	GuardCFCheckFunctionPointer uint64 `json:"guard_cf_check_function_pointer"`
   329  
   330  	// The VA where Control Flow Guard dispatch-function pointer is stored.
   331  	GuardCFDispatchFunctionPointer uint64 `json:"guard_cf_dispatch_function_pointer"`
   332  
   333  	// The VA of the sorted table of RVAs of each Control Flow Guard function in
   334  	// the image.
   335  	GuardCFFunctionTable uint64 `json:"guard_cf_function_table"`
   336  
   337  	// The count of unique RVAs in the above table.
   338  	GuardCFFunctionCount uint64 `json:"guard_cf_function_count"`
   339  
   340  	// Control Flow Guard related flags.
   341  	GuardFlags uint32 `json:"guard_flags"`
   342  
   343  	// Code integrity information.
   344  	CodeIntegrity ImageLoadConfigCodeIntegrity `json:"code_integrity"`
   345  
   346  	// The VA where Control Flow Guard address taken IAT table is stored.
   347  	GuardAddressTakenIATEntryTable uint64 `json:"guard_address_taken_iat_entry_table"`
   348  
   349  	// The count of unique RVAs in the above table.
   350  	GuardAddressTakenIATEntryCount uint64 `json:"guard_address_taken_iat_entry_count"`
   351  
   352  	// The VA where Control Flow Guard long jump target table is stored.
   353  	GuardLongJumpTargetTable uint64 `json:"guard_long_jump_target_table"`
   354  
   355  	// The count of unique RVAs in the above table.
   356  	GuardLongJumpTargetCount uint64 `json:"guard_long_jump_target_count"`
   357  
   358  	DynamicValueRelocTable uint64 `json:"dynamic_value_reloc_table"`
   359  
   360  	// Not sure when this was renamed from HybridMetadataPointer.
   361  	CHPEMetadataPointer uint64 `json:"chpe_metadata_pointer"`
   362  
   363  	GuardRFFailureRoutine                    uint64 `json:"guard_rf_failure_routine"`
   364  	GuardRFFailureRoutineFunctionPointer     uint64 `json:"guard_rf_failure_routine_function_pointer"`
   365  	DynamicValueRelocTableOffset             uint32 `json:"dynamic_value_reloc_table_offset"`
   366  	DynamicValueRelocTableSection            uint16 `json:"dynamic_value_reloc_table_section"`
   367  	Reserved2                                uint16 `json:"reserved_2"`
   368  	GuardRFVerifyStackPointerFunctionPointer uint64 `json:"guard_rf_verify_stack_pointer_function_pointer"`
   369  	HotPatchTableOffset                      uint32 `json:"hot_patch_table_offset"`
   370  	Reserved3                                uint32 `json:"reserved_3"`
   371  	EnclaveConfigurationPointer              uint64 `json:"enclave_configuration_pointer"`
   372  	VolatileMetadataPointer                  uint64 `json:"volatile_metadata_pointer"`
   373  	GuardEHContinuationTable                 uint64 `json:"guard_eh_continuation_table"`
   374  	GuardEHContinuationCount                 uint64 `json:"guard_eh_continuation_count"`
   375  	GuardXFGCheckFunctionPointer             uint64 `json:"guard_xfg_check_function_pointer"`
   376  	GuardXFGDispatchFunctionPointer          uint64 `json:"guard_xfg_dispatch_function_pointer"`
   377  	GuardXFGTableDispatchFunctionPointer     uint64 `json:"guard_xfg_table_dispatch_function_pointer"`
   378  	CastGuardOSDeterminedFailureMode         uint64 `json:"cast_guard_os_determined_failure_mode"`
   379  	GuardMemcpyFunctionPointer               uint64 `json:"guard_memcpy_function_pointer"`
   380  }
   381  
   382  // ImageCHPEMetadataX86 represents the X86_IMAGE_CHPE_METADATA_X86.
   383  type ImageCHPEMetadataX86 struct {
   384  	Version                                  uint32 `json:"version"`
   385  	CHPECodeAddressRangeOffset               uint32 `json:"chpe_code_address_range_offset"`
   386  	CHPECodeAddressRangeCount                uint32 `json:"chpe_code_address_range_count"`
   387  	WoWA64ExceptionHandlerFunctionPtr        uint32 `json:"wow_a64_exception_handler_function_ptr"`
   388  	WoWA64DispatchCallFunctionPtr            uint32 `json:"wow_a64_dispatch_call_function_ptr"`
   389  	WoWA64DispatchIndirectCallFunctionPtr    uint32 `json:"wow_a64_dispatch_indirect_call_function_ptr"`
   390  	WoWA64DispatchIndirectCallCfgFunctionPtr uint32 `json:"wow_a64_dispatch_indirect_call_cfg_function_ptr"`
   391  	WoWA64DispatchRetFunctionPtr             uint32 `json:"wow_a64_dispatch_ret_function_ptr"`
   392  	WoWA64DispatchRetLeafFunctionPtr         uint32 `json:"wow_a64_dispatch_ret_leaf_function_ptr"`
   393  	WoWA64DispatchJumpFunctionPtr            uint32 `json:"wow_a64_dispatch_jump_function_ptr"`
   394  	CompilerIATPointer                       uint32 `json:"compiler_iat_pointer"`       // Present if Version >= 2
   395  	WoWA64RDTSCFunctionPtr                   uint32 `json:"wow_a64_rdtsc_function_ptr"` // Present if Version >= 3
   396  }
   397  
   398  type CodeRange struct {
   399  	Begin   uint32 `json:"begin"`
   400  	Length  uint32 `json:"length"`
   401  	Machine uint8  `json:"machine"`
   402  }
   403  
   404  type CompilerIAT struct {
   405  	RVA         uint32 `json:"rva"`
   406  	Value       uint32 `json:"value"`
   407  	Description string `json:"description"`
   408  }
   409  
   410  type HybridPE struct {
   411  	CHPEMetadata interface{}   `json:"chpe_metadata"`
   412  	CodeRanges   []CodeRange   `json:"code_ranges"`
   413  	CompilerIAT  []CompilerIAT `json:"compiler_iat"`
   414  }
   415  
   416  // ImageDynamicRelocationTable represents the DVRT header.
   417  type ImageDynamicRelocationTable struct {
   418  	// Until now, there is only one version of the DVRT header (1)..
   419  	Version uint32 `json:"version"`
   420  	// Size represents the number of bytes after the header that contains
   421  	// retpoline information.
   422  	Size uint32 `json:"size"`
   423  	//  IMAGE_DYNAMIC_RELOCATION DynamicRelocations[0];
   424  }
   425  
   426  // Dynamic value relocation entries following IMAGE_DYNAMIC_RELOCATION_TABLE.
   427  // Each block starts with the header.
   428  
   429  // ImageDynamicRelocation32 represents the 32-bit version of a reloc entry.
   430  type ImageDynamicRelocation32 struct {
   431  	// Symbol field identifies one of the existing types of dynamic relocations
   432  	// so far (values 3, 4 and 5).
   433  	Symbol uint32 `json:"symbol"`
   434  
   435  	// Then, for each page, there is a block that starts with a relocation entry.
   436  	// BaseRelocSize represents the size of the block.
   437  	BaseRelocSize uint32 `json:"base_reloc_size"`
   438  	//  IMAGE_BASE_RELOCATION BaseRelocations[0];
   439  }
   440  
   441  // ImageDynamicRelocation64 represents the 64-bit version of a reloc entry.
   442  type ImageDynamicRelocation64 struct {
   443  	// Symbol field identifies one of the existing types of dynamic relocations
   444  	// so far (values 3, 4 and 5).
   445  	Symbol uint64 `json:"symbol"`
   446  
   447  	// Then, for each page, there is a block that starts with a relocation entry.
   448  	// BaseRelocSize represents the size of the block.
   449  	BaseRelocSize uint32 `json:"base_reloc_size"`
   450  	//  IMAGE_BASE_RELOCATION BaseRelocations[0];
   451  }
   452  
   453  type ImageDynamicRelocation32v2 struct {
   454  	HeaderSize    uint32 `json:"header_size"`
   455  	FixupInfoSize uint32 `json:"fixup_info_size"`
   456  	Symbol        uint32 `json:"symbol"`
   457  	SymbolGroup   uint32 `json:"symbol_group"`
   458  	Flags         uint32 `json:"flags"`
   459  	// ...     variable length header fields
   460  	// UCHAR   FixupInfo[FixupInfoSize]
   461  }
   462  
   463  type ImageDynamicRelocation64v2 struct {
   464  	HeaderSize    uint32 `json:"header_size"`
   465  	FixupInfoSize uint32 `json:"fixup_info_size"`
   466  	Symbol        uint64 `json:"symbol"`
   467  	SymbolGroup   uint32 `json:"symbol_group"`
   468  	Flags         uint32 `json:"flags"`
   469  	// ...     variable length header fields
   470  	// UCHAR   FixupInfo[FixupInfoSize]
   471  }
   472  
   473  type ImagePrologueDynamicRelocationHeader struct {
   474  	PrologueByteCount uint8 `json:"prologue_byte_count"`
   475  	// UCHAR   PrologueBytes[PrologueByteCount];
   476  }
   477  
   478  type ImageEpilogueDynamicRelocationHeader struct {
   479  	EpilogueCount               uint32 `json:"epilogue_count"`
   480  	EpilogueByteCount           uint8  `json:"epilogue_byte_count"`
   481  	BranchDescriptorElementSize uint8  `json:"branch_descriptor_element_size"`
   482  	BranchDescriptorCount       uint8  `json:"branch_descriptor_count"`
   483  	// UCHAR   BranchDescriptors[...];
   484  	// UCHAR   BranchDescriptorBitMap[...];
   485  }
   486  
   487  type CFGFunction struct {
   488  	// RVA of the target CFG call.
   489  	RVA uint32 `json:"rva"`
   490  
   491  	// Flags attached to each GFIDS entry if any call targets have metadata.
   492  	Flags       ImageGuardFlagType `json:"flags"`
   493  	Description string             `json:"description"`
   494  }
   495  
   496  type CFGIATEntry struct {
   497  	RVA         uint32 `json:"rva"`
   498  	IATValue    uint32 `json:"iat_value"`
   499  	INTValue    uint32 `json:"int_value"`
   500  	Description string `json:"description"`
   501  }
   502  
   503  type RelocBlock struct {
   504  	ImgBaseReloc ImageBaseRelocation `json:"img_base_reloc"`
   505  	TypeOffsets  []interface{}       `json:"type_offsets"`
   506  }
   507  type RelocEntry struct {
   508  	// Could be ImageDynamicRelocation32{} or ImageDynamicRelocation64{}
   509  	ImageDynamicRelocation interface{}  `json:"image_dynamic_relocation"`
   510  	RelocBlocks            []RelocBlock `json:"reloc_blocks"`
   511  }
   512  
   513  // ImageImportControlTransferDynamicRelocation represents the Imported Address
   514  // Retpoline (type 3), size = 4 bytes.
   515  type ImageImportControlTransferDynamicRelocation struct {
   516  	PageRelativeOffset uint16 `json:"page_relative_offset"` // (12 bits)
   517  	// 1 - the opcode is a CALL
   518  	// 0 - the opcode is a JMP.
   519  	IndirectCall uint16 `json:"indirect_call"` // (1 bit)
   520  	IATIndex     uint32 `json:"iat_index"`     // (19 bits)
   521  }
   522  
   523  // ImageIndirectControlTransferDynamicRelocation represents the Indirect Branch
   524  // Retpoline (type 4), size = 2 bytes.
   525  type ImageIndirectControlTransferDynamicRelocation struct {
   526  	PageRelativeOffset uint16 `json:"page_relative_offset"` // (12 bits)
   527  	IndirectCall       uint8  `json:"indirect_call"`        // (1 bit)
   528  	RexWPrefix         uint8  `json:"rex_w_prefix"`         // (1 bit)
   529  	CfgCheck           uint8  `json:"cfg_check"`            // (1 bit)
   530  	Reserved           uint8  `json:"reserved"`             // (1 bit)
   531  }
   532  
   533  // ImageSwitchableBranchDynamicRelocation represents the Switchable Retpoline
   534  // (type 5), size = 2 bytes.
   535  type ImageSwitchableBranchDynamicRelocation struct {
   536  	PageRelativeOffset uint16 `json:"page_relative_offset"` // (12 bits)
   537  	RegisterNumber     uint16 `json:"register_number"`      // (4 bits)
   538  }
   539  
   540  // DVRT represents the Dynamic Value Relocation Table.
   541  // The DVRT was originally introduced back in the Windows 10 Creators Update to
   542  // improve kernel address space layout randomization (KASLR). It allowed the
   543  // memory manager’s page frame number (PFN) database and page table self-map to
   544  // be assigned dynamic addresses at runtime. The DVRT is stored directly in the
   545  // binary and contains a series of relocation entries for each symbol (i.e.
   546  // address) that is to be relocated. The relocation entries are themselves
   547  // arranged in a hierarchical fashion grouped first by symbol and then by
   548  // containing page to allow for a compact description of all locations in the
   549  // binary that reference a relocatable symbol.
   550  // Reference: https://techcommunity.microsoft.com/t5/windows-os-platform-blog/mitigating-spectre-variant-2-with-retpoline-on-windows/ba-p/295618
   551  type DVRT struct {
   552  	ImageDynamicRelocationTable `json:"image_dynamic_relocation_table"`
   553  	Entries                     []RelocEntry `json:"entries"`
   554  }
   555  
   556  type Enclave struct {
   557  
   558  	// Points to either ImageEnclaveConfig32{} or ImageEnclaveConfig64{}.
   559  	Config interface{} `json:"config"`
   560  
   561  	Imports []ImageEnclaveImport `json:"imports"`
   562  }
   563  
   564  type RangeTableEntry struct {
   565  	RVA  uint32 `json:"rva"`
   566  	Size uint32 `json:"size"`
   567  }
   568  
   569  type VolatileMetadata struct {
   570  	Struct         ImageVolatileMetadata `json:"struct"`
   571  	AccessRVATable []uint32              `json:"access_rva_table"`
   572  	InfoRangeTable []RangeTableEntry     `json:"info_range_table"`
   573  }
   574  type LoadConfig struct {
   575  	Struct           interface{}       `json:"struct"`
   576  	SEH              []uint32          `json:"seh"`
   577  	GFIDS            []CFGFunction     `json:"gfids"`
   578  	CFGIAT           []CFGIATEntry     `json:"cfgiat"`
   579  	CFGLongJump      []uint32          `json:"cfg_long_jump"`
   580  	CHPE             *HybridPE         `json:"chpe"`
   581  	DVRT             *DVRT             `json:"dvrt"`
   582  	Enclave          *Enclave          `json:"enclave"`
   583  	VolatileMetadata *VolatileMetadata `json:"volatile_metadata"`
   584  }
   585  
   586  // ImageLoadConfigCodeIntegrity Code Integrity in load config (CI).
   587  type ImageLoadConfigCodeIntegrity struct {
   588  	// Flags to indicate if CI information is available, etc.
   589  	Flags uint16 `json:"flags"`
   590  	// 0xFFFF means not available
   591  	Catalog       uint16 `json:"catalog"`
   592  	CatalogOffset uint32 `json:"catalog_offset"`
   593  	// Additional bitmask to be defined later
   594  	Reserved uint32 `json:"reserved"`
   595  }
   596  
   597  type ImageEnclaveConfig32 struct {
   598  
   599  	// The size of the IMAGE_ENCLAVE_CONFIG32 structure, in bytes.
   600  	Size uint32 `json:"size"`
   601  
   602  	// The minimum size of the IMAGE_ENCLAVE_CONFIG32 structure that the image
   603  	// loader must be able to process in order for the enclave to be usable.
   604  	// This member allows an enclave to inform an earlier version of the image
   605  	// loader that the image loader can safely load the enclave and ignore optional
   606  	// members added to IMAGE_ENCLAVE_CONFIG32 for later versions of the enclave.
   607  
   608  	// If the size of IMAGE_ENCLAVE_CONFIG32 that the image loader can process is
   609  	// less than MinimumRequiredConfigSize, the enclave cannot be run securely.
   610  	// If MinimumRequiredConfigSize is zero, the minimum size of the
   611  	// IMAGE_ENCLAVE_CONFIG32 structure that the image loader must be able to
   612  	// process in order for the enclave to be usable is assumed to be the size
   613  	// of the structure through and including the MinimumRequiredConfigSize member.
   614  	MinimumRequiredConfigSize uint32 `json:"minimum_required_config_size"`
   615  
   616  	// A flag that indicates whether the enclave permits debugging.
   617  	PolicyFlags uint32 `json:"policy_flags"`
   618  
   619  	// The number of images in the array of images that the ImportList member
   620  	// points to.
   621  	NumberOfImports uint32 `json:"number_of_imports"`
   622  
   623  	// The relative virtual address of the array of images that the enclave
   624  	// image may import, with identity information for each image.
   625  	ImportList uint32 `json:"import_list"`
   626  
   627  	// The size of each image in the array of images that the ImportList member
   628  	// points to.
   629  	ImportEntrySize uint32 `json:"import_entry_size"`
   630  
   631  	// The family identifier that the author of the enclave assigned to the enclave.
   632  	FamilyID [ImageEnclaveShortIDLength]uint8 `json:"family_id"`
   633  
   634  	// The image identifier that the author of the enclave assigned to the enclave.
   635  	ImageID [ImageEnclaveShortIDLength]uint8 `json:"image_id"`
   636  
   637  	// The version number that the author of the enclave assigned to the enclave.
   638  	ImageVersion uint32 `json:"image_version"`
   639  
   640  	// The security version number that the author of the enclave assigned to
   641  	// the enclave.
   642  	SecurityVersion uint32 `json:"security_version"`
   643  
   644  	// The expected virtual size of the private address range for the enclave,
   645  	// in bytes.
   646  	EnclaveSize uint32 `json:"enclave_size"`
   647  
   648  	// The maximum number of threads that can be created within the enclave.
   649  	NumberOfThreads uint32 `json:"number_of_threads"`
   650  
   651  	// A flag that indicates whether the image is suitable for use as the
   652  	// primary image in the enclave.
   653  	EnclaveFlags uint32 `json:"enclave_flags"`
   654  }
   655  
   656  type ImageEnclaveConfig64 struct {
   657  
   658  	// The size of the IMAGE_ENCLAVE_CONFIG32 structure, in bytes.
   659  	Size uint32 `json:"size"`
   660  
   661  	// The minimum size of the IMAGE_ENCLAVE_CONFIG32 structure that the image
   662  	// loader must be able to process in order for the enclave to be usable.
   663  	// This member allows an enclave to inform an earlier version of the image
   664  	// loader that the image loader can safely load the enclave and ignore
   665  	// optional members added to IMAGE_ENCLAVE_CONFIG32 for later versions of
   666  	// the enclave.
   667  
   668  	// If the size of IMAGE_ENCLAVE_CONFIG32 that the image loader can process
   669  	// is less than MinimumRequiredConfigSize, the enclave cannot be run securely.
   670  	// If MinimumRequiredConfigSize is zero, the minimum size of the
   671  	// IMAGE_ENCLAVE_CONFIG32 structure that the image loader must be able to
   672  	// process in order for the enclave to be usable is assumed to be the size
   673  	// of the structure through and including the MinimumRequiredConfigSize member.
   674  	MinimumRequiredConfigSize uint32 `json:"minimum_required_config_size"`
   675  
   676  	// A flag that indicates whether the enclave permits debugging.
   677  	PolicyFlags uint32 `json:"policy_flags"`
   678  
   679  	// The number of images in the array of images that the ImportList member
   680  	// points to.
   681  	NumberOfImports uint32 `json:"number_of_imports"`
   682  
   683  	// The relative virtual address of the array of images that the enclave
   684  	// image may import, with identity information for each image.
   685  	ImportList uint32 `json:"import_list"`
   686  
   687  	// The size of each image in the array of images that the ImportList member
   688  	// points to.
   689  	ImportEntrySize uint32 `json:"import_entry_size"`
   690  
   691  	// The family identifier that the author of the enclave assigned to the enclave.
   692  	FamilyID [ImageEnclaveShortIDLength]uint8 `json:"family_id"`
   693  
   694  	// The image identifier that the author of the enclave assigned to the enclave.
   695  	ImageID [ImageEnclaveShortIDLength]uint8 `json:"image_id"`
   696  
   697  	// The version number that the author of the enclave assigned to the enclave.
   698  	ImageVersion uint32 `json:"image_version"`
   699  
   700  	// The security version number that the author of the enclave assigned to the enclave.
   701  	SecurityVersion uint32 `json:"security_version"`
   702  
   703  	// The expected virtual size of the private address range for the enclave,in bytes.
   704  	EnclaveSize uint64 `json:"enclave_size"`
   705  
   706  	// The maximum number of threads that can be created within the enclave.
   707  	NumberOfThreads uint32 `json:"number_of_threads"`
   708  
   709  	// A flag that indicates whether the image is suitable for use as the primary
   710  	// image in the enclave.
   711  	EnclaveFlags uint32 `json:"enclave_flags"`
   712  }
   713  
   714  // ImageEnclaveImport defines a entry in the array of images that an enclave can import.
   715  type ImageEnclaveImport struct {
   716  
   717  	// The type of identifier of the image that must match the value in the import record.
   718  	MatchType uint32 `json:"match_type"`
   719  
   720  	// The minimum enclave security version that each image must have for the
   721  	// image to be imported successfully. The image is rejected unless its
   722  	// enclave security version is equal to or greater than the minimum value in
   723  	// the import record. Set the value in the import record to zero to turn off
   724  	// the security version check.
   725  	MinimumSecurityVersion uint32 `json:"minimum_security_version"`
   726  
   727  	// The unique identifier of the primary module for the enclave, if the
   728  	// MatchType member is IMAGE_ENCLAVE_IMPORT_MATCH_UNIQUE_ID. Otherwise,
   729  	// the author identifier of the primary module for the enclave..
   730  	UniqueOrAuthorID [ImageEnclaveLongIDLength]uint8 `json:"unique_or_author_id"`
   731  
   732  	// The family identifier of the primary module for the enclave.
   733  	FamilyID [ImageEnclaveShortIDLength]uint8 `json:"family_id"`
   734  
   735  	// The image identifier of the primary module for the enclave.
   736  	ImageID [ImageEnclaveShortIDLength]uint8 `json:"image_id"`
   737  
   738  	// The relative virtual address of a NULL-terminated string that contains
   739  	// the same value found in the import directory for the image.
   740  	ImportName uint32 `json:"import_name"`
   741  
   742  	// Reserved.
   743  	Reserved uint32 `json:"reserved"`
   744  }
   745  
   746  type ImageVolatileMetadata struct {
   747  	Size                       uint32 `json:"size"`
   748  	Version                    uint32 `json:"version"`
   749  	VolatileAccessTable        uint32 `json:"volatile_access_table"`
   750  	VolatileAccessTableSize    uint32 `json:"volatile_access_table_size"`
   751  	VolatileInfoRangeTable     uint32 `json:"volatile_info_range_table"`
   752  	VolatileInfoRangeTableSize uint32 `json:"volatile_info_range_table_size"`
   753  }
   754  
   755  // The load configuration structure (IMAGE_LOAD_CONFIG_DIRECTORY) was formerly
   756  // used in very limited cases in the Windows NT operating system itself to
   757  // describe various features too difficult or too large to describe in the file
   758  
   759  // header or optional header of the image. Current versions of the Microsoft
   760  // linker and Windows XP and later versions of Windows use a new version of this
   761  // structure for 32-bit x86-based systems that include reserved SEH technology.
   762  // The data directory entry for a pre-reserved SEH load configuration structure
   763  // must specify a particular size of the load configuration structure because
   764  // the operating system loader always expects it to be a certain value. In that
   765  // regard, the size is really only a version check. For compatibility with
   766  // Windows XP and earlier versions of Windows, the size must be 64 for x86 images.
   767  func (pe *File) parseLoadConfigDirectory(rva, size uint32) error {
   768  
   769  	// As the load config structure changes over time,
   770  	// we first read it size to figure out which one we have to cast against.
   771  	fileOffset := pe.GetOffsetFromRva(rva)
   772  	structSize, err := pe.ReadUint32(fileOffset)
   773  	if err != nil {
   774  		return err
   775  	}
   776  
   777  	// Use this helper function to print struct size.
   778  	// PrintLoadConfigStruct()
   779  	var loadCfg interface{}
   780  
   781  	// Boundary check
   782  	totalSize := fileOffset + size
   783  
   784  	// Integer overflow
   785  	if (totalSize > fileOffset) != (size > 0) {
   786  		return ErrOutsideBoundary
   787  	}
   788  
   789  	if fileOffset >= pe.size || totalSize > pe.size {
   790  		return ErrOutsideBoundary
   791  	}
   792  
   793  	if pe.Is32 {
   794  		loadCfg32 := ImageLoadConfigDirectory32{}
   795  		imgLoadConfigDirectory := make([]byte, binary.Size(loadCfg32))
   796  		copy(imgLoadConfigDirectory, pe.data[fileOffset:fileOffset+structSize])
   797  		buf := bytes.NewReader(imgLoadConfigDirectory)
   798  		err = binary.Read(buf, binary.LittleEndian, &loadCfg32)
   799  		loadCfg = loadCfg32
   800  	} else {
   801  		loadCfg64 := ImageLoadConfigDirectory64{}
   802  		imgLoadConfigDirectory := make([]byte, binary.Size(loadCfg64))
   803  		copy(imgLoadConfigDirectory, pe.data[fileOffset:fileOffset+structSize])
   804  		buf := bytes.NewReader(imgLoadConfigDirectory)
   805  		err = binary.Read(buf, binary.LittleEndian, &loadCfg64)
   806  		loadCfg = loadCfg64
   807  	}
   808  
   809  	if err != nil {
   810  		return err
   811  	}
   812  
   813  	// Save the load config struct.
   814  	pe.HasLoadCFG = true
   815  	pe.LoadConfig.Struct = loadCfg
   816  
   817  	// Retrieve SEH handlers if there are any..
   818  	if pe.Is32 {
   819  		handlers := pe.getSEHHandlers()
   820  		pe.LoadConfig.SEH = handlers
   821  	}
   822  
   823  	// Retrieve Control Flow Guard Function Targets if there are any.
   824  	pe.LoadConfig.GFIDS = pe.getControlFlowGuardFunctions()
   825  
   826  	// Retrieve Control Flow Guard IAT entries if there are any.
   827  	pe.LoadConfig.CFGIAT = pe.getControlFlowGuardIAT()
   828  
   829  	// Retrieve Long jump target functions if there are any.
   830  	pe.LoadConfig.CFGLongJump = pe.getLongJumpTargetTable()
   831  
   832  	// Retrieve compiled hybrid PE metadata if there are any.
   833  	pe.LoadConfig.CHPE = pe.getHybridPE()
   834  
   835  	// Retrieve dynamic value relocation table if there are any.
   836  	pe.LoadConfig.DVRT = pe.getDynamicValueRelocTable()
   837  
   838  	// Retrieve enclave configuration if there are any.
   839  	pe.LoadConfig.Enclave = pe.getEnclaveConfiguration()
   840  
   841  	// Retrieve volatile metadata table if there are any.
   842  	pe.LoadConfig.VolatileMetadata = pe.getVolatileMetadata()
   843  
   844  	return nil
   845  }
   846  
   847  // StringifyGuardFlags returns list of strings which describes the GuardFlags.
   848  func StringifyGuardFlags(flags uint32) []string {
   849  	var values []string
   850  	guardFlagMap := map[uint32]string{
   851  		ImageGuardCfInstrumented:                 "Instrumented",
   852  		ImageGuardCfWInstrumented:                "WriteInstrumented",
   853  		ImageGuardCfFunctionTablePresent:         "TargetMetadata",
   854  		ImageGuardSecurityCookieUnused:           "SecurityCookieUnused",
   855  		ImageGuardProtectDelayLoadIAT:            "DelayLoadIAT",
   856  		ImageGuardDelayLoadIATInItsOwnSection:    "DelayLoadIATInItsOwnSection",
   857  		ImageGuardCfExportSuppressionInfoPresent: "ExportSuppressionInfoPresent",
   858  		ImageGuardCfEnableExportSuppression:      "EnableExportSuppression",
   859  		ImageGuardCfLongJumpTablePresent:         "LongJumpTablePresent",
   860  	}
   861  
   862  	for k, s := range guardFlagMap {
   863  		if k&flags != 0 {
   864  			values = append(values, s)
   865  		}
   866  	}
   867  	return values
   868  }
   869  
   870  func (pe *File) getSEHHandlers() []uint32 {
   871  
   872  	var handlers []uint32
   873  	v := reflect.ValueOf(pe.LoadConfig.Struct)
   874  
   875  	// SEHandlerCount is found in index 19 of the struct.
   876  	SEHandlerCount := uint32(v.Field(19).Uint())
   877  	if SEHandlerCount > 0 {
   878  		SEHandlerTable := uint32(v.Field(18).Uint())
   879  		imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader32).ImageBase
   880  		rva := SEHandlerTable - imageBase
   881  		for i := uint32(0); i < SEHandlerCount; i++ {
   882  			offset := pe.GetOffsetFromRva(rva + i*4)
   883  			handler, err := pe.ReadUint32(offset)
   884  			if err != nil {
   885  				return handlers
   886  			}
   887  
   888  			handlers = append(handlers, handler)
   889  		}
   890  	}
   891  
   892  	return handlers
   893  }
   894  
   895  func (pe *File) getControlFlowGuardFunctions() []CFGFunction {
   896  
   897  	v := reflect.ValueOf(pe.LoadConfig.Struct)
   898  	var GFIDS []CFGFunction
   899  	var err error
   900  
   901  	// The GFIDS table is an array of 4 + n bytes, where n is given by :
   902  	// ((GuardFlags & IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK) >>
   903  	// IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_SHIFT).
   904  
   905  	// This allows for extra metadata to be attached to CFG call targets in
   906  	// the future. The only currently defined metadata is an optional 1-byte
   907  	// extra flags field (“GFIDS flags”) that is attached to each GFIDS
   908  	// entry if any call targets have metadata.
   909  	GuardFlags := v.Field(24).Uint()
   910  	n := (GuardFlags & ImageGuardCfFunctionTableSizeMask) >>
   911  		ImageGuardCfFunctionTableSizeShift
   912  	GuardCFFunctionCount := v.Field(23).Uint()
   913  	if GuardCFFunctionCount > 0 {
   914  		if pe.Is32 {
   915  			GuardCFFunctionTable := uint32(v.Field(22).Uint())
   916  			imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader32).ImageBase
   917  			rva := GuardCFFunctionTable - imageBase
   918  			offset := pe.GetOffsetFromRva(rva)
   919  			for i := uint32(1); i <= uint32(GuardCFFunctionCount); i++ {
   920  				cfgFunction := CFGFunction{}
   921  				var cfgFlags uint8
   922  				cfgFunction.RVA, err = pe.ReadUint32(offset)
   923  				if err != nil {
   924  					return GFIDS
   925  				}
   926  				if n > 0 {
   927  					err = pe.structUnpack(&cfgFlags, offset+4, uint32(n))
   928  					if err != nil {
   929  						return GFIDS
   930  					}
   931  					cfgFunction.Flags = ImageGuardFlagType(cfgFlags)
   932  					if cfgFlags == ImageGuardFlagFIDSuppressed ||
   933  						cfgFlags == ImageGuardFlagExportSuppressed {
   934  						exportName := pe.GetExportFunctionByRVA(cfgFunction.RVA)
   935  						cfgFunction.Description = exportName.Name
   936  					}
   937  				}
   938  
   939  				GFIDS = append(GFIDS, cfgFunction)
   940  				offset += 4 + uint32(n)
   941  			}
   942  		} else {
   943  			GuardCFFunctionTable := v.Field(22).Uint()
   944  			imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader64).ImageBase
   945  			rva := uint32(GuardCFFunctionTable - imageBase)
   946  			offset := pe.GetOffsetFromRva(rva)
   947  			for i := uint64(1); i <= GuardCFFunctionCount; i++ {
   948  				var cfgFlags uint8
   949  				cfgFunction := CFGFunction{}
   950  				cfgFunction.RVA, err = pe.ReadUint32(offset)
   951  				if err != nil {
   952  					return GFIDS
   953  				}
   954  				if n > 0 {
   955  					pe.structUnpack(&cfgFlags, offset+4, uint32(n))
   956  					cfgFunction.Flags = ImageGuardFlagType(cfgFlags)
   957  					if cfgFlags == ImageGuardFlagFIDSuppressed ||
   958  						cfgFlags == ImageGuardFlagExportSuppressed {
   959  						exportName := pe.GetExportFunctionByRVA(cfgFunction.RVA)
   960  						cfgFunction.Description = exportName.Name
   961  					}
   962  				}
   963  
   964  				GFIDS = append(GFIDS, cfgFunction)
   965  				offset += 4 + uint32(n)
   966  			}
   967  		}
   968  	}
   969  	return GFIDS
   970  }
   971  
   972  func (pe *File) getControlFlowGuardIAT() []CFGIATEntry {
   973  
   974  	v := reflect.ValueOf(pe.LoadConfig.Struct)
   975  	var GFGIAT []CFGIATEntry
   976  	var err error
   977  
   978  	// GuardAddressTakenIatEntryCount is found in index 27 of the struct.
   979  	// An image that supports CFG ES includes a GuardAddressTakenIatEntryTable
   980  	// whose count is provided by the GuardAddressTakenIatEntryCount as part
   981  	// of its load configuration directory. This table is structurally
   982  	// formatted the same as the GFIDS table. It uses the same GuardFlags
   983  	// IMAGE_GUARD_CF_FUNCTION_TABLE_SIZE_MASK mechanism to encode extra
   984  	// optional metadata bytes in the address taken IAT table, though all
   985  	// metadata bytes must be zero for the address taken IAT table and are
   986  	// reserved.
   987  	GuardFlags := v.Field(24).Uint()
   988  	n := (GuardFlags & ImageGuardCfFunctionTableSizeMask) >>
   989  		ImageGuardCfFunctionTableSizeShift
   990  	GuardAddressTakenIatEntryCount := v.Field(27).Uint()
   991  	if GuardAddressTakenIatEntryCount > 0 {
   992  		if pe.Is32 {
   993  			GuardAddressTakenIatEntryTable := uint32(v.Field(26).Uint())
   994  			imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader32).ImageBase
   995  			rva := GuardAddressTakenIatEntryTable - imageBase
   996  			offset := pe.GetOffsetFromRva(rva)
   997  			for i := uint32(1); i <= uint32(GuardAddressTakenIatEntryCount); i++ {
   998  				cfgIATEntry := CFGIATEntry{}
   999  				cfgIATEntry.RVA, err = pe.ReadUint32(offset)
  1000  				if err != nil {
  1001  					return GFGIAT
  1002  				}
  1003  				imp, index := pe.GetImportEntryInfoByRVA(cfgIATEntry.RVA)
  1004  				if len(imp.Functions) != 0 {
  1005  					cfgIATEntry.INTValue = uint32(imp.Functions[index].OriginalThunkValue)
  1006  					cfgIATEntry.IATValue = uint32(imp.Functions[index].ThunkValue)
  1007  					cfgIATEntry.Description = imp.Name + "!" + imp.Functions[index].Name
  1008  				}
  1009  				GFGIAT = append(GFGIAT, cfgIATEntry)
  1010  				offset += 4 + uint32(n)
  1011  			}
  1012  		} else {
  1013  			GuardAddressTakenIatEntryTable := v.Field(26).Uint()
  1014  			imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader64).ImageBase
  1015  			rva := uint32(GuardAddressTakenIatEntryTable - imageBase)
  1016  			offset := pe.GetOffsetFromRva(rva)
  1017  			for i := uint64(1); i <= GuardAddressTakenIatEntryCount; i++ {
  1018  				cfgIATEntry := CFGIATEntry{}
  1019  				cfgIATEntry.RVA, err = pe.ReadUint32(offset)
  1020  				if err != nil {
  1021  					return GFGIAT
  1022  				}
  1023  				imp, index := pe.GetImportEntryInfoByRVA(cfgIATEntry.RVA)
  1024  				if len(imp.Functions) != 0 {
  1025  					cfgIATEntry.INTValue = uint32(imp.Functions[index].OriginalThunkValue)
  1026  					cfgIATEntry.IATValue = uint32(imp.Functions[index].ThunkValue)
  1027  					cfgIATEntry.Description = imp.Name + "!" + imp.Functions[index].Name
  1028  				}
  1029  
  1030  				GFGIAT = append(GFGIAT, cfgIATEntry)
  1031  				offset += 4 + uint32(n)
  1032  			}
  1033  		}
  1034  
  1035  	}
  1036  	return GFGIAT
  1037  }
  1038  
  1039  func (pe *File) getLongJumpTargetTable() []uint32 {
  1040  
  1041  	v := reflect.ValueOf(pe.LoadConfig.Struct)
  1042  	var longJumpTargets []uint32
  1043  
  1044  	// The long jump table represents a sorted array of RVAs that are valid
  1045  	// long jump targets. If a long jump target module sets
  1046  	// IMAGE_GUARD_CF_LONGJUMP_TABLE_PRESENT in its GuardFlags field, then
  1047  	// all long jump targets must be enumerated in the LongJumpTargetTable.
  1048  	GuardFlags := v.Field(24).Uint()
  1049  	n := (GuardFlags & ImageGuardCfFunctionTableSizeMask) >>
  1050  		ImageGuardCfFunctionTableSizeShift
  1051  
  1052  	// GuardLongJumpTargetCount is found in index 29 of the struct.
  1053  	GuardLongJumpTargetCount := v.Field(29).Uint()
  1054  	if GuardLongJumpTargetCount > 0 {
  1055  		if pe.Is32 {
  1056  			GuardLongJumpTargetTable := uint32(v.Field(28).Uint())
  1057  			imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader32).ImageBase
  1058  			rva := GuardLongJumpTargetTable - imageBase
  1059  			offset := pe.GetOffsetFromRva(rva)
  1060  			for i := uint32(1); i <= uint32(GuardLongJumpTargetCount); i++ {
  1061  				target, err := pe.ReadUint32(offset)
  1062  				if err != nil {
  1063  					return longJumpTargets
  1064  				}
  1065  				longJumpTargets = append(longJumpTargets, target)
  1066  				offset += 4 + uint32(n)
  1067  			}
  1068  		} else {
  1069  			GuardLongJumpTargetTable := v.Field(28).Uint()
  1070  			imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader64).ImageBase
  1071  			rva := uint32(GuardLongJumpTargetTable - imageBase)
  1072  			offset := pe.GetOffsetFromRva(rva)
  1073  			for i := uint64(1); i <= GuardLongJumpTargetCount; i++ {
  1074  				target, err := pe.ReadUint32(offset)
  1075  				if err != nil {
  1076  					return longJumpTargets
  1077  				}
  1078  				longJumpTargets = append(longJumpTargets, target)
  1079  				offset += 4 + uint32(n)
  1080  			}
  1081  		}
  1082  
  1083  	}
  1084  	return longJumpTargets
  1085  }
  1086  
  1087  func (pe *File) getHybridPE() *HybridPE {
  1088  	v := reflect.ValueOf(pe.LoadConfig.Struct)
  1089  
  1090  	// CHPEMetadataPointer is found in index 31 of the struct.
  1091  	CHPEMetadataPointer := v.Field(31).Uint()
  1092  	if CHPEMetadataPointer == 0 {
  1093  		return nil
  1094  	}
  1095  	var rva uint32
  1096  	if pe.Is32 {
  1097  		imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader32).ImageBase
  1098  		rva = uint32(CHPEMetadataPointer) - imageBase
  1099  	} else {
  1100  		imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader64).ImageBase
  1101  		rva = uint32(CHPEMetadataPointer - imageBase)
  1102  	}
  1103  
  1104  	// As the image CHPE metadata structure changes over time,
  1105  	// we first read its version to figure out which one we have to
  1106  	// cast against.
  1107  	fileOffset := pe.GetOffsetFromRva(rva)
  1108  	version, err := pe.ReadUint32(fileOffset)
  1109  	if err != nil {
  1110  		return nil
  1111  	}
  1112  
  1113  	structSize := uint32(0)
  1114  	imgCHPEMetaX86 := ImageCHPEMetadataX86{}
  1115  
  1116  	switch version {
  1117  	case 0x1:
  1118  		structSize = uint32(binary.Size(imgCHPEMetaX86) - 8)
  1119  	case 0x2:
  1120  		structSize = uint32(binary.Size(imgCHPEMetaX86) - 4)
  1121  	case 0x3:
  1122  		structSize = uint32(binary.Size(imgCHPEMetaX86))
  1123  	default:
  1124  		// This should be a newer version, default to the latest CHPE version.
  1125  		structSize = uint32(binary.Size(imgCHPEMetaX86))
  1126  	}
  1127  
  1128  	// Boundary check
  1129  	totalSize := fileOffset + structSize
  1130  
  1131  	// Integer overflow
  1132  	if (totalSize > fileOffset) != (structSize > 0) {
  1133  		pe.logger.Debug("encountered an outside read boundary when reading CHPE structure")
  1134  		return nil
  1135  	}
  1136  
  1137  	if fileOffset >= pe.size || totalSize > pe.size {
  1138  		pe.logger.Debug("encountered an outside read boundary when reading CHPE structure")
  1139  		return nil
  1140  	}
  1141  
  1142  	imgCHPEMeta := make([]byte, binary.Size(imgCHPEMetaX86))
  1143  	copy(imgCHPEMeta, pe.data[fileOffset:fileOffset+structSize])
  1144  	buf := bytes.NewReader(imgCHPEMeta)
  1145  	err = binary.Read(buf, binary.LittleEndian, &imgCHPEMetaX86)
  1146  	if err != nil {
  1147  		pe.logger.Debug("encountered an error while unpacking image CHPE Meta")
  1148  		return nil
  1149  	}
  1150  
  1151  	hybridPE := HybridPE{}
  1152  	hybridPE.CHPEMetadata = imgCHPEMetaX86
  1153  
  1154  	// Code Ranges
  1155  
  1156  	/*
  1157  		typedef struct _IMAGE_CHPE_RANGE_ENTRY {
  1158  			union {
  1159  				ULONG StartOffset;
  1160  				struct {
  1161  					ULONG NativeCode : 1;
  1162  					ULONG AddressBits : 31;
  1163  				} DUMMYSTRUCTNAME;
  1164  			} DUMMYUNIONNAME;
  1165  
  1166  			ULONG Length;
  1167  		} IMAGE_CHPE_RANGE_ENTRY, *PIMAGE_CHPE_RANGE_ENTRY;
  1168  	*/
  1169  
  1170  	rva = imgCHPEMetaX86.CHPECodeAddressRangeOffset
  1171  	for i := 0; i < int(imgCHPEMetaX86.CHPECodeAddressRangeCount); i++ {
  1172  
  1173  		codeRange := CodeRange{}
  1174  		fileOffset := pe.GetOffsetFromRva(rva)
  1175  		begin, err := pe.ReadUint32(fileOffset)
  1176  		if err != nil {
  1177  			break
  1178  		}
  1179  
  1180  		if begin&1 == 1 {
  1181  			codeRange.Machine = 1
  1182  			begin = uint32(int(begin) & ^1)
  1183  		}
  1184  		codeRange.Begin = begin
  1185  
  1186  		fileOffset += 4
  1187  		size, err := pe.ReadUint32(fileOffset)
  1188  		if err != nil {
  1189  			break
  1190  		}
  1191  		codeRange.Length = size
  1192  
  1193  		hybridPE.CodeRanges = append(hybridPE.CodeRanges, codeRange)
  1194  		rva += 8
  1195  	}
  1196  
  1197  	// Compiler IAT
  1198  	if imgCHPEMetaX86.CompilerIATPointer != 0 {
  1199  		rva := imgCHPEMetaX86.CompilerIATPointer
  1200  		for i := 0; i < 1024; i++ {
  1201  			compilerIAT := CompilerIAT{}
  1202  			compilerIAT.RVA = rva
  1203  			fileOffset = pe.GetOffsetFromRva(rva)
  1204  			compilerIAT.Value, err = pe.ReadUint32(fileOffset)
  1205  			if err != nil {
  1206  				break
  1207  			}
  1208  
  1209  			impFunc, _ := pe.GetImportEntryInfoByRVA(compilerIAT.RVA)
  1210  			compilerIAT.Description = impFunc.Name
  1211  			hybridPE.CompilerIAT = append(
  1212  				hybridPE.CompilerIAT, compilerIAT)
  1213  			rva += 4
  1214  		}
  1215  	}
  1216  	return &hybridPE
  1217  }
  1218  
  1219  func (pe *File) getDynamicValueRelocTable() *DVRT {
  1220  
  1221  	var structSize uint32
  1222  	var imgDynRelocSize uint32
  1223  	var retpolineType uint8
  1224  	dvrt := DVRT{}
  1225  	imgDynRelocTable := ImageDynamicRelocationTable{}
  1226  
  1227  	v := reflect.ValueOf(pe.LoadConfig.Struct)
  1228  	DynamicValueRelocTableOffset := v.Field(34).Uint()
  1229  	DynamicValueRelocTableSection := v.Field(35).Uint()
  1230  	if DynamicValueRelocTableOffset == 0 || DynamicValueRelocTableSection == 0 {
  1231  		return nil
  1232  	}
  1233  
  1234  	section := pe.getSectionByName(".reloc")
  1235  	if section == nil {
  1236  		return nil
  1237  	}
  1238  
  1239  	// Get the dynamic value relocation table header.
  1240  	rva := section.VirtualAddress + uint32(DynamicValueRelocTableOffset)
  1241  	offset := pe.GetOffsetFromRva(rva)
  1242  	structSize = uint32(binary.Size(imgDynRelocTable))
  1243  	err := pe.structUnpack(&imgDynRelocTable, offset, structSize)
  1244  	if err != nil {
  1245  		return nil
  1246  	}
  1247  
  1248  	dvrt.ImageDynamicRelocationTable = imgDynRelocTable
  1249  	offset += structSize
  1250  
  1251  	// Get dynamic relocation entries according to version.
  1252  	switch imgDynRelocTable.Version {
  1253  	case 1:
  1254  		relocTableIt := uint32(0)
  1255  		baseBlockSize := uint32(0)
  1256  
  1257  		// Iterate over our dynamic reloc table entries.
  1258  		for relocTableIt < imgDynRelocTable.Size {
  1259  
  1260  			relocEntry := RelocEntry{}
  1261  
  1262  			// Each block starts with the header.
  1263  			if pe.Is32 {
  1264  				imgDynReloc := ImageDynamicRelocation32{}
  1265  				imgDynRelocSize = uint32(binary.Size(imgDynReloc))
  1266  				err = pe.structUnpack(&imgDynReloc, offset, imgDynRelocSize)
  1267  				if err != nil {
  1268  					return nil
  1269  				}
  1270  				relocEntry.ImageDynamicRelocation = imgDynReloc
  1271  				baseBlockSize = imgDynReloc.BaseRelocSize
  1272  				retpolineType = uint8(imgDynReloc.Symbol)
  1273  			} else {
  1274  				imgDynReloc := ImageDynamicRelocation64{}
  1275  				imgDynRelocSize = uint32(binary.Size(imgDynReloc))
  1276  				err = pe.structUnpack(&imgDynReloc, offset, imgDynRelocSize)
  1277  				if err != nil {
  1278  					return nil
  1279  				}
  1280  				relocEntry.ImageDynamicRelocation = imgDynReloc
  1281  				baseBlockSize = imgDynReloc.BaseRelocSize
  1282  				retpolineType = uint8(imgDynReloc.Symbol)
  1283  			}
  1284  			offset += imgDynRelocSize
  1285  			relocTableIt += imgDynRelocSize
  1286  
  1287  			// Then, for each page, there is a block that starts with a relocation entry:
  1288  			blockIt := uint32(0)
  1289  			for blockIt <= baseBlockSize-imgDynRelocSize {
  1290  				relocBlock := RelocBlock{}
  1291  
  1292  				baseReloc := ImageBaseRelocation{}
  1293  				structSize = uint32(binary.Size(baseReloc))
  1294  				err = pe.structUnpack(&baseReloc, offset, structSize)
  1295  				if err != nil {
  1296  					return nil
  1297  				}
  1298  
  1299  				relocBlock.ImgBaseReloc = baseReloc
  1300  				offset += structSize
  1301  
  1302  				// After that there are entries for all of the places which need
  1303  				// to be overwritten by the retpoline jump. The structure used
  1304  				// for those entries depends on the type (symbol) that was used
  1305  				// above. There are three types of retpoline so far. Entry for
  1306  				//each of them will contain pageRelativeOffset. The kernel uses
  1307  				// that entry to apply the proper replacement under
  1308  				// virtualAddress + pageRelativeOffset address.
  1309  				branchIt := uint32(0)
  1310  				switch retpolineType {
  1311  				case 3:
  1312  					for branchIt < (baseReloc.SizeOfBlock-structSize)/4 {
  1313  						imgImpCtrlTransDynReloc := ImageImportControlTransferDynamicRelocation{}
  1314  
  1315  						dword, err := pe.ReadUint32(offset)
  1316  						if err != nil {
  1317  							return nil
  1318  						}
  1319  
  1320  						imgImpCtrlTransDynReloc.PageRelativeOffset = uint16(dword) & 0xfff
  1321  						imgImpCtrlTransDynReloc.IndirectCall = uint16(dword) & 0x1000 >> 12
  1322  						imgImpCtrlTransDynReloc.IATIndex = dword & 0xFFFFE000 >> 13
  1323  
  1324  						offset += 4
  1325  						branchIt += 1
  1326  						relocBlock.TypeOffsets = append(relocBlock.TypeOffsets, imgImpCtrlTransDynReloc)
  1327  					}
  1328  				case 4:
  1329  					for branchIt < (baseReloc.SizeOfBlock-structSize)/2 {
  1330  						imgIndirCtrlTransDynReloc := ImageIndirectControlTransferDynamicRelocation{}
  1331  
  1332  						word, err := pe.ReadUint16(offset)
  1333  						if err != nil {
  1334  							return nil
  1335  						}
  1336  						imgIndirCtrlTransDynReloc.PageRelativeOffset = word & 0xfff
  1337  						imgIndirCtrlTransDynReloc.IndirectCall = uint8(word & 0x1000 >> 12)
  1338  						imgIndirCtrlTransDynReloc.RexWPrefix = uint8(word & 0x2000 >> 13)
  1339  						imgIndirCtrlTransDynReloc.CfgCheck = uint8(word & 0x4000 >> 14)
  1340  						imgIndirCtrlTransDynReloc.Reserved = uint8(word & 0x8000 >> 15)
  1341  
  1342  						branchIt += 1
  1343  						offset += 2
  1344  
  1345  						// Padding might be added at the end of the block.
  1346  						if (ImageIndirectControlTransferDynamicRelocation{}) == imgIndirCtrlTransDynReloc {
  1347  							continue
  1348  						}
  1349  						relocBlock.TypeOffsets = append(relocBlock.TypeOffsets, imgIndirCtrlTransDynReloc)
  1350  					}
  1351  				case 5:
  1352  					for branchIt < (baseReloc.SizeOfBlock-structSize)/2 {
  1353  						imgSwitchBranchDynReloc := ImageSwitchableBranchDynamicRelocation{}
  1354  
  1355  						word, err := pe.ReadUint16(offset)
  1356  						if err != nil {
  1357  							return nil
  1358  						}
  1359  						imgSwitchBranchDynReloc.PageRelativeOffset = word & 0xfff
  1360  						imgSwitchBranchDynReloc.RegisterNumber = word & 0xf000 >> 12
  1361  
  1362  						offset += 2
  1363  						branchIt += 1
  1364  
  1365  						// Padding might be added at the end of the block.
  1366  						if (ImageSwitchableBranchDynamicRelocation{}) == imgSwitchBranchDynReloc {
  1367  							continue
  1368  						}
  1369  						relocBlock.TypeOffsets = append(relocBlock.TypeOffsets, imgSwitchBranchDynReloc)
  1370  					}
  1371  				}
  1372  
  1373  				blockIt += baseReloc.SizeOfBlock
  1374  				relocEntry.RelocBlocks = append(relocEntry.RelocBlocks, relocBlock)
  1375  			}
  1376  
  1377  			dvrt.Entries = append(dvrt.Entries, relocEntry)
  1378  			relocTableIt += baseBlockSize
  1379  		}
  1380  	case 2:
  1381  		fmt.Print("Got version 2 !")
  1382  	}
  1383  
  1384  	return &dvrt
  1385  }
  1386  
  1387  func (pe *File) getEnclaveConfiguration() *Enclave {
  1388  
  1389  	enclave := Enclave{}
  1390  
  1391  	v := reflect.ValueOf(pe.LoadConfig.Struct)
  1392  	EnclaveConfigurationPointer := v.Field(40).Uint()
  1393  	if EnclaveConfigurationPointer == 0 {
  1394  		return nil
  1395  	}
  1396  
  1397  	if pe.Is32 {
  1398  		imgEnclaveCfg := ImageEnclaveConfig32{}
  1399  		imgEnclaveCfgSize := uint32(binary.Size(imgEnclaveCfg))
  1400  		imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader32).ImageBase
  1401  		rva := uint32(EnclaveConfigurationPointer) - imageBase
  1402  		offset := pe.GetOffsetFromRva(rva)
  1403  		err := pe.structUnpack(&imgEnclaveCfg, offset, imgEnclaveCfgSize)
  1404  		if err != nil {
  1405  			return nil
  1406  		}
  1407  		enclave.Config = imgEnclaveCfg
  1408  	} else {
  1409  		imgEnclaveCfg := ImageEnclaveConfig64{}
  1410  		imgEnclaveCfgSize := uint32(binary.Size(imgEnclaveCfg))
  1411  		imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader64).ImageBase
  1412  		rva := uint32(EnclaveConfigurationPointer - imageBase)
  1413  		offset := pe.GetOffsetFromRva(rva)
  1414  		err := pe.structUnpack(&imgEnclaveCfg, offset, imgEnclaveCfgSize)
  1415  		if err != nil {
  1416  			return nil
  1417  		}
  1418  		enclave.Config = imgEnclaveCfg
  1419  	}
  1420  
  1421  	// Get the array of images that an enclave can import.
  1422  	val := reflect.ValueOf(enclave.Config)
  1423  	ImportListRVA := val.FieldByName("ImportList").Interface().(uint32)
  1424  	NumberOfImports := val.FieldByName("NumberOfImports").Interface().(uint32)
  1425  	ImportEntrySize := val.FieldByName("ImportEntrySize").Interface().(uint32)
  1426  
  1427  	offset := pe.GetOffsetFromRva(ImportListRVA)
  1428  	for i := uint32(0); i < NumberOfImports; i++ {
  1429  		imgEncImp := ImageEnclaveImport{}
  1430  		imgEncImpSize := uint32(binary.Size(imgEncImp))
  1431  		err := pe.structUnpack(&imgEncImp, offset, imgEncImpSize)
  1432  		if err != nil {
  1433  			return nil
  1434  		}
  1435  
  1436  		offset += ImportEntrySize
  1437  		enclave.Imports = append(enclave.Imports, imgEncImp)
  1438  	}
  1439  
  1440  	return &enclave
  1441  }
  1442  
  1443  func (pe *File) getVolatileMetadata() *VolatileMetadata {
  1444  
  1445  	volatileMeta := VolatileMetadata{}
  1446  	imgVolatileMeta := ImageVolatileMetadata{}
  1447  	rva := uint32(0)
  1448  
  1449  	v := reflect.ValueOf(pe.LoadConfig.Struct)
  1450  	if v.NumField() <= 41 {
  1451  		return nil
  1452  	}
  1453  
  1454  	VolatileMetadataPointer := v.Field(41).Uint()
  1455  	if VolatileMetadataPointer == 0 {
  1456  		return nil
  1457  	}
  1458  
  1459  	if pe.Is32 {
  1460  		imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader32).ImageBase
  1461  		rva = uint32(VolatileMetadataPointer) - imageBase
  1462  	} else {
  1463  		imageBase := pe.NtHeader.OptionalHeader.(ImageOptionalHeader64).ImageBase
  1464  		rva = uint32(VolatileMetadataPointer - imageBase)
  1465  	}
  1466  
  1467  	offset := pe.GetOffsetFromRva(rva)
  1468  	imgVolatileMetaSize := uint32(binary.Size(imgVolatileMeta))
  1469  	err := pe.structUnpack(&imgVolatileMeta, offset, imgVolatileMetaSize)
  1470  	if err != nil {
  1471  		return nil
  1472  	}
  1473  	volatileMeta.Struct = imgVolatileMeta
  1474  
  1475  	if imgVolatileMeta.VolatileAccessTable != 0 &&
  1476  		imgVolatileMeta.VolatileAccessTableSize != 0 {
  1477  		offset := pe.GetOffsetFromRva(imgVolatileMeta.VolatileAccessTable)
  1478  		for i := uint32(0); i < imgVolatileMeta.VolatileAccessTableSize/4; i++ {
  1479  			accessRVA, err := pe.ReadUint32(offset)
  1480  			if err != nil {
  1481  				break
  1482  			}
  1483  
  1484  			volatileMeta.AccessRVATable = append(volatileMeta.AccessRVATable, accessRVA)
  1485  			offset += 4
  1486  		}
  1487  	}
  1488  
  1489  	if imgVolatileMeta.VolatileInfoRangeTable != 0 && imgVolatileMeta.VolatileInfoRangeTableSize != 0 {
  1490  		offset := pe.GetOffsetFromRva(imgVolatileMeta.VolatileInfoRangeTable)
  1491  		rangeEntrySize := uint32(binary.Size(RangeTableEntry{}))
  1492  		for i := uint32(0); i < imgVolatileMeta.VolatileInfoRangeTableSize/rangeEntrySize; i++ {
  1493  			entry := RangeTableEntry{}
  1494  			err := pe.structUnpack(&entry, offset, rangeEntrySize)
  1495  			if err != nil {
  1496  				break
  1497  			}
  1498  
  1499  			volatileMeta.InfoRangeTable = append(volatileMeta.InfoRangeTable, entry)
  1500  			offset += rangeEntrySize
  1501  		}
  1502  	}
  1503  
  1504  	return &volatileMeta
  1505  }
  1506  
  1507  // String returns a string interpretation of the load config directory image
  1508  // guard flag.
  1509  func (flag ImageGuardFlagType) String() string {
  1510  	imageGuardFlagTypeMap := map[ImageGuardFlagType]string{
  1511  		ImageGuardFlagFIDSuppressed:    "FID Suppressed",
  1512  		ImageGuardFlagExportSuppressed: "Export Suppressed",
  1513  	}
  1514  
  1515  	v, ok := imageGuardFlagTypeMap[flag]
  1516  	if ok {
  1517  		return v
  1518  	}
  1519  
  1520  	return "?"
  1521  }