ios_backup_extractor 1.1.0 → 1.2.2
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 +5 -5
- data/exe/ios +4 -0
- data/ios_backup_extractor.gemspec +2 -2
- data/lib/ios_backup_extractor/backup_retriever.rb +1 -1
- data/lib/ios_backup_extractor/keybag.rb +2 -1
- data/lib/ios_backup_extractor/raw_backup.rb +2 -3
- data/lib/ios_backup_extractor/raw_backup10.rb +2 -1
- data/lib/ios_backup_extractor/raw_backup3.rb +58 -0
- data/lib/ios_backup_extractor/raw_backup4.rb +3 -21
- data/lib/ios_backup_extractor/version.rb +1 -1
- data/lib/ios_backup_extractor.rb +1 -0
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c550f9eaaf8ec2f4415286b9ad41046ee675c0ed1f2f44ec8fc213fe0cd58649
|
4
|
+
data.tar.gz: 254cb6e8da6cb2a4eca3e72cfae3f8c0d0790d79cf577cd39b97d63011f9859a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a36b324df7b41043d8f426aaa78b7bbe75857932a9cee1cad9face7fac89d0ce2f1547eb93cab5466a2e8bc4a8c67dbdacaa0a2d9a2a81df8152d98a1ee4663e
|
7
|
+
data.tar.gz: 6213ac85292d7e844ab6586fa25eabbf4c694fece157d5d4fd1b7ae6b1ff2c71f1a239979b475bc8b4623fd159aaac22e81cfa1d8cb6d60b620cde4ae7463dad
|
data/exe/ios
CHANGED
@@ -58,6 +58,10 @@ OptionParser.new do |opts|
|
|
58
58
|
backup_options[:password] = q.to_s
|
59
59
|
end
|
60
60
|
|
61
|
+
opts.on('--temp FOLDER', 'Folder to use for creating temp files') do |q|
|
62
|
+
backup_options[:temp_folder] = q.to_s
|
63
|
+
end
|
64
|
+
|
61
65
|
opts.on('--serial SERIAL', 'Target a specific device by its serial number') do |q|
|
62
66
|
options[:serial_number] = q.to_s.strip
|
63
67
|
end
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_dependency 'aes_key_wrap'
|
24
24
|
spec.add_dependency 'CFPropertyList'
|
25
25
|
spec.add_dependency 'sqlite3'
|
26
|
-
spec.add_development_dependency 'bundler', '~>
|
27
|
-
spec.add_development_dependency 'rake', '~>
|
26
|
+
spec.add_development_dependency 'bundler', '~> 2.2'
|
27
|
+
spec.add_development_dependency 'rake', '~> 12.3.3'
|
28
28
|
spec.add_development_dependency 'rspec'
|
29
29
|
end
|
@@ -17,7 +17,7 @@ module IosBackupExtractor
|
|
17
17
|
continue unless infos.has? InfoPlist::PRODUCT_VERSION
|
18
18
|
major = infos.versions.first
|
19
19
|
if major <= 3
|
20
|
-
|
20
|
+
@backups << RawBackup3.new(File.dirname(path))
|
21
21
|
elsif major < 10
|
22
22
|
@backups << RawBackup4.new(File.dirname(path))
|
23
23
|
else
|
@@ -9,6 +9,7 @@ module IosBackupExtractor
|
|
9
9
|
def initialize(data, version_major, version_minor)
|
10
10
|
@version_major = version_major
|
11
11
|
@version_minor = version_minor
|
12
|
+
logger.debug(self.class.name) { "Keybag for backup of iOS #{@version_major}.#{@version_minor}" }
|
12
13
|
parse_binary_blob(data)
|
13
14
|
end
|
14
15
|
|
@@ -58,7 +59,7 @@ module IosBackupExtractor
|
|
58
59
|
def get_passcode_key_from_passcode(password)
|
59
60
|
raise 'This is not a backup/icloud keybag' unless @type == 1 or @type == 3
|
60
61
|
|
61
|
-
if @version_major == 10 && @version_minor < 2
|
62
|
+
if @version_major < 10 || (@version_major == 10 && @version_minor < 2)
|
62
63
|
return OpenSSL::PKCS5.pbkdf2_hmac_sha1(password, @attributes['SALT'], @attributes['ITER'], 32)
|
63
64
|
end
|
64
65
|
|
@@ -9,7 +9,6 @@ module IosBackupExtractor
|
|
9
9
|
@backup_directory = NauktisUtils::FileBrowser.ensure_valid_directory(backup_directory)
|
10
10
|
@info_plist = InfoPlist.new(File.join(@backup_directory, INFO_PLIST))
|
11
11
|
@manifest_plist = IosBackupExtractor.plist_file_to_hash(File.join(@backup_directory, MANIFEST_PLIST))
|
12
|
-
raise 'This looks like a very old backup (iOS 3?)' unless @manifest_plist.has_key? 'BackupKeyBag'
|
13
12
|
end
|
14
13
|
|
15
14
|
##
|
@@ -39,8 +38,8 @@ module IosBackupExtractor
|
|
39
38
|
raise "Backup destination already exists. #{parent_directory}" if File.exist? parent_directory
|
40
39
|
FileUtils.mkdir(parent_directory)
|
41
40
|
logger.info(self.class.name) { "Starting backup extraction in directory #{parent_directory}" }
|
42
|
-
copy_files(
|
43
|
-
add_files_with_extensions(
|
41
|
+
copy_files(parent_directory, options)
|
42
|
+
add_files_with_extensions(parent_directory)
|
44
43
|
logger.info(self.class.name) { "Backup extraction finished. #{IosBackupExtractor.file_count(parent_directory)} files extracted." }
|
45
44
|
parent_directory
|
46
45
|
end
|
@@ -5,12 +5,13 @@ module IosBackupExtractor
|
|
5
5
|
private
|
6
6
|
|
7
7
|
def load!(options = {})
|
8
|
+
raise 'This looks like a very old backup (iOS 3?)' unless @manifest_plist.has_key? 'BackupKeyBag'
|
8
9
|
super(options)
|
9
10
|
|
10
11
|
# Grab a copy of the Manifest database
|
11
12
|
manifest_dir = Dir.mktmpdir
|
12
13
|
major, minor = info_plist.versions
|
13
|
-
if is_encrypted?
|
14
|
+
if is_encrypted? && (major > 10 || (major == 10 && minor >= 2))
|
14
15
|
protection_class = @manifest_plist['ManifestKey'][0..3].unpack('V')[0]
|
15
16
|
key = @keybag.unwrap_key_for_class(protection_class, @manifest_plist['ManifestKey'][4..-1])
|
16
17
|
copy_enc_file_from_backup(MANIFEST_DB, File.join(manifest_dir, MANIFEST_DB), key)
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module IosBackupExtractor
|
2
|
+
class RawBackup3 < RawBackup
|
3
|
+
private
|
4
|
+
|
5
|
+
def load!(options = {})
|
6
|
+
unless @loaded
|
7
|
+
logger.debug(self.class.name) { 'Loading backup' }
|
8
|
+
logger.info(self.class.name) { "Files in the original backup directory #{IosBackupExtractor.file_count(@backup_directory)}" }
|
9
|
+
|
10
|
+
p @backup_directory
|
11
|
+
|
12
|
+
|
13
|
+
if @manifest_plist['IsEncrypted'] && @manifest_plist['IsEncrypted'] != 0
|
14
|
+
raise "Encrypted backup for iOS 3 and below are not supported."
|
15
|
+
end
|
16
|
+
|
17
|
+
@manifest_data = IosBackupExtractor.plist_data_to_hash(@manifest_plist['Data'])
|
18
|
+
@loaded = true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Copy a file from the backup to destination
|
23
|
+
def copy_files(destination_directory, options = {})
|
24
|
+
destination_directory = NauktisUtils::FileBrowser.ensure_valid_directory(destination_directory)
|
25
|
+
|
26
|
+
@manifest_data['Files'].each_pair do |key, value|
|
27
|
+
puts key
|
28
|
+
puts value
|
29
|
+
|
30
|
+
mdinfo_file = File.join(@backup_directory, "#{key}.mdinfo")
|
31
|
+
mdinfo_file = File.expand_path(mdinfo_file)
|
32
|
+
raise "File #{mdinfo_file} doesn't exist in your backup source" unless File.exists?(mdinfo_file)
|
33
|
+
|
34
|
+
mddata_file = File.join(@backup_directory, "#{key}.mddata")
|
35
|
+
mddata_file = File.expand_path(mddata_file)
|
36
|
+
raise "File #{mddata_file} doesn't exist in your backup source" unless File.exists?(mddata_file)
|
37
|
+
|
38
|
+
mdinfo = IosBackupExtractor.plist_file_to_hash(mdinfo_file)
|
39
|
+
|
40
|
+
domain, path = mdinfo['Domain'], mdinfo['Path']
|
41
|
+
if mdinfo['Metadata']
|
42
|
+
mdinfo_metadata = IosBackupExtractor.plist_data_to_hash(mdinfo['Metadata'])
|
43
|
+
domain, path = mdinfo_metadata['Domain'], mdinfo_metadata['Path']
|
44
|
+
end
|
45
|
+
|
46
|
+
p mdinfo
|
47
|
+
p mdinfo_metadata
|
48
|
+
|
49
|
+
destination = File.expand_path(File.join(destination_directory, domain, path))
|
50
|
+
copy_file_from_backup(mddata_file, destination)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_files_with_extensions(destination_directory)
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -5,6 +5,7 @@ module IosBackupExtractor
|
|
5
5
|
private
|
6
6
|
|
7
7
|
def load!(options = {})
|
8
|
+
raise 'This looks like a very old backup (iOS 3?)' unless @manifest_plist.has_key? 'BackupKeyBag'
|
8
9
|
super(options)
|
9
10
|
@mbdb = MBDB.new(File.join(@backup_directory, MANIFEST_MBDB))
|
10
11
|
end
|
@@ -19,31 +20,12 @@ module IosBackupExtractor
|
|
19
20
|
continue unless should_include?(f[:domain], f[:file_path], options)
|
20
21
|
|
21
22
|
destination = File.expand_path(File.join(destination_directory, f[:domain], f[:file_path]))
|
22
|
-
raise "File #{destination} already exists" if File.exists?(destination)
|
23
|
-
|
24
|
-
source = File.expand_path(File.join(@backup_directory, f[:file_id]))
|
25
|
-
raise "File #{source} doesn't exist in your backup source" unless File.exists?(source)
|
26
|
-
|
27
|
-
logger.debug(self.class.name) { "Extracting #{destination}" }
|
28
|
-
FileUtils.mkdir_p(File.dirname(destination))
|
29
23
|
|
30
24
|
if not f[:encryption_key].nil? and not @keybag.nil?
|
31
25
|
key = @keybag.unwrap_key_for_class(f[:protection_class], f[:encryption_key][4..-1])
|
32
|
-
|
33
|
-
cipher = OpenSSL::Cipher::AES256.new(:CBC)
|
34
|
-
cipher.decrypt
|
35
|
-
cipher.key = key
|
36
|
-
buf = ''
|
37
|
-
File.open(destination, 'wb') do |outf|
|
38
|
-
File.open(source, 'rb') do |inf|
|
39
|
-
while inf.read(4096, buf)
|
40
|
-
outf << cipher.update(buf)
|
41
|
-
end
|
42
|
-
outf << cipher.final
|
43
|
-
end
|
44
|
-
end
|
26
|
+
copy_enc_file_from_backup(f[:file_id], destination, key)
|
45
27
|
else
|
46
|
-
|
28
|
+
copy_file_from_backup(f[:file_id], destination)
|
47
29
|
end
|
48
30
|
end
|
49
31
|
end
|
data/lib/ios_backup_extractor.rb
CHANGED
@@ -13,6 +13,7 @@ require 'ios_backup_extractor/info_plist'
|
|
13
13
|
require 'ios_backup_extractor/mbdb'
|
14
14
|
require 'ios_backup_extractor/keybag'
|
15
15
|
require 'ios_backup_extractor/raw_backup'
|
16
|
+
require 'ios_backup_extractor/raw_backup3'
|
16
17
|
require 'ios_backup_extractor/raw_backup4'
|
17
18
|
require 'ios_backup_extractor/raw_backup10'
|
18
19
|
require 'ios_backup_extractor/backup_retriever'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ios_backup_extractor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nauktis
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nauktis_utils
|
@@ -86,28 +86,28 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '2.2'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '2.2'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: rake
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
103
|
+
version: 12.3.3
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
110
|
+
version: 12.3.3
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: rspec
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -148,12 +148,13 @@ files:
|
|
148
148
|
- lib/ios_backup_extractor/mbdb.rb
|
149
149
|
- lib/ios_backup_extractor/raw_backup.rb
|
150
150
|
- lib/ios_backup_extractor/raw_backup10.rb
|
151
|
+
- lib/ios_backup_extractor/raw_backup3.rb
|
151
152
|
- lib/ios_backup_extractor/raw_backup4.rb
|
152
153
|
- lib/ios_backup_extractor/version.rb
|
153
154
|
homepage: https://github.com/Nauktis/ios_backup_extractor
|
154
155
|
licenses: []
|
155
156
|
metadata: {}
|
156
|
-
post_install_message:
|
157
|
+
post_install_message:
|
157
158
|
rdoc_options: []
|
158
159
|
require_paths:
|
159
160
|
- lib
|
@@ -168,9 +169,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
168
169
|
- !ruby/object:Gem::Version
|
169
170
|
version: '0'
|
170
171
|
requirements: []
|
171
|
-
|
172
|
-
|
173
|
-
signing_key:
|
172
|
+
rubygems_version: 3.1.2
|
173
|
+
signing_key:
|
174
174
|
specification_version: 4
|
175
175
|
summary: Ruby script to extract iOS backups.
|
176
176
|
test_files: []
|