Files
ipsw/pkg/kernelcache/kmutil.go

116 lines
3.0 KiB
Go

package kernelcache
import (
"bytes"
"encoding/json"
"fmt"
"regexp"
"strings"
"github.com/apex/log"
"github.com/blacktop/go-macho"
"github.com/blacktop/go-plist"
"github.com/blacktop/ipsw/internal/utils"
"github.com/dominikbraun/graph"
)
func InspectKM(m *macho.File, filter string, explicitOnly, asJSON bool) (string, error) {
if sec := m.Section("__PRELINK_INFO", "__info"); sec != nil {
dat, err := sec.Data()
if err != nil {
return "", fmt.Errorf("failed to read __PRELINK_INFO.__info section: %v", err)
}
var prelink PrelinkInfo
if err := plist.NewDecoder(bytes.NewReader(dat)).Decode(&prelink); err != nil {
return "", fmt.Errorf("failed to decode prelink info: %v", err)
}
if asJSON {
jsonPL, err := json.Marshal(prelink)
if err != nil {
return "", fmt.Errorf("failed to marshal prelink info: %v", err)
}
return string(jsonPL), nil
}
var whitelist []string
if len(filter) == 0 { // NO FILTER (add all bundles to whitelist)
for _, bundle := range prelink.PrelinkInfoDictionary {
if explicitOnly {
whitelist = append(whitelist, fmt.Sprintf("-b %s", bundle.ID))
} else {
whitelist = append(whitelist, bundle.ID)
}
}
} else {
re, err := regexp.Compile(filter)
if err != nil {
return "", fmt.Errorf("failed to compile filter regex: %v", err)
}
var filterlist []string
var blacklist []string
for _, bundle := range prelink.PrelinkInfoDictionary {
if re.MatchString(bundle.ID) {
filterlist = append(filterlist, bundle.ID)
}
}
g := graph.New(graph.StringHash, graph.Directed(), graph.PreventCycles())
// generate dependency graph
for _, bundle := range prelink.PrelinkInfoDictionary {
if len(bundle.OSBundleLibraries) > 0 {
g.AddVertex(bundle.ID)
for dependency := range bundle.OSBundleLibraries {
g.AddVertex(dependency)
if err := g.AddEdge(bundle.ID, dependency); err != nil {
return "", fmt.Errorf("failed to add edge: %v", err)
}
}
}
}
blacklist = append(blacklist, filterlist...)
// blacklist all bundles that dependacy paths contain filtered bundles
for _, skip := range filterlist {
for _, bundle := range prelink.PrelinkInfoDictionary {
path, err := graph.ShortestPath(g, bundle.ID, skip)
if err != nil {
continue
}
if len(path) > 0 {
blacklist = append(blacklist, bundle.ID)
}
}
}
// whitelist all bundles that are not blacklisted
for _, bundle := range prelink.PrelinkInfoDictionary {
if utils.StrSliceContains(blacklist, bundle.ID) {
utils.Indent(log.WithFields(log.Fields{
"bundle": bundle.ID,
}).Info, 2)("Filtered")
continue
}
if explicitOnly {
whitelist = append(whitelist, fmt.Sprintf("-b %s", bundle.ID))
} else {
whitelist = append(whitelist, bundle.ID)
}
}
}
if explicitOnly {
return strings.Join(whitelist, " "), nil
}
return strings.Join(whitelist, "\n"), nil
}
return "", fmt.Errorf("failed to find __PRELINK_INFO.__info section")
}