89 lines
2.1 KiB
Go
89 lines
2.1 KiB
Go
package analysis
|
|
|
|
import (
|
|
"github.com/andydixon/nexus/internal/leviathan/document"
|
|
)
|
|
|
|
// Overview returns a compact first-pass report intended for both UI
|
|
// surfaces. It favours fast, bounded summaries over exhaustive output.
|
|
func Overview(d *document.Document) (map[string]any, error) {
|
|
size := d.Size()
|
|
hashes, err := Hashes(d, 0, -1)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
entropy, err := Entropy(d, 0, min64(size, 8<<20), 4096, 0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
stringsOut, err := ExtractStrings(d, 0, min64(size, 16<<20), 4, []string{"ascii", "utf16le", "utf16be"}, 5000)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
iocs, err := ExtractIOCs(d, 0, min64(size, 16<<20), 5)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
carves, err := Carve(d, 0, min64(size, 64<<20), 128)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return map[string]any{
|
|
"name": d.Name(),
|
|
"size": size,
|
|
"hashes": hashes,
|
|
"entropy": overviewEntropy(entropy),
|
|
"strings": overviewStrings(stringsOut),
|
|
"iocs": iocs["totals"],
|
|
"carve": overviewCarve(carves),
|
|
"limits": map[string]any{
|
|
"entropyBytes": min64(size, 8<<20),
|
|
"stringsBytes": min64(size, 16<<20),
|
|
"iocBytes": min64(size, 16<<20),
|
|
"carveBytes": min64(size, 64<<20),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func overviewEntropy(in map[string]any) map[string]any {
|
|
return map[string]any{
|
|
"windowSize": in["windowSize"],
|
|
"step": in["step"],
|
|
"mean": in["mean"],
|
|
"min": in["min"],
|
|
"max": in["max"],
|
|
"highCount": in["highCount"],
|
|
}
|
|
}
|
|
|
|
func overviewStrings(items []map[string]any) map[string]any {
|
|
counts := map[string]int{}
|
|
for _, item := range items {
|
|
if enc, ok := item["encoding"].(string); ok {
|
|
counts[enc]++
|
|
}
|
|
}
|
|
return map[string]any{
|
|
"total": len(items),
|
|
"byEncoding": counts,
|
|
}
|
|
}
|
|
|
|
func overviewCarve(items []map[string]any) map[string]any {
|
|
counts := map[string]int{}
|
|
valid := 0
|
|
for _, item := range items {
|
|
if kind, ok := item["kind"].(string); ok {
|
|
counts[kind]++
|
|
}
|
|
if status, ok := item["status"].(string); ok && status == "valid" {
|
|
valid++
|
|
}
|
|
}
|
|
return map[string]any{
|
|
"total": len(items),
|
|
"valid": valid,
|
|
"byKind": counts,
|
|
}
|
|
}
|