Skip to content

Commit c7e7698

Browse files
committed
feat: WIP firmware key scrapin code
1 parent 57b22c7 commit c7e7698

File tree

7 files changed

+165
-1
lines changed

7 files changed

+165
-1
lines changed

Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ update_mod:
5656
update_devs:
5757
CGO_ENABLED=1 CGO_CFLAGS=-I/usr/local/include CGO_LDFLAGS=-L/usr/local/lib CC=gcc go run ./cmd/ipsw/main.go device-list-gen pkg/info/data/device_traits.json
5858

59+
.PHONY: update_keys
60+
update_keys:
61+
CGO_ENABLED=0 go run ./cmd/ipsw/main.go key-list-gen pkg/info/data/firmware_keys.json
62+
5963
.PHONY: dry_release
6064
dry_release:
6165
goreleaser --skip-publish --rm-dist --skip-validate

cmd/ipsw/cmd/key_list_gen.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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+
"encoding/json"
26+
"io/ioutil"
27+
"path/filepath"
28+
29+
"github.com/blacktop/ipsw/internal/download"
30+
"github.com/spf13/cobra"
31+
)
32+
33+
// keyListGenCmd represents the key-list-gen command
34+
var keyListGenCmd = &cobra.Command{
35+
Use: "key-list-gen",
36+
Short: "Generate iOS firmware key database",
37+
Args: cobra.MinimumNArgs(1),
38+
Hidden: true,
39+
RunE: func(cmd *cobra.Command, args []string) error {
40+
41+
keys, err := download.ScrapeKeys("")
42+
if err != nil {
43+
return err
44+
}
45+
46+
keysJSON, err := json.Marshal(keys)
47+
if err != nil {
48+
return err
49+
}
50+
return ioutil.WriteFile(filepath.Clean(args[0]), keysJSON, 0644)
51+
52+
return nil
53+
},
54+
}
55+
56+
func init() {
57+
rootCmd.AddCommand(keyListGenCmd)
58+
}

cmd/ipsw/cmd/sep.go

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040
// NOTE: https://www.blackhat.com/docs/us-16/materials/us-16-Mandt-Demystifying-The-Secure-Enclave-Processor.pdf
4141
// NOTE: http://mista.nu/research/sep-paper.pdf
4242
// NOTE: https://gist.github.com/xerub/0161aacd7258d31c6a27584f90fa2e8c
43+
// NOTE: https://github.com/matteyeux/sepsplit/blob/master/sepsplit.c
4344

4445
const legionStr = "Built by legion2"
4546
const appListOffsetFromSEPOS32bit = 0xec8

hack/extras/NOTES.md

+5
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,8 @@ Ideas
4242
- https://blog.gopheracademy.com/advent-2018/llvm-ir-and-go/
4343
- https://blog.felixangell.com/an-introduction-to-llvm-in-go
4444
- https://ldhldh.myds.me:10081/docs/llvm342_docs/_mach_o_dump_8cpp.html
45+
46+
### DWARF
47+
48+
- https://github.com/volatilityfoundation/dwarf2json/blob/master/main.go
49+
- https://github.com/dutchcoders/disassembler/blob/master/disassembler.go

internal/download/scrape.go

+71
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"regexp"
55
"sort"
66
"strings"
7+
"time"
78

89
"github.com/gocolly/colly/v2"
910
"github.com/pkg/errors"
@@ -24,6 +25,10 @@ type BetaIPSW struct {
2425
BuildID string `json:"buildid,omitempty"`
2526
}
2627

