75 lines
2.2 KiB
Go
75 lines
2.2 KiB
Go
package disasm
|
|
|
|
import (
|
|
"github.com/andydixon/nexus/internal/leviathan/document"
|
|
"github.com/andydixon/nexus/internal/leviathan/parsers"
|
|
)
|
|
|
|
// ImageAnalysis is a metadata-seeded analysis across file-backed executable
|
|
// regions in an ELF or PE image.
|
|
type ImageAnalysis struct {
|
|
Info *parsers.ExecutableInfo `json:"info"`
|
|
Programs []*Program `json:"programs"`
|
|
Truncated bool `json:"truncated"`
|
|
}
|
|
|
|
// DiscoverExecutable analyzes executable regions using header entries,
|
|
// symbols and exports as roots. Budgets apply across the whole image.
|
|
func DiscoverExecutable(d *document.Document, maxBytes int64, maxFunctions, maxInstr int) (*ImageAnalysis, error) {
|
|
info, err := parsers.InspectExecutable(d)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if maxBytes <= 0 || maxBytes > 32<<20 {
|
|
maxBytes = 8 << 20
|
|
}
|
|
if maxFunctions <= 0 || maxFunctions > 4096 {
|
|
maxFunctions = 512
|
|
}
|
|
if maxInstr <= 0 || maxInstr > 1_000_000 {
|
|
maxInstr = 131_072
|
|
}
|
|
analysis := &ImageAnalysis{Info: info}
|
|
remainingBytes := maxBytes
|
|
remainingFunctions := maxFunctions
|
|
remainingInstr := maxInstr
|
|
for _, region := range info.Regions {
|
|
if remainingBytes <= 0 || remainingFunctions <= 0 || remainingInstr <= 0 {
|
|
analysis.Truncated = true
|
|
break
|
|
}
|
|
length := region.Size
|
|
if length > 4<<20 {
|
|
length = 4 << 20
|
|
analysis.Truncated = true
|
|
}
|
|
if length > remainingBytes {
|
|
length = remainingBytes
|
|
analysis.Truncated = true
|
|
}
|
|
if length <= 0 {
|
|
continue
|
|
}
|
|
buf, err := d.Range(region.Offset, length)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
seeds := make([]Seed, 0)
|
|
for _, seed := range info.Seeds {
|
|
if seed.Offset >= region.Offset && seed.Offset < region.Offset+length {
|
|
seeds = append(seeds, Seed{Name: seed.Name, Entry: seed.Offset})
|
|
}
|
|
}
|
|
if len(seeds) == 0 {
|
|
seeds = append(seeds, Seed{Name: region.Name, Entry: region.Offset})
|
|
}
|
|
program := DiscoverFunctionsFromSeeds(buf, region.Offset, info.Arch, seeds, remainingFunctions, remainingInstr)
|
|
analysis.Programs = append(analysis.Programs, program)
|
|
remainingBytes -= length
|
|
remainingFunctions -= len(program.Functions)
|
|
remainingInstr -= program.Instructions
|
|
analysis.Truncated = analysis.Truncated || program.Truncated
|
|
}
|
|
return analysis, nil
|
|
}
|