idevice 1.1.5.0

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.
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