Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add non-darwin version of
ipsw dyld split
cmd
- Loading branch information
Showing
6 changed files
with
299 additions
and
87 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
//go:build darwin && cgo | ||
|
||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"runtime" | ||
|
||
"github.com/apex/log" | ||
"github.com/blacktop/ipsw/pkg/dyld" | ||
"github.com/pkg/errors" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
func init() { | ||
dyldCmd.AddCommand(splitCmd) | ||
|
||
splitCmd.Flags().StringP("xcode", "x", "", "Path to Xcode.app") | ||
viper.BindPFlag("dyld.split.xcode", ipswCmd.Flags().Lookup("xcode")) | ||
|
||
splitCmd.MarkZshCompPositionalArgumentFile(1, "dyld_shared_cache*") | ||
} | ||
|
||
// splitCmd represents the split command | ||
var splitCmd = &cobra.Command{ | ||
Use: "split <dyld_shared_cache> <optional_output_path>", | ||
Short: "Extracts all the dyld_shared_cache libraries", | ||
Args: cobra.MinimumNArgs(1), | ||
SilenceUsage: false, | ||
SilenceErrors: true, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
|
||
if Verbose { | ||
log.SetLevel(log.DebugLevel) | ||
} | ||
|
||
xcodePath := viper.GetString("dyld.split.xcode") | ||
dscPath := filepath.Clean(args[0]) | ||
|
||
fileInfo, err := os.Lstat(dscPath) | ||
if err != nil { | ||
return fmt.Errorf("file %s does not exist", dscPath) | ||
} | ||
|
||
// Check if file is a symlink | ||
if fileInfo.Mode()&os.ModeSymlink != 0 { | ||
symlinkPath, err := os.Readlink(dscPath) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to read symlink %s", dscPath) | ||
} | ||
// TODO: this seems like it would break | ||
linkParent := filepath.Dir(dscPath) | ||
linkRoot := filepath.Dir(linkParent) | ||
|
||
dscPath = filepath.Join(linkRoot, symlinkPath) | ||
} | ||
|
||
if runtime.GOOS != "darwin" { | ||
log.Fatal("dyld_shared_cache splitting only works on macOS") | ||
} | ||
|
||
if len(args) > 1 { | ||
outputPath, _ := filepath.Abs(filepath.Clean(args[1])) | ||
if _, err := os.Stat(outputPath); os.IsNotExist(err) { | ||
return fmt.Errorf("path %s does not exist", outputPath) | ||
} | ||
log.Infof("Splitting dyld_shared_cache to %s\n", outputPath) | ||
return dyld.Split(dscPath, outputPath, xcodePath) | ||
} | ||
|
||
log.Info("Splitting dyld_shared_cache") | ||
return dyld.Split(dscPath, filepath.Dir(dscPath), xcodePath) | ||
|
||
// dscPath := filepath.Clean(args[0]) | ||
|
||
// fileInfo, err := os.Lstat(dscPath) | ||
// if err != nil { | ||
// return fmt.Errorf("file %s does not exist", dscPath) | ||
// } | ||
|
||
// // Check if file is a symlink | ||
// if fileInfo.Mode()&os.ModeSymlink != 0 { | ||
// symlinkPath, err := os.Readlink(dscPath) | ||
// if err != nil { | ||
// return errors.Wrapf(err, "failed to read symlink %s", dscPath) | ||
// } | ||
// // TODO: this seems like it would break | ||
// linkParent := filepath.Dir(dscPath) | ||
// linkRoot := filepath.Dir(linkParent) | ||
|
||
// dscPath = filepath.Join(linkRoot, symlinkPath) | ||
// } | ||
|
||
// f, err := dyld.Open(dscPath) | ||
// if err != nil { | ||
// return err | ||
// } | ||
// defer f.Close() | ||
|
||
// var wg sync.WaitGroup | ||
|
||
// for _, i := range f.Images { | ||
// wg.Add(1) | ||
|
||
// go func(i *dyld.CacheImage) { | ||
// defer wg.Done() | ||
|
||
// m, err := i.GetMacho() | ||
// if err != nil { | ||
// // return err | ||
// } | ||
// defer m.Close() | ||
|
||
// // f.GetLocalSymbolsForImage(i) | ||
|
||
// folder := filepath.Dir(dscPath) // default to folder of shared cache | ||
// fname := filepath.Join(folder, i.Name) // default to full dylib path | ||
|
||
// if err := m.Export(fname, nil, m.GetBaseAddress(), i.GetLocalSymbols()); err != nil { | ||
// // return fmt.Errorf("failed to export entry MachO %s; %v", i.Name, err) | ||
// } | ||
|
||
// if err := rebaseMachO(f, fname); err != nil { | ||
// // return fmt.Errorf("failed to rebase macho via cache slide info: %v", err) | ||
// } | ||
// }(i) | ||
|
||
// } | ||
|
||
// wg.Wait() | ||
|
||
// return nil | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
//go:build !(darwin && cgo) | ||
|
||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/apex/log" | ||
"github.com/blacktop/ipsw/pkg/dyld" | ||
"github.com/pkg/errors" | ||
"github.com/spf13/cobra" | ||
"github.com/vbauerster/mpb/v7" | ||
"github.com/vbauerster/mpb/v7/decor" | ||
) | ||
|
||
func init() { | ||
dyldCmd.AddCommand(splitCmd) | ||
splitCmd.Flags().BoolP("all", "a", false, "Split ALL dylibs") | ||
splitCmd.Flags().Bool("force", false, "Overwrite existing extracted dylib(s)") | ||
splitCmd.Flags().String("output", "o", "Directory to extract the dylib(s)") | ||
splitCmd.MarkZshCompPositionalArgumentFile(1, "dyld_shared_cache*") | ||
} | ||
|
||
// splitCmd represents the split command | ||
var splitCmd = &cobra.Command{ | ||
Use: "split <dyld_shared_cache> <optional_output_path>", | ||
Short: "Extracts all the dyld_shared_cache libraries", | ||
Args: cobra.MinimumNArgs(1), | ||
SilenceUsage: false, | ||
SilenceErrors: true, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
|
||
var bar *mpb.Bar | ||
|
||
if Verbose { | ||
log.SetLevel(log.DebugLevel) | ||
} | ||
|
||
dumpALL, _ := cmd.Flags().GetBool("all") | ||
forceExtract, _ := cmd.Flags().GetBool("force") | ||
extractPath, _ := cmd.Flags().GetString("output") | ||
|
||
dscPath := filepath.Clean(args[0]) | ||
|
||
fileInfo, err := os.Lstat(dscPath) | ||
if err != nil { | ||
return fmt.Errorf("file %s does not exist", dscPath) | ||
} | ||
|
||
// Check if file is a symlink | ||
if fileInfo.Mode()&os.ModeSymlink != 0 { | ||
symlinkPath, err := os.Readlink(dscPath) | ||
if err != nil { | ||
return errors.Wrapf(err, "failed to read symlink %s", dscPath) | ||
} | ||
// TODO: this seems like it would break | ||
linkParent := filepath.Dir(dscPath) | ||
linkRoot := filepath.Dir(linkParent) | ||
|
||
dscPath = filepath.Join(linkRoot, symlinkPath) | ||
} | ||
|
||
f, err := dyld.Open(dscPath) | ||
if err != nil { | ||
return err | ||
} | ||
defer f.Close() | ||
|
||
if len(args) > 1 || dumpALL { | ||
|
||
var images []*dyld.CacheImage | ||
|
||
if dumpALL { | ||
images = f.Images | ||
// initialize progress bar | ||
p := mpb.New(mpb.WithWidth(80)) | ||
// adding a single bar, which will inherit container's width | ||
bar = p.Add(int64(len(images)), | ||
// progress bar filler with customized style | ||
mpb.NewBarFiller(mpb.BarStyle().Lbound("[").Filler("=").Tip(">").Padding("-").Rbound("|")), | ||
mpb.PrependDecorators( | ||
decor.Name(" ", decor.WC{W: len(" ") + 1, C: decor.DidentRight}), | ||
// replace ETA decorator with "done" message, OnComplete event | ||
decor.OnComplete( | ||
decor.AverageETA(decor.ET_STYLE_GO, decor.WC{W: 4}), "✅ ", | ||
), | ||
), | ||
mpb.AppendDecorators( | ||
decor.Percentage(), | ||
// decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_GO, float64(len(images))/2048), "✅ "), | ||
decor.Name(" ] "), | ||
), | ||
) | ||
} else { | ||
if img := f.Image(args[1]); img != nil { | ||
images = append(images, img) | ||
} else { | ||
log.Errorf("dylib %s not found in %s", args[1], dscPath) | ||
return nil | ||
} | ||
} | ||
|
||
for _, i := range images { | ||
m, err := i.GetMacho() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
folder := filepath.Dir(dscPath) // default to folder of shared cache | ||
if len(extractPath) > 0 { | ||
folder = extractPath | ||
} | ||
|
||
fname := filepath.Join(folder, filepath.Base(i.Name)) // default to NOT full dylib path | ||
if dumpALL { | ||
fname = filepath.Join(folder, i.Name) | ||
} | ||
|
||
if _, err := os.Stat(fname); os.IsNotExist(err) || forceExtract { | ||
|
||
f.GetLocalSymbolsForImage(i) | ||
|
||
if err := m.Export(fname, nil, m.GetBaseAddress(), i.GetLocalSymbols()); err != nil { | ||
return fmt.Errorf("failed to export entry MachO %s; %v", i.Name, err) | ||
} | ||
|
||
if err := rebaseMachO(f, fname); err != nil { | ||
return fmt.Errorf("failed to rebase macho via cache slide info: %v", err) | ||
} | ||
|
||
if !dumpALL { | ||
log.Infof("Created %s", fname) | ||
} else { | ||
bar.Increment() | ||
} | ||
} else { | ||
if !dumpALL { | ||
log.Warnf("dylib already exists: %s", fname) | ||
} else { | ||
bar.Increment() | ||
} | ||
} | ||
m.Close() | ||
} | ||
} | ||
|
||
return nil | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.