github.com/saferwall/pe@v1.5.2/loadconfig_test.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 package pe 6 7 import ( 8 "reflect" 9 "testing" 10 ) 11 12 func TestLoadConfigDirectory(t *testing.T) { 13 14 tests := []struct { 15 in string 16 out interface{} 17 }{ 18 { 19 in: getAbsoluteFilePath("test/pspluginwkr.dll"), 20 out: ImageLoadConfigDirectory32{ 21 Size: 0x48, 22 SecurityCookie: 0x45e44220, 23 SEHandlerTable: 0x45e382e0, 24 SEHandlerCount: 0x1, 25 }, 26 }, 27 { 28 in: getAbsoluteFilePath("test/00da1a2a9d9ebf447508bf6550f05f466f8eabb4ed6c4f2a524c0769b2d75bc1"), 29 out: ImageLoadConfigDirectory32{ 30 Size: 0x5c, 31 SecurityCookie: 0x43D668, 32 SEHandlerTable: 0x439C70, 33 SEHandlerCount: 0x25, 34 GuardCFCheckFunctionPointer: 0x432260, 35 GuardCFFunctionTable: 0x4322D4, 36 GuardCFFunctionCount: 0x90, 37 GuardFlags: 0x10013500, 38 }, 39 }, 40 { 41 in: getAbsoluteFilePath("test/3a081c7fe475ec68ed155c76d30cfddc4d41f7a09169810682d1c75421e98eaa"), 42 out: ImageLoadConfigDirectory32{ 43 Size: 0xa0, 44 SecurityCookie: 0x417008, 45 SEHandlerTable: 0x415410, 46 SEHandlerCount: 0x2, 47 GuardCFCheckFunctionPointer: 0x40e384, 48 GuardFlags: 0x100, 49 }, 50 }, 51 52 { 53 in: getAbsoluteFilePath("test/IEAdvpack.dll"), 54 out: ImageLoadConfigDirectory32{ 55 Size: 0xa4, 56 SecurityCookie: 0x6501b074, 57 SEHandlerTable: 0x650046d0, 58 SEHandlerCount: 0x1, 59 GuardCFCheckFunctionPointer: 0x6502937c, 60 GuardCFFunctionTable: 0x650010f0, 61 GuardCFFunctionCount: 0x55, 62 GuardFlags: 0x10017500, 63 GuardAddressTakenIATEntryTable: 0x6500129c, 64 GuardAddressTakenIATEntryCount: 0x1, 65 GuardLongJumpTargetTable: 0x650012a4, 66 GuardLongJumpTargetCount: 0x2, 67 }, 68 }, 69 { 70 in: getAbsoluteFilePath("test/KernelBase.dll"), 71 out: ImageLoadConfigDirectory32{ 72 Size: 0xb8, 73 DependentLoadFlags: 0x800, 74 SecurityCookie: 0x101f3b50, 75 SEHandlerTable: 0x10090c40, 76 SEHandlerCount: 0x3, 77 GuardCFCheckFunctionPointer: 0x101f7b08, 78 GuardCFFunctionTable: 0x1005ab70, 79 GuardCFFunctionCount: 0xc4a, 80 GuardFlags: 0x10017500, 81 GuardAddressTakenIATEntryTable: 0x1005e8e4, 82 GuardAddressTakenIATEntryCount: 0xa, 83 VolatileMetadataPointer: 0x10090c4c, 84 }, 85 }, 86 { 87 in: getAbsoluteFilePath("test/WdfCoInstaller01011.dll"), 88 out: ImageLoadConfigDirectory64{ 89 Size: 0x70, 90 SecurityCookie: 0x18000f108, 91 }, 92 }, 93 { 94 in: getAbsoluteFilePath("test/D2D1Debug2.dll"), 95 out: ImageLoadConfigDirectory64{ 96 Size: 0x94, 97 SecurityCookie: 0x180061008, 98 GuardCFCheckFunctionPointer: 0x180001000, 99 }, 100 }, 101 { 102 in: getAbsoluteFilePath("test/amdxata.sys"), 103 out: ImageLoadConfigDirectory64{ 104 Size: 0xa0, 105 SecurityCookie: 0x1c00030b0, 106 GuardCFCheckFunctionPointer: 0x1c0005160, 107 GuardCFDispatchFunctionPointer: 0x1c0005168, 108 GuardCFFunctionTable: 0x1c0009000, 109 GuardCFFunctionCount: 0x17, 110 GuardFlags: 0x500, 111 }, 112 }, 113 { 114 in: getAbsoluteFilePath("test/amdi2c.sys"), 115 out: ImageLoadConfigDirectory64{ 116 Size: 0xd0, 117 SecurityCookie: 0x140009090, 118 GuardCFCheckFunctionPointer: 0x140008100, 119 GuardCFDispatchFunctionPointer: 0x140008108, 120 GuardFlags: 0x100, 121 }, 122 }, 123 { 124 in: getAbsoluteFilePath("test/brave.exe"), 125 out: ImageLoadConfigDirectory64{ 126 Size: 0x100, 127 SecurityCookie: 0x14017b648, 128 GuardCFCheckFunctionPointer: 0x140191000, 129 GuardCFDispatchFunctionPointer: 0x140191008, 130 GuardCFFunctionTable: 0x14016b627, 131 GuardCFFunctionCount: 0x561, 132 GuardFlags: 0x500, 133 }, 134 }, 135 { 136 in: getAbsoluteFilePath("test/shimeng.dll"), 137 out: ImageLoadConfigDirectory64{ 138 Size: 0x108, 139 SecurityCookie: 0x180003000, 140 GuardCFCheckFunctionPointer: 0x180002188, 141 GuardCFDispatchFunctionPointer: 0x180002190, 142 GuardCFFunctionTable: 0x180002198, 143 GuardCFFunctionCount: 0x3, 144 GuardFlags: 0x17500, 145 }, 146 }, 147 { 148 in: getAbsoluteFilePath("test/kernel32.dll"), 149 out: ImageLoadConfigDirectory64{ 150 Size: 0x118, 151 SecurityCookie: 0x1800b3220, 152 GuardCFCheckFunctionPointer: 0x180084218, 153 GuardCFDispatchFunctionPointer: 0x180084220, 154 GuardCFFunctionTable: 0x180084388, 155 GuardCFFunctionCount: 0x5e6, 156 GuardFlags: 0x10417500, 157 GuardAddressTakenIATEntryTable: 0x180086108, 158 GuardAddressTakenIATEntryCount: 0x3, 159 GuardEHContinuationTable: 0x180084228, 160 GuardEHContinuationCount: 0x46, 161 }, 162 }, 163 } 164 165 for _, tt := range tests { 166 t.Run(tt.in, func(t *testing.T) { 167 ops := Options{Fast: true} 168 file, err := New(tt.in, &ops) 169 if err != nil { 170 t.Fatalf("New(%s) failed, reason: %v", tt.in, err) 171 } 172 173 err = file.Parse() 174 if err != nil { 175 t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err) 176 } 177 178 var va, size uint32 179 180 if file.Is64 { 181 oh64 := file.NtHeader.OptionalHeader.(ImageOptionalHeader64) 182 dirEntry := oh64.DataDirectory[ImageDirectoryEntryLoadConfig] 183 va = dirEntry.VirtualAddress 184 size = dirEntry.Size 185 } else { 186 oh32 := file.NtHeader.OptionalHeader.(ImageOptionalHeader32) 187 dirEntry := oh32.DataDirectory[ImageDirectoryEntryLoadConfig] 188 va = dirEntry.VirtualAddress 189 size = dirEntry.Size 190 } 191 192 err = file.parseLoadConfigDirectory(va, size) 193 if err != nil { 194 t.Fatalf("parseLoadConfigDirectory(%s) failed, reason: %v", 195 tt.in, err) 196 } 197 198 imgLoadCfgDirectory := file.LoadConfig.Struct 199 if imgLoadCfgDirectory != tt.out { 200 t.Fatalf("load config directory structure assertion failed, got %v, want %v", 201 imgLoadCfgDirectory, tt.out) 202 } 203 204 }) 205 } 206 } 207 208 func TestLoadConfigDirectorySEHHandlers(t *testing.T) { 209 210 tests := []struct { 211 in string 212 out []uint32 213 }{ 214 { 215 in: getAbsoluteFilePath("test/KernelBase.dll"), 216 out: []uint32{0x14ad30, 0x14af40, 0x14b0d0}, 217 }, 218 } 219 220 for _, tt := range tests { 221 t.Run(tt.in, func(t *testing.T) { 222 223 ops := Options{Fast: true} 224 file, err := New(tt.in, &ops) 225 if err != nil { 226 t.Fatalf("New(%s) failed, reason: %v", tt.in, err) 227 } 228 229 err = file.Parse() 230 if err != nil { 231 t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err) 232 } 233 234 var va, size uint32 235 236 if file.Is64 { 237 oh64 := file.NtHeader.OptionalHeader.(ImageOptionalHeader64) 238 dirEntry := oh64.DataDirectory[ImageDirectoryEntryLoadConfig] 239 va = dirEntry.VirtualAddress 240 size = dirEntry.Size 241 } else { 242 oh32 := file.NtHeader.OptionalHeader.(ImageOptionalHeader32) 243 dirEntry := oh32.DataDirectory[ImageDirectoryEntryLoadConfig] 244 va = dirEntry.VirtualAddress 245 size = dirEntry.Size 246 } 247 248 err = file.parseLoadConfigDirectory(va, size) 249 if err != nil { 250 t.Fatalf("parseLoadConfigDirectory(%s) failed, reason: %v", 251 tt.in, err) 252 } 253 254 sehHandlers := file.LoadConfig.SEH 255 if !reflect.DeepEqual(sehHandlers, tt.out) { 256 t.Fatalf("load config SEH handlers assertion failed, got %v, want %v", 257 sehHandlers, tt.out) 258 } 259 }) 260 } 261 } 262 263 func TestLoadConfigDirectoryControlFlowGuardFunctions(t *testing.T) { 264 265 type TestGFIDSEntry struct { 266 entriesCount int 267 entryIndex int 268 CFGFunction CFGFunction 269 } 270 271 tests := []struct { 272 in string 273 out TestGFIDSEntry 274 }{ 275 { 276 in: getAbsoluteFilePath("test/KernelBase.dll"), 277 out: TestGFIDSEntry{ 278 entriesCount: 0xc4a, 279 entryIndex: 0x1, 280 CFGFunction: CFGFunction{ 281 RVA: 0xfe2a0, 282 Flags: ImageGuardFlagExportSuppressed, 283 Description: "GetCalendarInfoEx", 284 }, 285 }, 286 }, 287 { 288 in: getAbsoluteFilePath("test/kernel32.dll"), 289 out: TestGFIDSEntry{ 290 entriesCount: 0x5e6, 291 entryIndex: 0x5d3, 292 CFGFunction: CFGFunction{ 293 RVA: 0x71390, 294 Flags: ImageGuardFlagExportSuppressed, 295 Description: "QuirkIsEnabledForPackage2Worker", 296 }, 297 }, 298 }, 299 } 300 301 for _, tt := range tests { 302 t.Run(tt.in, func(t *testing.T) { 303 304 ops := Options{Fast: false} 305 file, err := New(tt.in, &ops) 306 if err != nil { 307 t.Fatalf("New(%s) failed, reason: %v", tt.in, err) 308 } 309 310 err = file.Parse() 311 if err != nil { 312 t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err) 313 } 314 315 var va, size uint32 316 317 if file.Is64 { 318 oh64 := file.NtHeader.OptionalHeader.(ImageOptionalHeader64) 319 dirEntry := oh64.DataDirectory[ImageDirectoryEntryLoadConfig] 320 va = dirEntry.VirtualAddress 321 size = dirEntry.Size 322 } else { 323 oh32 := file.NtHeader.OptionalHeader.(ImageOptionalHeader32) 324 dirEntry := oh32.DataDirectory[ImageDirectoryEntryLoadConfig] 325 va = dirEntry.VirtualAddress 326 size = dirEntry.Size 327 } 328 329 err = file.parseLoadConfigDirectory(va, size) 330 if err != nil { 331 t.Fatalf("parseLoadConfigDirectory(%s) failed, reason: %v", 332 tt.in, err) 333 } 334 335 gfids := file.LoadConfig.GFIDS 336 if len(gfids) != tt.out.entriesCount { 337 t.Fatalf("load config GFIDS entries count assert failed, got %v, want %v", 338 len(gfids), tt.out.entriesCount) 339 } 340 341 guardedFunction := gfids[tt.out.entryIndex] 342 if !reflect.DeepEqual(guardedFunction, tt.out.CFGFunction) { 343 t.Fatalf("load config GFIDS entry assertion failed, got %v, want %v", 344 guardedFunction, tt.out.CFGFunction) 345 } 346 }) 347 } 348 } 349 350 func TestLoadConfigDirectoryControlFlowGuardIAT(t *testing.T) { 351 352 type TestGFIDSEntry struct { 353 entriesCount int 354 entryIndex int 355 CFGFunction CFGIATEntry 356 } 357 358 tests := []struct { 359 in string 360 out TestGFIDSEntry 361 }{ 362 { 363 in: getAbsoluteFilePath("test/KernelBase.dll"), 364 out: TestGFIDSEntry{ 365 entriesCount: 0xa, 366 entryIndex: 0x9, 367 CFGFunction: CFGIATEntry{ 368 RVA: 0x1f7924, 369 IATValue: 0x80000008, 370 INTValue: 0x80000008, 371 Description: "ntdll.dll!#8", 372 }, 373 }, 374 }, 375 { 376 in: getAbsoluteFilePath("test/kernel32.dll"), 377 out: TestGFIDSEntry{ 378 entriesCount: 0x3, 379 entryIndex: 0x2, 380 CFGFunction: CFGIATEntry{ 381 RVA: 0x83838, 382 IATValue: 0xac0e0, 383 INTValue: 0xac0e0, 384 Description: "ntdll.dll!RtlGetLengthWithoutLastFullDosOrNtPathElement", 385 }, 386 }, 387 }, 388 } 389 390 for _, tt := range tests { 391 t.Run(tt.in, func(t *testing.T) { 392 393 ops := Options{Fast: false} 394 file, err := New(tt.in, &ops) 395 if err != nil { 396 t.Fatalf("New(%s) failed, reason: %v", tt.in, err) 397 } 398 399 err = file.Parse() 400 if err != nil { 401 t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err) 402 } 403 404 var va, size uint32 405 406 if file.Is64 { 407 oh64 := file.NtHeader.OptionalHeader.(ImageOptionalHeader64) 408 dirEntry := oh64.DataDirectory[ImageDirectoryEntryLoadConfig] 409 va = dirEntry.VirtualAddress 410 size = dirEntry.Size 411 } else { 412 oh32 := file.NtHeader.OptionalHeader.(ImageOptionalHeader32) 413 dirEntry := oh32.DataDirectory[ImageDirectoryEntryLoadConfig] 414 va = dirEntry.VirtualAddress 415 size = dirEntry.Size 416 } 417 418 err = file.parseLoadConfigDirectory(va, size) 419 if err != nil { 420 t.Fatalf("parseLoadConfigDirectory(%s) failed, reason: %v", 421 tt.in, err) 422 } 423 424 cfgIAT := file.LoadConfig.CFGIAT 425 if len(cfgIAT) != tt.out.entriesCount { 426 t.Fatalf("load config CFG IAT entries count assert failed, got %v, want %v", 427 len(cfgIAT), tt.out.entriesCount) 428 } 429 430 cfgIATEntry := cfgIAT[tt.out.entryIndex] 431 if !reflect.DeepEqual(cfgIATEntry, tt.out.CFGFunction) { 432 t.Fatalf("load config CFG IAT entry assertion failed, got %v, want %v", 433 cfgIATEntry, tt.out.CFGFunction) 434 } 435 }) 436 } 437 } 438 439 func TestLoadConfigDirectoryControlFlowGuardLongJump(t *testing.T) { 440 441 tests := []struct { 442 in string 443 out []uint32 444 }{ 445 { 446 in: getAbsoluteFilePath("test/IEAdvpack.dll"), 447 out: []uint32{0x13EDD, 0x1434F}, 448 }, 449 { 450 in: getAbsoluteFilePath("test/PSCRIPT5.DLL"), 451 out: []uint32{0x3FE11, 0x401F8, 0x4077D, 0x40B53, 0x40DFD, 0x40FB3}, 452 }, 453 } 454 455 for _, tt := range tests { 456 t.Run(tt.in, func(t *testing.T) { 457 458 ops := Options{Fast: true} 459 file, err := New(tt.in, &ops) 460 if err != nil { 461 t.Fatalf("New(%s) failed, reason: %v", tt.in, err) 462 } 463 464 err = file.Parse() 465 if err != nil { 466 t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err) 467 } 468 469 var va, size uint32 470 471 if file.Is64 { 472 oh64 := file.NtHeader.OptionalHeader.(ImageOptionalHeader64) 473 dirEntry := oh64.DataDirectory[ImageDirectoryEntryLoadConfig] 474 va = dirEntry.VirtualAddress 475 size = dirEntry.Size 476 } else { 477 oh32 := file.NtHeader.OptionalHeader.(ImageOptionalHeader32) 478 dirEntry := oh32.DataDirectory[ImageDirectoryEntryLoadConfig] 479 va = dirEntry.VirtualAddress 480 size = dirEntry.Size 481 } 482 483 err = file.parseLoadConfigDirectory(va, size) 484 if err != nil { 485 t.Fatalf("parseLoadConfigDirectory(%s) failed, reason: %v", 486 tt.in, err) 487 } 488 489 cfgLongJumpTargetTable := file.LoadConfig.CFGLongJump 490 if !reflect.DeepEqual(cfgLongJumpTargetTable, tt.out) { 491 t.Fatalf("load config CFG long jump target table assertion failed, got %v, want %v", 492 cfgLongJumpTargetTable, tt.out) 493 } 494 }) 495 } 496 } 497 498 func TestLoadConfigDirectoryHybridPE(t *testing.T) { 499 500 type TestCHPE struct { 501 imgCHPEMetadata ImageCHPEMetadataX86 502 codeRanges []CodeRange 503 compilerIAT CompilerIAT 504 } 505 506 tests := []struct { 507 in string 508 out TestCHPE 509 }{ 510 { 511 in: getAbsoluteFilePath("test/msyuv.dll"), 512 out: TestCHPE{ 513 imgCHPEMetadata: ImageCHPEMetadataX86{ 514 Version: 0x4, 515 CHPECodeAddressRangeOffset: 0x26f8, 516 CHPECodeAddressRangeCount: 0x4, 517 WoWA64ExceptionHandlerFunctionPtr: 0x1000c, 518 WoWA64DispatchCallFunctionPtr: 0x10000, 519 WoWA64DispatchIndirectCallFunctionPtr: 0x10004, 520 WoWA64DispatchIndirectCallCfgFunctionPtr: 0x10008, 521 WoWA64DispatchRetFunctionPtr: 0x10010, 522 WoWA64DispatchRetLeafFunctionPtr: 0x10014, 523 WoWA64DispatchJumpFunctionPtr: 0x10018, 524 CompilerIATPointer: 0x11000, 525 WoWA64RDTSCFunctionPtr: 0x1001c, 526 }, 527 codeRanges: []CodeRange{ 528 { 529 Begin: 0x1000, 530 Length: 0x10, 531 Machine: 0x0, 532 }, 533 { 534 Begin: 0x2a00, 535 Length: 0x4e28, 536 Machine: 0x1, 537 }, 538 { 539 Begin: 0x8000, 540 Length: 0x4b1, 541 Machine: 0x0, 542 }, 543 { 544 Begin: 0x9000, 545 Length: 0x2090, 546 Machine: 0x1, 547 }, 548 }, 549 }, 550 }, 551 } 552 553 for _, tt := range tests { 554 t.Run(tt.in, func(t *testing.T) { 555 556 ops := Options{Fast: false} 557 file, err := New(tt.in, &ops) 558 if err != nil { 559 t.Fatalf("New(%s) failed, reason: %v", tt.in, err) 560 } 561 562 err = file.Parse() 563 if err != nil { 564 t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err) 565 } 566 567 var va, size uint32 568 569 if file.Is64 { 570 oh64 := file.NtHeader.OptionalHeader.(ImageOptionalHeader64) 571 dirEntry := oh64.DataDirectory[ImageDirectoryEntryLoadConfig] 572 va = dirEntry.VirtualAddress 573 size = dirEntry.Size 574 } else { 575 oh32 := file.NtHeader.OptionalHeader.(ImageOptionalHeader32) 576 dirEntry := oh32.DataDirectory[ImageDirectoryEntryLoadConfig] 577 va = dirEntry.VirtualAddress 578 size = dirEntry.Size 579 } 580 581 err = file.parseLoadConfigDirectory(va, size) 582 if err != nil { 583 t.Fatalf("parseLoadConfigDirectory(%s) failed, reason: %v", 584 tt.in, err) 585 } 586 587 chpe := file.LoadConfig.CHPE 588 if chpe.CHPEMetadata != tt.out.imgCHPEMetadata { 589 t.Fatalf("load config CHPE metadata assertion failed, got %v, want %v", 590 chpe.CHPEMetadata, tt.out.imgCHPEMetadata) 591 } 592 593 if !reflect.DeepEqual(chpe.CodeRanges, tt.out.codeRanges) { 594 t.Fatalf("load config CHPE code ranges assertion failed, got %v, want %v", 595 chpe.CodeRanges, tt.out.codeRanges) 596 } 597 598 // TODO: test compiler IAT. 599 }) 600 } 601 } 602 603 func TestLoadConfigDirectoryDVRT(t *testing.T) { 604 605 type TestDVRT struct { 606 imgDynRelocTable ImageDynamicRelocationTable 607 relocEntriesCount int 608 } 609 610 tests := []struct { 611 in string 612 out TestDVRT 613 }{ 614 { 615 in: getAbsoluteFilePath("test/WdBoot.sys"), 616 out: TestDVRT{ 617 imgDynRelocTable: ImageDynamicRelocationTable{ 618 Version: 0x1, 619 Size: 0x2dc, 620 }, 621 relocEntriesCount: 0x2, 622 }, 623 }, 624 } 625 626 for _, tt := range tests { 627 t.Run(tt.in, func(t *testing.T) { 628 629 ops := Options{Fast: true} 630 file, err := New(tt.in, &ops) 631 if err != nil { 632 t.Fatalf("New(%s) failed, reason: %v", tt.in, err) 633 } 634 635 err = file.Parse() 636 if err != nil { 637 t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err) 638 } 639 640 var va, size uint32 641 642 if file.Is64 { 643 oh64 := file.NtHeader.OptionalHeader.(ImageOptionalHeader64) 644 dirEntry := oh64.DataDirectory[ImageDirectoryEntryLoadConfig] 645 va = dirEntry.VirtualAddress 646 size = dirEntry.Size 647 } else { 648 oh32 := file.NtHeader.OptionalHeader.(ImageOptionalHeader32) 649 dirEntry := oh32.DataDirectory[ImageDirectoryEntryLoadConfig] 650 va = dirEntry.VirtualAddress 651 size = dirEntry.Size 652 } 653 654 err = file.parseLoadConfigDirectory(va, size) 655 if err != nil { 656 t.Fatalf("parseLoadConfigDirectory(%s) failed, reason: %v", 657 tt.in, err) 658 } 659 660 DVRT := file.LoadConfig.DVRT 661 if DVRT.ImageDynamicRelocationTable != tt.out.imgDynRelocTable { 662 t.Fatalf("load config DVRT header assertion failed, got %v, want %v", 663 DVRT.ImageDynamicRelocationTable, tt.out.imgDynRelocTable) 664 } 665 666 if len(DVRT.Entries) != tt.out.relocEntriesCount { 667 t.Fatalf("load config DVRT entries count assertion failed, got %v, want %v", 668 len(DVRT.Entries), tt.out.relocEntriesCount) 669 } 670 }) 671 } 672 } 673 674 func TestLoadConfigDirectoryDVRTRetpolineType(t *testing.T) { 675 676 type DVRTRetpolineType struct { 677 relocEntryIdx int 678 imgDynReloc interface{} 679 RelocBlockCount int 680 relocBlockIdx int 681 relocBlock RelocBlock 682 } 683 684 tests := []struct { 685 in string 686 out DVRTRetpolineType 687 }{ 688 { 689 in: getAbsoluteFilePath("test/WdBoot.sys"), 690 out: DVRTRetpolineType{ 691 relocEntryIdx: 0x0, 692 imgDynReloc: ImageDynamicRelocation64{ 693 Symbol: 0x3, 694 BaseRelocSize: 0x278, 695 }, 696 RelocBlockCount: 0x7, 697 relocBlockIdx: 0x0, 698 relocBlock: RelocBlock{ 699 ImgBaseReloc: ImageBaseRelocation{ 700 VirtualAddress: 0x2000, 701 SizeOfBlock: 0xc, 702 }, 703 TypeOffsets: []interface{}{ 704 ImageImportControlTransferDynamicRelocation{ 705 PageRelativeOffset: 0x611, 706 IndirectCall: 0x0, 707 IATIndex: 0x28, 708 }, 709 }, 710 }, 711 }, 712 }, 713 { 714 in: getAbsoluteFilePath("test/WdBoot.sys"), 715 out: DVRTRetpolineType{ 716 relocEntryIdx: 0x1, 717 imgDynReloc: ImageDynamicRelocation64{ 718 Symbol: 0x4, 719 BaseRelocSize: 0x4c, 720 }, 721 RelocBlockCount: 0x5, 722 relocBlockIdx: 0x4, 723 relocBlock: RelocBlock{ 724 ImgBaseReloc: ImageBaseRelocation{ 725 VirtualAddress: 0xb000, 726 SizeOfBlock: 0xc, 727 }, 728 TypeOffsets: []interface{}{ 729 ImageIndirectControlTransferDynamicRelocation{ 730 PageRelativeOffset: 0x58e, 731 IndirectCall: 0x1, 732 CfgCheck: 0x1, 733 }, 734 }, 735 }, 736 }, 737 }, 738 { 739 in: getAbsoluteFilePath("test/acpi.sys"), 740 out: DVRTRetpolineType{ 741 relocEntryIdx: 0x2, 742 imgDynReloc: ImageDynamicRelocation64{ 743 Symbol: 0x5, 744 BaseRelocSize: 0x4c, 745 }, 746 RelocBlockCount: 0x6, 747 relocBlockIdx: 0x5, 748 relocBlock: RelocBlock{ 749 ImgBaseReloc: ImageBaseRelocation{ 750 VirtualAddress: 0x43000, 751 SizeOfBlock: 0xc, 752 }, 753 TypeOffsets: []interface{}{ 754 ImageSwitchableBranchDynamicRelocation{ 755 PageRelativeOffset: 0xd1, 756 RegisterNumber: 0x1, 757 }, 758 }, 759 }, 760 }, 761 }, 762 } 763 764 for _, tt := range tests { 765 t.Run(tt.in, func(t *testing.T) { 766 767 ops := Options{Fast: true} 768 file, err := New(tt.in, &ops) 769 if err != nil { 770 t.Fatalf("New(%s) failed, reason: %v", tt.in, err) 771 } 772 773 err = file.Parse() 774 if err != nil { 775 t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err) 776 } 777 778 var va, size uint32 779 780 if file.Is64 { 781 oh64 := file.NtHeader.OptionalHeader.(ImageOptionalHeader64) 782 dirEntry := oh64.DataDirectory[ImageDirectoryEntryLoadConfig] 783 va = dirEntry.VirtualAddress 784 size = dirEntry.Size 785 } else { 786 oh32 := file.NtHeader.OptionalHeader.(ImageOptionalHeader32) 787 dirEntry := oh32.DataDirectory[ImageDirectoryEntryLoadConfig] 788 va = dirEntry.VirtualAddress 789 size = dirEntry.Size 790 } 791 792 err = file.parseLoadConfigDirectory(va, size) 793 if err != nil { 794 t.Fatalf("parseLoadConfigDirectory(%s) failed, reason: %v", 795 tt.in, err) 796 } 797 798 DVRT := file.LoadConfig.DVRT 799 relocEntry := DVRT.Entries[tt.out.relocEntryIdx] 800 if relocEntry.ImageDynamicRelocation != tt.out.imgDynReloc { 801 t.Fatalf("load config DVRT reloc entry imaged dynamic relocation assertion failed, got %#v, want %#v", 802 relocEntry.ImageDynamicRelocation, tt.out.imgDynReloc) 803 } 804 805 if len(relocEntry.RelocBlocks) != tt.out.RelocBlockCount { 806 t.Fatalf("load config DVRT reloc block count dynamic relocation assertion failed, got %v, want %v", 807 len(relocEntry.RelocBlocks), tt.out.RelocBlockCount) 808 } 809 810 relocBlock := relocEntry.RelocBlocks[tt.out.relocBlockIdx] 811 if !reflect.DeepEqual(relocBlock, tt.out.relocBlock) { 812 t.Fatalf("load config DVRT reloc block assertion failed, got %#v, want %#v", 813 relocBlock, tt.out.relocBlock) 814 } 815 }) 816 } 817 } 818 819 func TestLoadConfigDirectoryEnclave(t *testing.T) { 820 821 tests := []struct { 822 in string 823 out Enclave 824 }{ 825 { 826 in: getAbsoluteFilePath("test/SgrmEnclave_secure.dll"), 827 out: Enclave{ 828 Config: ImageEnclaveConfig64{ 829 Size: 0x50, 830 MinimumRequiredConfigSize: 0x4c, 831 NumberOfImports: 0x4, 832 ImportList: 0x55224, 833 ImportEntrySize: 0x50, 834 FamilyID: [ImageEnclaveShortIDLength]uint8{0xb1, 0x35, 0x7c, 0x2b, 0x69, 0x9f, 0x47, 0xf9, 0xbb, 0xc9, 0x4f, 0x44, 0xf2, 0x54, 0xdb, 0x9d}, 835 ImageID: [ImageEnclaveShortIDLength]uint8{0x24, 0x56, 0x46, 0x36, 0xcd, 0x4a, 0x4a, 0xd8, 0x86, 0xa2, 0xf4, 0xec, 0x25, 0xa9, 0x72, 0x2}, 836 ImageVersion: 0x1, 837 SecurityVersion: 0x1, 838 EnclaveSize: 0x10000000, 839 NumberOfThreads: 0x8, 840 EnclaveFlags: 0x1, 841 }, 842 Imports: []ImageEnclaveImport{ 843 { 844 MatchType: 0x0, 845 ImportName: 0xffff, 846 }, 847 { 848 MatchType: 0x4, 849 ImageID: [ImageEnclaveShortIDLength]uint8{ 850 0xf0, 0x3c, 0xcd, 0xa7, 0xe8, 0x7b, 0x46, 0xeb, 0xaa, 0xe7, 0x1f, 0x13, 0xd5, 0xcd, 0xde, 0x5d}, 851 ImportName: 0x5b268, 852 }, 853 { 854 MatchType: 0x4, 855 ImageID: [ImageEnclaveShortIDLength]uint8{ 856 0x20, 0x27, 0xbd, 0x68, 0x75, 0x59, 0x49, 0xb7, 0xbe, 0x6, 0x34, 0x50, 0xe2, 0x16, 0xd7, 0xed}, 857 ImportName: 0x5b428, 858 }, 859 { 860 MatchType: 0x4, 861 ImageID: [ImageEnclaveShortIDLength]uint8{ 862 0x72, 0x84, 0x41, 0x72, 0x67, 0xa8, 0x4e, 0x8d, 0xbf, 0x1, 0x28, 0x4b, 0x7, 0x43, 0x2b, 0x1e}, 863 ImportName: 0x5b63c, 864 }, 865 }, 866 }, 867 }, 868 } 869 870 for _, tt := range tests { 871 t.Run(tt.in, func(t *testing.T) { 872 873 ops := Options{Fast: true} 874 file, err := New(tt.in, &ops) 875 if err != nil { 876 t.Fatalf("New(%s) failed, reason: %v", tt.in, err) 877 } 878 879 err = file.Parse() 880 if err != nil { 881 t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err) 882 } 883 884 var va, size uint32 885 886 if file.Is64 { 887 oh64 := file.NtHeader.OptionalHeader.(ImageOptionalHeader64) 888 dirEntry := oh64.DataDirectory[ImageDirectoryEntryLoadConfig] 889 va = dirEntry.VirtualAddress 890 size = dirEntry.Size 891 } else { 892 oh32 := file.NtHeader.OptionalHeader.(ImageOptionalHeader32) 893 dirEntry := oh32.DataDirectory[ImageDirectoryEntryLoadConfig] 894 va = dirEntry.VirtualAddress 895 size = dirEntry.Size 896 } 897 898 err = file.parseLoadConfigDirectory(va, size) 899 if err != nil { 900 t.Fatalf("parseLoadConfigDirectory(%s) failed, reason: %v", 901 tt.in, err) 902 } 903 904 enclave := file.LoadConfig.Enclave 905 if !reflect.DeepEqual(*enclave, tt.out) { 906 t.Fatalf("load config enclave assertion failed, got %#v, want %#v", 907 enclave, tt.out) 908 } 909 910 }) 911 } 912 } 913 914 func TestLoadConfigDirectoryVolatileMetadata(t *testing.T) { 915 916 type TestVolatileMetadata struct { 917 imgVolatileMetadata ImageVolatileMetadata 918 accessRVATableCount int 919 accessRVATableIndex int 920 accessRVAEntry uint32 921 infoRangeTableCount int 922 infoRangeTableIndex int 923 infoRangeEntry RangeTableEntry 924 } 925 926 tests := []struct { 927 in string 928 out TestVolatileMetadata 929 }{ 930 { 931 in: getAbsoluteFilePath("test/KernelBase.dll"), 932 out: TestVolatileMetadata{ 933 imgVolatileMetadata: ImageVolatileMetadata{ 934 Size: 0x18, 935 Version: 0x1, 936 VolatileAccessTable: 0x00090C64, 937 VolatileAccessTableSize: 0x00002E48, 938 VolatileInfoRangeTable: 0x00093AAC, 939 VolatileInfoRangeTableSize: 0x000001D0, 940 }, 941 accessRVATableCount: 0xB92, 942 accessRVATableIndex: 0xB91, 943 accessRVAEntry: 0x1DF998, 944 infoRangeTableCount: 0x3A, 945 infoRangeTableIndex: 0x39, 946 infoRangeEntry: RangeTableEntry{ 947 RVA: 0x16BB10, 948 Size: 0x75550, 949 }, 950 }, 951 }, 952 } 953 954 for _, tt := range tests { 955 t.Run(tt.in, func(t *testing.T) { 956 957 ops := Options{Fast: true} 958 file, err := New(tt.in, &ops) 959 if err != nil { 960 t.Fatalf("New(%s) failed, reason: %v", tt.in, err) 961 } 962 963 err = file.Parse() 964 if err != nil { 965 t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err) 966 } 967 968 var va, size uint32 969 970 if file.Is64 { 971 oh64 := file.NtHeader.OptionalHeader.(ImageOptionalHeader64) 972 dirEntry := oh64.DataDirectory[ImageDirectoryEntryLoadConfig] 973 va = dirEntry.VirtualAddress 974 size = dirEntry.Size 975 } else { 976 oh32 := file.NtHeader.OptionalHeader.(ImageOptionalHeader32) 977 dirEntry := oh32.DataDirectory[ImageDirectoryEntryLoadConfig] 978 va = dirEntry.VirtualAddress 979 size = dirEntry.Size 980 } 981 982 err = file.parseLoadConfigDirectory(va, size) 983 if err != nil { 984 t.Fatalf("parseLoadConfigDirectory(%s) failed, reason: %v", 985 tt.in, err) 986 } 987 988 volatileMetadata := file.LoadConfig.VolatileMetadata 989 if volatileMetadata.Struct != tt.out.imgVolatileMetadata { 990 t.Fatalf("load config image volatile metadata assertion failed, got %v, want %v", 991 volatileMetadata, tt.out.imgVolatileMetadata) 992 } 993 994 if len(volatileMetadata.AccessRVATable) != tt.out.accessRVATableCount { 995 t.Fatalf("load config access RVA table entries count assert failed, got %v, want %v", 996 len(volatileMetadata.AccessRVATable), tt.out.accessRVATableCount) 997 } 998 999 accessRVAEntry := volatileMetadata.AccessRVATable[tt.out.accessRVATableIndex] 1000 if accessRVAEntry != tt.out.accessRVAEntry { 1001 t.Fatalf("load config access RVA table entry assertion failed, got %v, want %v", 1002 accessRVAEntry, tt.out.accessRVAEntry) 1003 } 1004 1005 if len(volatileMetadata.InfoRangeTable) != tt.out.infoRangeTableCount { 1006 t.Fatalf("load config info range table entries count assert failed, got %v, want %v", 1007 len(volatileMetadata.InfoRangeTable), tt.out.infoRangeTableCount) 1008 } 1009 1010 infoRangeEntry := volatileMetadata.InfoRangeTable[tt.out.infoRangeTableIndex] 1011 if infoRangeEntry != tt.out.infoRangeEntry { 1012 t.Fatalf("load config info range table entry assertion failed, got %v, want %v", 1013 infoRangeEntry, tt.out.infoRangeEntry) 1014 } 1015 }) 1016 } 1017 }