Skip to content

Commit fe4de62

Browse files
committed
feat: 🆕 img4 dec cmd
1 parent 7d2e653 commit fe4de62

File tree

8 files changed

+322
-3
lines changed

8 files changed

+322
-3
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ dyld_shared_cache*
2828
System
2929
usr
3030
*.xz
31-
31+
*.bin
32+
*.s
3233
.DS_Store
3334

3435
# Repo
@@ -45,3 +46,4 @@ checksums.txt.sha1
4546
public
4647

4748
*.unstripped
49+
*.bndb

cmd/ipsw/cmd/img4.go

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
Copyright © 2020 blacktop
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
*/
22+
package cmd
23+
24+
import (
25+
"github.com/spf13/cobra"
26+
)
27+
28+
// img4Cmd represents the img4 command
29+
var img4Cmd = &cobra.Command{
30+
Use: "img4",
31+
Short: "Parse Img4",
32+
Args: cobra.NoArgs,
33+
Run: func(cmd *cobra.Command, args []string) {
34+
cmd.Help()
35+
},
36+
}
37+
38+
func init() {
39+
rootCmd.AddCommand(img4Cmd)
40+
}

cmd/ipsw/cmd/img4_dec.go

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
Copyright © 2020 blacktop
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
*/
22+
package cmd
23+
24+
import (
25+
"crypto/aes"
26+
"crypto/cipher"
27+
"encoding/hex"
28+
"fmt"
29+
"io/ioutil"
30+
"os"
31+
32+
"github.com/apex/log"
33+
lzfse "github.com/blacktop/go-lzfse"
34+
"github.com/blacktop/ipsw/internal/utils"
35+
"github.com/blacktop/ipsw/pkg/img4"
36+
"github.com/pkg/errors"
37+
"github.com/spf13/cobra"
38+
)
39+
40+
func init() {
41+
img4Cmd.AddCommand(decImg4Cmd)
42+
43+
decImg4Cmd.PersistentFlags().StringP("iv-key", "k", "", "AES key")
44+
}
45+
46+
// decCmd represents the dec command
47+
var decImg4Cmd = &cobra.Command{
48+
Use: "dec",
49+
Short: "List kernel extentions",
50+
Args: cobra.MinimumNArgs(1),
51+
RunE: func(cmd *cobra.Command, args []string) error {
52+
53+
if Verbose {
54+
log.SetLevel(log.DebugLevel)
55+
}
56+
57+
ivkeyStr, _ := cmd.Flags().GetString("iv-key")
58+
ivkey, _ := hex.DecodeString(ivkeyStr)
59+
iv := ivkey[:aes.BlockSize]
60+
key := ivkey[aes.BlockSize:]
61+
62+
f, err := os.Open(args[0])
63+
if err != nil {
64+
return errors.Wrapf(err, "unabled to open file: %s", args[0])
65+
}
66+
67+
i, err := img4.ParseIm4p(f)
68+
if err != nil {
69+
return errors.Wrap(err, "unabled to parse Im4p")
70+
}
71+
72+
block, err := aes.NewCipher(key)
73+
if err != nil {
74+
return errors.Wrap(err, "failed to create new AES cipher")
75+
}
76+
77+
// The IV needs to be unique, but not secure. Therefore it's common to
78+
// include it at the beginning of the ciphertext.
79+
if len(i.Data) < aes.BlockSize {
80+
return errors.Errorf("Im4p data too short")
81+
}
82+
83+
// CBC mode always works in whole blocks.
84+
if len(i.Data)%aes.BlockSize != 0 {
85+
return errors.Errorf("Im4p data is not a multiple of the block size")
86+
}
87+
88+
mode := cipher.NewCBCDecrypter(block, iv)
89+
90+
// CryptBlocks can work in-place if the two arguments are the same.
91+
mode.CryptBlocks(i.Data, i.Data)
92+
93+
decData := lzfse.DecodeBuffer(i.Data)
94+
95+
utils.Indent(log.Info, 2)(fmt.Sprintf("Decrypting file to %s", args[0]+".dec"))
96+
err = ioutil.WriteFile(args[0]+".dec", decData, 0644)
97+
if err != nil {
98+
return errors.Wrap(err, "unabled decrypt Img4")
99+
}
100+
101+
return nil
102+
},
103+
}

