github.com/saferwall/pe@v1.5.2/tls.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  // TLSDirectoryCharacteristicsType represents the type of a TLS directory
    12  // Characteristics.
    13  type TLSDirectoryCharacteristicsType uint32
    14  
    15  // TLSDirectory represents tls directory information with callback entries.
    16  type TLSDirectory struct {
    17  
    18  	// of type *IMAGE_TLS_DIRECTORY32 or *IMAGE_TLS_DIRECTORY64 structure.
    19  	Struct interface{} `json:"struct"`
    20  
    21  	// of type []uint32 or []uint64.
    22  	Callbacks interface{} `json:"callbacks"`
    23  }
    24  
    25  // ImageTLSDirectory32 represents the IMAGE_TLS_DIRECTORY32 structure.
    26  // It Points to the Thread Local Storage initialization section.
    27  type ImageTLSDirectory32 struct {
    28  
    29  	// The starting address of the TLS template. The template is a block of data
    30  	// that is used to initialize TLS data.
    31  	StartAddressOfRawData uint32 `json:"start_address_of_raw_data"`
    32  
    33  	// The address of the last byte of the TLS, except for the zero fill.
    34  	// As with the Raw Data Start VA field, this is a VA, not an RVA.
    35  	EndAddressOfRawData uint32 `json:"end_address_of_raw_data"`
    36  
    37  	// The location to receive the TLS index, which the loader assigns. This
    38  	// location is in an ordinary data section, so it can be given a symbolic
    39  	// name that is accessible to the program.
    40  	AddressOfIndex uint32 `json:"address_of_index"`
    41  
    42  	// The pointer to an array of TLS callback functions. The array is
    43  	// null-terminated, so if no callback function is supported, this field
    44  	// points to 4 bytes set to zero.
    45  	AddressOfCallBacks uint32 `json:"address_of_callbacks"`
    46  
    47  	// The size in bytes of the template, beyond the initialized data delimited
    48  	// by the Raw Data Start VA and Raw Data End VA fields. The total template
    49  	// size should be the same as the total size of TLS data in the image file.
    50  	// The zero fill is the amount of data that comes after the initialized
    51  	// nonzero data.
    52  	SizeOfZeroFill uint32 `json:"size_of_zero_fill"`
    53  
    54  	// The four bits [23:20] describe alignment info. Possible values are those
    55  	// defined as IMAGE_SCN_ALIGN_*, which are also used to describe alignment
    56  	// of section in object files. The other 28 bits are reserved for future use.
    57  	Characteristics TLSDirectoryCharacteristicsType `json:"characteristics"`
    58  }
    59  
    60  // ImageTLSDirectory64 represents the IMAGE_TLS_DIRECTORY64 structure.
    61  // It Points to the Thread Local Storage initialization section.
    62  type ImageTLSDirectory64 struct {
    63  	// The starting address of the TLS template. The template is a block of data
    64  	// that is used to initialize TLS data.
    65  	StartAddressOfRawData uint64 `json:"start_address_of_raw_data"`
    66  
    67  	// The address of the last byte of the TLS, except for the zero fill. As
    68  	// with the Raw Data Start VA field, this is a VA, not an RVA.
    69  	EndAddressOfRawData uint64 `json:"end_address_of_raw_data"`
    70  
    71  	// The location to receive the TLS index, which the loader assigns. This
    72  	// location is in an ordinary data section, so it can be given a symbolic
    73  	// name that is accessible to the program.
    74  	AddressOfIndex uint64 `json:"address_of_index"`
    75  
    76  	// The pointer to an array of TLS callback functions. The array is
    77  	// null-terminated, so if no callback function is supported, this field
    78  	// points to 4 bytes set to zero.
    79  	AddressOfCallBacks uint64 `json:"address_of_callbacks"`
    80  
    81  	// The size in bytes of the template, beyond the initialized data delimited
    82  	// by the Raw Data Start VA and Raw Data End VA fields. The total template
    83  	// size should be the same as the total size of TLS data in the image file.
    84  	// The zero fill is the amount of data that comes after the initialized
    85  	// nonzero data.
    86  	SizeOfZeroFill uint32 `json:"size_of_zero_fill"`
    87  
    88  	// The four bits [23:20] describe alignment info. Possible values are those
    89  	// defined as IMAGE_SCN_ALIGN_*, which are also used to describe alignment
    90  	// of section in object files. The other 28 bits are reserved for future use.
    91  	Characteristics TLSDirectoryCharacteristicsType `json:"characteristics"`
    92  }
    93  
    94  // TLS provides direct PE and COFF support for static thread local storage (TLS).
    95  // TLS is a special storage class that Windows supports in which a data object
    96  // is not an automatic (stack) variable, yet is local to each individual thread
    97  // that runs the code. Thus, each thread can maintain a different value for a
    98  // variable declared by using TLS.
    99  func (pe *File) parseTLSDirectory(rva, size uint32) error {
   100  
   101  	tls := TLSDirectory{}
   102  
   103  	if pe.Is64 {
   104  		tlsDir := ImageTLSDirectory64{}
   105  		tlsSize := uint32(binary.Size(tlsDir))
   106  		fileOffset := pe.GetOffsetFromRva(rva)
   107  		err := pe.structUnpack(&tlsDir, fileOffset, tlsSize)
   108  		if err != nil {
   109  			return err
   110  		}
   111  		tls.Struct = tlsDir
   112  
   113  		if tlsDir.AddressOfCallBacks != 0 {
   114  			callbacks := make([]uint64, 0)
   115  			rvaAddressOfCallBacks := uint32(tlsDir.AddressOfCallBacks -
   116  				pe.NtHeader.OptionalHeader.(ImageOptionalHeader64).ImageBase)
   117  			offset := pe.GetOffsetFromRva(rvaAddressOfCallBacks)
   118  			for {
   119  				c, err := pe.ReadUint64(offset)
   120  				if err != nil || c == 0 {
   121  					break
   122  				}
   123  				callbacks = append(callbacks, c)
   124  				offset += 8
   125  			}
   126  			tls.Callbacks = callbacks
   127  		}
   128  	} else {
   129  		tlsDir := ImageTLSDirectory32{}
   130  		tlsSize := uint32(binary.Size(tlsDir))
   131  		fileOffset := pe.GetOffsetFromRva(rva)
   132  		err := pe.structUnpack(&tlsDir, fileOffset, tlsSize)
   133  		if err != nil {
   134  			return err
   135  		}
   136  		tls.Struct = tlsDir
   137  
   138  		// 94a9dc17d47b03f6fb01cb639e25503b37761b452e7c07ec6b6c2280635f1df9
   139  		// Callbacks may be empty.
   140  		if tlsDir.AddressOfCallBacks != 0 {
   141  			callbacks := make([]uint32, 0)
   142  			rvaAddressOfCallBacks := tlsDir.AddressOfCallBacks -
   143  				pe.NtHeader.OptionalHeader.(ImageOptionalHeader32).ImageBase
   144  			offset := pe.GetOffsetFromRva(rvaAddressOfCallBacks)
   145  			for {
   146  				c, err := pe.ReadUint32(offset)
   147  				if err != nil || c == 0 {
   148  					break
   149  				}
   150  				callbacks = append(callbacks, c)
   151  				offset += 4
   152  			}
   153  			tls.Callbacks = callbacks
   154  		}
   155  	}
   156  
   157  	pe.TLS = tls
   158  	pe.HasTLS = true
   159  	return nil
   160  }
   161  
   162  // String returns the string representations of the `Characteristics` field of
   163  // TLS directory.
   164  func (characteristics TLSDirectoryCharacteristicsType) String() string {
   165  
   166  	m := map[TLSDirectoryCharacteristicsType]string{
   167  		ImageSectionAlign1Bytes:    "Align 1-Byte",
   168  		ImageSectionAlign2Bytes:    "Align 2-Bytes",
   169  		ImageSectionAlign4Bytes:    "Align 4-Bytes",
   170  		ImageSectionAlign8Bytes:    "Align 8-Bytes",
   171  		ImageSectionAlign16Bytes:   "Align 16-Bytes",
   172  		ImageSectionAlign32Bytes:   "Align 32-Bytes",
   173  		ImageSectionAlign64Bytes:   "Align 64-Bytes",
   174  		ImageSectionAlign128Bytes:  "Align 128-Bytes",
   175  		ImageSectionAlign256Bytes:  "Align 265-Bytes",
   176  		ImageSectionAlign512Bytes:  "Align 512-Bytes",
   177  		ImageSectionAlign1024Bytes: "Align 1024-Bytes",
   178  		ImageSectionAlign2048Bytes: "Align 2048-Bytes",
   179  		ImageSectionAlign4096Bytes: "Align 4096-Bytes",
   180  		ImageSectionAlign8192Bytes: "Align 8192-Bytes",
   181  	}
   182  
   183  	v, ok := m[characteristics]
   184  	if ok {
   185  		return v
   186  	}
   187  
   188  	return "?"
   189  }