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  }