28+
type Keys map[string]string
29+
type BuildKeys map[string]Keys
30+
type DeviceKeys map[string]BuildKeys
31+
2732
func trimQuotes(s string) string {
2833
if len(s) > 0 && s[0] == '"' {
2934
s = s[1:]
@@ -126,3 +131,69 @@ func ScrapeURLs(build string) (map[string]BetaIPSW, error) {
126131

127132
return ipsws, nil
128133
}
134+
135+
// ScrapeKeys will scrape the iPhone Wiki for firmware keys
136+
func ScrapeKeys(version string) (map[string]map[string]map[string]string, error) {
137+
keys := make(map[string]map[string]map[string]string, 1000)
138+
139+
c := colly.NewCollector(
140+
colly.AllowedDomains("www.theiphonewiki.com"),
141+
colly.URLFilters(
142+
regexp.MustCompile("https://www.theiphonewiki.com/wiki/(.+)$"),
143+
),
144+
// colly.Async(true),
145+
colly.MaxDepth(1),
146+
colly.UserAgent("free0"),
147+
colly.IgnoreRobotsTxt(),
148+
)
149+
150+
// On every a element which has href attribute call callback
151+
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
152+
if strings.Contains(e.Attr("href"), "/wiki/") && !strings.Contains(e.Attr("href"), "redlink=1") {
153+
c.Visit(e.Request.AbsoluteURL(e.Attr("href")))
154+
}
155+
})
156+
157+
c.OnHTML("body", func(e *colly.HTMLElement) {
158+
e.ForEach("code", func(_ int, code *colly.HTMLElement) {
159+
if len(code.Attr("id")) > 0 {
160+
if strings.Contains(code.Attr("id"), "-iv") || strings.Contains(code.Attr("id"), "-key") {
161+
if code.Text != "Unknown" {
162+
urlParts := strings.Split(code.Request.URL.Path, "_")
163+
buildID := urlParts[1]
164+
deviceID := strings.Trim(urlParts[2], "()")
165+
if keys[deviceID] == nil {
166+
keys[deviceID] = map[string]map[string]string{}
167+
}
168+
if keys[deviceID][buildID] == nil {
169+
keys[deviceID][buildID] = map[string]string{}
170+
}
171+
keys[deviceID][buildID][strings.TrimPrefix(code.Attr("id"), "keypage-")] = code.Text
172+
// fmt.Printf("%#v\n", keys[deviceID])
173+
}
174+
175+
}
176+
}
177+
})
178+
})
179+
180+
// Set error handler
181+
// c.OnError(func(r *colly.Response, err error) {
182+
// // fmt.Println("Request URL:", r.Request.URL, "failed with response:", r, "\nError:", err)
183+
// fmt.Println("Error:", err)
184+
// })
185+
186+
c.SetRequestTimeout(60 * time.Second)
187+
188+
// for _, v := range []string{"1.x", "2.x", "3.x", "4.x", "5.x", "6.x", "7.x", "8.x", "9.x", "10.x", "11.x", "12.x", "13.x", "14.x"} {
189+
for _, v := range []string{"13.x", "14.x"} {
190+
err := c.Visit("https://www.theiphonewiki.com/wiki/Firmware_Keys/" + v)
191+
if err != nil {
192+
return nil, errors.Wrap(err, "failed to scrape https://www.theiphonewiki.com/wiki/Firmware_Keys/"+v)
193+
}
194+
}
195+
196+
c.Wait()
197+
198+
return keys, nil
199+
}

internal/statik/statik.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/info/info.go

+25
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,31 @@ func getProcessor(cpuid string) processors {
7575
return processors{}
7676
}
7777

78+
func getFirmwareKeys(device, build string) map[string]string {
79+
var keys map[string]map[string]map[string]string
80+
81+
statikFS, err := fs.New()
82+
if err != nil {
83+
log.Fatal(err)
84+
}
85+
keysJSON, err := statikFS.Open("/firmware_keys.json")
86+
if err != nil {
87+
log.Fatal(err)
88+
}
89+
90+
data, err := ioutil.ReadAll(keysJSON)
91+
if err != nil {
92+
log.Fatal(err)
93+
}
94+
95+
err = json.Unmarshal(data, &keys)
96+
if err != nil {
97+
log.Fatal(err)
98+
}
99+
100+
return keys[device][build]
101+
}
102+
78103
func (i *Info) String() string {
79104
var iStr string
80105
iStr += fmt.Sprintf(

0 commit comments

Comments
 (0)