github.com/saferwall/pe@v1.5.2/cmd/dump.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 main
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/binary"
    10  	"encoding/hex"
    11  	"encoding/json"
    12  	"fmt"
    13  	"os"
    14  	"path/filepath"
    15  	"reflect"
    16  	"strings"
    17  	"sync"
    18  	"text/tabwriter"
    19  	"time"
    20  	"unicode"
    21  	"unsafe"
    22  
    23  	peparser "github.com/saferwall/pe"
    24  	"github.com/saferwall/pe/log"
    25  )
    26  
    27  var (
    28  	wg   sync.WaitGroup
    29  	jobs chan string = make(chan string)
    30  )
    31  
    32  func loopFilesWorker(cfg config) error {
    33  	for path := range jobs {
    34  		files, err := os.ReadDir(path)
    35  		if err != nil {
    36  			wg.Done()
    37  			return err
    38  		}
    39  
    40  		for _, file := range files {
    41  			if !file.IsDir() {
    42  				fullpath := filepath.Join(path, file.Name())
    43  				parsePE(fullpath, cfg)
    44  			}
    45  		}
    46  		wg.Done()
    47  	}
    48  	return nil
    49  }
    50  
    51  func LoopDirsFiles(path string) error {
    52  	files, err := os.ReadDir(path)
    53  	if err != nil {
    54  		return err
    55  	}
    56  
    57  	go func() {
    58  		wg.Add(1)
    59  		jobs <- path
    60  	}()
    61  	for _, file := range files {
    62  		if file.IsDir() {
    63  			LoopDirsFiles(filepath.Join(path, file.Name()))
    64  		}
    65  	}
    66  	return nil
    67  }
    68  
    69  func prettyPrint(iface interface{}) string {
    70  	var prettyJSON bytes.Buffer
    71  	buff, _ := json.Marshal(iface)
    72  	err := json.Indent(&prettyJSON, buff, "", "\t")
    73  	if err != nil {
    74  		log.Errorf("JSON parse error: %v", err)
    75  		return string(buff)
    76  	}
    77  
    78  	return prettyJSON.String()
    79  }
    80  
    81  func humanizeTimestamp(ts uint32) string {
    82  	unixTimeUTC := time.Unix(int64(ts), 0)
    83  	return unixTimeUTC.String()
    84  }
    85  
    86  func hexDump(b []byte) {
    87  	var a [16]byte
    88  	n := (len(b) + 15) &^ 15
    89  	for i := 0; i < n; i++ {
    90  		if i%16 == 0 {
    91  			fmt.Printf("%4d", i)
    92  		}
    93  		if i%8 == 0 {
    94  			fmt.Print(" ")
    95  		}
    96  		if i < len(b) {
    97  			fmt.Printf(" %02X", b[i])
    98  		} else {
    99  			fmt.Print("   ")
   100  		}
   101  		if i >= len(b) {
   102  			a[i%16] = ' '
   103  		} else if b[i] < 32 || b[i] > 126 {
   104  			a[i%16] = '.'
   105  		} else {
   106  			a[i%16] = b[i]
   107  		}
   108  		if i%16 == 15 {
   109  			fmt.Printf("  %s\n", string(a[:]))
   110  		}
   111  	}
   112  }
   113  
   114  func hexDumpSize(b []byte, size int) {
   115  	var a [16]byte
   116  
   117  	// Append null bytes when length of the buffer
   118  	// is smaller than the requested size.
   119  	if len(b) < size {
   120  		temp := make([]byte, size)
   121  		copy(temp, b)
   122  		b = temp
   123  	}
   124  
   125  	n := (size + 15) &^ 15
   126  	for i := 0; i < n; i++ {
   127  		if i%16 == 0 {
   128  			fmt.Printf("%4d", i)
   129  		}
   130  		if i%8 == 0 {
   131  			fmt.Print(" ")
   132  		}
   133  		if i < len(b) {
   134  			fmt.Printf(" %02X", b[i])
   135  		} else {
   136  			fmt.Print("   ")
   137  		}
   138  		if i >= len(b) {
   139  			a[i%16] = ' '
   140  		} else if b[i] < 32 || b[i] > 126 {
   141  			a[i%16] = '.'
   142  		} else {
   143  			a[i%16] = b[i]
   144  		}
   145  		if i%16 == 15 {
   146  			fmt.Printf("  %s\n", string(a[:]))
   147  		}
   148  	}
   149  }
   150  
   151  func IntToByteArray(num uint64) []byte {
   152  	size := int(unsafe.Sizeof(num))
   153  	arr := make([]byte, size)
   154  	for i := 0; i < size; i++ {
   155  		byt := *(*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(&num)) + uintptr(i)))
   156  		arr[i] = byt
   157  	}
   158  	return arr
   159  }
   160  
   161  func sentenceCase(s string) string {
   162  	newString := string(s[0])
   163  	for i, r := range s[1:] {
   164  		if unicode.IsLower(r) && unicode.IsLetter(r) {
   165  			newString += string(r)
   166  		} else {
   167  			if i < len(s)-2 {
   168  				nextChar := rune(s[i+2])
   169  				previousChar := rune(s[i])
   170  				if unicode.IsLower(previousChar) && unicode.IsLetter(previousChar) {
   171  					newString += " " + string(r)
   172  				} else {
   173  					if unicode.IsLower(nextChar) && unicode.IsLetter(nextChar) {
   174  						newString += " " + string(r)
   175  					} else {
   176  						newString += string(r)
   177  					}
   178  				}
   179  			}
   180  		}
   181  	}
   182  
   183  	return newString
   184  }
   185  
   186  func isDirectory(path string) bool {
   187  	fileInfo, err := os.Stat(path)
   188  	if err != nil {
   189  		return false
   190  	}
   191  	return fileInfo.IsDir()
   192  }
   193  
   194  func parse(filePath string, cfg config) {
   195  
   196  	// filePath points to a file.
   197  	if !isDirectory(filePath) {
   198  		parsePE(filePath, cfg)
   199  
   200  	} else {
   201  		// filePath points to a directory,
   202  		// walk recursively through all files.
   203  		fileList := []string{}
   204  		filepath.Walk(filePath, func(path string, f os.FileInfo, err error) error {
   205  			if !isDirectory(path) {
   206  				fileList = append(fileList, path)
   207  			}
   208  			return nil
   209  		})
   210  
   211  		for _, file := range fileList {
   212  			parsePE(file, cfg)
   213  		}
   214  	}
   215  }
   216  
   217  func parsePE(filename string, cfg config) {
   218  
   219  	logger := log.NewStdLogger(os.Stdout)
   220  	logger = log.NewFilter(logger, log.FilterLevel(log.LevelInfo))
   221  	log := log.NewHelper(logger)
   222  
   223  	log.Infof("parsing filename %s", filename)
   224  
   225  	data, _ := os.ReadFile(filename)
   226  	pe, err := peparser.NewBytes(data, &peparser.Options{
   227  		Logger:                logger,
   228  		DisableCertValidation: false,
   229  		Fast:                  false,
   230  	})
   231  
   232  	if err != nil {
   233  		log.Infof("Error while opening file: %s, reason: %s", filename, err)
   234  		return
   235  	}
   236  	defer pe.Close()
   237  
   238  	err = pe.Parse()
   239  	if err != nil {
   240  		if err != peparser.ErrDOSMagicNotFound {
   241  			log.Infof("Error while parsing file: %s, reason: %s", filename, err)
   242  		}
   243  		return
   244  	}
   245  
   246  	// Dump all results to disk in JSON format.
   247  	// f, err := os.Create("out.json")
   248  	// if err != nil {
   249  	// 	return
   250  	// }
   251  	// defer f.Close()
   252  	// f.WriteString(prettyPrint(pe))
   253  
   254  	if cfg.wantDOSHeader {
   255  		DOSHeader := pe.DOSHeader
   256  		magic := string(IntToByteArray(uint64(DOSHeader.Magic)))
   257  		signature := string(IntToByteArray(uint64(pe.NtHeader.Signature)))
   258  		w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', tabwriter.AlignRight)
   259  		fmt.Print("\n\t------[ DOS Header ]------\n\n")
   260  		fmt.Fprintf(w, "Magic:\t 0x%x (%s)\n", DOSHeader.Magic, magic)
   261  		fmt.Fprintf(w, "Bytes On Last Page Of File:\t 0x%x\n", DOSHeader.BytesOnLastPageOfFile)
   262  		fmt.Fprintf(w, "Pages In File:\t 0x%x\n", DOSHeader.PagesInFile)
   263  		fmt.Fprintf(w, "Relocations:\t 0x%x\n", DOSHeader.Relocations)
   264  		fmt.Fprintf(w, "Size Of Header:\t 0x%x\n", DOSHeader.SizeOfHeader)
   265  		fmt.Fprintf(w, "Min Extra Paragraphs Needed:\t 0x%x\n", DOSHeader.MinExtraParagraphsNeeded)
   266  		fmt.Fprintf(w, "Max Extra Paragraphs Needed:\t 0x%x\n", DOSHeader.MaxExtraParagraphsNeeded)
   267  		fmt.Fprintf(w, "Initial SS:\t 0x%x\n", DOSHeader.InitialSS)
   268  		fmt.Fprintf(w, "Initial SP:\t 0x%x\n", DOSHeader.InitialSP)
   269  		fmt.Fprintf(w, "Checksum:\t 0x%x\n", DOSHeader.Checksum)
   270  		fmt.Fprintf(w, "Initial IP:\t 0x%x\n", DOSHeader.InitialIP)
   271  		fmt.Fprintf(w, "Initial CS:\t 0x%x\n", DOSHeader.InitialCS)
   272  		fmt.Fprintf(w, "Address Of Relocation Table:\t 0x%x\n", DOSHeader.AddressOfRelocationTable)
   273  		fmt.Fprintf(w, "Overlay Number:\t 0x%x\n", DOSHeader.OverlayNumber)
   274  		fmt.Fprintf(w, "OEM Identifier:\t 0x%x\n", DOSHeader.OEMIdentifier)
   275  		fmt.Fprintf(w, "OEM Information:\t 0x%x\n", DOSHeader.OEMInformation)
   276  		fmt.Fprintf(w, "Address Of New EXE Header:\t 0x%x (%s)\n", DOSHeader.AddressOfNewEXEHeader, signature)
   277  		w.Flush()
   278  	}
   279  
   280  	if cfg.wantRichHeader && pe.FileInfo.HasRichHdr {
   281  		richHeader := pe.RichHeader
   282  		fmt.Printf("\nRICH HEADER\n***********\n")
   283  		w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', tabwriter.AlignRight)
   284  		fmt.Fprintf(w, "\t0x%x\t XOR Key\n", richHeader.XORKey)
   285  		fmt.Fprintf(w, "\t0x%x\t DanS offset\n", richHeader.DansOffset)
   286  		fmt.Fprintf(w, "\t0x%x\t Checksum\n\n", pe.RichHeaderChecksum())
   287  		fmt.Fprintln(w, "ProductID\tMinorCV\tCount\tUnmasked\tMeaning\tVSVersion\t")
   288  		for _, compID := range pe.RichHeader.CompIDs {
   289  			fmt.Fprintf(w, "0x%x\t0x%x\t0x%x\t0x%x\t%s\t%s\t\n",
   290  				compID.ProdID, compID.MinorCV, compID.Count, compID.Unmasked,
   291  				peparser.ProdIDtoStr(compID.ProdID), peparser.ProdIDtoVSversion(compID.ProdID))
   292  		}
   293  		w.Flush()
   294  		fmt.Print("\n   ---Raw header dump---\n")
   295  		hexDump(richHeader.Raw)
   296  	}
   297  
   298  	if cfg.wantNTHeader {
   299  		ntHeader := pe.NtHeader.FileHeader
   300  		w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', tabwriter.AlignRight)
   301  		characteristics := strings.Join(ntHeader.Characteristics.String(), " | ")
   302  
   303  		fmt.Print("\n\t------[ File Header ]------\n\n")
   304  		fmt.Fprintf(w, "Machine:\t 0x%x (%s)\n", int(ntHeader.Machine), ntHeader.Machine.String())
   305  		fmt.Fprintf(w, "Number Of Sections:\t 0x%x\n", ntHeader.NumberOfSections)
   306  		fmt.Fprintf(w, "TimeDateStamp:\t 0x%x (%s)\n", ntHeader.TimeDateStamp, humanizeTimestamp(ntHeader.TimeDateStamp))
   307  		fmt.Fprintf(w, "Pointer To Symbol Table:\t 0x%x\n", ntHeader.PointerToSymbolTable)
   308  		fmt.Fprintf(w, "Number Of Symbols:\t 0x%x\n", ntHeader.NumberOfSymbols)
   309  		fmt.Fprintf(w, "Number Of Symbols:\t 0x%x\n", ntHeader.NumberOfSymbols)
   310  		fmt.Fprintf(w, "Size Of Optional Header:\t 0x%x\n", ntHeader.SizeOfOptionalHeader)
   311  		fmt.Fprintf(w, "Characteristics:\t 0x%x (%s)\n", ntHeader.Characteristics, characteristics)
   312  		w.Flush()
   313  
   314  		fmt.Print("\n\t------[ Optional Header ]------\n\n")
   315  		if pe.Is64 {
   316  			oh := pe.NtHeader.OptionalHeader.(peparser.ImageOptionalHeader64)
   317  			dllCharacteristics := strings.Join(oh.DllCharacteristics.String(), " | ")
   318  			fmt.Fprintf(w, "Magic:\t 0x%x (%s)\n", oh.Magic, pe.PrettyOptionalHeaderMagic())
   319  			fmt.Fprintf(w, "Major Linker Version:\t 0x%x\n", oh.MajorLinkerVersion)
   320  			fmt.Fprintf(w, "Minor Linker Version:\t 0x%x\n", oh.MinorLinkerVersion)
   321  			fmt.Fprintf(w, "Size Of Code:\t 0x%x (%s)\n", oh.SizeOfCode, BytesSize(float64(oh.SizeOfCode)))
   322  			fmt.Fprintf(w, "Size Of Initialized Data:\t 0x%x (%s)\n", oh.SizeOfInitializedData,
   323  				BytesSize(float64(oh.SizeOfInitializedData)))
   324  			fmt.Fprintf(w, "Size Of Uninitialized Data:\t 0x%x (%s)\n", oh.SizeOfUninitializedData,
   325  				BytesSize(float64(oh.SizeOfUninitializedData)))
   326  			fmt.Fprintf(w, "Address Of Entry Point:\t 0x%x\n", oh.AddressOfEntryPoint)
   327  			fmt.Fprintf(w, "Base Of Code:\t 0x%x\n", oh.BaseOfCode)
   328  			fmt.Fprintf(w, "Image Base:\t 0x%x\n", oh.ImageBase)
   329  			fmt.Fprintf(w, "Section Alignment:\t 0x%x (%s)\n", oh.SectionAlignment,
   330  				BytesSize(float64(oh.SectionAlignment)))
   331  			fmt.Fprintf(w, "File Alignment:\t 0x%x (%s)\n", oh.FileAlignment,
   332  				BytesSize(float64(oh.FileAlignment)))
   333  			fmt.Fprintf(w, "Major OS Version:\t 0x%x\n", oh.MajorOperatingSystemVersion)
   334  			fmt.Fprintf(w, "Minor OS Version:\t 0x%x\n", oh.MinorOperatingSystemVersion)
   335  			fmt.Fprintf(w, "Major Image Version:\t 0x%x\n", oh.MajorImageVersion)
   336  			fmt.Fprintf(w, "Minor Image Version:\t 0x%x\n", oh.MinorImageVersion)
   337  			fmt.Fprintf(w, "Major Subsystem Version:\t 0x%x\n", oh.MajorSubsystemVersion)
   338  			fmt.Fprintf(w, "Minor Subsystem Version:\t 0x%x\n", oh.MinorSubsystemVersion)
   339  			fmt.Fprintf(w, "Win32 Version Value:\t 0x%x\n", oh.Win32VersionValue)
   340  			fmt.Fprintf(w, "Size Of Image:\t 0x%x (%s)\n", oh.SizeOfImage, BytesSize(float64(oh.SizeOfImage)))
   341  			fmt.Fprintf(w, "Size Of Headers:\t 0x%x (%s)\n", oh.SizeOfHeaders, BytesSize(float64(oh.SizeOfHeaders)))
   342  			fmt.Fprintf(w, "Checksum:\t 0x%x\n", oh.CheckSum)
   343  			fmt.Fprintf(w, "Subsystem:\t 0x%x (%s)\n", uint16(oh.Subsystem), oh.Subsystem.String())
   344  			fmt.Fprintf(w, "Dll Characteristics:\t 0x%x (%s)\n", uint16(oh.DllCharacteristics), dllCharacteristics)
   345  			fmt.Fprintf(w, "Size Of Stack Reserve:\t 0x%x (%s)\n", oh.SizeOfStackReserve, BytesSize(float64(oh.SizeOfStackReserve)))
   346  			fmt.Fprintf(w, "Size Of Stack Commit:\t 0x%x (%s)\n", oh.SizeOfStackCommit, BytesSize(float64(oh.SizeOfStackCommit)))
   347  			fmt.Fprintf(w, "Size Of Heap Reserve:\t 0x%x (%s)\n", oh.SizeOfHeapReserve, BytesSize(float64(oh.SizeOfHeapReserve)))
   348  			fmt.Fprintf(w, "Size Of Heap Commit:\t 0x%x (%s)\n", oh.SizeOfHeapCommit, BytesSize(float64(oh.SizeOfHeapCommit)))
   349  			fmt.Fprintf(w, "Loader Flags:\t 0x%x\n", oh.LoaderFlags)
   350  			fmt.Fprintf(w, "Number Of RVA And Sizes:\t 0x%x\n", oh.NumberOfRvaAndSizes)
   351  			fmt.Fprintf(w, "\n")
   352  			for entry := peparser.ImageDirectoryEntry(0); entry < peparser.ImageNumberOfDirectoryEntries; entry++ {
   353  				rva := oh.DataDirectory[entry].VirtualAddress
   354  				size := oh.DataDirectory[entry].Size
   355  				fmt.Fprintf(w, "%s Table:\t RVA: 0x%0.8x\t Size:0x%0.8x\t\n", entry.String(), rva, size)
   356  			}
   357  		} else {
   358  			oh := pe.NtHeader.OptionalHeader.(peparser.ImageOptionalHeader32)
   359  			dllCharacteristics := strings.Join(oh.DllCharacteristics.String(), " | ")
   360  			fmt.Fprintf(w, "Magic:\t 0x%x (%s)\n", oh.Magic, pe.PrettyOptionalHeaderMagic())
   361  			fmt.Fprintf(w, "Major Linker Version:\t 0x%x\n", oh.MajorLinkerVersion)
   362  			fmt.Fprintf(w, "Minor Linker Version:\t 0x%x\n", oh.MinorLinkerVersion)
   363  			fmt.Fprintf(w, "Size Of Code:\t 0x%x (%s)\n", oh.SizeOfCode, BytesSize(float64(oh.SizeOfCode)))
   364  			fmt.Fprintf(w, "Size Of Initialized Data:\t 0x%x (%s)\n", oh.SizeOfInitializedData,
   365  				BytesSize(float64(oh.SizeOfInitializedData)))
   366  			fmt.Fprintf(w, "Size Of Uninitialized Data:\t 0x%x (%s)\n", oh.SizeOfUninitializedData,
   367  				BytesSize(float64(oh.SizeOfUninitializedData)))
   368  			fmt.Fprintf(w, "Address Of Entry Point:\t 0x%x\n", oh.AddressOfEntryPoint)
   369  			fmt.Fprintf(w, "Base Of Code:\t 0x%x\n", oh.BaseOfCode)
   370  			fmt.Fprintf(w, "Image Base:\t 0x%x\n", oh.ImageBase)
   371  			fmt.Fprintf(w, "Section Alignment:\t 0x%x (%s)\n", oh.SectionAlignment,
   372  				BytesSize(float64(oh.SectionAlignment)))
   373  			fmt.Fprintf(w, "File Alignment:\t 0x%x (%s)\n", oh.FileAlignment,
   374  				BytesSize(float64(oh.FileAlignment)))
   375  			fmt.Fprintf(w, "Major OS Version:\t 0x%x\n", oh.MajorOperatingSystemVersion)
   376  			fmt.Fprintf(w, "Minor OS Version:\t 0x%x\n", oh.MinorOperatingSystemVersion)
   377  			fmt.Fprintf(w, "Major Image Version:\t 0x%x\n", oh.MajorImageVersion)
   378  			fmt.Fprintf(w, "Minor Image Version:\t 0x%x\n", oh.MinorImageVersion)
   379  			fmt.Fprintf(w, "Major Subsystem Version:\t 0x%x\n", oh.MajorSubsystemVersion)
   380  			fmt.Fprintf(w, "Minor Subsystem Version:\t 0x%x\n", oh.MinorSubsystemVersion)
   381  			fmt.Fprintf(w, "Win32 Version Value:\t 0x%x\n", oh.Win32VersionValue)
   382  			fmt.Fprintf(w, "Size Of Image:\t 0x%x (%s)\n", oh.SizeOfImage, BytesSize(float64(oh.SizeOfImage)))
   383  			fmt.Fprintf(w, "Size Of Headers:\t 0x%x (%s)\n", oh.SizeOfHeaders, BytesSize(float64(oh.SizeOfHeaders)))
   384  			fmt.Fprintf(w, "Checksum:\t 0x%x\n", oh.CheckSum)
   385  			fmt.Fprintf(w, "Subsystem:\t 0x%x (%s)\n", uint16(oh.Subsystem), oh.Subsystem.String())
   386  			fmt.Fprintf(w, "Dll Characteristics:\t 0x%x (%s)\n", uint16(oh.DllCharacteristics), dllCharacteristics)
   387  			fmt.Fprintf(w, "Size Of Stack Reserve:\t 0x%x (%s)\n", oh.SizeOfStackReserve, BytesSize(float64(oh.SizeOfStackReserve)))
   388  			fmt.Fprintf(w, "Size Of Stack Commit:\t 0x%x (%s)\n", oh.SizeOfStackCommit, BytesSize(float64(oh.SizeOfStackCommit)))
   389  			fmt.Fprintf(w, "Size Of Heap Reserve:\t 0x%x (%s)\n", oh.SizeOfHeapReserve, BytesSize(float64(oh.SizeOfHeapReserve)))
   390  			fmt.Fprintf(w, "Size Of Heap Commit:\t 0x%x (%s)\n", oh.SizeOfHeapCommit, BytesSize(float64(oh.SizeOfHeapCommit)))
   391  			fmt.Fprintf(w, "Loader Flags:\t 0x%x\n", oh.LoaderFlags)
   392  			fmt.Fprintf(w, "Number Of RVA And Sizes:\t 0x%x\n", oh.NumberOfRvaAndSizes)
   393  			fmt.Fprintf(w, "\n")
   394  			for entry := peparser.ImageDirectoryEntry(0); entry < peparser.ImageNumberOfDirectoryEntries; entry++ {
   395  				rva := oh.DataDirectory[entry].VirtualAddress
   396  				size := oh.DataDirectory[entry].Size
   397  				fmt.Fprintf(w, "%s Table:\t RVA: 0x%0.8x\t Size:0x%0.8x\t\n", entry.String(), rva, size)
   398  			}
   399  		}
   400  		w.Flush()
   401  	}
   402  
   403  	if cfg.wantCOFF && pe.FileInfo.HasCOFF {
   404  		fmt.Printf("\nCOFF\n****\n")
   405  		w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', tabwriter.AlignRight)
   406  		fmt.Fprintln(w, "Name\tValue\tSectionNumber\tType\tStorageClass\tNumberOfAuxSymbols\t")
   407  		for _, sym := range pe.COFF.SymbolTable {
   408  			symName, _ := sym.String(pe)
   409  			fmt.Fprintf(w, "%s\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t\n",
   410  				symName, sym.Value, sym.SectionNumber,
   411  				sym.Type, sym.StorageClass, sym.NumberOfAuxSymbols)
   412  		}
   413  		w.Flush()
   414  	}
   415  
   416  	if cfg.wantSections && pe.FileInfo.HasSections {
   417  		w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', tabwriter.AlignRight)
   418  		for i, sec := range pe.Sections {
   419  			hdr := sec.Header
   420  			fmt.Printf("\n\t------[ Section Header #%d ]------\n\n", i)
   421  			fmt.Fprintf(w, "Name:\t %v (%s)\n", hdr.Name, sec.String())
   422  			fmt.Fprintf(w, "Virtual Size:\t 0x%x (%s)\n", hdr.VirtualSize,
   423  				BytesSize(float64(hdr.VirtualSize)))
   424  			fmt.Fprintf(w, "Virtual Address:\t 0x%x\n", hdr.VirtualAddress)
   425  			fmt.Fprintf(w, "Size Of Raw Data Size:\t 0x%x (%s)\n", hdr.SizeOfRawData,
   426  				BytesSize(float64(hdr.SizeOfRawData)))
   427  			fmt.Fprintf(w, "Pointer To Raw Data:\t 0x%x\n", hdr.PointerToRawData)
   428  			fmt.Fprintf(w, "Pointer To Relocations:\t 0x%x\n", hdr.PointerToRelocations)
   429  			fmt.Fprintf(w, "Pointer To Line Numbers:\t 0x%x\n", hdr.PointerToLineNumbers)
   430  			fmt.Fprintf(w, "Number Of Relocations:\t 0x%x\n", hdr.NumberOfRelocations)
   431  			fmt.Fprintf(w, "Number Of Line Numbers:\t 0x%x\n", hdr.NumberOfLineNumbers)
   432  			fmt.Fprintf(w, "Characteristics:\t 0x%x (%s)\n", hdr.Characteristics,
   433  				strings.Join(sec.PrettySectionFlags(), " | "))
   434  			fmt.Fprintf(w, "Entropy:\t %f\n", sec.CalculateEntropy(pe))
   435  			w.Flush()
   436  
   437  			fmt.Fprintf(w, "\n")
   438  			hexDumpSize(sec.Data(0, hdr.PointerToRawData, pe), 128)
   439  		}
   440  	}
   441  
   442  	if cfg.wantImport && pe.FileInfo.HasImport {
   443  		fmt.Printf("\nIMPORTS\n********\n")
   444  		w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', tabwriter.AlignRight)
   445  		for _, imp := range pe.Imports {
   446  			desc := imp.Descriptor
   447  			fmt.Printf("\n\t------[ %s ]------\n\n", imp.Name)
   448  			fmt.Fprintf(w, "Name:\t 0x%x\n", desc.Name)
   449  			fmt.Fprintf(w, "Original First Thunk:\t 0x%x\n", desc.OriginalFirstThunk)
   450  			fmt.Fprintf(w, "First Thunk:\t 0x%x\n", desc.FirstThunk)
   451  			fmt.Fprintf(w, "TimeDateStamp:\t 0x%x (%s\n", desc.TimeDateStamp,
   452  				humanizeTimestamp(desc.TimeDateStamp))
   453  			fmt.Fprintf(w, "Forwarder Chain:\t 0x%x\n", desc.ForwarderChain)
   454  			fmt.Fprintf(w, "\n")
   455  			fmt.Fprintln(w, "Name\tThunkRVA\tThunkValue\tOriginalThunkRVA\tOriginalThunkValue\tHint\t")
   456  			for _, impFunc := range imp.Functions {
   457  				fmt.Fprintf(w, "%s\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t\n",
   458  					impFunc.Name, impFunc.ThunkRVA, impFunc.ThunkValue,
   459  					impFunc.OriginalThunkRVA, impFunc.OriginalThunkValue, impFunc.Hint)
   460  			}
   461  			w.Flush()
   462  
   463  		}
   464  	}
   465  
   466  	if cfg.wantResource && pe.FileInfo.HasResource {
   467  		var printRsrcDir func(rsrcDir peparser.ResourceDirectory)
   468  		padding := 0
   469  
   470  		printRsrcDataEntry := func(entry peparser.ResourceDataEntry) {
   471  			padding++
   472  			w := tabwriter.NewWriter(os.Stdout, 1, 1, padding, ' ', 0)
   473  			imgRsrcDataEntry := entry.Struct
   474  			fmt.Fprintf(w, "\n\t\u27A1 Resource Data Entry\n\t")
   475  			fmt.Fprintf(w, "|- Offset To Data: 0x%x\n\t", imgRsrcDataEntry.OffsetToData)
   476  			fmt.Fprintf(w, "|- Size: 0x%x\n\t", imgRsrcDataEntry.Size)
   477  			fmt.Fprintf(w, "|- Code Page: 0x%x\n\t", imgRsrcDataEntry.CodePage)
   478  			fmt.Fprintf(w, "|- Reserved: 0x%x\n\t", imgRsrcDataEntry.Reserved)
   479  			fmt.Fprintf(w, "|- Language: %d (%s)\n\t", entry.Lang, entry.Lang.String())
   480  			fmt.Fprintf(w, "|- Sub-language: %s\n\t", peparser.PrettyResourceLang(entry.Lang, int(entry.SubLang)))
   481  			w.Flush()
   482  			padding--
   483  		}
   484  
   485  		printRsrcDir = func(rsrcDir peparser.ResourceDirectory) {
   486  			padding++
   487  			w := tabwriter.NewWriter(os.Stdout, 1, 1, padding, ' ', 0)
   488  			imgRsrcDir := rsrcDir.Struct
   489  			fmt.Fprintf(w, "\n\t\u27A1 Resource Directory\n\t")
   490  			fmt.Fprintf(w, "|- Characteristics: 0x%x\n\t", imgRsrcDir.Characteristics)
   491  			fmt.Fprintf(w, "|- TimeDateStamp: 0x%x\n\t", imgRsrcDir.TimeDateStamp)
   492  			fmt.Fprintf(w, "|- Major Version: 0x%x\n\t", imgRsrcDir.MajorVersion)
   493  			fmt.Fprintf(w, "|- Minor Version: 0x%x\n\t", imgRsrcDir.MinorVersion)
   494  			fmt.Fprintf(w, "|- Number Of Named Entries: 0x%x\n\t", imgRsrcDir.NumberOfNamedEntries)
   495  			fmt.Fprintf(w, "|- Number Of ID Entries: 0x%x\n\t", imgRsrcDir.NumberOfIDEntries)
   496  			fmt.Fprintf(w, "|----------------------------------\n\t")
   497  			padding++
   498  			w.Flush()
   499  			w = tabwriter.NewWriter(os.Stdout, 1, 1, padding, ' ', 0)
   500  			for i, entry := range rsrcDir.Entries {
   501  				fmt.Fprintf(w, "\t|- \u27A1 Resource Directory Entry %d, ID: %d", i+1, entry.ID)
   502  
   503  				// Print the interpretation of a resource ID only in root node.
   504  				if padding == 2 {
   505  					if entry.ID <= peparser.RTManifest {
   506  						fmt.Fprintf(w, " (%s)", peparser.ResourceType(entry.ID).String())
   507  					}
   508  				}
   509  				fmt.Fprintf(w, "\n\t|- Name: 0x%x\n\t", entry.Struct.Name)
   510  				if entry.Name != "" {
   511  					fmt.Fprintf(w, " (%s)", entry.Name)
   512  				}
   513  				fmt.Fprintf(w, "|- Offset To Data: 0x%x\t", entry.Struct.OffsetToData)
   514  				fmt.Fprintf(w, "\n\t|----------------------------------\t")
   515  				w.Flush()
   516  				if entry.IsResourceDir {
   517  					printRsrcDir(entry.Directory)
   518  				} else {
   519  					printRsrcDataEntry(entry.Data)
   520  				}
   521  
   522  			}
   523  			padding -= 2
   524  
   525  		}
   526  
   527  		fmt.Printf("\nRESOURCES\n**********\n")
   528  		printRsrcDir(pe.Resources)
   529  
   530  		versionInfo, err := pe.ParseVersionResources()
   531  		if err != nil {
   532  			log.Errorf("failed to parse version resources: %v", err)
   533  		} else {
   534  			fmt.Printf("\nVersion Info: %v", prettyPrint(versionInfo))
   535  		}
   536  	}
   537  
   538  	if cfg.wantException && pe.FileInfo.HasException {
   539  		fmt.Printf("\nEXCEPTIONS\n***********\n")
   540  		for _, exception := range pe.Exceptions {
   541  			entry := exception.RuntimeFunction
   542  			fmt.Printf("\n\u27A1 BeginAddress: 0x%x EndAddress:0x%x UnwindInfoAddress:0x%x\t\n",
   543  				entry.BeginAddress, entry.EndAddress, entry.UnwindInfoAddress)
   544  
   545  			ui := exception.UnwindInfo
   546  			handlerFlags := peparser.PrettyUnwindInfoHandlerFlags(ui.Flags)
   547  			prettyFlags := strings.Join(handlerFlags, ",")
   548  			fmt.Printf("|- Version: 0x%x\n", ui.Version)
   549  			fmt.Printf("|- Flags: 0x%x", ui.Flags)
   550  			if ui.Flags == 0 {
   551  				fmt.Print(" (None)\n")
   552  			} else {
   553  				fmt.Printf(" (%s)\n", prettyFlags)
   554  			}
   555  
   556  			fmt.Printf("|- Size Of Prolog: 0x%x\n", ui.SizeOfProlog)
   557  			fmt.Printf("|- Count Of Codes: 0x%x\n", ui.CountOfCodes)
   558  			fmt.Printf("|- Exception Handler: 0x%x\n", ui.ExceptionHandler)
   559  			fmt.Print("|- Unwind codes:\n")
   560  			for _, uc := range ui.UnwindCodes {
   561  				fmt.Printf("|-  * %.2x: %s, %s\n", uc.CodeOffset,
   562  					uc.UnwindOp.String(), uc.Operand)
   563  			}
   564  		}
   565  	}
   566  
   567  	if cfg.wantCertificate && pe.FileInfo.HasCertificate {
   568  		fmt.Printf("\nSECURITY\n*********\n")
   569  
   570  		cert := pe.Certificates
   571  		w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', tabwriter.AlignRight)
   572  		fmt.Fprintln(w, "Length\tRevision\tCertificateType\t")
   573  		fmt.Fprintf(w, "0x%x\t0x%x\t0x%x\t\n", cert.Header.Length, cert.Header.Revision,
   574  			cert.Header.CertificateType)
   575  		w.Flush()
   576  		fmt.Print("\n   ---Raw Certificate dump---\n")
   577  		hexDump(cert.Raw)
   578  		fmt.Print("\n---Certificate ---\n\n")
   579  		fmt.Fprintf(w, "Issuer Name:\t %s\n", cert.Info.Issuer)
   580  		fmt.Fprintf(w, "Subject Name:\t %s\n", cert.Info.Subject)
   581  		fmt.Fprintf(w, "Serial Number:\t %x\n", cert.Info.SerialNumber)
   582  		fmt.Fprintf(w, "Validity From:\t %s to %s\n", cert.Info.NotBefore.String(), cert.Info.NotAfter.String())
   583  		fmt.Fprintf(w, "Signature Algorithm:\t %s\n", cert.Info.SignatureAlgorithm.String())
   584  		fmt.Fprintf(w, "PublicKey Algorithm:\t %s\n", cert.Info.PublicKeyAlgorithm.String())
   585  		w.Flush()
   586  
   587  		// Calculate the PE authentihash.
   588  		pe.Authentihash()
   589  	}
   590  
   591  	if cfg.wantReloc && pe.FileInfo.HasReloc {
   592  		fmt.Printf("\nRELOCATIONS\n***********\n")
   593  		for _, reloc := range pe.Relocations {
   594  			fmt.Printf("\n\u27A1 Virtual Address: 0x%x | Size Of Block:0x%x | Entries Count:0x%x\t\n",
   595  				reloc.Data.VirtualAddress, reloc.Data.SizeOfBlock, len(reloc.Entries))
   596  			fmt.Print("|- Entries:\n")
   597  			for _, relocEntry := range reloc.Entries {
   598  				fmt.Printf("|-  Data: 0x%x |  Offset: 0x%x | Type:0x%x (%s)\n", relocEntry.Data,
   599  					relocEntry.Offset, relocEntry.Type, relocEntry.Type.String(pe))
   600  			}
   601  		}
   602  	}
   603  
   604  	if cfg.wantDebug && pe.FileInfo.HasDebug {
   605  		fmt.Printf("\nDEBUGS\n*******\n")
   606  		w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', tabwriter.AlignRight)
   607  		for _, debug := range pe.Debugs {
   608  			imgDbgDir := debug.Struct
   609  			fmt.Fprintf(w, "\n\t------[ %s ]------\n", debug.Type)
   610  			fmt.Fprintf(w, "Characteristics:\t 0x%x\n", imgDbgDir.Characteristics)
   611  			fmt.Fprintf(w, "TimeDateStamp:\t 0x%x (%s)\n", imgDbgDir.TimeDateStamp,
   612  				humanizeTimestamp(imgDbgDir.TimeDateStamp))
   613  			fmt.Fprintf(w, "Major Version:\t 0x%x\n", imgDbgDir.MajorVersion)
   614  			fmt.Fprintf(w, "Minor Version:\t 0x%x\n", imgDbgDir.MinorVersion)
   615  			fmt.Fprintf(w, "Type:\t 0x%x\n", imgDbgDir.Type)
   616  			fmt.Fprintf(w, "Size Of Data:\t 0x%x (%s)\n", imgDbgDir.SizeOfData,
   617  				BytesSize(float64(imgDbgDir.SizeOfData)))
   618  			fmt.Fprintf(w, "Address Of Raw Data:\t 0x%x\n", imgDbgDir.AddressOfRawData)
   619  			fmt.Fprintf(w, "Pointer To Raw Data:\t 0x%x\n", imgDbgDir.PointerToRawData)
   620  			fmt.Fprintf(w, "\n")
   621  			switch imgDbgDir.Type {
   622  			case peparser.ImageDebugTypeCodeView:
   623  				debugSignature, err := pe.ReadUint32(imgDbgDir.PointerToRawData)
   624  				if err != nil {
   625  					continue
   626  				}
   627  				if debugSignature == peparser.CVSignatureRSDS {
   628  					pdb := debug.Info.(peparser.CVInfoPDB70)
   629  					fmt.Fprintf(w, "CV Signature:\t 0x%x (%s)\n", pdb.CVSignature,
   630  						pdb.CVSignature.String())
   631  					fmt.Fprintf(w, "Signature:\t %s\n", pdb.Signature.String())
   632  					fmt.Fprintf(w, "Age:\t 0x%x\n", pdb.Age)
   633  					fmt.Fprintf(w, "PDB FileName:\t %s\n", pdb.PDBFileName)
   634  				} else if debugSignature == peparser.CVSignatureNB10 {
   635  					pdb := debug.Info.(peparser.CVInfoPDB20)
   636  					fmt.Fprintf(w, "CV Header Signature:\t 0x%x (%s)\n",
   637  						pdb.CVHeader.Signature, pdb.CVHeader.Signature.String())
   638  					fmt.Fprintf(w, "CV Header Offset:\t 0x%x\n", pdb.CVHeader.Offset)
   639  					fmt.Fprintf(w, "Signature:\t 0x%x (%s)\n", pdb.Signature,
   640  						humanizeTimestamp(pdb.Signature))
   641  					fmt.Fprintf(w, "Age:\t 0x%x\n", pdb.Age)
   642  					fmt.Fprintf(w, "PDBFileName:\t %s\n", pdb.PDBFileName)
   643  
   644  				}
   645  			case peparser.ImageDebugTypePOGO:
   646  				pogo := debug.Info.(peparser.POGO)
   647  				if len(pogo.Entries) > 0 {
   648  					fmt.Fprintf(w, "Signature:\t 0x%x (%s)\n\n", pogo.Signature,
   649  						pogo.Signature.String())
   650  					fmt.Fprintln(w, "RVA\tSize\tName\tDescription\t")
   651  					fmt.Fprintln(w, "---\t----\t----\t-----------\t")
   652  					for _, pogoEntry := range pogo.Entries {
   653  						fmt.Fprintf(w, "0x%x\t0x%x\t%s\t%s\t\n", pogoEntry.RVA,
   654  							pogoEntry.Size, pogoEntry.Name,
   655  							peparser.SectionAttributeDescription(pogoEntry.Name))
   656  					}
   657  				}
   658  			case peparser.ImageDebugTypeRepro:
   659  				repro := debug.Info.(peparser.REPRO)
   660  				fmt.Fprintf(w, "Hash:\t %x\n", repro.Hash)
   661  				fmt.Fprintf(w, "Size:\t 0x%x (%s)\n", repro.Size, BytesSize(float64(repro.Size)))
   662  			case peparser.ImageDebugTypeExDllCharacteristics:
   663  				exDllCharacteristics := debug.Info.(peparser.DllCharacteristicsExType)
   664  				fmt.Fprintf(w, "Value:\t %d (%s)\n", exDllCharacteristics,
   665  					exDllCharacteristics.String())
   666  			case peparser.ImageDebugTypeVCFeature:
   667  				VCFeature := debug.Info.(peparser.VCFeature)
   668  				fmt.Fprintf(w, "Pre VC11:\t 0x%x\n", VCFeature.PreVC11)
   669  				fmt.Fprintf(w, "C/C++:\t 0x%x\n", VCFeature.CCpp)
   670  				fmt.Fprintf(w, "/GS:\t 0x%x\n", VCFeature.Gs)
   671  				fmt.Fprintf(w, "/sdl:\t 0x%x\n", VCFeature.Sdl)
   672  				fmt.Fprintf(w, "GuardN:\t 0x%x\n", VCFeature.GuardN)
   673  			case peparser.ImageDebugTypeFPO:
   674  				fpo := debug.Info.([]peparser.FPOData)
   675  				if len(fpo) > 0 {
   676  					fmt.Fprintln(w, "OffsetStart\tProcSize\tNumLocals\tParamsSize\tPrologLength\tSavedRegsCount\tHasSEH\tUseBP\tReserved\tFrameType\t")
   677  					fmt.Fprintln(w, "------\t------\t------\t------\t------\t------\t------\t------\t------\t------\t")
   678  					for _, fpoData := range fpo {
   679  						fmt.Fprintf(w, "0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t%d (%s)\t\n",
   680  							fpoData.OffsetStart, fpoData.ProcSize, fpoData.NumLocals,
   681  							fpoData.ParamsSize, fpoData.PrologLength,
   682  							fpoData.SavedRegsCount, fpoData.HasSEH, fpoData.UseBP,
   683  							fpoData.Reserved, fpoData.FrameType, fpoData.FrameType.String())
   684  					}
   685  				}
   686  			}
   687  		}
   688  
   689  		w.Flush()
   690  	}
   691  
   692  	if cfg.wantBoundImp && pe.FileInfo.HasBoundImp {
   693  		fmt.Printf("\nBOUND IMPORTS\n************\n")
   694  
   695  		w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', tabwriter.AlignRight)
   696  		for _, bndImp := range pe.BoundImports {
   697  			fmt.Printf("\n\t------[ %s ]------\n\n", bndImp.Name)
   698  			fmt.Fprintf(w, "TimeDateStamp:\t 0x%x (%s)\n", bndImp.Struct.TimeDateStamp,
   699  				humanizeTimestamp(bndImp.Struct.TimeDateStamp))
   700  			fmt.Fprintf(w, "Offset Module  Name:\t 0x%x\n", bndImp.Struct.OffsetModuleName)
   701  			fmt.Fprintf(w, "# Module Forwarder Refs:\t 0x%x\n", bndImp.Struct.NumberOfModuleForwarderRefs)
   702  			fmt.Fprintf(w, "\n")
   703  			if len(bndImp.ForwardedRefs) > 0 {
   704  				fmt.Fprintln(w, "Name\tTimeDateStamp\tOffsetModuleName\tReserved\t")
   705  				for _, fr := range bndImp.ForwardedRefs {
   706  					fmt.Fprintf(w, "%s\t0x%x\t0x%x\t0x%x\t\n", fr.Name,
   707  						fr.Struct.TimeDateStamp, fr.Struct.OffsetModuleName,
   708  						fr.Struct.Reserved)
   709  				}
   710  			}
   711  			w.Flush()
   712  		}
   713  	}
   714  
   715  	if cfg.wantTLS && pe.FileInfo.HasTLS {
   716  		fmt.Printf("\nTLS\n*****\n\n")
   717  
   718  		tls := pe.TLS
   719  		w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', tabwriter.AlignRight)
   720  		if pe.Is64 {
   721  			imgTLSDirectory64 := tls.Struct.(peparser.ImageTLSDirectory64)
   722  			fmt.Fprintf(w, "Start Address Of Raw Data:\t 0x%x\n", imgTLSDirectory64.StartAddressOfRawData)
   723  			fmt.Fprintf(w, "End Address Of Raw Data:\t 0x%x\n", imgTLSDirectory64.EndAddressOfRawData)
   724  			fmt.Fprintf(w, "Address Of Index:\t %x\n", imgTLSDirectory64.AddressOfIndex)
   725  			fmt.Fprintf(w, "Address Of CallBacks:\t 0x%x\n", imgTLSDirectory64.AddressOfCallBacks)
   726  			fmt.Fprintf(w, "Size Of Zero Fill:\t 0x%x\n", imgTLSDirectory64.SizeOfZeroFill)
   727  			fmt.Fprintf(w, "Characteristics:\t 0x%x (%s)\n", imgTLSDirectory64.Characteristics,
   728  				imgTLSDirectory64.Characteristics.String())
   729  			fmt.Fprintf(w, "Callbacks:\n")
   730  			if len(tls.Callbacks.([]uint64)) > 0 {
   731  				for _, callback := range tls.Callbacks.([]uint64) {
   732  					fmt.Fprintf(w, "0x%x\t\n", callback)
   733  				}
   734  			}
   735  		} else {
   736  			imgTLSDirectory32 := tls.Struct.(peparser.ImageTLSDirectory32)
   737  			fmt.Fprintf(w, "Start Address Of Raw Data:\t 0x%x\n", imgTLSDirectory32.StartAddressOfRawData)
   738  			fmt.Fprintf(w, "End Address Of Raw Data:\t 0x%x\n", imgTLSDirectory32.EndAddressOfRawData)
   739  			fmt.Fprintf(w, "Address Of Index:\t %x\n", imgTLSDirectory32.AddressOfIndex)
   740  			fmt.Fprintf(w, "Address Of CallBacks:\t 0x%x\n", imgTLSDirectory32.AddressOfCallBacks)
   741  			fmt.Fprintf(w, "Size Of Zero Fill:\t 0x%x\n", imgTLSDirectory32.SizeOfZeroFill)
   742  			fmt.Fprintf(w, "Characteristics:\t 0x%x (%s)\n", imgTLSDirectory32.Characteristics,
   743  				imgTLSDirectory32.Characteristics.String())
   744  			fmt.Fprintf(w, "Callbacks:\n")
   745  			if len(tls.Callbacks.([]uint32)) > 0 {
   746  				for _, callback := range tls.Callbacks.([]uint32) {
   747  					fmt.Fprintf(w, "0x%x\t\n", callback)
   748  				}
   749  			}
   750  		}
   751  
   752  		w.Flush()
   753  	}
   754  
   755  	if cfg.wantLoadCfg && pe.FileInfo.HasLoadCFG {
   756  		fmt.Printf("\nLOAD CONFIG\n************\n\n")
   757  
   758  		loadConfig := pe.LoadConfig
   759  		w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', tabwriter.TabIndent)
   760  		v := reflect.ValueOf(loadConfig.Struct)
   761  		typeOfS := v.Type()
   762  		imgLoadConfigDirectorySize := v.Field(0).Interface().(uint32)
   763  		tmp := uint32(0)
   764  		for i := 0; i < v.NumField(); i++ {
   765  			// Do not print the fields of the image load config directory structure
   766  			// that does not belong to it.
   767  			tmp += uint32(binary.Size((v.Field(i).Interface())))
   768  			if tmp > imgLoadConfigDirectorySize {
   769  				break
   770  			}
   771  			fmt.Fprintf(w, "  %s\t : 0x%v\n", sentenceCase(typeOfS.Field(i).Name),
   772  				v.Field(i).Interface())
   773  		}
   774  		w.Flush()
   775  	}
   776  
   777  	if cfg.wantCLR && pe.FileInfo.HasCLR {
   778  		fmt.Printf("\nCLR\n****\n")
   779  
   780  		fmt.Print("\n\t------[ CLR Header ]------\n\n")
   781  		clr := pe.CLR
   782  		w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', tabwriter.AlignRight)
   783  
   784  		clrHdr := clr.CLRHeader
   785  		flags := strings.Join(clrHdr.Flags.String(), " | ")
   786  		fmt.Fprintf(w, "Size Of Header:\t 0x%x\n", clrHdr.Cb)
   787  		fmt.Fprintf(w, "Major Runtime Version:\t 0x%x\n", clrHdr.MajorRuntimeVersion)
   788  		fmt.Fprintf(w, "Minor Runtime Version:\t 0x%x\n", clrHdr.MinorRuntimeVersion)
   789  		fmt.Fprintf(w, "MetaData RVA:\t 0x%x\n", clrHdr.MetaData.VirtualAddress)
   790  		fmt.Fprintf(w, "MetaData Size:\t 0x%x\n", clrHdr.MetaData.Size)
   791  		fmt.Fprintf(w, "Flags:\t 0x%x (%v)\n", clrHdr.Flags, flags)
   792  		fmt.Fprintf(w, "EntryPoint RVA or Token:\t 0x%x\n", clrHdr.EntryPointRVAorToken)
   793  		fmt.Fprintf(w, "Resources RVA:\t 0x%x\n", clrHdr.Resources.VirtualAddress)
   794  		fmt.Fprintf(w, "Resources Size:\t 0x%x (%s)\n", clrHdr.Resources.Size, BytesSize(float64(clrHdr.Resources.Size)))
   795  		fmt.Fprintf(w, "Strong Name Signature RVA:\t 0x%x\n", clrHdr.StrongNameSignature.VirtualAddress)
   796  		fmt.Fprintf(w, "Strong Name Signature Size:\t 0x%x (%s)\n", clrHdr.StrongNameSignature.Size, BytesSize(float64(clrHdr.StrongNameSignature.Size)))
   797  		fmt.Fprintf(w, "Code Manager Table RVA:\t 0x%x\n", clrHdr.CodeManagerTable.VirtualAddress)
   798  		fmt.Fprintf(w, "Code Manager Table Size:\t 0x%x (%s)\n", clrHdr.CodeManagerTable.Size, BytesSize(float64(clrHdr.CodeManagerTable.Size)))
   799  		fmt.Fprintf(w, "VTable Fixups RVA:\t 0x%x\n", clrHdr.VTableFixups.VirtualAddress)
   800  		fmt.Fprintf(w, "VTable Fixups Size:\t 0x%x (%s)\n", clrHdr.VTableFixups.Size, BytesSize(float64(clrHdr.VTableFixups.Size)))
   801  		fmt.Fprintf(w, "Export Address Table Jumps RVA:\t 0x%x\n", clrHdr.ExportAddressTableJumps.VirtualAddress)
   802  		fmt.Fprintf(w, "Export Address Table Jumps Size:\t 0x%x (%s)\n", clrHdr.ExportAddressTableJumps.Size, BytesSize(float64(clrHdr.ExportAddressTableJumps.Size)))
   803  		fmt.Fprintf(w, "Managed Native Header RVA:\t 0x%x\n", clrHdr.ManagedNativeHeader.VirtualAddress)
   804  		fmt.Fprintf(w, "Managed Native Header Size:\t 0x%x (%s)\n", clrHdr.ManagedNativeHeader.Size, BytesSize(float64(clrHdr.ManagedNativeHeader.Size)))
   805  		w.Flush()
   806  
   807  		fmt.Print("\n\t------[ MetaData Header ]------\n\n")
   808  		mdHdr := clr.MetadataHeader
   809  		fmt.Fprintf(w, "Signature:\t 0x%x (%s)\n", mdHdr.Signature,
   810  			string(IntToByteArray(uint64(mdHdr.Signature))))
   811  		fmt.Fprintf(w, "Major Version:\t 0x%x\n", mdHdr.MajorVersion)
   812  		fmt.Fprintf(w, "Minor Version:\t 0x%x\n", mdHdr.MinorVersion)
   813  		fmt.Fprintf(w, "Extra Data:\t 0x%x\n", mdHdr.ExtraData)
   814  		fmt.Fprintf(w, "Version String Length:\t 0x%x\n", mdHdr.VersionString)
   815  		fmt.Fprintf(w, "Version String:\t %s\n", mdHdr.Version)
   816  		fmt.Fprintf(w, "Flags:\t 0x%x\n", mdHdr.Flags)
   817  		fmt.Fprintf(w, "Streams Count:\t 0x%x\n", mdHdr.Streams)
   818  		w.Flush()
   819  
   820  		fmt.Print("\n\t------[ MetaData Streams ]------\n\n")
   821  		for _, sh := range clr.MetadataStreamHeaders {
   822  			fmt.Fprintf(w, "Stream Name:\t %s\n", sh.Name)
   823  			fmt.Fprintf(w, "Offset:\t 0x%x\n", sh.Offset)
   824  			fmt.Fprintf(w, "Size:\t 0x%x (%s)\n", sh.Size, BytesSize(float64(sh.Size)))
   825  			w.Flush()
   826  			fmt.Print("\n   ---Stream Content---\n")
   827  			hexDumpSize(clr.MetadataStreams[sh.Name], 128)
   828  			fmt.Print("\n")
   829  		}
   830  
   831  		fmt.Print("\n\t------[ MetaData Tables Stream Header ]------\n\n")
   832  		mdTablesStreamHdr := clr.MetadataTablesStreamHeader
   833  		fmt.Fprintf(w, "Reserved:\t 0x%x\n", mdTablesStreamHdr.Reserved)
   834  		fmt.Fprintf(w, "Major Version:\t 0x%x\n", mdTablesStreamHdr.MajorVersion)
   835  		fmt.Fprintf(w, "Minor Version:\t 0x%x\n", mdTablesStreamHdr.MinorVersion)
   836  		fmt.Fprintf(w, "Heaps:\t 0x%x\n", mdTablesStreamHdr.Heaps)
   837  		fmt.Fprintf(w, "RID:\t 0x%x\n", mdTablesStreamHdr.RID)
   838  		fmt.Fprintf(w, "MaskValid:\t 0x%x\n", mdTablesStreamHdr.MaskValid)
   839  		fmt.Fprintf(w, "Sorted:\t 0x%x\n", mdTablesStreamHdr.Sorted)
   840  		w.Flush()
   841  
   842  		fmt.Print("\n\t------[ MetaData Tables ]------\n\n")
   843  		mdTables := clr.MetadataTables
   844  		for _, mdTable := range mdTables {
   845  			fmt.Fprintf(w, "Name:\t %s | Items Count:\t 0x%x\n", mdTable.Name, mdTable.CountCols)
   846  		}
   847  		w.Flush()
   848  
   849  		for table, modTable := range pe.CLR.MetadataTables {
   850  			switch table {
   851  			case peparser.Module:
   852  				fmt.Print("\n\t[Modules]\n\t---------\n")
   853  				modTableRow := modTable.Content.(peparser.ModuleTableRow)
   854  				modName := pe.GetStringFromData(modTableRow.Name, pe.CLR.MetadataStreams["#Strings"])
   855  				Mvid := pe.GetStringFromData(modTableRow.Mvid, pe.CLR.MetadataStreams["#GUID"])
   856  				MvidStr := hex.EncodeToString(Mvid)
   857  				fmt.Fprintf(w, "Generation:\t 0x%x\n", modTableRow.Generation)
   858  				fmt.Fprintf(w, "Name:\t 0x%x (%s)\n", modTableRow.Name, string(modName))
   859  				fmt.Fprintf(w, "Mvid:\t 0x%x (%s)\n", modTableRow.Mvid, MvidStr)
   860  				fmt.Fprintf(w, "EncID:\t 0x%x\n", modTableRow.EncID)
   861  				fmt.Fprintf(w, "EncBaseID:\t 0x%x\n", modTableRow.EncBaseID)
   862  				w.Flush()
   863  
   864  			}
   865  		}
   866  	}
   867  
   868  	// Get file type.
   869  	if pe.IsEXE() {
   870  		log.Debug("File is Exe")
   871  	}
   872  	if pe.IsDLL() {
   873  		log.Debug("File is DLL")
   874  	}
   875  	if pe.IsDriver() {
   876  		log.Debug("File is Driver")
   877  	}
   878  
   879  	// Calculate the PE checksum.
   880  	pe.Checksum()
   881  
   882  	fmt.Print("\n")
   883  }