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 }