diff --git a/cmd/dump.go b/cmd/dump.go index d3e1a61..1f91a95 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -14,6 +14,7 @@ import ( "path/filepath" "reflect" "strings" + "sync" "text/tabwriter" "time" "unicode" @@ -23,11 +24,54 @@ import ( "github.com/saferwall/pe/log" ) -func prettyPrint(buff []byte) string { +var ( + wg sync.WaitGroup + jobs chan string = make(chan string) +) + +func loopFilesWorker(cfg config) error { + for path := range jobs { + files, err := os.ReadDir(path) + if err != nil { + wg.Done() + return err + } + + for _, file := range files { + if !file.IsDir() { + fullpath := filepath.Join(path, file.Name()) + parsePE(fullpath, cfg) + } + } + wg.Done() + } + return nil +} + +func LoopDirsFiles(path string) error { + files, err := os.ReadDir(path) + if err != nil { + return err + } + + go func() { + wg.Add(1) + jobs <- path + }() + for _, file := range files { + if file.IsDir() { + LoopDirsFiles(filepath.Join(path, file.Name())) + } + } + return nil +} + +func prettyPrint(iface interface{}) string { var prettyJSON bytes.Buffer - error := json.Indent(&prettyJSON, buff, "", "\t") - if error != nil { - log.Info("JSON parse error: ", error) + buff, _ := json.Marshal(iface) + err := json.Indent(&prettyJSON, buff, "", "\t") + if err != nil { + log.Errorf("JSON parse error: %v", err) return string(buff) } @@ -200,30 +244,12 @@ func parsePE(filename string, cfg config) { } // Dump all results to disk in JSON format. - // b, _ := json.Marshal(pe) // f, err := os.Create("out.json") // if err != nil { // return // } // defer f.Close() - // f.WriteString(prettyPrint(b)) - - // Calculate the PE authentihash. - pe.Authentihash() - - // Calculate the PE checksum. - pe.Checksum() - - // Get file type. - if pe.IsEXE() { - log.Debug("File is Exe") - } - if pe.IsDLL() { - log.Debug("File is DLL") - } - if pe.IsDriver() { - log.Debug("File is Driver") - } + // f.WriteString(prettyPrint(pe)) if cfg.wantDOSHeader { DOSHeader := pe.DOSHeader @@ -500,6 +526,13 @@ func parsePE(filename string, cfg config) { fmt.Printf("\nRESOURCES\n**********\n") printRsrcDir(pe.Resources) + + versionInfo, err := pe.ParseVersionResources() + if err != nil { + log.Errorf("failed to parse version resources: %v", err) + } else { + fmt.Printf("\nVersion Info: %v", prettyPrint(versionInfo)) + } } if cfg.wantException && pe.FileInfo.HasException { @@ -550,6 +583,9 @@ func parsePE(filename string, cfg config) { fmt.Fprintf(w, "Signature Algorithm:\t %s\n", cert.Info.SignatureAlgorithm.String()) fmt.Fprintf(w, "PublicKey Algorithm:\t %s\n", cert.Info.PublicKeyAlgorithm.String()) w.Flush() + + // Calculate the PE authentihash. + pe.Authentihash() } if cfg.wantReloc && pe.FileInfo.HasReloc { @@ -647,7 +683,6 @@ func parsePE(filename string, cfg config) { fpoData.Reserved, fpoData.FrameType, fpoData.FrameType.String()) } } - } } @@ -830,5 +865,19 @@ func parsePE(filename string, cfg config) { } } + // Get file type. + if pe.IsEXE() { + log.Debug("File is Exe") + } + if pe.IsDLL() { + log.Debug("File is DLL") + } + if pe.IsDriver() { + log.Debug("File is Driver") + } + + // Calculate the PE checksum. + pe.Checksum() + fmt.Print("\n") } diff --git a/cmd/main.go b/cmd/main.go index 55cd5f0..4ff7a11 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -8,6 +8,7 @@ import ( "flag" "fmt" "os" + "runtime" ) type config struct { @@ -88,7 +89,20 @@ func main() { wantCLR: *dumpCLR, } - parse(os.Args[2], cfg) + // Start as many workers you want, default to cpu count -1. + numWorkers := runtime.GOMAXPROCS(runtime.NumCPU() - 1) + for w := 1; w <= numWorkers; w++ { + go loopFilesWorker(cfg) + } + + if !isDirectory(os.Args[2]) { + // Input path in a single file. + parsePE(os.Args[2], cfg) + } else { + // Input path in a directory. + LoopDirsFiles(os.Args[2]) + wg.Wait() + } case "version": verCmd.Parse(os.Args[2:]) @@ -109,5 +123,6 @@ func showHelp() { Brought to you by Saferwall (c) 2018 MIT `) fmt.Println("\nAvailable sub-commands 'dump' or 'version' subcommands") + os.Exit(1) }