docs/content/docs/commands/img4.md

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
title: "Img4"
3+
date: 2020-03-30T17:48:08-04:00
4+
draft: false
5+
weight: 16
6+
summary: Parse Img4 files.
7+
---
8+
9+
## **img4 dec**
10+
11+
### Decrypt an `Im4p` file
12+
13+
Download _just_ iBoot
14+
15+
```bash
16+
$ ipsw download pattern -v 13.4 -d iPhone12,3 iBoot
17+
```
18+
19+
Decrypt it with things from tweets 😏
20+
21+
```bash
22+
$ ipsw img4 dec --iv-key <IVKEY> iPhone12,3_D421AP_17E255/iBoot.d421.RELEASE.im4p
23+
• Parsing Im4p
24+
• Decrypting file to iPhone12,3_D421AP_17E255/iBoot.d421.RELEASE.im4p.dec
25+
```
26+
27+
It's a thing of beauty 😍
28+
29+
```bash
30+
$ hexdump -C -s 512 -n 80 iPhone12,3_D421AP_17E255/iBoot.d421.RELEASE.im4p.dec
31+
32+
00000200 69 42 6f 6f 74 20 66 6f 72 20 64 34 32 31 2c 20 |iBoot for d421, |
33+
00000210 43 6f 70 79 72 69 67 68 74 20 32 30 30 37 2d 32 |Copyright 2007-2|
34+
00000220 30 31 39 2c 20 41 70 70 6c 65 20 49 6e 63 2e 00 |019, Apple Inc..|
35+
00000230 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
36+
00000240 52 45 4c 45 41 53 45 00 00 00 00 00 00 00 00 00 |RELEASE.........|
37+
```

docs/content/docs/roadmap/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ My main goal is to create a mantainable _dyld_shared_cache_ splitter
1919
- [ ] pure Go lzfse
2020
- [x] OTA support
2121
- [ ] APFS/HFS parsing to pull dyld without mounting
22-
- [ ] create offline copy of ipsw.me API
22+
- [ ] watch for new IPSW files with https://github.com/radovskyb/watcher
2323
- [ ] https://github.com/xerub/img4lib and https://github.com/tihmstar/img4tool
2424
- [ ] devicetree read/write
2525
- [ ] add 💄https://github.com/muesli/termenv

pkg/img4/img4.go

+16
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,19 @@ func Parse(r io.Reader) (*Img4, error) {
307307
},
308308
}, nil
309309
}
310+
311+
func ParseIm4p(r io.Reader) (*im4p, error) {
312+
utils.Indent(log.Info, 1)("Parsing Im4p")
313+
314+
data := new(bytes.Buffer)
315+
data.ReadFrom(r)
316+
317+
var i im4p
318+
319+
_, err := asn1.Unmarshal(data.Bytes(), &i)
320+
if err != nil {
321+
return nil, errors.Wrap(err, "failed to ASN.1 parse Im4p")
322+
}
323+
324+
return &i, nil
325+
}

