Skip to content

Commit f64f267

Browse files
committed
feat(extract): add 'ident' flag for selecting specific RestoreRamDisk and update DMG extraction options
1 parent 4a53ab8 commit f64f267

File tree

5 files changed

+43
-24
lines changed

5 files changed

+43
-24
lines changed

cmd/ipsw/cmd/extract.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func init() {
4646
extractCmd.Flags().BoolP("kernel", "k", false, "Extract kernelcache")
4747
extractCmd.Flags().BoolP("dyld", "d", false, "Extract dyld_shared_cache")
4848
extractCmd.Flags().Bool("dtree", false, "Extract DeviceTree")
49-
extractCmd.Flags().String("dmg", "", "Extract DMG file (app, sys, fs)")
49+
extractCmd.Flags().String("dmg", "", fmt.Sprintf("Extract DMG file (%s)", strings.Join(mount.DmgTypes, ", ")))
5050
extractCmd.Flags().Bool("iboot", false, "Extract iBoot")
5151
extractCmd.Flags().Bool("sep", false, "Extract sep-firmware")
5252
extractCmd.Flags().Bool("sptm", false, "Extract SPTM and TXM Firmwares")
@@ -67,12 +67,14 @@ func init() {
6767
})
6868
extractCmd.Flags().Bool("driverkit", false, "Extract DriverKit dyld_shared_cache")
6969
extractCmd.Flags().String("device", "", "Device to extract kernel for (e.g. iPhone10,6)")
70+
extractCmd.Flags().String("ident", "", "Identity Variant to select specific RestoreRamDisk (e.g. 'Erase', 'Upgrade', 'Recovery')")
7071
extractCmd.RegisterFlagCompletionFunc("dmg", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
7172
return []string{
7273
"app\tAppOS",
7374
"sys\tSystemOS",
7475
"fs\tFileSystem",
7576
"exc\tExclave",
77+
"rdisk\tRestoreRamDisk",
7678
}, cobra.ShellCompDirectiveDefault
7779
})
7880

@@ -100,6 +102,7 @@ func init() {
100102
viper.BindPFlag("extract.dyld-arch", extractCmd.Flags().Lookup("dyld-arch"))
101103
viper.BindPFlag("extract.driverkit", extractCmd.Flags().Lookup("driverkit"))
102104
viper.BindPFlag("extract.device", extractCmd.Flags().Lookup("device"))
105+
viper.BindPFlag("extract.ident", extractCmd.Flags().Lookup("ident"))
103106
}
104107

105108
// extractCmd represents the extract command
@@ -190,6 +193,7 @@ var extractCmd = &cobra.Command{
190193
Output: viper.GetString("extract.output"),
191194
JSON: viper.GetBool("extract.json"),
192195
Lookup: viper.GetBool("extract.lookup"),
196+
Ident: viper.GetString("extract.ident"),
193197
}
194198

