mirror of
https://github.com/blacktop/ipsw.git
synced 2026-05-08 12:22:26 +00:00
207 lines
7.9 KiB
Go
207 lines
7.9 KiB
Go
package kernelcache
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"sort"
|
|
|
|
"github.com/apex/log"
|
|
"github.com/blacktop/go-macho"
|
|
"github.com/blacktop/go-macho/pkg/fixupchains"
|
|
"github.com/blacktop/go-plist"
|
|
)
|
|
|
|
const tagPtrMask = 0xffff000000000000
|
|
|
|
type PrelinkInfo struct {
|
|
PrelinkInfoDictionary []CFBundle `plist:"_PrelinkInfoDictionary,omitempty" json:"prelink_info_dictionary,omitempty"`
|
|
}
|
|
|
|
type CFBundle struct {
|
|
ID string `plist:"CFBundleIdentifier,omitempty" json:"id,omitempty"`
|
|
Name string `plist:"CFBundleName,omitempty" json:"name,omitempty"`
|
|
|
|
SDK string `plist:"DTSDKName,omitempty" json:"sdk,omitempty"`
|
|
SDKBuild string `plist:"DTSDKBuild,omitempty" json:"sdk_build,omitempty"`
|
|
Xcode string `plist:"DTXcode,omitempty" json:"xcode,omitempty"`
|
|
XcodeBuild string `plist:"DTXcodeBuild,omitempty" json:"xcode_build,omitempty"`
|
|
Copyright string `plist:"NSHumanReadableCopyright,omitempty" json:"copyright,omitempty"`
|
|
BuildMachineOSBuild string `plist:"BuildMachineOSBuild,omitempty" json:"build_machine_os_build,omitempty"`
|
|
DevelopmentRegion string `plist:"CFBundleDevelopmentRegion,omitempty" json:"development_region,omitempty"`
|
|
PlatformName string `plist:"DTPlatformName,omitempty" json:"platform_name,omitempty"`
|
|
PlatformVersion string `plist:"DTPlatformVersion,omitempty" json:"platform_version,omitempty"`
|
|
PlatformBuild string `plist:"DTPlatformBuild,omitempty" json:"platform_build,omitempty"`
|
|
PackageType string `plist:"CFBundlePackageType,omitempty" json:"package_type,omitempty"`
|
|
Version string `plist:"CFBundleVersion,omitempty" json:"version,omitempty"`
|
|
ShortVersionString string `plist:"CFBundleShortVersionString,omitempty" json:"short_version_string,omitempty"`
|
|
CompatibleVersion string `plist:"OSBundleCompatibleVersion,omitempty" json:"compatible_version,omitempty"`
|
|
MinimumOSVersion string `plist:"MinimumOSVersion,omitempty" json:"minimum_os_version,omitempty"`
|
|
SupportedPlatforms []string `plist:"CFBundleSupportedPlatforms,omitempty" json:"supported_platforms,omitempty"`
|
|
Signature string `plist:"CFBundleSignature,omitempty" json:"signature,omitempty"`
|
|
|
|
IOKitPersonalities map[string]interface{} `plist:"IOKitPersonalities,omitempty" json:"io_kit_personalities,omitempty"`
|
|
OSBundleLibraries map[string]string `plist:"OSBundleLibraries,omitempty" json:"os_bundle_libraries,omitempty"`
|
|
UIDeviceFamily []int `plist:"UIDeviceFamily,omitempty" json:"ui_device_family,omitempty"`
|
|
|
|
OSBundleRequired string `plist:"OSBundleRequired,omitempty" json:"os_bundle_required,omitempty"`
|
|
UIRequiredDeviceCapabilities []string `plist:"UIRequiredDeviceCapabilities,omitempty" json:"ui_required_device_capabilities,omitempty"`
|
|
|
|
AppleSecurityExtension bool `plist:"AppleSecurityExtension,omitempty" json:"apple_security_extension,omitempty"`
|
|
|
|
InfoDictionaryVersion string `plist:"CFBundleInfoDictionaryVersion,omitempty" json:"info_dictionary_version,omitempty"`
|
|
OSKernelResource bool `plist:"OSKernelResource,omitempty" json:"os_kernel_resource,omitempty"`
|
|
GetInfoString string `plist:"CFBundleGetInfoString,omitempty" json:"get_info_string,omitempty"`
|
|
AllowUserLoad bool `plist:"OSBundleAllowUserLoad,omitempty" json:"allow_user_load,omitempty"`
|
|
ExecutableLoadAddr uint64 `plist:"_PrelinkExecutableLoadAddr,omitempty" json:"executable_load_addr,omitempty"`
|
|
|
|
ModuleIndex uint64 `plist:"ModuleIndex,omitempty" json:"module_index,omitempty"`
|
|
Executable string `plist:"CFBundleExecutable,omitempty" json:"executable,omitempty"`
|
|
BundlePath string `plist:"_PrelinkBundlePath,omitempty" json:"bundle_path,omitempty"`
|
|
RelativePath string `plist:"_PrelinkExecutableRelativePath,omitempty" json:"relative_path,omitempty"`
|
|
}
|
|
|
|
type KmodInfoT struct {
|
|
NextAddr uint64
|
|
InfoVersion int32
|
|
ID uint32
|
|
Name [64]byte
|
|
Version [64]byte
|
|
ReferenceCount int32 // # linkage refs to this
|
|
ReferenceListAddr uint64 // who this refs (links on)
|
|
Address uint64 // starting address
|
|
Size uint64 // total size
|
|
HeaderSize uint64 // unwired hdr size
|
|
StartAddr uint64
|
|
StopAddr uint64
|
|
}
|
|
|
|
func (i KmodInfoT) String() string {
|
|
return fmt.Sprintf("id: %#x, name: %s, version: %s, ref_cnt: %d, ref_list: %#x, addr: %#x, size: %#x, header_size: %#x, start: %#x, stop: %#x, next: %#x, info_ver: %d",
|
|
i.ID,
|
|
string(i.Name[:]),
|
|
string(i.Version[:]),
|
|
i.ReferenceCount,
|
|
i.ReferenceListAddr,
|
|
i.Address,
|
|
i.Size,
|
|
i.HeaderSize,
|
|
i.StartAddr,
|
|
i.StopAddr,
|
|
i.NextAddr,
|
|
i.InfoVersion,
|
|
)
|
|
}
|
|
|
|
func GetKextStartVMAddrs(m *macho.File) ([]uint64, error) {
|
|
if kmodStart := m.Section("__PRELINK_INFO", "__kmod_start"); kmodStart != nil {
|
|
data, err := kmodStart.Data()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ptrs := make([]uint64, kmodStart.Size/8)
|
|
if err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &ptrs); err != nil {
|
|
return nil, err
|
|
}
|
|
return ptrs, nil
|
|
}
|
|
return nil, fmt.Errorf("section __PRELINK_INFO.__kmod_start not found")
|
|
}
|
|
|
|
func GetKextInfos(m *macho.File) ([]KmodInfoT, error) {
|
|
var infos []KmodInfoT
|
|
if kmodStart := m.Section("__PRELINK_INFO", "__kmod_info"); kmodStart != nil {
|
|
data, err := kmodStart.Data()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ptrs := make([]uint64, kmodStart.Size/8)
|
|
if err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &ptrs); err != nil {
|
|
return nil, err
|
|
}
|
|
for _, ptr := range ptrs {
|
|
// fmt.Printf("ptr: %#x, untagged: %#x\n", ptr, unTag(ptr))
|
|
off, err := m.GetOffset(ptr | tagPtrMask)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
info := KmodInfoT{}
|
|
infoBytes := make([]byte, binary.Size(info))
|
|
_, err = m.ReadAt(infoBytes, int64(off))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := binary.Read(bytes.NewReader(infoBytes), binary.LittleEndian, &info); err != nil {
|
|
return nil, fmt.Errorf("failed to read KmodInfoT at %#x: %v", off, err)
|
|
}
|
|
|
|
// fixups
|
|
info.StartAddr = fixupchains.DyldChainedPtr64KernelCacheRebase{Pointer: info.StartAddr}.Target() + m.GetBaseAddress()
|
|
info.StopAddr = fixupchains.DyldChainedPtr64KernelCacheRebase{Pointer: info.StopAddr}.Target() + m.GetBaseAddress()
|
|
|
|
infos = append(infos, info)
|
|
}
|
|
return infos, nil
|
|
}
|
|
return nil, fmt.Errorf("section __PRELINK_INFO.__kmod_start not found")
|
|
}
|
|
|
|
func GetKexts(kernel *macho.File) ([]CFBundle, error) {
|
|
if infoSec := kernel.Section("__PRELINK_INFO", "__info"); infoSec != nil {
|
|
|
|
data, err := infoSec.Data()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read __PRELINK_INFO.__info section: %v", err)
|
|
}
|
|
|
|
var prelink PrelinkInfo
|
|
decoder := plist.NewDecoder(bytes.NewReader(bytes.Trim([]byte(data), "\x00")))
|
|
err = decoder.Decode(&prelink)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decode __PRELINK_INFO.__info section: %v", err)
|
|
}
|
|
return prelink.PrelinkInfoDictionary, nil
|
|
}
|
|
return nil, fmt.Errorf("section __PRELINK_INFO.__info not found")
|
|
}
|
|
|
|
// KextList lists all the kernel extensions in the kernelcache
|
|
func KextList(kernelPath string, diffable bool) ([]string, error) {
|
|
var out []string
|
|
|
|
m, err := macho.Open(kernelPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer m.Close()
|
|
|
|
bundles, err := GetKexts(m)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
kextStartAdddrs, err := GetKextStartVMAddrs(m)
|
|
if err != nil {
|
|
log.Debugf("failed to get kext start addresses: %v", err)
|
|
}
|
|
|
|
if diffable {
|
|
for _, bundle := range bundles {
|
|
out = append(out, fmt.Sprintf("%s (%s)", bundle.ID, bundle.Version))
|
|
}
|
|
} else {
|
|
for _, bundle := range bundles {
|
|
if !bundle.OSKernelResource && len(kextStartAdddrs) > 0 {
|
|
out = append(out, fmt.Sprintf("%#x: %s (%s)", kextStartAdddrs[bundle.ModuleIndex]|tagPtrMask, bundle.ID, bundle.Version))
|
|
} else {
|
|
out = append(out, fmt.Sprintf("%#x: %s (%s)", bundle.ExecutableLoadAddr, bundle.ID, bundle.Version))
|
|
}
|
|
}
|
|
}
|
|
|
|
sort.Strings(out)
|
|
|
|
return out, nil
|
|
}
|