github.com/saferwall/pe@v1.5.2/delayimports.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  // ImageDelayImportDescriptor represents the _IMAGE_DELAYLOAD_DESCRIPTOR structure.
    12  type ImageDelayImportDescriptor struct {
    13  	// As yet, no attribute flags are defined. The linker sets this field to zero
    14  	// in the image. This field can be used to extend the record by indicating
    15  	// the presence of new fields, or it can be used to indicate behaviors to
    16  	// the delay or unload helper functions.
    17  	Attributes uint32 `json:"attributes"`
    18  
    19  	// The name of the DLL to be delay-loaded resides in the read-only data
    20  	// section of the image. It is referenced through the szName field.
    21  	Name uint32 `json:"name"`
    22  
    23  	// The handle of the DLL to be delay-loaded is in the data section of the
    24  	// image. The phmod field points to the handle. The supplied delay-load
    25  	// helper uses this location to store the handle to the loaded DLL.
    26  	ModuleHandleRVA uint32 `json:"module_handle_rva"`
    27  
    28  	// The delay import address table (IAT) is referenced by the delay import
    29  	// descriptor through the pIAT field. The delay-load helper updates these
    30  	// pointers with the real entry points so that the thunks are no longer in
    31  	// the calling loop
    32  	ImportAddressTableRVA uint32 `json:"import_address_table_rva"`
    33  
    34  	// The delay import name table (INT) contains the names of the imports that
    35  	// might require loading. They are ordered in the same fashion as the
    36  	// function pointers in the IAT.
    37  	ImportNameTableRVA uint32 `json:"import_name_table_rva"`
    38  
    39  	// The delay bound import address table (BIAT) is an optional table of
    40  	// IMAGE_THUNK_DATA items that is used along with the timestamp field
    41  	// of the delay-load directory table by a post-process binding phase.
    42  	BoundImportAddressTableRVA uint32 `json:"bound_import_address_table_rva"`
    43  
    44  	// The delay unload import address table (UIAT) is an optional table of
    45  	// IMAGE_THUNK_DATA items that the unload code uses to handle an explicit
    46  	// unload request. It consists of initialized data in the read-only section
    47  	// that is an exact copy of the original IAT that referred the code to the
    48  	// delay-load thunks. On the unload request, the library can be freed,
    49  	// the *phmod cleared, and the UIAT written over the IAT to restore
    50  	// everything to its preload state.
    51  	UnloadInformationTableRVA uint32 `json:"unload_information_table_rva"`
    52  
    53  	// 0 if not bound, otherwise, date/time of the target DLL.
    54  	TimeDateStamp uint32 `json:"time_date_stamp"`
    55  }
    56  
    57  // DelayImport represents an entry in the delay import table.
    58  type DelayImport struct {
    59  	Offset     uint32                     `json:"offset"`
    60  	Name       string                     `json:"name"`
    61  	Functions  []ImportFunction           `json:"functions"`
    62  	Descriptor ImageDelayImportDescriptor `json:"descriptor"`
    63  }
    64  
    65  // Delay-Load Import Tables tables were added to the image to support a uniform
    66  // mechanism for applications to delay the loading of a DLL until the first call
    67  // into that DLL. The delay-load directory table is the counterpart to the
    68  // import directory table.
    69  func (pe *File) parseDelayImportDirectory(rva, size uint32) error {
    70  	for {
    71  		importDelayDesc := ImageDelayImportDescriptor{}
    72  		fileOffset := pe.GetOffsetFromRva(rva)
    73  		importDescSize := uint32(binary.Size(importDelayDesc))
    74  		err := pe.structUnpack(&importDelayDesc, fileOffset, importDescSize)
    75  
    76  		// If the RVA is invalid all would blow up. Some EXEs seem to be
    77  		// specially nasty and have an invalid RVA.
    78  		if err != nil {
    79  			return err
    80  		}
    81  
    82  		// If the structure is all zeros, we reached the end of the list.
    83  		if importDelayDesc == (ImageDelayImportDescriptor{}) {
    84  			break
    85  		}
    86  
    87  		rva += importDescSize
    88  
    89  		// If the array of thunks is somewhere earlier than the import
    90  		// descriptor we can set a maximum length for the array. Otherwise
    91  		// just set a maximum length of the size of the file
    92  		maxLen := uint32(len(pe.data)) - fileOffset
    93  		if rva > importDelayDesc.ImportNameTableRVA ||
    94  			rva > importDelayDesc.ImportAddressTableRVA {
    95  			if rva < importDelayDesc.ImportNameTableRVA {
    96  				maxLen = rva - importDelayDesc.ImportAddressTableRVA
    97  			} else if rva < importDelayDesc.ImportAddressTableRVA {
    98  				maxLen = rva - importDelayDesc.ImportNameTableRVA
    99  			} else {
   100  				maxLen = Max(rva-importDelayDesc.ImportNameTableRVA,
   101  					rva-importDelayDesc.ImportAddressTableRVA)
   102  			}
   103  		}
   104  
   105  		var importedFunctions []ImportFunction
   106  		if pe.Is64 {
   107  			importedFunctions, err = pe.parseImports64(&importDelayDesc, maxLen)
   108  		} else {
   109  			importedFunctions, err = pe.parseImports32(&importDelayDesc, maxLen)
   110  		}
   111  		if err != nil {
   112  			return err
   113  		}
   114  
   115  		nameRVA := uint32(0)
   116  		if importDelayDesc.Attributes == 0 {
   117  			nameRVA = importDelayDesc.Name -
   118  				pe.NtHeader.OptionalHeader.(ImageOptionalHeader32).ImageBase
   119  		} else {
   120  			nameRVA = importDelayDesc.Name
   121  		}
   122  		dllName := pe.getStringAtRVA(nameRVA, maxLen)
   123  		if !IsValidDosFilename(dllName) {
   124  			dllName = "*invalid*"
   125  			continue
   126  		}
   127  
   128  		pe.DelayImports = append(pe.DelayImports, DelayImport{
   129  			Offset:     fileOffset,
   130  			Name:       string(dllName),
   131  			Functions:  importedFunctions,
   132  			Descriptor: importDelayDesc,
   133  		})
   134  	}
   135  
   136  	if len(pe.DelayImports) > 0 {
   137  		pe.HasDelayImp = true
   138  	}
   139  
   140  	return nil
   141  }
   142  
   143  // GetDelayImportEntryInfoByRVA return an import function + index of the entry given
   144  // an RVA.
   145  func (pe *File) GetDelayImportEntryInfoByRVA(rva uint32) (DelayImport, int) {
   146  	for _, imp := range pe.DelayImports {
   147  		for i, entry := range imp.Functions {
   148  			if entry.ThunkRVA == rva {
   149  				return imp, i
   150  			}
   151  		}
   152  	}
   153  
   154  	return DelayImport{}, 0
   155  }