195199
if viper.GetBool("extract.remote") {

internal/commands/extract/extract.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ type Config struct {
7878
Info bool `json:"info,omitempty"`
7979
// Lookup decryption keys from theapplewiki.com
8080
Lookup bool `json:"lookup,omitempty"`
81+
// BuildManifest identity selector (used for rdisk)
82+
Ident string `json:"ident,omitempty"`
8183

8284
info *info.Info
8385
wikiKeys download.WikiFWKeys
@@ -647,6 +649,11 @@ func DMG(c *Config) ([]string, error) {
647649
if err != nil {
648650
return nil, fmt.Errorf("failed to find exclaveOS DMG in IPSW: %v", err)
649651
}
652+
case "rdisk":
653+
dmgPath, err = i.GetRestoreRamDiskDmg(c.Ident)
654+
if err != nil {
655+
return nil, fmt.Errorf("failed to find RestoreRamDisk DMG in IPSW: %v", err)
656+
}
650657
}
651658

652659
return utils.SearchZip(zr.File, regexp.MustCompile(dmgPath), filepath.Join(filepath.Clean(c.Output), folder), c.Flatten, c.Progress)

internal/commands/mount/mount.go

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
"github.com/blacktop/ipsw/pkg/info"
2121
)
2222

23-
var DmgTypes = []string{"fs", "sys", "app", "exc", "rdisk"}
23+
var DmgTypes = []string{"app", "sys", "fs", "exc", "rdisk"}
2424

2525
// Config contains optional options for mounting a DMG from an IPSW
2626
type Config struct {
@@ -119,27 +119,9 @@ func DmgInIPSW(path, typ string, cfg *Config) (*Context, error) {
119119
return nil, fmt.Errorf("failed to get ExclaveOS DMG: %v", err)
120120
}
121121
case "rdisk":
122-
if len(cfg.Ident) > 0 {
123-
dmgPath, err = i.GetRestoreRamDiskDmgByIdent(cfg.Ident)
124-
if err != nil {
125-
return nil, fmt.Errorf("failed to get RestoreRamDisk DMG: %v", err)
126-
}
127-
} else {
128-
// Prefer Erase -> Update -> first
129-
if p, err := i.GetRestoreRamDiskDmgByIdent("Erase"); err == nil {
130-
dmgPath = p
131-
} else if p, err := i.GetRestoreRamDiskDmgByIdent("Update"); err == nil {
132-
dmgPath = p
133-
} else {
134-
if dmgs, err := i.GetRestoreRamDiskDmgs(); err == nil {
135-
if len(dmgs) == 0 {
136-
return nil, fmt.Errorf("no RestoreRamDisk DMG found")
137-
}
138-
dmgPath = dmgs[0]
139-
} else {
140-
return nil, fmt.Errorf("failed to get RestoreRamDisk DMGs: %v", err)
141-
}
142-
}
122+
dmgPath, err = i.GetRestoreRamDiskDmg(cfg.Ident)
123+
if err != nil {
124+
return nil, fmt.Errorf("failed to get RestoreRamDisk DMG: %v", err)
143125
}
144126
default:
145127
return nil, fmt.Errorf("invalid subcommand: %s; must be one of: '%s'", typ, strings.Join(DmgTypes, "', '"))

pkg/info/info.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,30 @@ func (i *Info) GetRestoreRamDiskDmgByIdent(ident string) (string, error) {
481481
}
482482
}
483483

484+
// GetRestoreRamDiskDmg returns the best RestoreRamDisk DMG path.
485+
// If ident is non-empty, it finds a matching identity. Otherwise, it prefers
486+
// Erase, then Update, then falls back to the first available DMG.
487+
func (i *Info) GetRestoreRamDiskDmg(ident string) (string, error) {
488+
if len(ident) > 0 {
489+
return i.GetRestoreRamDiskDmgByIdent(ident)
490+
}
491+
// Prefer Erase -> Update -> first
492+
if p, err := i.GetRestoreRamDiskDmgByIdent("Erase"); err == nil {
493+
return p, nil
494+
}
495+
if p, err := i.GetRestoreRamDiskDmgByIdent("Update"); err == nil {
496+
return p, nil
497+
}
498+
dmgs, err := i.GetRestoreRamDiskDmgs()
499+
if err != nil {
500+
return "", fmt.Errorf("failed to get RestoreRamDisk DMGs: %w", err)
501+
}
502+
if len(dmgs) == 0 {
503+
return "", fmt.Errorf("no RestoreRamDisk DMG found")
504+
}
505+
return dmgs[0], nil
506+
}
507+
484508
func (i *Info) GetExclaveOSDmg() (string, error) {
485509
var dmgs []string
486510
if i.Plists != nil && i.Plists.BuildManifest != nil {

www/docs/cli/ipsw/extract.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ $ ipsw extract --dyld --driverkit macOS.ipsw
4747

4848
```
4949
--device string Device to extract kernel for (e.g. iPhone10,6)
50-
--dmg string Extract DMG file (app, sys, fs)
50+
--dmg string Extract DMG file (app, sys, fs, exc, rdisk)
5151
--driverkit Extract DriverKit dyld_shared_cache
5252
--dtree Extract DeviceTree
5353
-d, --dyld Extract dyld_shared_cache
@@ -58,10 +58,12 @@ $ ipsw extract --dyld --driverkit macOS.ipsw
5858
--flat Do NOT preserve directory structure when extracting
5959
-h, --help help for extract
6060
--iboot Extract iBoot
61+
--ident string Identity Variant to select specific RestoreRamDisk (e.g. 'Erase', 'Upgrade', 'Recovery')
6162
--insecure do not verify ssl certs
6263
-j, --json Output extracted paths as JSON
6364
--kbag Extract Im4p Keybags
6465
-k, --kernel Extract kernelcache
66+
-l, --lookup Lookup decryption keys on theapplewiki.com
6567
-o, --output string Folder to extract files to
6668
-p, --pattern string Extract files that match regex
6769
--pem-db string AEA pem DB JSON file

0 commit comments

Comments
 (0)