pkg/kernelcache/kernelcache.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,9 @@ type CompressedCache struct {
6969
func ParseImg4Data(data []byte) (*CompressedCache, error) {
7070
utils.Indent(log.Info, 2)("Parsing Kernelcache IMG4")
7171

72+
// NOTE: openssl asn1parse -i -inform DER -in kernelcache.iphone10 | less (to get offset)
73+
// openssl asn1parse -i -inform DER -in kernelcache.iphone10 -strparse OFFSET -noout -out lzfse.bin
7274
var i Img4
73-
// NOTE: openssl asn1parse -i -inform DER -in kernelcache.iphone10
7475
if _, err := asn1.Unmarshal(data, &i); err != nil {
7576
return nil, errors.Wrap(err, "failed to ASN.1 parse Kernelcache")
7677
}

pkg/macho/types/codesign.go

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package types
2+
3+
const (
4+
// Magic numbers used by Code Signing
5+
CSMAGIC_REQUIREMENT = 0xfade0c00 // single Requirement blob
6+
CSMAGIC_REQUIREMENTS = 0xfade0c01 // Requirements vector (internal requirements)
7+
CSMAGIC_CODEDIRECTORY = 0xfade0c02 // CodeDirectory blob
8+
CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0 // embedded form of signature data
9+
CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1 // multi-arch collection of embedded signatures
10+
CSMAGIC_BLOBWRAPPER = 0xfade0b01 // used for the cms blob
11+
)
12+
13+
const (
14+
CS_PAGE_SIZE = 4096
15+
16+
CS_HASHTYPE_SHA1 = 1
17+
CS_HASHTYPE_SHA256 = 2
18+
CS_HASHTYPE_SHA256_TRUNCATED = 3
19+
CS_HASHTYPE_SHA384 = 4
20+
21+
CS_HASH_SIZE_SHA1 = 20
22+
CS_HASH_SIZE_SHA256 = 32
23+
CS_HASH_SIZE_SHA256_TRUNCATED = 20
24+
25+
CSSLOT_CODEDIRECTORY = 0
26+
CSSLOT_INFOSLOT = 1
27+
CSSLOT_REQUIREMENTS = 2
28+
CSSLOT_RESOURCEDIR = 3
29+
CSSLOT_APPLICATION = 4
30+
CSSLOT_ENTITLEMENTS = 5
31+
CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000
32+
CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5
33+
CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX
34+
CSSLOT_CMS_SIGNATURE = 0x10000
35+
36+
kSecCodeSignatureAdhoc = 2
37+
)
38+
39+
const CS_REQUIRE_LV = 0x0002000 // require library validation
40+
41+
// Structure of a SuperBlob
42+
type CsBlobIndex struct {
43+
Type uint32 // type of entry
44+
Offset uint32 // offset of entry
45+
}
46+
47+
type CsSuperBlob struct {
48+
Magic uint32 // magic number
49+
Length uint32 // total length of SuperBlob
50+
Count uint32 // number of index entries following
51+
// Index []CsBlobIndex // (count) entries
52+
// followed by Blobs in no particular order as indicated by offsets in index
53+
}
54+
55+
// type CsSuperBlob struct {
56+
// Magic uint32 // magic number
57+
// Length uint32 // total length of SuperBlob
58+
// Count uint32 // number of index entries following
59+
// Index []CsBlobIndex // (count) entries
60+
// // followed by Blobs in no particular order as indicated by offsets in index
61+
// }
62+
63+
// C form of a CodeDirectory.
64+
type CsCodeDirectory struct {
65+
Magic uint32 // magic number (CSMAGIC_CODEDIRECTORY) */
66+
Length uint32 // total length of CodeDirectory blob
67+
Version uint32 // compatibility version
68+
Flags uint32 // setup and mode flags
69+
HashOffset uint32 // offset of hash slot element at index zero
70+
IdentOffset uint32 // offset of identifier string
71+
NSpecialSlots uint32 // number of special hash slots
72+
NCodeSlots uint32 // number of ordinary (code) hash slots
73+
CodeLimit uint32 // limit to main image signature range
74+
HashSize uint8 // size of each hash in bytes
75+
HashType uint8 // type of hash (cdHashType* constants)
76+
Platform uint8 // platform identifier zero if not platform binary
77+
PageSize uint8 // log2(page size in bytes) 0 => infinite
78+
Spare2 uint32 // unused (must be zero)
79+
80+
EndEarliest [0]uint8
81+
82+
/* Version 0x20100 */
83+
ScatterOffset uint32 /* offset of optional scatter vector */
84+
EndWithScatter [0]uint8
85+
86+
/* Version 0x20200 */
87+
TeamOffset uint32 /* offset of optional team identifier */
88+
EndWithTeam [0]uint8
89+
90+
/* Version 0x20300 */
91+
Spare3 uint32 /* unused (must be zero) */
92+
CodeLimit64 uint64 /* limit to main image signature range, 64 bits */
93+
EndWithCodeLimit64 [0]uint8
94+
95+
/* Version 0x20400 */
96+
ExecSegBase uint64 /* offset of executable segment */
97+
ExecSegLimit uint64 /* limit of executable segment */
98+
ExecSegFlags uint64 /* exec segment flags */
99+
EndWithExecSeg [0]uint8
100+
101+
/* followed by dynamic content as located by offset fields above */
102+
}
103+
104+
type CsBlob struct {
105+
Magic uint32 // magic number
106+
Length uint32 // total length of blob
107+
}
108+
109+
type CsRequirementsBlob struct {
110+
Magic uint32 // magic number
111+
Length uint32 // total length of blob
112+
Data uint32 // zero for dyld shared cache
113+
}
114+
115+
type CsScatter struct {
116+
Count uint32 // number of pages zero for sentinel (only)
117+
Base uint32 // first page number
118+
TargetOffset uint64 // byte offset in target
119+
Spare uint64 // reserved (must be zero)
120+
}

0 commit comments

Comments
 (0)