Skip to content

Commit

Permalink
fix: exclavecore bundle file extraction
Browse files Browse the repository at this point in the history
  • Loading branch information
blacktop committed May 28, 2024
1 parent ac0daad commit 82fa323
Show file tree
Hide file tree
Showing 8 changed files with 269 additions and 160 deletions.
22 changes: 16 additions & 6 deletions cmd/ipsw/cmd/fw/aop.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"path/filepath"

"github.com/apex/log"
"github.com/blacktop/go-macho"
"github.com/blacktop/ipsw/internal/magic"
"github.com/blacktop/ipsw/pkg/bundle"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand Down Expand Up @@ -63,13 +65,21 @@ var aopCmd = &cobra.Command{
showInfo := viper.GetBool("fw.aop.info")
// output := viper.GetString("fw.aop.output")

bn, err := bundle.Parse(filepath.Clean(args[0]))
if err != nil {
return err
}

if showInfo {
fmt.Println(bn)
if ok, _ := magic.IsMachO(args[0]); ok { /* MachO binary */
m, err := macho.Open(filepath.Clean(args[0]))
if err != nil {
return fmt.Errorf("failed to parse MachO file: %v", err)
}
defer m.Close()
fmt.Println(m.FileTOC.String())
} else {
bn, err := bundle.Parse(filepath.Clean(args[0]))
if err != nil {
return err
}
fmt.Println(bn)
}
} else {
panic("not implemented")
}
Expand Down
22 changes: 16 additions & 6 deletions cmd/ipsw/cmd/fw/dcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"path/filepath"

"github.com/apex/log"
"github.com/blacktop/go-macho"
"github.com/blacktop/ipsw/internal/magic"
"github.com/blacktop/ipsw/pkg/bundle"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand Down Expand Up @@ -61,13 +63,21 @@ var dcpCmd = &cobra.Command{
showInfo := viper.GetBool("fw.dcp.info")
// output := viper.GetString("fw.dcp.output")

bn, err := bundle.Parse(filepath.Clean(args[0]))
if err != nil {
return err
}

if showInfo {
fmt.Println(bn)
if ok, _ := magic.IsMachO(args[0]); ok { /* MachO binary */
m, err := macho.Open(filepath.Clean(args[0]))
if err != nil {
return fmt.Errorf("failed to parse MachO file: %v", err)
}
defer m.Close()
fmt.Println(m.FileTOC.String())
} else {
bn, err := bundle.Parse(filepath.Clean(args[0]))
if err != nil {
return err
}
fmt.Println(bn)
}
} else {
panic("not implemented")
}
Expand Down
48 changes: 18 additions & 30 deletions cmd/ipsw/cmd/fw/exc.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ package fw

import (
"fmt"
"io"
"os"
"path/filepath"

"github.com/apex/log"
fwcmd "github.com/blacktop/ipsw/internal/commands/fw"
"github.com/blacktop/ipsw/internal/utils"
"github.com/blacktop/ipsw/pkg/bundle"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand All @@ -51,8 +51,9 @@ var excCmd = &cobra.Command{
Use: "exclave",
Aliases: []string{"exc"},
Short: "🚧 Dump MachOs",
Args: cobra.ExactArgs(1),
Hidden: true,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(cmd *cobra.Command, args []string) (err error) {

if viper.GetBool("verbose") {
log.SetLevel(log.DebugLevel)
Expand All @@ -62,38 +63,25 @@ var excCmd = &cobra.Command{
showInfo := viper.GetBool("fw.exclave.info")
output := viper.GetString("fw.exclave.output")

bn, err := bundle.Parse(filepath.Clean(args[0]))
if err != nil {
return err
}

if showInfo {
fmt.Println(bn)
} else {
f, err := os.Open(filepath.Clean(args[0]))
bn, err := bundle.Parse(filepath.Clean(args[0]))
if err != nil {
return fmt.Errorf("failed to open file %s: %v", filepath.Clean(args[0]), err)
return fmt.Errorf("failed to parse bundle: %v", err)
}
defer f.Close()

for _, bf := range bn.Files {
fmt.Println(bf)

fname := filepath.Join(output, bf.Type, bf.Name)
if err := os.MkdirAll(filepath.Dir(fname), 0o750); err != nil {
return fmt.Errorf("failed to create directory %s: %v", filepath.Dir(fname), err)
}

of, err := os.Create(fname)
if err != nil {
return fmt.Errorf("failed to create file %s: %v", fname, err)
}
defer of.Close()
if bn.Type != 3 {
return fmt.Errorf("bundle is not an exclave bundle")
}

for _, seg := range bf.Segments {
f.Seek(int64(seg.Offset), io.SeekStart)
io.CopyN(of, f, int64(seg.Size))
}
fmt.Println(bn)
} else {
log.Info("Extracting Exclave Bundle")
out, err := fwcmd.Extract(filepath.Clean(args[0]), output)
if err != nil {
return fmt.Errorf("failed to extract files from exclave bundle: %v", err)
}
for _, f := range out {
utils.Indent(log.Info, 2)("Created " + f)
}
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/aymanbagabas/go-udiff v0.2.0
github.com/blacktop/arm64-cgo v1.0.57
github.com/blacktop/go-dwarf v1.0.10
github.com/blacktop/go-macho v1.1.212
github.com/blacktop/go-macho v1.1.213
github.com/blacktop/go-plist v1.0.2
github.com/blacktop/lzfse-cgo v1.1.19
github.com/blacktop/lzss v0.1.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ github.com/blacktop/cast v1.5.1 h1:gwXxBZ2XlcNnU57Ws+pTDFYHKKtLdxwBqvUI2wS31wg=
github.com/blacktop/cast v1.5.1/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/blacktop/go-dwarf v1.0.10 h1:i9zYgcIROETsNZ6V+zZn3uDH21FCG5BLLZ837GitxS0=
github.com/blacktop/go-dwarf v1.0.10/go.mod h1:4W2FKgSFYcZLDwnR7k+apv5i3nrau4NGl9N6VQ9DSTo=
github.com/blacktop/go-macho v1.1.212 h1:zjH7MiZcjBXB5LT5gyCohacABY3llnxxIQ6830/i8XU=
github.com/blacktop/go-macho v1.1.212/go.mod h1:dtlW2AJKQpFzImBVPWiUKZ6OxrQ2MLfWi/BPPe0EONE=
github.com/blacktop/go-macho v1.1.213 h1:63gQpzIWJzJ7gMJz+1IuAn++udVQTEZsyLjFYF/Tp+M=
github.com/blacktop/go-macho v1.1.213/go.mod h1:dtlW2AJKQpFzImBVPWiUKZ6OxrQ2MLfWi/BPPe0EONE=
github.com/blacktop/go-plist v1.0.2 h1:DMX8uBiE308HWZkO9o37j7Z2b0neI3GSzN2caNa2zXk=
github.com/blacktop/go-plist v1.0.2/go.mod h1:fqVhCVVXVJWsIGY9QPgdK0mDWZD82HrRMfU5PanvdTA=
github.com/blacktop/lzfse-cgo v1.1.19 h1:1I/1y9/sjyDLomACLrR4f7GFJ1fTaIjhWb1PQrEtKiw=
Expand Down
36 changes: 4 additions & 32 deletions internal/commands/extract/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/url"
"os"
"path/filepath"
Expand All @@ -16,9 +15,9 @@ import (

"github.com/blacktop/go-macho"
"github.com/blacktop/go-plist"
fwcmd "github.com/blacktop/ipsw/internal/commands/fw"
"github.com/blacktop/ipsw/internal/download"
"github.com/blacktop/ipsw/internal/utils"
"github.com/blacktop/ipsw/pkg/bundle"
"github.com/blacktop/ipsw/pkg/dyld"
"github.com/blacktop/ipsw/pkg/img4"
"github.com/blacktop/ipsw/pkg/info"
Expand Down Expand Up @@ -284,38 +283,11 @@ func Exclave(c *Config) ([]string, error) {
}

for _, exc := range outfiles {
bn, err := bundle.Parse(exc)
out, err := fwcmd.Extract(exc, filepath.Dir(exc))
if err != nil {
return nil, fmt.Errorf("failed to parse exclave bundle: %v", err)
}

f, err := os.Open(exc)
if err != nil {
return nil, fmt.Errorf("failed to open file %s: %v", exc, err)
}
defer f.Close()

for _, bf := range bn.Files {
fmt.Println(bf)

fname := filepath.Join(filepath.Dir(exc), bf.Type, bf.Name)
if err := os.MkdirAll(filepath.Dir(fname), 0o750); err != nil {
return nil, fmt.Errorf("failed to create directory %s: %v", filepath.Dir(fname), err)
}

of, err := os.Create(fname)
if err != nil {
return nil, fmt.Errorf("failed to create file %s: %v", fname, err)
}
defer of.Close()

for _, seg := range bf.Segments {
f.Seek(int64(seg.Offset), io.SeekStart)
io.CopyN(of, f, int64(seg.Size))
}

outfiles = append(outfiles, fname)
return nil, fmt.Errorf("failed to extract files from exclave bundle: %v", err)
}
outfiles = append(outfiles, out...)
}

return outfiles, nil
Expand Down
113 changes: 113 additions & 0 deletions internal/commands/fw/exclave.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package fw

import (
"bytes"
"encoding/binary"
"fmt"
"io"
"os"
"path/filepath"

"github.com/blacktop/go-macho"
"github.com/blacktop/go-macho/types"
"github.com/blacktop/ipsw/pkg/bundle"
)

func Extract(input, output string) ([]string, error) {
var m *macho.File
var outfiles []string

bn, err := bundle.Parse(input)
if err != nil {
return nil, fmt.Errorf("failed to parse bundle: %v", err)
}

if bn.Type != 3 {
return nil, fmt.Errorf("bundle is not an exclave bundle")
}

f, err := os.Open(input)
if err != nil {
return nil, fmt.Errorf("failed to open file %s: %v", input, err)
}
defer f.Close()

for idx, bf := range bn.Files {
fname := filepath.Join(output, bf.Type, bf.Name)
if err := os.MkdirAll(filepath.Dir(fname), 0o750); err != nil {
return nil, fmt.Errorf("failed to create directory %s: %v", filepath.Dir(fname), err)
}

of, err := os.Create(fname)
if err != nil {
return nil, fmt.Errorf("failed to create file %s: %v", fname, err)
}
defer of.Close()

if len(bf.Segments) == 0 { // FIXME: should this be removed?
continue
}

// Get MachO header
if entry := bn.Config.TOC[idx].GetEntry(); entry != nil && entry.Type == 2 { // kernel (SYSTEM)
if _, err := f.Seek(int64(bn.Config.Assets[idx].Offset), io.SeekStart); err != nil {
return nil, fmt.Errorf("failed to seek to offset %d: %v", bn.Config.Assets[idx].Offset, err)
}
mHdrData := make([]byte, bn.Config.Assets[idx].Size) // __MACHOHEADERLC
if err := binary.Read(f, binary.LittleEndian, &mHdrData); err != nil {
return nil, fmt.Errorf("failed to read data from file %s: %v", fname, err)
}
m, err = macho.NewFile(bytes.NewReader(mHdrData), macho.FileConfig{
LoadIncluding: []types.LoadCmd{types.LC_SEGMENT_64},
})
if err != nil {
return nil, fmt.Errorf("failed to parse MachO file: %v", err)
}
defer m.Close()
// write MACHOHEADERLC to output file
if _, err := of.Write(mHdrData); err != nil {
return nil, fmt.Errorf("failed to write data to file %s: %v", fname, err)
}
} else {
if text := bf.Segment("TEXT"); text == nil {
return nil, fmt.Errorf("failed to find TEXT segment")
} else {
if _, err := f.Seek(int64(text.Offset), io.SeekStart); err != nil {
return nil, fmt.Errorf("failed to seek to offset %d: %v", text.Offset, err)
}
tdata := make([]byte, text.Size)
if err := binary.Read(f, binary.LittleEndian, &tdata); err != nil {
return nil, fmt.Errorf("failed to read data from file %s: %v", fname, err)
}
m, err = macho.NewFile(bytes.NewReader(tdata), macho.FileConfig{
LoadIncluding: []types.LoadCmd{types.LC_SEGMENT_64},
})
if err != nil {
return nil, fmt.Errorf("failed to parse MachO file: %v", err)
}
defer m.Close()
}
}

for _, seg := range bf.Segments {
if _, err := f.Seek(int64(seg.Offset), io.SeekStart); err != nil {
return nil, fmt.Errorf("failed to seek to offset %d: %v", seg.Offset, err)
}
data := make([]byte, seg.Size)
if err := binary.Read(f, binary.LittleEndian, &data); err != nil {
return nil, fmt.Errorf("failed to read data from file %s: %v", fname, err)
}
if s := m.Segment("__" + seg.Name); s == nil { // lookup segment in MachO header
return nil, fmt.Errorf("failed to find segment %s", seg.Name)
} else {
if _, err := of.WriteAt(data, int64(s.Offset)); err != nil {
return nil, fmt.Errorf("failed to write data to file %s: %v", fname, err)
}
}
}

outfiles = append(outfiles, fname)
}

return outfiles, nil
}
Loading

0 comments on commit 82fa323

Please sign in to comment.