idevice 1.1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/.gitignore +18 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +4 -0
  4. data/NOTICE +202 -0
  5. data/README.md +74 -0
  6. data/Rakefile +37 -0
  7. data/examples/idevimgmount +58 -0
  8. data/examples/idumplockdownvalues +64 -0
  9. data/examples/ifetchcrashreports +54 -0
  10. data/examples/ilistapps +38 -0
  11. data/examples/ilistudids +26 -0
  12. data/examples/ilog +35 -0
  13. data/examples/installipa +51 -0
  14. data/examples/iremoveapp +42 -0
  15. data/examples/irestart +26 -0
  16. data/examples/iscreenshotr +39 -0
  17. data/idevice.gemspec +33 -0
  18. data/lib/idevice.rb +69 -0
  19. data/lib/idevice/afc.rb +518 -0
  20. data/lib/idevice/c.rb +129 -0
  21. data/lib/idevice/diagnostics_relay.rb +185 -0
  22. data/lib/idevice/file_relay.rb +83 -0
  23. data/lib/idevice/heartbeat.rb +99 -0
  24. data/lib/idevice/house_arrest.rb +138 -0
  25. data/lib/idevice/idevice.rb +208 -0
  26. data/lib/idevice/image_mounter.rb +117 -0
  27. data/lib/idevice/installation_proxy.rb +193 -0
  28. data/lib/idevice/lockdown.rb +350 -0
  29. data/lib/idevice/misagent.rb +112 -0
  30. data/lib/idevice/mobilebackup.rb +183 -0
  31. data/lib/idevice/mobilebackup2.rb +174 -0
  32. data/lib/idevice/mobilesync.rb +306 -0
  33. data/lib/idevice/notification_proxy.rb +168 -0
  34. data/lib/idevice/plist.rb +366 -0
  35. data/lib/idevice/restore.rb +176 -0
  36. data/lib/idevice/sbservices.rb +152 -0
  37. data/lib/idevice/screenshotr.rb +88 -0
  38. data/lib/idevice/version.rb +3 -0
  39. data/lib/idevice/webinspector.rb +96 -0
  40. data/spec/afc_devicespec.rb +409 -0
  41. data/spec/diagnostics_relay_devicespec.rb +125 -0
  42. data/spec/file_relay_devicespec.rb +45 -0
  43. data/spec/heartbeat_devicespec.rb +39 -0
  44. data/spec/idevice_devicespec.rb +93 -0
  45. data/spec/idevice_spec.rb +29 -0
  46. data/spec/image_mounter_devicespec.rb +65 -0
  47. data/spec/installation_proxy_devicespec.rb +54 -0
  48. data/spec/lockdown_devicespec.rb +106 -0
  49. data/spec/misagent_devicespec.rb +43 -0
  50. data/spec/mobilebackup2_devicespec.rb +58 -0
  51. data/spec/mobilebackup_devicespec.rb +41 -0
  52. data/spec/mobilesync_devicespec.rb +62 -0
  53. data/spec/notification_proxy_devicespec.rb +45 -0
  54. data/spec/plist_spec.rb +176 -0
  55. data/spec/restore_devicespec.rb +72 -0
  56. data/spec/samples/plist.bin +0 -0
  57. data/spec/samples/plist.xml +10 -0
  58. data/spec/sbservices_devicespec.rb +64 -0
  59. data/spec/screenshotr_devicespec.rb +39 -0
  60. data/spec/spec_helper.rb +73 -0
  61. data/spec/webinspector_devicespec.rb +36 -0
  62. metadata +233 -0
