Add eslogger completion and Go tools
This commit is contained in:
5
tools/go/bincmp/go.mod
Normal file
5
tools/go/bincmp/go.mod
Normal file
@@ -0,0 +1,5 @@
|
||||
module gobincmp
|
||||
|
||||
go 1.24.4
|
||||
|
||||
require github.com/glaslos/ssdeep v0.4.0
|
||||
10
tools/go/bincmp/go.sum
Normal file
10
tools/go/bincmp/go.sum
Normal file
@@ -0,0 +1,10 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/glaslos/ssdeep v0.4.0 h1:w9PtY1HpXbWLYgrL/rvAVkj2ZAMOtDxoGKcBHcUFCLs=
|
||||
github.com/glaslos/ssdeep v0.4.0/go.mod h1:il4NniltMO8eBtU7dqoN+HVJ02gXxbpbUfkcyUvNtG0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
216
tools/go/bincmp/gobincmp.go
Normal file
216
tools/go/bincmp/gobincmp.go
Normal file
@@ -0,0 +1,216 @@
|
||||
// main.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/glaslos/ssdeep"
|
||||
)
|
||||
|
||||
const blockSize = 1024 * 1024
|
||||
|
||||
// main is the entry point of the program.
|
||||
func main() {
|
||||
// 1. Get and validate command-line arguments
|
||||
if len(os.Args) != 3 {
|
||||
usage := `
|
||||
Binwally (Go Version): Binary and Directory tree comparison tool
|
||||
using the Fuzzy Hashing concept (ssdeep)
|
||||
|
||||
Usage: go run . <dir1/file1> <dir2/file2>
|
||||
`
|
||||
fmt.Printf(usage)
|
||||
os.Exit(1)
|
||||
}
|
||||
path1 := os.Args[1]
|
||||
path2 := os.Args[2]
|
||||
|
||||
info1, err1 := os.Stat(path1)
|
||||
if err1 != nil {
|
||||
log.Fatalf("Invalid path: %s", path1)
|
||||
}
|
||||
info2, err2 := os.Stat(path2)
|
||||
if err2 != nil {
|
||||
log.Fatalf("Invalid path: %s", path2)
|
||||
}
|
||||
|
||||
// 2. Route to appropriate comparison logic
|
||||
if info1.IsDir() && info2.IsDir() {
|
||||
// Both are directories
|
||||
var diffs []int
|
||||
fmt.Println("\nSCORE RESULT PATH")
|
||||
compareTrees(path1, path2, &diffs)
|
||||
|
||||
if len(diffs) == 0 {
|
||||
fmt.Println("No diffs found\n")
|
||||
} else {
|
||||
totalScore := 0
|
||||
for _, score := range diffs {
|
||||
totalScore += score
|
||||
}
|
||||
averageScore := totalScore / len(diffs)
|
||||
fmt.Println("\nTotal files compared:", len(diffs))
|
||||
fmt.Printf("Overall match score: %d%%\n\n", averageScore)
|
||||
}
|
||||
} else if !info1.IsDir() && !info2.IsDir() {
|
||||
// Both are files
|
||||
hash1, err := ssdeep.HashFromFile(path1) // CORRECTED
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to hash file %s: %v", path1, err)
|
||||
}
|
||||
hash2, err := ssdeep.HashFromFile(path2) // CORRECTED
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to hash file %s: %v", path2, err)
|
||||
}
|
||||
score, err := ssdeep.Distance(hash1, hash2) // CORRECTED
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to compare hashes: %v", err)
|
||||
}
|
||||
fmt.Printf("Overall match score: %d%%\n\n", score)
|
||||
} else {
|
||||
log.Fatal("Error: Both arguments must be files or both must be directories.")
|
||||
}
|
||||
}
|
||||
|
||||
// compareTrees recursively compares two directory trees.
|
||||
func compareTrees(dir1, dir2 string, diffs *[]int) {
|
||||
// 1. Read contents of both directories
|
||||
entries1, err := os.ReadDir(dir1)
|
||||
if err != nil {
|
||||
log.Printf("Error reading directory %s: %v", dir1, err)
|
||||
return
|
||||
}
|
||||
entries2, err := os.ReadDir(dir2)
|
||||
if err != nil {
|
||||
log.Printf("Error reading directory %s: %v", dir2, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Create maps for quick lookup by name
|
||||
map1 := make(map[string]os.DirEntry)
|
||||
for _, e := range entries1 {
|
||||
map1[e.Name()] = e
|
||||
}
|
||||
map2 := make(map[string]os.DirEntry)
|
||||
for _, e := range entries2 {
|
||||
map2[e.Name()] = e
|
||||
}
|
||||
|
||||
// 2. Find and report unique files/dirs
|
||||
reportUniques(map1, map2, dir1, " <<< unique ", diffs) // In dir1 only
|
||||
reportUniques(map2, map1, dir2, " >>> unique ", diffs) // In dir2 only
|
||||
|
||||
// 3. Process common items
|
||||
for name, e1 := range map1 {
|
||||
if e2, ok := map2[name]; ok {
|
||||
// Name exists in both directories
|
||||
path1 := filepath.Join(dir1, name)
|
||||
path2 := filepath.Join(dir2, name)
|
||||
|
||||
isDir1 := e1.IsDir()
|
||||
isDir2 := e2.IsDir()
|
||||
|
||||
if isDir1 && isDir2 {
|
||||
// Both are directories, recurse
|
||||
compareTrees(path1, path2, diffs)
|
||||
} else if !isDir1 && !isDir2 {
|
||||
// Both are files, compare them
|
||||
compareFiles(path1, path2, diffs)
|
||||
} else {
|
||||
// Mismatched types (file vs dir) or symlinks
|
||||
fmt.Printf(" - ignored %s (symlink or type mismatch)\n", path1)
|
||||
*diffs = append(*diffs, 100) // Original script counts this as 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reportUniques finds items in map1 not in map2 and reports them.
|
||||
func reportUniques(map1, map2 map[string]os.DirEntry, baseDir, prefix string, diffs *[]int) {
|
||||
for name, entry := range map1 {
|
||||
if _, exists := map2[name]; !exists {
|
||||
fullPath := filepath.Join(baseDir, name)
|
||||
if !entry.IsDir() {
|
||||
// It's a unique file
|
||||
fmt.Println(prefix, fullPath)
|
||||
*diffs = append(*diffs, 0)
|
||||
} else {
|
||||
// It's a unique directory, walk it and report all files within
|
||||
filepath.WalkDir(fullPath, func(path string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !d.IsDir() {
|
||||
fmt.Println(prefix, path)
|
||||
*diffs = append(*diffs, 0)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compareFiles compares two files, first byte-by-byte, then with ssdeep if different.
|
||||
func compareFiles(path1, path2 string, diffs *[]int) {
|
||||
f1, err := os.Open(path1)
|
||||
if err != nil {
|
||||
log.Printf("Error opening file %s: %v", path1, err)
|
||||
return
|
||||
}
|
||||
defer f1.Close()
|
||||
|
||||
f2, err := os.Open(path2)
|
||||
if err != nil {
|
||||
log.Printf("Error opening file %s: %v", path2, err)
|
||||
return
|
||||
}
|
||||
defer f2.Close()
|
||||
|
||||
// Compare files chunk by chunk
|
||||
for {
|
||||
b1 := make([]byte, blockSize)
|
||||
_, err1 := f1.Read(b1)
|
||||
|
||||
b2 := make([]byte, blockSize)
|
||||
_, err2 := f2.Read(b2)
|
||||
|
||||
if err1 == io.EOF && err2 == io.EOF {
|
||||
// Files are identical
|
||||
fmt.Printf("%5s matches %s\n", "100", getRelativePath(path1))
|
||||
*diffs = append(*diffs, 100)
|
||||
return
|
||||
}
|
||||
|
||||
if err1 != nil && err1 != io.EOF || err2 != nil && err2 != io.EOF {
|
||||
log.Printf("Error reading from files: %v, %v", err1, err2)
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(b1, b2) {
|
||||
// Files differ, use ssdeep
|
||||
hash1, _ := ssdeep.HashFromFile(path1) // CORRECTED
|
||||
hash2, _ := ssdeep.HashFromFile(path2) // CORRECTED
|
||||
score, _ := ssdeep.Distance(hash1, hash2) // CORRECTED
|
||||
fmt.Printf("%5s differs %s\n", strconv.Itoa(score), getRelativePath(path1))
|
||||
*diffs = append(*diffs, score)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getRelativePath tries to mimic the Python script's path trimming.
|
||||
func getRelativePath(path string) string {
|
||||
parts := strings.Split(filepath.ToSlash(path), "/")
|
||||
if len(parts) > 1 {
|
||||
return strings.Join(parts[1:], "/")
|
||||
}
|
||||
return path
|
||||
}
|
||||
Reference in New Issue
Block a user