mootool 0.2.2 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +3 -2
- data/Gemfile.lock +8 -2
- data/lib/mootool/models/decompressor.rb +32 -0
- data/lib/mootool/models/device_tree.rb +87 -55
- data/lib/mootool/models/img4.rb +4 -1
- data/lib/mootool/version.rb +1 -1
- data/mootool.gemspec +3 -0
- metadata +45 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4cfbbe3c322b64f68aa32ecfd9373b4158cabb53cec3c6ba392f6c8e1d9a7761
|
4
|
+
data.tar.gz: 9ec26119e06df11ccae1aa7eb28796db2d8a6b3af889ba20882ca22847274bff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eeed0e6c5d966626700309b618f517169b14d643e76ba9af7f48d66e1c6fae173129011e81f425c9eb209d312f0007ce03be2978520df4d8ebbf1eef585d437a
|
7
|
+
data.tar.gz: 7501f0bd4de48f2decc42d5c62ebdcaedf3a9e1720c72a316060eb02a3943032f87120927ac3bebd3b3e068691e3ed42c27b833884141ffbb2ec6a3fdad30046
|
data/.github/workflows/ci.yml
CHANGED
@@ -16,8 +16,9 @@ on:
|
|
16
16
|
jobs:
|
17
17
|
test:
|
18
18
|
|
19
|
-
runs-on: ubuntu-
|
19
|
+
runs-on: ubuntu-latest
|
20
20
|
strategy:
|
21
|
+
fail-fast: false
|
21
22
|
matrix:
|
22
23
|
ruby-version: [ '3.0', '3.1.2', '3.2.0-preview1' ]
|
23
24
|
|
@@ -27,7 +28,7 @@ jobs:
|
|
27
28
|
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
28
29
|
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
29
30
|
# uses: ruby/setup-ruby@v1
|
30
|
-
uses: ruby/setup-ruby@
|
31
|
+
uses: ruby/setup-ruby@v1
|
31
32
|
with:
|
32
33
|
ruby-version: ${{ matrix.ruby-version }}
|
33
34
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
mootool (0.2.
|
4
|
+
mootool (0.2.5)
|
5
|
+
lzfse
|
6
|
+
lzss
|
5
7
|
plist (~> 3)
|
8
|
+
ruby-lzma
|
6
9
|
ruby-macho (~> 3)
|
7
10
|
rubyzip (~> 2)
|
8
11
|
sorbet-runtime (~> 0)
|
@@ -17,6 +20,8 @@ GEM
|
|
17
20
|
docile (1.4.0)
|
18
21
|
iniparse (1.5.0)
|
19
22
|
json (2.6.2)
|
23
|
+
lzfse (0.0.1)
|
24
|
+
lzss (0.1)
|
20
25
|
method_source (1.0.0)
|
21
26
|
netrc (0.11.0)
|
22
27
|
overcommit (0.59.1)
|
@@ -68,6 +73,7 @@ GEM
|
|
68
73
|
rubocop (~> 1.0)
|
69
74
|
rubocop-rspec (2.12.1)
|
70
75
|
rubocop (~> 1.31)
|
76
|
+
ruby-lzma (0.4.3)
|
71
77
|
ruby-macho (3.0.0)
|
72
78
|
ruby-progressbar (1.11.0)
|
73
79
|
rubyzip (2.3.2)
|
@@ -90,7 +96,7 @@ GEM
|
|
90
96
|
sorbet (>= 0.5.9204)
|
91
97
|
sorbet-runtime (>= 0.5.9204)
|
92
98
|
thor (>= 0.19.2)
|
93
|
-
tapioca (0.9.
|
99
|
+
tapioca (0.9.4)
|
94
100
|
bundler (>= 1.17.3)
|
95
101
|
netrc (>= 0.11.0)
|
96
102
|
parallel (>= 1.21.0)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lzfse'
|
4
|
+
require 'lzma'
|
5
|
+
require 'compress/lzss'
|
6
|
+
|
7
|
+
module MooTool
|
8
|
+
# The magic Apple decompressor (as in it uses magics)
|
9
|
+
class Decompressor
|
10
|
+
COMPRESSION_LZSS = 'lzss'
|
11
|
+
COMPRESSION_LZVN = 'lzvn'
|
12
|
+
COMPRESSION_LZFSE = 'bvx2'
|
13
|
+
COMPRESSION_LZMA = 'lzma'
|
14
|
+
|
15
|
+
attr_reader :value
|
16
|
+
|
17
|
+
def initialize(data)
|
18
|
+
@value = case data[0..3]
|
19
|
+
when COMPRESSION_LZFSE
|
20
|
+
LZFSE.lzfse_decompress(data)
|
21
|
+
when COMPRESSION_LZVN
|
22
|
+
LZFSE.lzvn_decompress(data)
|
23
|
+
when COMPRESSION_LZSS
|
24
|
+
Compress::LZSS.decompress(data)
|
25
|
+
when COMPRESSION_LZMA
|
26
|
+
LZMA.decompress(data)
|
27
|
+
else
|
28
|
+
data
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -4,82 +4,114 @@
|
|
4
4
|
require 'sorbet-runtime'
|
5
5
|
|
6
6
|
module MooTool
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
# DeviceTree is a Apple Device Tree node that has been parsed
|
8
|
+
class DeviceTree
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
NODE_FORMAT = 'VV'
|
12
|
+
PROP_FORMAT = 'A32V'
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
+
PHANDLE_PROP = 'AAPL,phandle'
|
15
|
+
COMPATIBLE_PROP = 'compatible'
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
# Represents a single node in the device tree
|
18
|
+
class Node
|
19
|
+
extend T::Sig
|
18
20
|
|
19
|
-
|
21
|
+
attr_reader :children, :properties
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
sig { params(tree: DeviceTree, data: T.any(IO, StringIO)).void }
|
24
|
+
def initialize(tree, data)
|
25
|
+
@tree = tree
|
26
|
+
vals = T.must(data.read(8)).unpack(NODE_FORMAT)
|
27
|
+
property_count = T.cast(vals[0], Integer)
|
28
|
+
child_count = T.cast(vals[1], Integer)
|
26
29
|
|
27
|
-
|
28
|
-
|
30
|
+
@properties = T.let({}, T::Hash[String, Property])
|
31
|
+
@children = T.let([], T::Array[Node])
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
child_count.times { @children << Node.new(data) }
|
33
|
+
property_count.times do
|
34
|
+
prop = Property.new(data)
|
35
|
+
@properties[prop.name] = prop
|
35
36
|
end
|
37
|
+
child_count.times { @children << Node.new(tree, data) }
|
38
|
+
|
39
|
+
@tree.add_handle(self, @properties[PHANDLE_PROP].value) if @properties.key? PHANDLE_PROP
|
36
40
|
end
|
37
41
|
|
38
|
-
|
39
|
-
|
40
|
-
|
42
|
+
def to_h
|
43
|
+
props = @properties.transform_values(&:value)
|
44
|
+
if @children.any?
|
45
|
+
props.merge({ children: @children.map(&:to_h) })
|
46
|
+
else
|
47
|
+
props
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
41
51
|
|
42
|
-
|
52
|
+
# Represents a single property and it's value
|
53
|
+
class Property
|
54
|
+
extend T::Sig
|
43
55
|
|
44
|
-
|
45
|
-
def initialize(data)
|
46
|
-
args = T.must(data.read(36)).unpack(PROP_FORMAT)
|
56
|
+
attr_accessor :name, :value
|
47
57
|
|
48
|
-
|
49
|
-
|
58
|
+
sig { params(data: T.any(StringIO, IO)).void }
|
59
|
+
def initialize(data)
|
60
|
+
args = T.must(data.read(36)).unpack(PROP_FORMAT)
|
50
61
|
|
51
|
-
|
52
|
-
|
53
|
-
@size &= 0x7fffffff
|
54
|
-
end
|
62
|
+
@name = T.let(T.cast(args[0], String), String)
|
63
|
+
@size = T.let(T.cast(args[1], Integer), Integer)
|
55
64
|
|
56
|
-
|
57
|
-
@
|
65
|
+
if @size & 0x80000000 != 0
|
66
|
+
@template = true
|
67
|
+
@size &= 0x7fffffff
|
58
68
|
end
|
69
|
+
|
70
|
+
@value = T.must(data.read(@size.align(4)))[0..(@size - 1)]
|
71
|
+
|
72
|
+
normalize
|
59
73
|
end
|
60
74
|
|
61
|
-
|
75
|
+
private
|
62
76
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
data = T.assert_type!(data, Pathname)
|
69
|
-
@data = File.open(data.realpath, 'rb')
|
70
|
-
when String
|
71
|
-
data = T.assert_type!(data, String)
|
72
|
-
@data = StringIO.new(data)
|
73
|
-
when IO
|
74
|
-
@data = T.cast(data, IO)
|
75
|
-
end
|
76
|
-
@root = Node.new(@data)
|
77
|
+
def normalize
|
78
|
+
@value = @value.split("\x00").map(&:chomp) if @name == COMPATIBLE_PROP
|
79
|
+
@value = @value.unpack1('V') if @size == 4
|
80
|
+
|
81
|
+
@value = @value.chomp("\x00") if @value.is_a?(String) && @value.count("\x00") == 1 && @value.end_with?("\x00")
|
77
82
|
end
|
83
|
+
end
|
78
84
|
|
79
|
-
|
80
|
-
|
81
|
-
|
85
|
+
attr_reader :root
|
86
|
+
|
87
|
+
# @param [String] data
|
88
|
+
sig { params(data: T.any(IO, String, StringIO, Pathname)).void }
|
89
|
+
def initialize(data)
|
90
|
+
@handles = {}
|
91
|
+
case data
|
92
|
+
when Pathname
|
93
|
+
data = T.assert_type!(data, Pathname)
|
94
|
+
@data = File.open(data.realpath, 'rb')
|
95
|
+
when String
|
96
|
+
data = T.assert_type!(data, String)
|
97
|
+
@data = StringIO.new(data)
|
98
|
+
when IO
|
99
|
+
@data = T.cast(data, IO)
|
82
100
|
end
|
101
|
+
@root = Node.new(self, @data)
|
102
|
+
end
|
103
|
+
|
104
|
+
def add_handle(node, handle)
|
105
|
+
@handles[handle] = node
|
106
|
+
end
|
107
|
+
|
108
|
+
sig { params(path: String).returns(DeviceTree) }
|
109
|
+
def self.open(path)
|
110
|
+
MooTool::DeviceTree.new(Pathname.new(path))
|
111
|
+
end
|
112
|
+
|
113
|
+
def to_h
|
114
|
+
@root.to_h
|
83
115
|
end
|
84
116
|
end
|
85
117
|
end
|
data/lib/mootool/models/img4.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'openssl'
|
4
|
+
require_relative 'decompressor'
|
4
5
|
|
5
6
|
module MooTool
|
6
7
|
# Module for Apple's IMG4 encryption and signing format
|
@@ -18,12 +19,14 @@ module MooTool
|
|
18
19
|
when 'IM4P'
|
19
20
|
@type = @data.value[1].value
|
20
21
|
@build = @data.value[2].value
|
21
|
-
@payload = @data.value[3].value
|
22
|
+
@payload = MooTool::Decompressor.new(@data.value[3].value).value
|
22
23
|
when 'IMG4', 'IM4M'
|
23
24
|
raise 'Not implemented'
|
24
25
|
else
|
25
26
|
raise "Unknown IMG4 type #{@data.first.value}"
|
26
27
|
end
|
28
|
+
|
29
|
+
@manifest = Manifest.new(@payload) if @payload.start_with?('IM4M')
|
27
30
|
end
|
28
31
|
|
29
32
|
def payload?
|
data/lib/mootool/version.rb
CHANGED
data/mootool.gemspec
CHANGED
@@ -37,7 +37,10 @@ Gem::Specification.new do |spec|
|
|
37
37
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
38
38
|
spec.require_paths = ['lib']
|
39
39
|
|
40
|
+
spec.add_runtime_dependency 'lzfse'
|
41
|
+
spec.add_runtime_dependency 'lzss'
|
40
42
|
spec.add_runtime_dependency 'plist', '~> 3'
|
43
|
+
spec.add_runtime_dependency 'ruby-lzma'
|
41
44
|
spec.add_runtime_dependency 'ruby-macho', '~> 3'
|
42
45
|
spec.add_runtime_dependency 'rubyzip', '~> 2'
|
43
46
|
spec.add_runtime_dependency 'sorbet-runtime', '~> 0'
|
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mootool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rick Mark
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-08-
|
11
|
+
date: 2022-08-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: lzfse
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: lzss
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
13
41
|
- !ruby/object:Gem::Dependency
|
14
42
|
name: plist
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -24,6 +52,20 @@ dependencies:
|
|
24
52
|
- - "~>"
|
25
53
|
- !ruby/object:Gem::Version
|
26
54
|
version: '3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: ruby-lzma
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
27
69
|
- !ruby/object:Gem::Dependency
|
28
70
|
name: ruby-macho
|
29
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,6 +146,7 @@ files:
|
|
104
146
|
- lib/mootool/controllers/kernel_collection.rb
|
105
147
|
- lib/mootool/controllers/sections.rb
|
106
148
|
- lib/mootool/core_extensions.rb
|
149
|
+
- lib/mootool/models/decompressor.rb
|
107
150
|
- lib/mootool/models/device_tree.rb
|
108
151
|
- lib/mootool/models/img4.rb
|
109
152
|
- lib/mootool/models/ipsw.rb
|