@@ -0,0 +1,138 @@
1
+ #
2
+ # Copyright (c) 2013 Eric Monti - Bluebox Security
3
+ #
4
+ # Licensed to the Apache Software Foundation (ASF) under one
5
+ # or more contributor license agreements. See the NOTICE file
6
+ # distributed with this work for additional information
7
+ # regarding copyright ownership. The ASF licenses this file
8
+ # to you under the Apache License, Version 2.0 (the
9
+ # "License"); you may not use this file except in compliance
10
+ # with the License. You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing,
15
+ # software distributed under the License is distributed on an
16
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17
+ # KIND, either express or implied. See the License for the
18
+ # specific language governing permissions and limitations
19
+ # under the License.
20
+
21
+ require 'idevice/c'
22
+ require 'idevice/idevice'
23
+ require 'idevice/lockdown'
24
+ require 'idevice/plist'
25
+
26
+ module Idevice
27
+ class HouseArrestError < IdeviceLibError
28
+ end
29
+
30
+ class HouseArrestClient < C::ManagedOpaquePointer
31
+ include LibHelpers
32
+
33
+ def self.release(ptr)
34
+ C.house_arrest_client_free(ptr) unless ptr.null?
35
+ end
36
+
37
+ def self.attach(opts={})
38
+ _attach_helper("com.apple.mobile.house_arrest", opts) do |idevice, ldsvc, p_ha|
39
+ err = C.house_arrest_client_new(idevice, ldsvc, p_ha)
40
+ raise HouseArrestError, "house_arrest error: #{err}" if err != :SUCCESS
41
+ ha = p_ha.read_pointer
42
+ raise HouseArrestError, "house_arrest_client_new returned a NULL house_arrest_client_t pointer" if ha.null?
43
+ return new(ha)
44
+ end
45
+ end
46
+
47
+ def send_request(dict)
48
+ err = C.house_arrest_send_request(self, dict.to_plist_t)
49
+ raise HouseArrestError, "house_arrest error: #{err}" if err != :SUCCESS
50
+ return true
51
+ end
52
+
53
+ def send_command(command, appid)
54
+ err = C.house_arrest_send_command(self, command, appid)
55
+ raise HouseArrestError, "house_arrest error: #{err}" if err != :SUCCESS
56
+ return true
57
+ end
58
+
59
+ def get_result
60
+ FFI::MemoryPointer.new(:pointer) do |p_result|
61
+ err = C.house_arrest_get_result(self, p_result)
62
+ raise HouseArrestError, "house_arrest error: #{err}" if err != :SUCCESS
63
+ result = p_result.read_pointer.read_plist_t
64
+ raise HouseArrestError, "house_arrest_get_result returned a null plist_t" if result.nil?
65
+ return result
66
+ end
67
+ end
68
+
69
+ def vend_container(appid)
70
+ send_command("VendContainer", appid)
71
+ res = get_result
72
+ if res["Error"]
73
+ raise HouseArrestError, "Error vending container to appid: #{appid} - #{res.inspect}"
74
+ end
75
+ end
76
+
77
+ def vend_documents(appid)
78
+ send_command("VendDocuments", appid)
79
+ res = get_result
80
+ if res["Error"]
81
+ raise HouseArrestError, "Error vending documents to appid: #{appid} - #{res.inspect}"
82
+ end
83
+ end
84
+
85
+ def afc_client
86
+ FFI::MemoryPointer.new(:pointer) do |p_afc|
87
+ err = C.afc_client_new_from_house_arrest_client(self, p_afc)
88
+ raise AFCError, "AFC Error: #{err}" if err != :SUCCESS
89
+ afc = p_afc.read_pointer
90
+ raise AFCError, "afc_client_new_from_house_arrest_client returned a NULL afc_client_t pointer" if afc.null?
91
+ cli = AFCClient.new(afc)
92
+
93
+ # save a reference to ourselves in the afc client to avoid premature garbage collection...
94
+ cli.instance_variable_set(:@house_arrest, self)
95
+ return cli
96
+ end
97
+ end
98
+
99
+ def afc_client_for_container(appid)
100
+ vend_container(appid)
101
+ return afc_client
102
+ end
103
+
104
+ def afc_client_for_documents(appid)
105
+ vend_documents(appid)
106
+ return afc_client
107
+ end
108
+ end
109
+
110
+ module C
111
+ ffi_lib 'imobiledevice'
112
+
113
+ typedef enum(
114
+ :SUCCESS , 0,
115
+ :INVALID_ARG , -1,
116
+ :PLIST_ERROR , -2,
117
+ :CONN_FAILED , -3,
118
+ :INVALID_MODE , -4,
119
+ :UNKNOWN_ERROR , -256,
120
+ ), :house_arrest_error_t
121
+
122
+ #house_arrest_error_t house_arrest_client_new(idevice_t device, lockdownd_service_descriptor_t service, house_arrest_client_t *client);
123
+ attach_function :house_arrest_client_new, [Idevice, LockdownServiceDescriptor, :pointer], :house_arrest_error_t
124
+
125
+ #house_arrest_error_t house_arrest_client_free(house_arrest_client_t client);
126
+ attach_function :house_arrest_client_free, [HouseArrestClient], :house_arrest_error_t
127
+
128
+ #house_arrest_error_t house_arrest_send_request(house_arrest_client_t client, plist_t dict);
129
+ attach_function :house_arrest_send_request, [HouseArrestClient, Plist_t], :house_arrest_error_t
130
+
131
+ #house_arrest_error_t house_arrest_send_command(house_arrest_client_t client, const char *command, const char *appid);
132
+ attach_function :house_arrest_send_command, [HouseArrestClient, :string, :string], :house_arrest_error_t
133
+
134
+ #house_arrest_error_t house_arrest_get_result(house_arrest_client_t client, plist_t *dict);
135
+ attach_function :house_arrest_get_result, [HouseArrestClient, :pointer], :house_arrest_error_t
136
+
137
+ end
138
+ end
@@ -0,0 +1,208 @@
1
+ #
2
+ # Copyright (c) 2013 Eric Monti - Bluebox Security
3
+ #
4
+ # Licensed to the Apache Software Foundation (ASF) under one
5
+ # or more contributor license agreements. See the NOTICE file
6
+ # distributed with this work for additional information
7
+ # regarding copyright ownership. The ASF licenses this file
8
+ # to you under the Apache License, Version 2.0 (the
9
+ # "License"); you may not use this file except in compliance
10
+ # with the License. You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing,
15
+ # software distributed under the License is distributed on an
16
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17
+ # KIND, either express or implied. See the License for the
18
+ # specific language governing permissions and limitations
19
+ # under the License.
20
+
21
+ require 'ffi'
22
+ require 'idevice/c'
23
+ require 'stringio'
24
+
25
+ module Idevice
26
+ class IdeviceLibError < StandardError
27
+ end
28
+
29
+ class Idevice < C::ManagedOpaquePointer
30
+ def self.release(ptr)
31
+ C.idevice_free(ptr) unless ptr.null?
32
+ end
33
+
34
+ # Use this instead of 'new' to attach to an idevice using libimobiledevice
35
+ # and instantiate a new idevice_t handle
36
+ def self.attach(opts={})
37
+ @udid = opts[:udid]
38
+
39
+ FFI::MemoryPointer.new(:pointer) do |tmpptr|
40
+ err = C.idevice_new(tmpptr, @udid)
41
+ raise IdeviceLibError, "Idevice error: #{err}" if err != :SUCCESS
42
+
43
+ idevice_t = tmpptr.read_pointer
44
+ if idevice_t.null?
45
+ raise IdeviceLibError, "idevice_new created a null pointer"
46
+ else
47
+ return new(tmpptr.read_pointer)
48
+ end
49
+ end
50
+ end
51
+
52
+ def udid
53
+ return @udid if @udid
54
+
55
+ @udid = nil
56
+ FFI::MemoryPointer.new(:pointer) do |udid_ptr|
57
+ err = C.idevice_get_udid(self, udid_ptr)
58
+ raise IdeviceLibError, "Idevice error: #{err}" if err != :SUCCESS
59
+ unless udid_ptr.read_pointer.null?
60
+ @udid = udid_ptr.read_pointer.read_string
61
+ C.free(udid_ptr.read_pointer)
62
+ end
63
+ end
64
+ return @udid
65
+ end
66
+
67
+ def handle
68
+ @handle = nil
69
+ FFI::MemoryPointer.new(:uint32) do |tmpptr|
70
+ err = C.idevice_get_handle(self, tmpptr)
71
+ raise IdeviceLibError, "Idevice error: #{err}" if err != :SUCCESS
72
+ return tmpptr.read_uint32
73
+ end
74
+ end
75
+
76
+ def connect port
77
+ IdeviceConnection.connect(self, port)
78
+ end
79
+ end
80
+
81
+ class IdeviceConnection < C::ManagedOpaquePointer
82
+ def self.release(ptr)
83
+ C.idevice_disconnect(ptr) unless ptr.null? or ptr.disconnected?
84
+ end
85
+
86
+ def self.connect(idevice, port)
87
+ FFI::MemoryPointer.new(:pointer) do |tmpptr|
88
+ err = C.idevice_connect(idevice, port, tmpptr)
89
+ raise IdeviceLibError, "Idevice error: #{err}" if err != :SUCCESS
90
+ idev_connection = tmpptr.read_pointer
91
+ if idev_connection.null?
92
+ raise IdeviceLibError, "idevice_connect returned a null idevice_connection_t"
93
+ else
94
+ return new(idev_connection)
95
+ end
96
+ end
97
+ end
98
+
99
+ def disconnect
100
+ err = C.idevice_disconnect(self)
101
+ raise IdeviceLibError, "Idevice error: #{err}" if err != :SUCCESS
102
+ @_disconnected = true
103
+ nil
104
+ end
105
+
106
+ def connected?
107
+ not disconnected?
108
+ end
109
+
110
+ def disconnected?
111
+ @_disconnected == true
112
+ end
113
+
114
+ def send_data(data)
115
+ FFI::MemoryPointer.from_bytes(data) do |data_ptr|
116
+ FFI::MemoryPointer.new(:uint32) do |sent_bytes|
117
+ begin
118
+ err = C.idevice_connection_send(self, data_ptr, data_ptr.size, sent_bytes)
119
+ raise IdeviceLibError, "Idevice error: #{err}" if err != :SUCCESS
120
+ sent = sent_bytes.read_uint32
121
+ break if sent == 0
122
+ data_ptr += sent
123
+ end while data_ptr.size > 0
124
+ end
125
+ end
126
+ return
127
+ end
128
+
129
+ DEFAULT_RECV_TIMEOUT = 0
130
+ DEFAULT_RECV_CHUNKSZ = 8192
131
+ # blocking read - optionally yields to a block with each chunk read
132
+ def receive_all(timeout=nil, chunksz=nil)
133
+ timeout ||= DEFAULT_RECV_TIMEOUT
134
+ chunksz ||= DEFAULT_RECV_CHUNKSZ
135
+ recvdata = StringIO.new unless block_given?
136
+
137
+ FFI::MemoryPointer.new(chunksz) do |data_ptr|
138
+ FFI::MemoryPointer.new(:uint32) do |recv_bytes|
139
+ while (ierr=C.idevice_connection_receive_timeout(self, data_ptr, data_ptr.size, recv_bytes, timeout)) == :SUCCESS
140
+ chunk = data_ptr.read_bytes(recv_bytes.read_uint32)
141
+ if block_given?
142
+ yield chunk
143
+ else
144
+ recvdata << chunk
145
+ end
146
+ end
147
+
148
+ # UNKNOWN_ERROR seems to indicate end of data/connection
149
+ raise IdeviceLibError, "Idevice error: #{ierr}" if ierr != :UNKNOWN_ERROR
150
+ end
151
+ end
152
+
153
+ return recvdata.string unless block_given?
154
+ end
155
+
156
+ # read up to maxlen bytes
157
+ def receive_data(maxlen, timeout=nil)
158
+ timeout ||= DEFAULT_RECV_TIMEOUT
159
+ recvdata = StringIO.new
160
+
161
+ FFI::MemoryPointer.new(maxlen) do |data_ptr|
162
+ FFI::MemoryPointer.new(:uint32) do |recv_bytes|
163
+ # one-shot, read up to max-len and we're done
164
+ err = C.idevice_connection_receive_timeout(self, data_ptr, data_ptr.size, recv_bytes, timeout)
165
+ raise IdeviceLibError, "Idevice error: #{err}" if err != :SUCCESS
166
+ recvdata << data_ptr.read_bytes(recv_bytes.read_uint32)
167
+ end
168
+ end
169
+ return recvdata.string
170
+ end
171
+ end
172
+
173
+ module C
174
+ ffi_lib 'imobiledevice'
175
+
176
+ typedef enum(
177
+ :SUCCESS, 0,
178
+ :INVALID_ARG, -1,
179
+ :UNKNOWN_ERROR, -2,
180
+ :NO_DEVICE, -3,
181
+ :NOT_ENOUGH_DATA, -4,
182
+ :BAD_HEADER, -5,
183
+ :SSL_ERROR, -6,
184
+ ), :idevice_error_t
185
+
186
+ # discovery (synchronous)
187
+ attach_function :idevice_set_debug_level, [:int], :void
188
+ attach_function :idevice_get_device_list, [:pointer, :pointer], :idevice_error_t
189
+ attach_function :idevice_device_list_free, [:pointer], :idevice_error_t
190
+
191
+ # device structure creation and destruction
192
+ attach_function :idevice_new, [:pointer, :string], :idevice_error_t
193
+ attach_function :idevice_free, [:pointer], :idevice_error_t
194
+
195
+ # connection/disconnection
196
+ attach_function :idevice_connect, [Idevice, :uint16, :pointer], :idevice_error_t
197
+ attach_function :idevice_disconnect, [IdeviceConnection], :idevice_error_t
198
+
199
+ # communication
200
+ attach_function :idevice_connection_send, [IdeviceConnection, :pointer, :uint32, :pointer], :idevice_error_t
201
+ attach_function :idevice_connection_receive_timeout, [IdeviceConnection, :pointer, :uint32, :pointer, :uint], :idevice_error_t
202
+ attach_function :idevice_connection_receive, [IdeviceConnection, :pointer, :uint32, :pointer], :idevice_error_t
203
+
204
+ # misc
205
+ attach_function :idevice_get_handle, [Idevice, :pointer], :idevice_error_t
206
+ attach_function :idevice_get_udid, [Idevice, :pointer], :idevice_error_t
207
+ end
208
+ end
@@ -0,0 +1,117 @@
1
+ #
2
+ # Copyright (c) 2013 Eric Monti - Bluebox Security
3
+ #
4
+ # Licensed to the Apache Software Foundation (ASF) under one
5
+ # or more contributor license agreements. See the NOTICE file
6
+ # distributed with this work for additional information
7
+ # regarding copyright ownership. The ASF licenses this file
8
+ # to you under the Apache License, Version 2.0 (the
9
+ # "License"); you may not use this file except in compliance
10
+ # with the License. You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing,
15
+ # software distributed under the License is distributed on an
16
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17
+ # KIND, either express or implied. See the License for the
18
+ # specific language governing permissions and limitations
19
+ # under the License.
20
+
21
+ require 'idevice/c'
22
+ require 'idevice/plist'
23
+ require 'idevice/idevice'
24
+ require 'idevice/lockdown'
25
+
26
+
27
+ module Idevice
28
+ class ImageMounterError < IdeviceLibError
29
+ end
30
+
31
+ # Used to mount developer/debug disk images on the device.
32
+ class ImageMounterClient < C::ManagedOpaquePointer
33
+ include LibHelpers
34
+
35
+ def self.release(ptr)
36
+ C.mobile_image_mounter_free(ptr) unless ptr.null?
37
+ end
38
+
39
+ def self.attach(opts={})
40
+ _attach_helper("com.apple.mobile.mobile_image_mounter", opts) do |idevice, ldsvc, p_mim|
41
+ err = C.mobile_image_mounter_new(idevice, ldsvc, p_mim)
42
+ raise ImageMounterError, "ImageMounter error: #{err}" if err != :SUCCESS
43
+
44
+ mim = p_mim.read_pointer
45
+ raise ImageMounterError, "mobile_image_mounter_new returned a NULL client" if mim.null?
46
+ return new(mim)
47
+ end
48
+ end
49
+
50
+ def is_mounted?(image_type="Developer")
51
+ ret = lookup_image(image_type)
52
+ return (ret["ImagePresent"] == true)
53
+ end
54
+
55
+ def lookup_image(image_type="Developer")
56
+ FFI::MemoryPointer.new(:pointer) do |p_result|
57
+ err = C.mobile_image_mounter_lookup_image(self, image_type, p_result)
58
+ raise ImageMounterError, "ImageMounter error: #{err}" if err != :SUCCESS
59
+
60
+ result = p_result.read_pointer.read_plist_t
61
+ raise ImageMounterError, "mobile_image_mounter_lookup_image returned a NULL result" if result.nil?
62
+
63
+ return result
64
+ end
65
+ end
66
+
67
+ def mount_image(path, signature, image_type="Developer")
68
+ signature = signature.dup.force_encoding('binary')
69
+ FFI::MemoryPointer.from_bytes(signature) do |p_signature|
70
+ FFI::MemoryPointer.new(:pointer) do |p_result|
71
+ err = C.mobile_image_mounter_mount_image(self, path, p_signature, p_signature.size, image_type, p_result)
72
+ raise ImageMounterError, "ImageMounter error: #{err}" if err != :SUCCESS
73
+
74
+ result = p_result.read_pointer.read_plist_t
75
+ raise ImageMounterError, "mobile_image_mounter_mount_image returned a NULL result" if result.nil?
76
+
77
+ return result
78
+ end
79
+ end
80
+ end
81
+
82
+ def hangup
83
+ err = C.mobile_image_mounter_hangup(self)
84
+ raise ImageMounterError, "ImageMounter error: #{err}" if err != :SUCCESS
85
+
86
+ return true
87
+ end
88
+ end
89
+
90
+ module C
91
+ ffi_lib 'imobiledevice'
92
+
93
+ typedef enum(
94
+ :SUCCESS , 0,
95
+ :INVALID_ARG , -1,
96
+ :PLIST_ERROR , -2,
97
+ :CONN_FAILED , -3,
98
+ :UNKNOWN_ERROR, -256,
99
+ ), :image_mounter_error_t
100
+
101
+ #mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t service, mobile_image_mounter_client_t *client);
102
+ attach_function :mobile_image_mounter_new, [Idevice, LockdownServiceDescriptor, :pointer], :image_mounter_error_t
103
+
104
+ #mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client);
105
+ attach_function :mobile_image_mounter_free, [ImageMounterClient], :image_mounter_error_t
106
+
107
+ #mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, const char *image_type, plist_t *result);
108
+ attach_function :mobile_image_mounter_lookup_image, [ImageMounterClient, :string, :pointer], :image_mounter_error_t
109
+
110
+ #mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, const char *image_path, const char *image_signature, uint16_t signature_length, const char *image_type, plist_t *result);
111
+ attach_function :mobile_image_mounter_mount_image, [ImageMounterClient, :string, :pointer, :uint16, :string, :pointer], :image_mounter_error_t
112
+
113
+ #mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client);
114
+ attach_function :mobile_image_mounter_hangup, [ImageMounterClient], :image_mounter_error_t
115
+
116
+ end
117
+ end