├── go.mod ├── Pictures ├── image.png └── image-1.png ├── .gitignore ├── .goreleaser.yml ├── README.md ├── readme_en.md └── EntropyCalc.go /go.mod: -------------------------------------------------------------------------------- 1 | module EntropyCalc 2 | 3 | go 1.21.6 4 | -------------------------------------------------------------------------------- /Pictures/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutianqaq/EntropyCalc_Go/HEAD/Pictures/image.png -------------------------------------------------------------------------------- /Pictures/image-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yutianqaq/EntropyCalc_Go/HEAD/Pictures/image-1.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | dist/ 23 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | 3 | builds: 4 | - binary: EntropyCalc 5 | main: ./EntropyCalc.go 6 | flags: 7 | - -trimpath 8 | ldflags: 9 | - -s -w 10 | goos: 11 | - linux 12 | - windows 13 | - darwin 14 | goarch: 15 | - amd64 16 | - 386 17 | 18 | archives: 19 | - id: tgz 20 | format: tar.gz 21 | format_overrides: 22 | - goos: windows 23 | format: zip 24 | name_template: >- 25 | {{ .ProjectName }}_v{{.Version}}_ 26 | {{- title .Os }}_ 27 | {{- if eq .Arch "amd64" }}x86_64 28 | {{- else if eq .Arch "386" }}i386 29 | {{- else }}{{ .Arch }}{{ end }} 30 | {{- if .Arm }}v{{ .Arm }}{{ end }} 31 | files: 32 | - none* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EntropyCalc_Go 2 | 3 | [English](https://github.com/yutianqaq/EntropyCalc_Go/blob/main/readme_en.md) [简体中文] 4 | 5 | [MalDev Academy](https://maldevacademy.com/) 中 Binary Entropy Reduction 章节的二进制文件熵计算器的 Golang 实现 6 | 7 | 用于计算二进制文件熵值 8 | 9 | 根据 https://practicalsecurityanalytics.com/file-entropy/ 可得知合法软件与恶意软件熵值的分布 10 | 11 | 合法软件熵值为 4.8 - 7.2 之间 12 | 13 | 恶意软件熵值大于 7.2 (用红色标识) 14 | 15 | 可以配合 https://github.com/yutianqaq/Supernova_CN 来加密 Shellcode,降低熵值 16 | 17 | ## 安装 18 | 19 | ## 从源码构建 20 | 21 | ``` 22 | git clone https://github.com/yutianqaq/EntropyCalc_Go 23 | cd EntropyCalc_Go 24 | go build 25 | ``` 26 | 27 | ## 下载二进制版本 28 | 29 | [https://github.com/yutianqaq/EntropyCalc/releases](https://github.com/yutianqaq/EntropyCalc_Go/releases) 30 | 31 | ## 使用方法 32 | 33 | ``` 34 | ./EntropyCalc -file filename 35 | ``` 36 | 37 | 38 | 39 | 恶意软件 40 | 41 | 熵值用红色标识 42 | 43 | ![alt text](Pictures/image.png) 44 | 45 | 合法软件 46 | 47 | 熵值用绿色标识 48 | 49 | ![alt text](Pictures/image-1.png) 50 | 51 | # 参考 52 | - https://practicalsecurityanalytics.com/file-entropy/ 53 | - https://rosettacode.org/wiki/Entropy#Go 54 | - [MalDev Academy](https://maldevacademy.com/) 55 | -------------------------------------------------------------------------------- /readme_en.md: -------------------------------------------------------------------------------- 1 | # EntropyCalc_Go 2 | 3 | [英文] [简体中文](https://github.com/yutianqaq/EntropyCalc_Go) 4 | 5 | Golang Implementation of a Binary File Entropy Calculator, as featured in the Binary Entropy Reduction section of [MalDev Academy](https://maldevacademy.com/). 6 | 7 | It helps gauge file entropy, with legitimate software usually having entropy between 4.8 and 7.2, while malicious software tends to exceed 7.2 (highlighted in red). 8 | 9 | This tool can be used in conjunction with [Supernova_CN](https://github.com/yutianqaq/Supernova_CN) for encrypting shellcode, thereby reducing the entropy. 10 | 11 | ## Installation 12 | 13 | ### Build from Source 14 | 15 | ```bash 16 | git clone https://github.com/yutianqaq/EntropyCalc_Go 17 | cd EntropyCalc_Go 18 | go build 19 | ``` 20 | 21 | 22 | ### Download Binary Version 23 | 24 | [https://github.com/yutianqaq/EntropyCalc/releases](https://github.com/yutianqaq/EntropyCalc_Go/releases) 25 | 26 | ## Usage 27 | 28 | ``` 29 | bash 30 | ./EntropyCalc -file filename 31 | ``` 32 | 33 | Malicious software is identified with red color highlighting in the entropy values. 34 | 35 | ![Malicious Software](Pictures/image.png) 36 | 37 | Legitimate software is identified with green color highlighting in the entropy values. 38 | 39 | ![Legitimate Software](Pictures/image-1.png) 40 | 41 | # References 42 | - https://practicalsecurityanalytics.com/file-entropy/ 43 | - https://rosettacode.org/wiki/Entropy#Go 44 | - [MalDev Academy](https://maldevacademy.com/) 45 | 46 | -------------------------------------------------------------------------------- /EntropyCalc.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "debug/pe" 5 | "flag" 6 | "fmt" 7 | "io" 8 | "log" 9 | "math" 10 | "os" 11 | ) 12 | 13 | func calculateEntropy(buffer []byte) float64 { 14 | l := float64(len(buffer)) 15 | m := map[byte]float64{} 16 | for _, b := range buffer { 17 | m[b]++ 18 | } 19 | 20 | var hm float64 21 | for _, c := range m { 22 | hm += c * math.Log2(c) 23 | } 24 | 25 | return math.Log2(l) - hm/l 26 | } 27 | 28 | func calculateFileEntropy(filename string) { 29 | fileBuffer, err := os.ReadFile(filename) 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | 34 | fileEntropy := calculateEntropy(fileBuffer) 35 | 36 | fmt.Printf("Entropy of \033[36m%s \033[0m as a whole file is: ", filename) 37 | 38 | if fileEntropy >= 5.6 && fileEntropy <= 6.8 { 39 | fmt.Printf("\033[32m%f\033[0m\n", fileEntropy) // Green - legitimate 40 | } else if fileEntropy > 7.2 && fileEntropy <= 8.0 { 41 | fmt.Printf("\033[31m%f\033[0m\n", fileEntropy) // Red - malicious 42 | } else { 43 | fmt.Printf("%f\n", fileEntropy) 44 | } 45 | } 46 | 47 | func calculatePESectionEntropy(filename string) { 48 | file, err := os.Open(filename) 49 | if err != nil { 50 | log.Fatal(err) 51 | } 52 | defer file.Close() 53 | 54 | filePE, err := pe.NewFile(file) 55 | if err != nil { 56 | log.Fatal(err) 57 | } 58 | 59 | calculateFileEntropy(filename) 60 | 61 | fmt.Printf("[i] Parsing \033[36m%s\033[0m 's PE Section Headers ...\n", filename) 62 | 63 | colorIndex := 0 64 | colors := []string{"\033[33m", "\033[32m", "\033[36m", "\033[35m", "\033[34m"} 65 | 66 | for _, section := range filePE.Sections { 67 | sectionName := string(section.Name[:]) 68 | sectionSize := section.Size 69 | 70 | switch sectionName { 71 | case ".text", ".data", ".rdata", ".pdata", ".xdata", ".CRT", ".rsrc", ".reloc": 72 | sectionContent := make([]byte, sectionSize) 73 | _, err := file.Seek(int64(section.Offset), 0) 74 | if err != nil { 75 | log.Fatal(err) 76 | } 77 | _, err = io.ReadFull(file, sectionContent) 78 | if err != nil { 79 | log.Fatal(err) 80 | } 81 | 82 | sectionEntropy := calculateEntropy(sectionContent) 83 | 84 | color := colors[colorIndex] 85 | colorIndex = (colorIndex + 1) % len(colors) 86 | 87 | fmt.Printf("\t>>> %s%s%s Scored Entropy Of Value: %f\033[0m\n", color, "\""+sectionName+"\"", color, sectionEntropy) 88 | } 89 | } 90 | 91 | } 92 | 93 | func main() { 94 | filename := flag.String("file", "", "File to calculate entropy") 95 | flag.Parse() 96 | 97 | if *filename == "" { 98 | flag.Usage() 99 | return 100 | } 101 | 102 | file, err := os.Open(*filename) 103 | if err != nil { 104 | log.Fatal(err) 105 | } 106 | defer file.Close() 107 | 108 | _, err = pe.NewFile(file) 109 | if err == nil { 110 | calculatePESectionEntropy(*filename) 111 | } else { 112 | calculateFileEntropy(*filename) 113 | } 114 | } 115 | --------------------------------------------------------------------------------