github.com/saferwall/pe@v1.5.2/exception_test.go (about) 1 // Copyright 2021 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 "strconv" 10 "testing" 11 ) 12 13 type TestExceptionEntry struct { 14 entryCount int 15 entryIndex int 16 runtimeFunc ImageRuntimeFunctionEntry 17 unwindInfo UnwindInfo 18 } 19 20 func TestParseExceptionDirectory(t *testing.T) { 21 22 tests := []struct { 23 in string 24 out TestExceptionEntry 25 }{ 26 { 27 getAbsoluteFilePath("test/kernel32.dll"), 28 TestExceptionEntry{ 29 entryCount: 1835, 30 entryIndex: 0, 31 runtimeFunc: ImageRuntimeFunctionEntry{ 32 BeginAddress: 0x1010, 33 EndAddress: 0x1053, 34 UnwindInfoAddress: 0x938b8, 35 }, 36 unwindInfo: UnwindInfo{ 37 Version: 0x1, 38 Flags: 0x0, 39 SizeOfProlog: 0x7, 40 CountOfCodes: 0x1, 41 FrameRegister: 0x0, 42 FrameOffset: 0x0, 43 UnwindCodes: []UnwindCode{ 44 { 45 CodeOffset: 0x07, 46 UnwindOp: 0x2, 47 OpInfo: 0x8, 48 Operand: "Size=72", 49 FrameOffset: 0x0, 50 }, 51 }, 52 }, 53 }, 54 }, 55 { 56 // fake exception directory 57 getAbsoluteFilePath("test/0585495341e0ffaae1734acb78708ff55cd3612d844672d37226ef63d12652d0"), 58 TestExceptionEntry{ 59 entryCount: 3349, 60 entryIndex: 0, 61 runtimeFunc: ImageRuntimeFunctionEntry{ 62 BeginAddress: 0xf860617, 63 EndAddress: 0x205fef60, 64 UnwindInfoAddress: 0x2c0365b4, 65 }, 66 unwindInfo: UnwindInfo{}, 67 }, 68 }, 69 } 70 71 for _, tt := range tests { 72 t.Run(tt.in, func(t *testing.T) { 73 ops := Options{Fast: true} 74 file, err := New(tt.in, &ops) 75 if err != nil { 76 t.Fatalf("New(%s) failed, reason: %v", tt.in, err) 77 } 78 79 err = file.Parse() 80 if err != nil { 81 t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err) 82 } 83 84 var va, size uint32 85 switch file.Is64 { 86 case true: 87 oh64 := file.NtHeader.OptionalHeader.(ImageOptionalHeader64) 88 dirEntry := oh64.DataDirectory[ImageDirectoryEntryException] 89 va = dirEntry.VirtualAddress 90 size = dirEntry.Size 91 case false: 92 oh32 := file.NtHeader.OptionalHeader.(ImageOptionalHeader32) 93 dirEntry := oh32.DataDirectory[ImageDirectoryEntryException] 94 va = dirEntry.VirtualAddress 95 size = dirEntry.Size 96 } 97 98 err = file.parseExceptionDirectory(va, size) 99 if err != nil { 100 t.Fatalf("parseExceptionDirectory(%s) failed, reason: %v", tt.in, err) 101 } 102 got := file.Exceptions 103 if len(got) != tt.out.entryCount { 104 t.Errorf("Exception entry count assertion failed, got %v, want %v", len(got), tt.out.entryCount) 105 } 106 107 runtimeFunc := file.Exceptions[tt.out.entryIndex].RuntimeFunction 108 if runtimeFunc != tt.out.runtimeFunc { 109 t.Errorf("RuntimeFunction assertion failed, got %v, want %v", len(got), tt.out.entryCount) 110 } 111 112 unwindInfo := file.Exceptions[tt.out.entryIndex].UnwindInfo 113 if !reflect.DeepEqual(unwindInfo, tt.out.unwindInfo) { 114 t.Errorf("UnwindInfo assertion failed, got %v, want %v", unwindInfo, tt.out.unwindInfo) 115 } 116 117 }) 118 } 119 } 120 121 func TestExceptionDirectoryUnwindOpcode(t *testing.T) { 122 123 tests := []struct { 124 in UnwindOpType 125 out string 126 }{ 127 { 128 UwOpPushNonVol, 129 "UWOP_PUSH_NONVOL", 130 }, 131 { 132 UnwindOpType(0xff), 133 "?", 134 }, 135 } 136 137 for _, tt := range tests { 138 name := "CaseUnwindOpcodeEqualTo_" + strconv.Itoa(int(tt.in)) 139 t.Run(name, func(t *testing.T) { 140 got := tt.in.String() 141 if got != tt.out { 142 t.Errorf("unwind opcode string interpretation, got %v, want %v", 143 got, tt.out) 144 } 145 }) 146 } 147 }