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  }