github.com/saferwall/pe@v1.5.2/boundimports.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  	"encoding/binary"
     9  )
    10  
    11  const (
    12  	// MaxStringLength represents the maximum length of a string to be retrieved
    13  	// from the file. It's there to prevent loading massive amounts of data from
    14  	// memory mapped files. Strings longer than 0x100B should be rather rare.
    15  	MaxStringLength = uint32(0x100)
    16  )
    17  
    18  // ImageBoundImportDescriptor represents the IMAGE_BOUND_IMPORT_DESCRIPTOR.
    19  type ImageBoundImportDescriptor struct {
    20  	// TimeDateStamp is just the value from the Exports information of the DLL
    21  	// which is being imported from.
    22  	TimeDateStamp uint32 `json:"time_date_stamp"`
    23  	// Offset of the DLL name counted from the beginning of the BOUND_IMPORT table.
    24  	OffsetModuleName uint16 `json:"offset_module_name"`
    25  	// Number of forwards,
    26  	NumberOfModuleForwarderRefs uint16 `json:"number_of_module_forwarder_refs"`
    27  	// Array of zero or more IMAGE_BOUND_FORWARDER_REF follows.
    28  }
    29  
    30  // ImageBoundForwardedRef represents the IMAGE_BOUND_FORWARDER_REF.
    31  type ImageBoundForwardedRef struct {
    32  	TimeDateStamp    uint32 `json:"time_date_stamp"`
    33  	OffsetModuleName uint16 `json:"offset_module_name"`
    34  	Reserved         uint16 `json:"reserved"`
    35  }
    36  
    37  // BoundImportDescriptorData represents the descriptor in addition to forwarded refs.
    38  type BoundImportDescriptorData struct {
    39  	Struct        ImageBoundImportDescriptor `json:"struct"`
    40  	Name          string                     `json:"name"`
    41  	ForwardedRefs []BoundForwardedRefData    `json:"forwarded_refs"`
    42  }
    43  
    44  // BoundForwardedRefData represents the struct in addition to the dll name.
    45  type BoundForwardedRefData struct {
    46  	Struct ImageBoundForwardedRef `json:"struct"`
    47  	Name   string                 `json:"name"`
    48  }
    49  
    50  // This table is an array of bound import descriptors, each of which describes
    51  // a DLL this image was bound up with at the time of the image creation.
    52  // The descriptors also carry the time stamps of the bindings, and if the
    53  // bindings are up-to-date, the OS loader uses these bindings as a “shortcut”
    54  // for API import. Otherwise, the loader ignores the bindings and resolves the
    55  // imported APIs through the Import tables.
    56  func (pe *File) parseBoundImportDirectory(rva, size uint32) (err error) {
    57  	var sectionsAfterOffset []uint32
    58  	var safetyBoundary uint32
    59  	var start = rva
    60  
    61  	for {
    62  		bndDesc := ImageBoundImportDescriptor{}
    63  		bndDescSize := uint32(binary.Size(bndDesc))
    64  		err = pe.structUnpack(&bndDesc, rva, bndDescSize)
    65  		// If the RVA is invalid all would blow up. Some EXEs seem to be
    66  		// specially nasty and have an invalid RVA.
    67  		if err != nil {
    68  			return err
    69  		}
    70  
    71  		// If the structure is all zeros, we reached the end of the list.
    72  		if bndDesc == (ImageBoundImportDescriptor{}) {
    73  			break
    74  		}
    75  
    76  		rva += bndDescSize
    77  		sectionsAfterOffset = nil
    78  
    79  		fileOffset := pe.GetOffsetFromRva(rva)
    80  		section := pe.getSectionByRva(rva)
    81  		if section == nil {
    82  			safetyBoundary = pe.size - fileOffset
    83  			for _, section := range pe.Sections {
    84  				if section.Header.PointerToRawData > fileOffset {
    85  					sectionsAfterOffset = append(
    86  						sectionsAfterOffset, section.Header.PointerToRawData)
    87  				}
    88  			}
    89  			if len(sectionsAfterOffset) > 0 {
    90  				// Find the first section starting at a later offset than that
    91  				// specified by 'rva'
    92  				firstSectionAfterOffset := Min(sectionsAfterOffset)
    93  				section = pe.getSectionByOffset(firstSectionAfterOffset)
    94  				if section != nil {
    95  					safetyBoundary = section.Header.PointerToRawData - fileOffset
    96  				}
    97  			}
    98  		} else {
    99  			sectionLen := uint32(len(section.Data(0, 0, pe)))
   100  			safetyBoundary = (section.Header.PointerToRawData + sectionLen) - fileOffset
   101  		}
   102  
   103  		if section == nil {
   104  			pe.logger.Warnf("RVA of IMAGE_BOUND_IMPORT_DESCRIPTOR points to an invalid address: 0x%x", rva)
   105  			return nil
   106  		}
   107  
   108  		bndFrwdRef := ImageBoundForwardedRef{}
   109  		bndFrwdRefSize := uint32(binary.Size(bndFrwdRef))
   110  		count := min(uint32(bndDesc.NumberOfModuleForwarderRefs), safetyBoundary/bndFrwdRefSize)
   111  
   112  		forwarderRefs := make([]BoundForwardedRefData, 0)
   113  		for i := uint32(0); i < count; i++ {
   114  			err = pe.structUnpack(&bndFrwdRef, rva, bndFrwdRefSize)
   115  			if err != nil {
   116  				return err
   117  			}
   118  
   119  			rva += bndFrwdRefSize
   120  
   121  			offset := start + uint32(bndFrwdRef.OffsetModuleName)
   122  			DllNameBuff := string(pe.GetStringFromData(0, pe.data[offset:offset+MaxStringLength]))
   123  			DllName := string(DllNameBuff)
   124  
   125  			// OffsetModuleName points to a DLL name. These shouldn't be too long.
   126  			// Anything longer than a safety length of 128 will be taken to indicate
   127  			// a corrupt entry and abort the processing of these entries.
   128  			// Names shorter than 4 characters will be taken as invalid as well.
   129  			if DllName != "" && (len(DllName) > 256 || !IsPrintable(DllName)) {
   130  				break
   131  			}
   132  
   133  			forwarderRefs = append(forwarderRefs, BoundForwardedRefData{
   134  				Struct: bndFrwdRef, Name: DllName})
   135  		}
   136  
   137  		offset := start + uint32(bndDesc.OffsetModuleName)
   138  		DllNameBuff := pe.GetStringFromData(0, pe.data[offset:offset+MaxStringLength])
   139  		DllName := string(DllNameBuff)
   140  		if DllName != "" && (len(DllName) > 256 || !IsPrintable(DllName)) {
   141  			break
   142  		}
   143  
   144  		pe.BoundImports = append(pe.BoundImports, BoundImportDescriptorData{
   145  			Struct:        bndDesc,
   146  			Name:          DllName,
   147  			ForwardedRefs: forwarderRefs})
   148  	}
   149  
   150  	if len(pe.BoundImports) > 0 {
   151  		pe.HasBoundImp = true
   152  	}
   153  	return nil
   154  }