CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/parser/apple_backup_manifestdb.rb
Views: 1904
1
# -*- coding: binary -*-
2
#
3
# This is a Ruby port of the Python manifest parsing code posted to:
4
# http://stackoverflow.com/questions/3085153/how-to-parse-the-manifest-mbdb-file-in-an-ios-4-0-itunes-backup/3130860#3130860
5
#
6
7
module Rex
8
module Parser
9
class AppleBackupManifestDB
10
11
attr_accessor :entry_offsets
12
attr_accessor :entries
13
attr_accessor :mbdb, :mbdx
14
attr_accessor :mbdb_data, :mbdx_data
15
attr_accessor :mbdb_offset, :mbdx_offset
16
17
def initialize(mbdb_data, mbdx_data)
18
self.entries = {}
19
self.entry_offsets = {}
20
self.mbdb_data = mbdb_data
21
self.mbdx_data = mbdx_data
22
parse_mbdb
23
parse_mbdx
24
end
25
26
def self.from_files(mbdb_file, mbdx_file)
27
mbdb_data = ""
28
::File.open(mbdb_file, "rb") {|fd| mbdb_data = fd.read(fd.stat.size) }
29
mbdx_data = ""
30
::File.open(mbdx_file, "rb") {|fd| mbdx_data = fd.read(fd.stat.size) }
31
32
self.new(mbdb_data, mbdx_data)
33
end
34
35
def parse_mbdb
36
raise ArgumentError, "Not valid MBDB data" if self.mbdb_data[0,4] != "mbdb"
37
self.mbdb_offset = 4
38
self.mbdb_offset = self.mbdb_offset + 2 # Maps to \x05 \x00 (unknown)
39
40
while self.mbdb_offset < self.mbdb_data.length
41
info = {}
42
info[:start_offset] = self.mbdb_offset
43
info[:domain] = mbdb_read_string
44
info[:filename] = mbdb_read_string
45
info[:linktarget] = mbdb_read_string
46
info[:datahash] = mbdb_read_string
47
info[:unknown1] = mbdb_read_string
48
info[:mode] = mbdb_read_int(2)
49
info[:unknown2] = mbdb_read_int(4)
50
info[:unknown3] = mbdb_read_int(4)
51
info[:uid] = mbdb_read_int(4)
52
info[:gid] = mbdb_read_int(4)
53
info[:mtime] = ::Time.at(mbdb_read_int(4))
54
info[:atime] = ::Time.at(mbdb_read_int(4))
55
info[:ctime] = ::Time.at(mbdb_read_int(4))
56
info[:length] = mbdb_read_int(8)
57
info[:flag] = mbdb_read_int(1)
58
property_count = mbdb_read_int(1)
59
info[:properties] = {}
60
1.upto(property_count) do |i|
61
k = mbdb_read_string
62
v = mbdb_read_string
63
info[:properties][k] = v
64
end
65
self.entry_offsets[ info[:start_offset] ] = info
66
end
67
self.mbdb_data = ""
68
end
69
70
def parse_mbdx
71
raise ArgumentError, "Not a valid MBDX file" if self.mbdx_data[0,4] != "mbdx"
72
73
self.mbdx_offset = 4
74
self.mbdx_offset = self.mbdx_offset + 2 # Maps to \x02 \x00 (unknown)
75
76
file_count = mbdx_read_int(4)
77
78
while self.mbdx_offset < self.mbdx_data.length
79
file_id = self.mbdx_data[self.mbdx_offset, 20].unpack("C*").map{|c| "%02x" % c}.join
80
self.mbdx_offset += 20
81
entry_offset = mbdx_read_int(4) + 6
82
mode = mbdx_read_int(2)
83
entry = entry_offsets[ entry_offset ]
84
# May be corrupted if there is no matching entry, but what to do about it?
85
next if not entry
86
self.entries[file_id] = entry.merge({:mbdx_mode => mode, :file_id => file_id})
87
end
88
self.mbdx_data = ""
89
end
90
91
def mbdb_read_string
92
raise RuntimeError, "Corrupted MBDB file" if self.mbdb_offset > self.mbdb_data.length
93
len = self.mbdb_data[self.mbdb_offset, 2].unpack("n")[0]
94
self.mbdb_offset += 2
95
return '' if len == 65535
96
val = self.mbdb_data[self.mbdb_offset, len]
97
self.mbdb_offset += len
98
return val
99
end
100
101
def mbdb_read_int(size)
102
val = 0
103
size.downto(1) do |i|
104
val = (val << 8) + self.mbdb_data[self.mbdb_offset, 1].unpack("C")[0]
105
self.mbdb_offset += 1
106
end
107
val
108
end
109
110
def mbdx_read_string
111
raise RuntimeError, "Corrupted MBDX file" if self.mbdx_offset > self.mbdx_data.length
112
len = self.mbdx_data[self.mbdx_offset, 2].unpack("n")[0]
113
self.mbdx_offset += 2
114
return '' if len == 65535
115
val = self.mbdx_data[self.mbdx_offset, len]
116
self.mbdx_offset += len
117
return val
118
end
119
120
def mbdx_read_int(size)
121
val = 0
122
size.downto(1) do |i|
123
val = (val << 8) + self.mbdx_data[self.mbdx_offset, 1].unpack("C")[0]
124
self.mbdx_offset += 1
125
end
126
val
127
end
128
end
129
130
131
end
132
end
133
134