idb 2.1.0 → 2.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +7 -2
- data/lib/gui/app_details_group_box.rb +40 -72
- data/lib/gui/app_list_dialog.rb +10 -0
- data/lib/gui/app_tab_widget.rb +52 -0
- data/lib/gui/cache_db_widget.rb +7 -3
- data/lib/gui/device_info_group_box.rb +15 -6
- data/lib/gui/device_status_dialog.rb +4 -1
- data/lib/gui/fs_viewer_tab_widget.rb +38 -8
- data/lib/gui/global_app_details_group_box.rb +87 -0
- data/lib/gui/main_tab_widget.rb +16 -2
- data/lib/gui/plist_file_widget.rb +5 -1
- data/lib/gui/screenshot_wizard.rb +1 -1
- data/lib/gui/sqlite_widget.rb +8 -3
- data/lib/idb.rb +47 -48
- data/lib/idb/version.rb +1 -1
- data/lib/lib/CgBI.rb +18 -13
- data/lib/lib/app.rb +81 -14
- data/lib/lib/device.rb +28 -11
- data/lib/lib/ios8_last_launch_services_map_wrapper.rb +20 -0
- data/lib/lib/plist_util.rb +14 -1
- data/lib/lib/rsync_git_manager.rb +24 -20
- data/lib/lib/screen_shot_util.rb +4 -3
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64226ae62cd205643d25b1ba1864b5a54d163b4d
|
4
|
+
data.tar.gz: 40eeb316e70e2165a12c96ba7da69fc1932ac111
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 388da49012ccce3480ccc91fba98e7c8fddb384559a589b246d69000da16f0770f5792df830e628542645458002ab5ec6663828b931405740d01bf086aef3732
|
7
|
+
data.tar.gz: 9da5c592809bb8e364818d82d0e522d56155fb1d0610c0dcc583cc2169c184aecc7fe5fb106a209c363bca77123d30d13746c87e94b3305422e56d95869c0e5e
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
idb (2.
|
4
|
+
idb (2.5.0)
|
5
5
|
awesome_print
|
6
6
|
coderay
|
7
7
|
ffi
|
@@ -29,7 +29,7 @@ GEM
|
|
29
29
|
tilt
|
30
30
|
hexdump (0.2.3)
|
31
31
|
htmlentities (4.3.2)
|
32
|
-
launchy (2.4.
|
32
|
+
launchy (2.4.3)
|
33
33
|
addressable (~> 2.3)
|
34
34
|
libxml-ruby (2.7.0)
|
35
35
|
libxml4r (0.2.6)
|
data/README.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
[](http://badge.fury.io/rb/idb)
|
2
|
+
[](https://gemnasium.com/dmayer/idb)
|
3
|
+
[](https://codeclimate.com/github/dmayer/idb)
|
4
|
+
<img src="https://stats.cysec.org/piwik.php?idsite=2&rec=1" style="border:0" alt="" />
|
5
|
+
|
1
6
|
# Idb
|
2
7
|
|
3
8
|
idb is a tool to simplify some common tasks for iOS pentesting and research. Originally there was a command line version of the tool, but it is no longer under development so you should get the GUI version.
|
@@ -10,10 +15,10 @@ idb has some prerequisites. As it turns out, things like ruby and Qt are difficu
|
|
10
15
|
|
11
16
|
### 1. Prerequisites
|
12
17
|
#### 1.1 Ruby Environment
|
13
|
-
idb requires a valid ruby 1.9.3 or 2.1 installation. **Ruby 2.0 does not work properly** due to issues with qtbindings.
|
18
|
+
idb requires a valid ruby 1.9.3 or 2.1 installation and it is recommended to install the used ruby using [RVM](https://rvm.io/). **Ruby 2.0 does not work properly** due to issues with qtbindings.
|
14
19
|
|
15
20
|
**Important Note:** Shared library support is required! This is the default for many system rubies, but if you install a ruby via `rvm` or similar, you need to do one of the following:
|
16
|
-
* Under `rvm` use
|
21
|
+
* **Under `rvm` use `rvm install 2.1 --enable-shared` when installing ruby.**
|
17
22
|
* Under `ruby-install`/`chruby` use `-- --enable-shared` when installing ruby.
|
18
23
|
* Under `ruby-build`/`rbenv` with `ruby-build` use `CONFIGURE_OPTS=--enable-shared [command]` when installing Ruby.
|
19
24
|
|
@@ -3,7 +3,7 @@ require_relative '../lib/app'
|
|
3
3
|
module Idb
|
4
4
|
|
5
5
|
class AppDetailsGroupBox < Qt::GroupBox
|
6
|
-
attr_accessor :uuid, :bundle_id
|
6
|
+
attr_accessor :uuid, :bundle_id, :vals, :icon
|
7
7
|
signals "app_changed()"
|
8
8
|
signals "show_device_status()"
|
9
9
|
|
@@ -16,56 +16,6 @@ module Idb
|
|
16
16
|
setTitle "App Details"
|
17
17
|
|
18
18
|
|
19
|
-
@icon_button_layout = Qt::GridLayout.new
|
20
|
-
|
21
|
-
|
22
|
-
# select app
|
23
|
-
@select_app_button = Qt::PushButton.new "Select App..."
|
24
|
-
@select_app_button.setEnabled(false)
|
25
|
-
@select_app_button.connect(SIGNAL(:released)) { |x|
|
26
|
-
@app_list = AppListDialog.new
|
27
|
-
@app_list.connect(SIGNAL('accepted()')) {
|
28
|
-
$selected_app = @app_list.app_list.currentItem().app
|
29
|
-
@vals['uuid'].setText($selected_app.uuid)
|
30
|
-
@vals['bundle_id'].setText($selected_app.bundle_id)
|
31
|
-
@vals['bundle_name'].setText($selected_app.bundle_name)
|
32
|
-
@vals['url_handlers'].setText($selected_app.get_url_handlers.join("\n"))
|
33
|
-
@vals['platform_version'].setText($selected_app.platform_version)
|
34
|
-
@vals['sdk_version'].setText($selected_app.sdk_version)
|
35
|
-
@vals['minimum_os_version'].setText($selected_app.minimum_os_version)
|
36
|
-
@launch_app.setEnabled(true)
|
37
|
-
@open_folder.setEnabled(true)
|
38
|
-
|
39
|
-
begin
|
40
|
-
icon_file = $selected_app.get_icon_file
|
41
|
-
pixmap = Qt::Pixmap.new(icon_file)
|
42
|
-
@icon.setPixmap pixmap.scaledToWidth(50) unless icon_file.nil?
|
43
|
-
|
44
|
-
rescue => e
|
45
|
-
$log.error "Icon CONVERSION failed. #{e.message}"
|
46
|
-
@icon.setPixmap Qt::Pixmap.new
|
47
|
-
# lets ignore conversion errors for now..
|
48
|
-
end
|
49
|
-
|
50
|
-
emit app_changed()
|
51
|
-
}
|
52
|
-
|
53
|
-
@app_list.exec
|
54
|
-
}
|
55
|
-
|
56
|
-
|
57
|
-
@icon_button_widget = Qt::Widget.new self
|
58
|
-
@icon_button_widget.setLayout @icon_button_layout
|
59
|
-
|
60
|
-
@icon = Qt::Label.new
|
61
|
-
|
62
|
-
@icon_button_layout.addWidget @icon, 0, 0, 1, 1
|
63
|
-
@icon_button_layout.addWidget @select_app_button, 0, 1, 1, 3
|
64
|
-
@layout.addWidget @icon_button_widget, 0, 0, 1, 2
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
19
|
@labels = Hash.new
|
70
20
|
@vals = Hash.new
|
71
21
|
@cur_row = 1
|
@@ -77,6 +27,8 @@ module Idb
|
|
77
27
|
addDetail 'platform_version', 'Platform Version'
|
78
28
|
addDetail 'sdk_version', 'SDK Version'
|
79
29
|
addDetail 'minimum_os_version', 'Minimum OS'
|
30
|
+
addDetail 'keychain_access_groups', 'Keychain Access Groups'
|
31
|
+
addDetail 'data_dir', 'Data Directory'
|
80
32
|
|
81
33
|
@launch_app = Qt::PushButton.new "Launch App"
|
82
34
|
@launch_app.setEnabled(false)
|
@@ -106,17 +58,38 @@ module Idb
|
|
106
58
|
|
107
59
|
}
|
108
60
|
|
61
|
+
clear
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
def app_changed
|
66
|
+
@vals['uuid'].setText($selected_app.uuid)
|
67
|
+
@vals['bundle_id'].setText($selected_app.bundle_id)
|
68
|
+
@vals['bundle_name'].setText($selected_app.bundle_name)
|
69
|
+
@vals['url_handlers'].setText($selected_app.get_url_handlers.join("\n"))
|
70
|
+
@vals['platform_version'].setText($selected_app.platform_version)
|
71
|
+
@vals['sdk_version'].setText($selected_app.sdk_version)
|
72
|
+
@vals['minimum_os_version'].setText($selected_app.minimum_os_version)
|
73
|
+
@vals['keychain_access_groups'].setText($selected_app.keychain_access_groups)
|
74
|
+
@vals['data_dir'].setText($selected_app.data_directory.sub("/private/var/mobile/Containers/Data/Application",""))
|
75
|
+
@launch_app.setEnabled(true)
|
76
|
+
@open_folder.setEnabled(true)
|
77
|
+
|
78
|
+
|
79
|
+
|
109
80
|
end
|
110
81
|
|
111
82
|
def clear
|
112
83
|
$selected_app = nil
|
113
|
-
@vals['uuid'].setText("")
|
114
|
-
@vals['bundle_id'].setText("")
|
115
|
-
@vals['bundle_name'].setText("")
|
116
|
-
@vals['url_handlers'].setText("")
|
117
|
-
@vals['platform_version'].setText("")
|
118
|
-
@vals['sdk_version'].setText("")
|
119
|
-
@vals['minimum_os_version'].setText("")
|
84
|
+
@vals['uuid'].setText("[No Application Selected]")
|
85
|
+
@vals['bundle_id'].setText("[No Application Selected]")
|
86
|
+
@vals['bundle_name'].setText("[No Application Selected]")
|
87
|
+
@vals['url_handlers'].setText("[No Application Selected]")
|
88
|
+
@vals['platform_version'].setText("[No Application Selected]")
|
89
|
+
@vals['sdk_version'].setText("[No Application Selected]")
|
90
|
+
@vals['minimum_os_version'].setText("[No Application Selected]")
|
91
|
+
@vals['data_dir'].setText("[No Application Selected]")
|
92
|
+
@vals['keychain_access_groups'].setText("[No Application Selected]")
|
120
93
|
@launch_app.setEnabled(false)
|
121
94
|
@open_folder.setEnabled(false)
|
122
95
|
|
@@ -124,6 +97,8 @@ module Idb
|
|
124
97
|
|
125
98
|
|
126
99
|
|
100
|
+
|
101
|
+
|
127
102
|
def addDetail id, label
|
128
103
|
@labels[id] = Qt::Label.new "<b>#{label}</b>", self, 0
|
129
104
|
@vals[id] = Qt::Label.new "", self, 0
|
@@ -132,15 +107,6 @@ module Idb
|
|
132
107
|
@cur_row += 1
|
133
108
|
end
|
134
109
|
|
135
|
-
|
136
|
-
def enable_select_app
|
137
|
-
@select_app_button.setEnabled(true)
|
138
|
-
end
|
139
|
-
|
140
|
-
def disable_select_app
|
141
|
-
@select_app_button.setEnabled(false)
|
142
|
-
end
|
143
|
-
|
144
110
|
end
|
145
111
|
|
146
112
|
class AppBinaryGroupBox < Qt::GroupBox
|
@@ -180,6 +146,8 @@ module Idb
|
|
180
146
|
addDetail 'canaries', 'Stack Canaries'
|
181
147
|
addDetail 'arc', 'ARC'
|
182
148
|
|
149
|
+
clear
|
150
|
+
|
183
151
|
end
|
184
152
|
|
185
153
|
|
@@ -197,11 +165,11 @@ module Idb
|
|
197
165
|
end
|
198
166
|
|
199
167
|
def clear
|
200
|
-
@vals['encryption_enabled'].setText("")
|
201
|
-
@vals['cryptid'].setText("")
|
202
|
-
@vals['pie'].setText("")
|
203
|
-
@vals['canaries'].setText("")
|
204
|
-
@vals['arc'].setText("")
|
168
|
+
@vals['encryption_enabled'].setText("[Binary not yet analyzed]")
|
169
|
+
@vals['cryptid'].setText("[Binary not yet analyzed]")
|
170
|
+
@vals['pie'].setText("[Binary not yet analyzed]")
|
171
|
+
@vals['canaries'].setText("[Binary not yet analyzed]")
|
172
|
+
@vals['arc'].setText("[Binary not yet analyzed]")
|
205
173
|
end
|
206
174
|
|
207
175
|
def disable_analyze_binary
|
data/lib/gui/app_list_dialog.rb
CHANGED
@@ -41,6 +41,16 @@ module Idb
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def refresh_app_list
|
44
|
+
if $device.ios_version == 8
|
45
|
+
box = Qt::MessageBox.new 1, "Refreshing...", "Refreshing uicache to ensure app information is up-to-date. This may take a few seconds."
|
46
|
+
box.setStandardButtons(0)
|
47
|
+
box.show
|
48
|
+
box.raise
|
49
|
+
# need to refresh iOS uicache in case app was installed after last reboot.
|
50
|
+
# Otherwise the /var/mobile/Library/MobileInstallation/LastLaunchServicesMap.plist will be out of date
|
51
|
+
$device.ops.execute "/usr/bin/uicache"
|
52
|
+
box.hide
|
53
|
+
end
|
44
54
|
app_uuids = $device.get_app_uuids
|
45
55
|
progress = Qt::ProgressDialog.new "Reading App list...", nil, 1, app_uuids.size, self
|
46
56
|
progress.setAutoClose true
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Idb
|
2
|
+
class AppTabWidget < Qt::TabWidget
|
3
|
+
attr_accessor :app_details, :app_binary
|
4
|
+
signals "app_changed()"
|
5
|
+
signals "binary_analyzed()"
|
6
|
+
|
7
|
+
def initialize *args
|
8
|
+
super *args
|
9
|
+
|
10
|
+
@layout = Qt::GridLayout.new self
|
11
|
+
setLayout(@layout)
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
@layout.addWidget @select_app_button, 0,0
|
16
|
+
|
17
|
+
# Box for App details
|
18
|
+
@app_details = AppDetailsGroupBox.new @central_widget
|
19
|
+
@app_details.connect(SIGNAL(:show_device_status)) {
|
20
|
+
@device_status = DeviceStatusDialog.new
|
21
|
+
@device_status.exec
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
@layout.addWidget @app_details, 1,0, 2, 1
|
26
|
+
|
27
|
+
# App Binary Details
|
28
|
+
@app_binary = AppBinaryGroupBox.new @central_widget
|
29
|
+
@layout.addWidget @app_binary, 1,1
|
30
|
+
@app_binary.connect(SIGNAL('binary_analyzed()')) {
|
31
|
+
emit binary_analyzed()
|
32
|
+
}
|
33
|
+
|
34
|
+
@spacer_horizontal = Qt::SpacerItem.new 0,1, Qt::SizePolicy::Expanding, Qt::SizePolicy::Fixed
|
35
|
+
@layout.addItem @spacer_horizontal, 1, 2
|
36
|
+
|
37
|
+
@spacer = Qt::SpacerItem.new 0,1, Qt::SizePolicy::Fixed, Qt::SizePolicy::Expanding
|
38
|
+
|
39
|
+
@layout.addItem @spacer, 2, 1, 2,1
|
40
|
+
@layout.addItem @spacer, 3, 0
|
41
|
+
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def app_changed
|
46
|
+
@app_binary.app_changed
|
47
|
+
@app_details.app_changed
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
data/lib/gui/cache_db_widget.rb
CHANGED
@@ -20,9 +20,9 @@ module Idb
|
|
20
20
|
$log.error "File #{item.full_path} could not be downloaded. Either the file does not exist (e.g., dead symlink) or there is a permission problem."
|
21
21
|
else
|
22
22
|
if RbConfig::CONFIG['host_os'] =~ /linux/
|
23
|
-
Process.spawn "'#{$settings['sqlite_editor']}' '#{
|
23
|
+
Process.spawn "'#{$settings['sqlite_editor']}' '#{cache_name}'"
|
24
24
|
else
|
25
|
-
Process.spawn "open -a '#{$settings['sqlite_editor']}' '#{
|
25
|
+
Process.spawn "open -a '#{$settings['sqlite_editor']}' '#{cache_name}'"
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -50,7 +50,11 @@ module Idb
|
|
50
50
|
item.setText full_path.sub($selected_app.app_dir,'')
|
51
51
|
else
|
52
52
|
pc = $device.protection_class full_path
|
53
|
-
|
53
|
+
if full_path.start_with? $selected_app.app_dir
|
54
|
+
item.setText "[App Bundle]" + full_path.sub($selected_app.app_dir,'') + " => " + pc.strip
|
55
|
+
elsif full_path.start_with? $selected_app.data_dir
|
56
|
+
item.setText "[Data Dir]" + full_path.sub($selected_app.data_dir,'') + " => " + pc.strip
|
57
|
+
end
|
54
58
|
end
|
55
59
|
item.full_path = full_path
|
56
60
|
@list.addItem item
|
@@ -3,6 +3,7 @@ require_relative 'device_status_dialog'
|
|
3
3
|
module Idb
|
4
4
|
class DeviceInfoGroupBox < Qt::GroupBox
|
5
5
|
signals "disconnect()"
|
6
|
+
signals "connect_clicked()"
|
6
7
|
|
7
8
|
def initialize *args
|
8
9
|
super *args
|
@@ -12,19 +13,25 @@ module Idb
|
|
12
13
|
setLayout(@layout)
|
13
14
|
setTitle "Selected Device"
|
14
15
|
|
15
|
-
@device = Qt::Label.new "<b><font color='red'>Please select a device from the 'Devices' menu.</font></b>", self, 0
|
16
|
-
@layout.addWidget @device, 0, 0, 2,
|
16
|
+
@device = Qt::Label.new "<b><font color='red'>Please select a device from the 'Devices' menu or click 'Connect'.</font></b>", self, 0
|
17
|
+
@layout.addWidget @device, 0, 0, 2 ,1
|
18
|
+
@connect = Qt::PushButton.new "Connect to USB/SSH device"
|
19
|
+
@connect.connect(SIGNAL(:released)) {
|
20
|
+
emit connect_clicked()
|
21
|
+
}
|
22
|
+
@layout.addWidget @connect, 0,1,2,1
|
17
23
|
end
|
18
24
|
|
19
25
|
def update_device
|
20
26
|
if $device.device?
|
27
|
+
@connect.hide
|
21
28
|
uname = $device.ops.execute("/bin/uname -a")
|
22
29
|
ssh_connection_info = ""
|
23
30
|
if $device.mode == "usb"
|
24
31
|
ssh_connection_info = " "
|
25
|
-
@device.setText "<b>USB device:</b>
|
32
|
+
@device.setText "<b>USB device:</b> Manually connect via SSH as #{$settings.ssh_username}@localhost:#{$device.usb_ssh_port}"
|
26
33
|
else
|
27
|
-
@device.setText "<b>
|
34
|
+
@device.setText "<b>SSH device:</b> ssh://#{$settings.ssh_username}:[redacted]@#{$settings.ssh_host}:#{$settings.ssh_port}"
|
28
35
|
end
|
29
36
|
|
30
37
|
@status = Qt::PushButton.new "Status"
|
@@ -39,12 +46,14 @@ module Idb
|
|
39
46
|
$device.close unless $device.nil?
|
40
47
|
$device = nil
|
41
48
|
emit disconnect()
|
42
|
-
@disconnect.
|
43
|
-
@
|
49
|
+
@disconnect.hide
|
50
|
+
@connect.show
|
51
|
+
@status.hide
|
44
52
|
@device.setText("<b><font color='red'>Please select a device from the 'Devices' menu.</font></b>")
|
45
53
|
}
|
46
54
|
@layout.addWidget @disconnect, 1, 1
|
47
55
|
|
56
|
+
|
48
57
|
else
|
49
58
|
@device.setText "<b>Simulator:</b> #{$device.sim_dir}"
|
50
59
|
end
|
@@ -99,7 +99,10 @@ module Idb
|
|
99
99
|
else
|
100
100
|
@install_aptget = Qt::PushButton.new "Install"
|
101
101
|
@install_aptget.connect(SIGNAL(:released)) {
|
102
|
-
|
102
|
+
error = Qt::MessageBox.new
|
103
|
+
error.setText("Aptitude or apt-get must be installed on the device using Cydia.")
|
104
|
+
error.setIcon(Qt::MessageBox::Critical)
|
105
|
+
error.exec
|
103
106
|
if $device.apt_get_installed?
|
104
107
|
@install_aptget.hide
|
105
108
|
mark_apt_get_installed
|
@@ -15,7 +15,14 @@ module Idb
|
|
15
15
|
@rsync = Qt::PushButton.new "Rsync + Git"
|
16
16
|
@layout.addWidget @rsync, 0,0
|
17
17
|
@rsync.connect(SIGNAL :released) {
|
18
|
-
@manager.
|
18
|
+
@manager.start_new_revision
|
19
|
+
if $device.ios_version == 8
|
20
|
+
@manager.sync_dir $selected_app.app_dir, "app_bundle"
|
21
|
+
@manager.sync_dir $selected_app.data_dir, "data_bundle"
|
22
|
+
else
|
23
|
+
@manager.sync_dir $selected_app.app_dir, "app_bundle"
|
24
|
+
end
|
25
|
+
@manager.commit_new_revision
|
19
26
|
|
20
27
|
}
|
21
28
|
|
@@ -228,17 +235,40 @@ module Idb
|
|
228
235
|
tree_item
|
229
236
|
end
|
230
237
|
|
231
|
-
def
|
238
|
+
def update_start
|
232
239
|
@treeview.clear
|
240
|
+
@selected_dir = $selected_app.app_dir
|
241
|
+
@local_path = "#{$selected_app.cache_dir}/idb_mirror.git"
|
242
|
+
@manager = RsyncGitManager.new @local_path
|
243
|
+
|
244
|
+
if $device.ios_version == 8
|
245
|
+
start_ios_8
|
246
|
+
else
|
247
|
+
start_ios_pre8
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def start_ios_pre8
|
233
252
|
@root_node = Qt::TreeWidgetItem.new
|
234
|
-
@root_node.setText(0, "
|
253
|
+
@root_node.setText(0, "[App Bundle]")
|
235
254
|
@root_node.setChildIndicatorPolicy(Qt::TreeWidgetItem::ShowIndicator)
|
236
255
|
@treeview.addTopLevelItem @root_node
|
237
|
-
@
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
@
|
256
|
+
@root_node.setText(1, $selected_app.app_dir)
|
257
|
+
end
|
258
|
+
|
259
|
+
def start_ios_8
|
260
|
+
@bundle_root_node = Qt::TreeWidgetItem.new
|
261
|
+
@bundle_root_node.setText(0, "[App Bundle]")
|
262
|
+
@bundle_root_node.setChildIndicatorPolicy(Qt::TreeWidgetItem::ShowIndicator)
|
263
|
+
@bundle_root_node.setText(1, $selected_app.app_dir)
|
264
|
+
|
265
|
+
@data_root_node = Qt::TreeWidgetItem.new
|
266
|
+
@data_root_node.setText(0, "[Data Dir]")
|
267
|
+
@data_root_node.setChildIndicatorPolicy(Qt::TreeWidgetItem::ShowIndicator)
|
268
|
+
@data_root_node.setText(1, $selected_app.data_dir)
|
269
|
+
|
270
|
+
@treeview.addTopLevelItem @bundle_root_node
|
271
|
+
@treeview.addTopLevelItem @data_root_node
|
242
272
|
end
|
243
273
|
|
244
274
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
|
2
|
+
module Idb
|
3
|
+
class GlobalAppDetailsGroupBox < Qt::GroupBox
|
4
|
+
signals "app_changed()"
|
5
|
+
|
6
|
+
def initialize *args
|
7
|
+
super *args
|
8
|
+
|
9
|
+
# details on selected app
|
10
|
+
@layout = Qt::GridLayout.new
|
11
|
+
setLayout(@layout)
|
12
|
+
setTitle "Selected Application"
|
13
|
+
|
14
|
+
@app = Qt::Label.new "<b>Connect to a device first.</b>", self, 0
|
15
|
+
@layout.addWidget @app, 0, 0
|
16
|
+
|
17
|
+
@app_details = Qt::Widget.new
|
18
|
+
@app_details_layout = Qt::GridLayout.new
|
19
|
+
@app_details_layout.setContentsMargins(0,0,0,0)
|
20
|
+
|
21
|
+
@app_details.setLayout(@app_details_layout)
|
22
|
+
|
23
|
+
@icon = Qt::Label.new
|
24
|
+
@app_details_layout.addWidget @icon, 0, 0, 2,1
|
25
|
+
|
26
|
+
@selected_app_label = Qt::Label.new "<b>Selected App:</b>"
|
27
|
+
@selected_app = Qt::Label.new ""
|
28
|
+
@app_details_layout.addWidget @selected_app_label, 0, 1
|
29
|
+
@app_details_layout.addWidget @selected_app, 0,2
|
30
|
+
|
31
|
+
@uuid_label = Qt::Label.new "<b>UUID:</b>"
|
32
|
+
@uuid = Qt::Label.new ""
|
33
|
+
@app_details_layout.addWidget @uuid_label, 1, 1
|
34
|
+
@app_details_layout.addWidget @uuid, 1,2
|
35
|
+
|
36
|
+
@layout.addWidget @app_details, 0,0
|
37
|
+
@app_details.hide
|
38
|
+
|
39
|
+
|
40
|
+
@select_app_button = Qt::PushButton.new "Select App..."
|
41
|
+
@select_app_button.setEnabled(false)
|
42
|
+
@select_app_button.connect(SIGNAL(:released)) { |x|
|
43
|
+
@app_list = AppListDialog.new
|
44
|
+
@app_list.connect(SIGNAL('accepted()')) {
|
45
|
+
$selected_app = @app_list.app_list.currentItem().app
|
46
|
+
@selected_app.setText($selected_app.bundle_name + " (" + $selected_app.bundle_id + ")")
|
47
|
+
@uuid.setText($selected_app.uuid)
|
48
|
+
begin
|
49
|
+
icon_file = $selected_app.get_icon_file
|
50
|
+
pixmap = Qt::Pixmap.new(icon_file)
|
51
|
+
@icon.setPixmap pixmap.scaledToWidth(50) unless icon_file.nil?
|
52
|
+
|
53
|
+
rescue => e
|
54
|
+
$log.error "Icon CONVERSION failed. #{e.message}"
|
55
|
+
@icon.setPixmap Qt::Pixmap.new
|
56
|
+
# lets ignore conversion errors for now..
|
57
|
+
end
|
58
|
+
|
59
|
+
@app_details.show
|
60
|
+
@app.hide
|
61
|
+
emit app_changed()
|
62
|
+
}
|
63
|
+
@app_list.exec
|
64
|
+
}
|
65
|
+
|
66
|
+
@layout.addWidget @select_app_button, 0,1
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def disconnect
|
71
|
+
@app.setText("<b>Connect to a device first.</b>")
|
72
|
+
@app.show
|
73
|
+
@app_details.hide
|
74
|
+
@select_app_button.setEnabled(false)
|
75
|
+
end
|
76
|
+
|
77
|
+
def enable
|
78
|
+
@app.setText("<b><font color='red'>Please click the 'Select Application' button.</font></b>")
|
79
|
+
@app.show
|
80
|
+
@app_details.hide
|
81
|
+
@select_app_button.setEnabled(true)
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
data/lib/gui/main_tab_widget.rb
CHANGED
@@ -8,16 +8,25 @@ require_relative 'pasteboard_monitor_widget'
|
|
8
8
|
require_relative 'fs_viewer_tab_widget'
|
9
9
|
require_relative 'keychain_widget'
|
10
10
|
require_relative 'tool_widget'
|
11
|
+
require_relative 'app_tab_widget'
|
11
12
|
require 'Qt'
|
12
13
|
|
13
14
|
module Idb
|
14
15
|
class MainTabWidget < Qt::TabWidget
|
15
|
-
|
16
|
+
attr_accessor :app_info
|
16
17
|
|
17
18
|
def initialize *args
|
18
19
|
super *args
|
19
20
|
@tabs = Hash.new
|
20
21
|
|
22
|
+
|
23
|
+
@app_info = AppTabWidget.new self
|
24
|
+
@tabs[:app_info] = addTab(@app_info, "App Info")
|
25
|
+
@app_info.connect(SIGNAL('binary_analyzed()')) {
|
26
|
+
enableAppBinary
|
27
|
+
}
|
28
|
+
|
29
|
+
|
21
30
|
@local_storage = LocalStorageTabWidget.new self
|
22
31
|
@local_storage.setEnabled(false)
|
23
32
|
@tabs[:local_storage] = addTab(@local_storage, "Storage")
|
@@ -76,6 +85,10 @@ module Idb
|
|
76
85
|
disable_all
|
77
86
|
end
|
78
87
|
|
88
|
+
def enable_select_app
|
89
|
+
@app_info.enable_select_app
|
90
|
+
end
|
91
|
+
|
79
92
|
def enableLog
|
80
93
|
@log.setEnabled(true)
|
81
94
|
setTabEnabled(@tabs[:log], true)
|
@@ -165,8 +178,9 @@ module Idb
|
|
165
178
|
enableURLHandlers
|
166
179
|
# refresh_current_tab
|
167
180
|
@app_binary.refresh
|
181
|
+
@app_info.app_changed
|
168
182
|
enableFSViewer
|
169
|
-
@fs_viewer.
|
183
|
+
@fs_viewer.update_start
|
170
184
|
enableTools
|
171
185
|
@tools.enable_screenshot
|
172
186
|
|
@@ -52,7 +52,11 @@ module Idb
|
|
52
52
|
item.setText full_path.sub($selected_app.app_dir,'')
|
53
53
|
else
|
54
54
|
pc = $device.protection_class full_path
|
55
|
-
|
55
|
+
if full_path.start_with? $selected_app.app_dir
|
56
|
+
item.setText "[App Bundle]" + full_path.sub($selected_app.app_dir,'') + " => " + pc.strip
|
57
|
+
elsif full_path.start_with? $selected_app.data_dir
|
58
|
+
item.setText "[Data Dir]" + full_path.sub($selected_app.data_dir,'') + " => " + pc.strip
|
59
|
+
end
|
56
60
|
end
|
57
61
|
item.full_path = full_path
|
58
62
|
@list.addItem item
|
data/lib/gui/sqlite_widget.rb
CHANGED
@@ -20,13 +20,14 @@ module Idb
|
|
20
20
|
error.exec
|
21
21
|
else
|
22
22
|
cache_name = $selected_app.cache_file item.full_path
|
23
|
+
puts cache_name
|
23
24
|
if cache_name.nil?
|
24
25
|
$log.error "File #{item.full_path} could not be downloaded. Either the file does not exist (e.g., dead symlink) or there is a permission problem."
|
25
26
|
else
|
26
27
|
if RbConfig::CONFIG['host_os'] =~ /linux/
|
27
|
-
Process.spawn "'#{$settings['sqlite_editor']}' '#{
|
28
|
+
Process.spawn "'#{$settings['sqlite_editor']}' '#{cache_name}'"
|
28
29
|
else
|
29
|
-
Process.spawn "open -a '#{$settings['sqlite_editor']}' '#{
|
30
|
+
Process.spawn "open -a '#{$settings['sqlite_editor']}' '#{cache_name}'"
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
@@ -62,7 +63,11 @@ module Idb
|
|
62
63
|
item.setText full_path.sub($selected_app.app_dir,'')
|
63
64
|
else
|
64
65
|
pc = $device.protection_class full_path
|
65
|
-
|
66
|
+
if full_path.start_with? $selected_app.app_dir
|
67
|
+
item.setText "[App Bundle]" + full_path.sub($selected_app.app_dir,'') + " => " + pc.strip
|
68
|
+
elsif full_path.start_with? $selected_app.data_dir
|
69
|
+
item.setText "[Data Dir]" + full_path.sub($selected_app.data_dir,'') + " => " + pc.strip
|
70
|
+
end
|
66
71
|
end
|
67
72
|
|
68
73
|
item.full_path = full_path
|
data/lib/idb.rb
CHANGED
@@ -12,6 +12,7 @@ require_relative 'gui/main_tab_widget'
|
|
12
12
|
require_relative 'gui/settings_dialog'
|
13
13
|
require_relative 'gui/device_info_group_box'
|
14
14
|
require_relative 'gui/ca_manager_dialog'
|
15
|
+
require_relative 'gui/global_app_details_group_box'
|
15
16
|
|
16
17
|
module Idb
|
17
18
|
TARGET = "Hello"
|
@@ -69,9 +70,10 @@ module Idb
|
|
69
70
|
|
70
71
|
# center
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
|
73
|
+
self.showMaximized()
|
74
|
+
self.raise
|
75
|
+
self.activateWindow
|
76
|
+
|
75
77
|
end
|
76
78
|
|
77
79
|
def self.execute_in_main_thread(blocking = false, sleep_period = 0.001)
|
@@ -96,47 +98,47 @@ module Idb
|
|
96
98
|
|
97
99
|
@grid.setColumnMinimumWidth(0,450)
|
98
100
|
|
99
|
-
|
100
|
-
# Box for App details
|
101
|
-
@app_details = AppDetailsGroupBox.new @central_widget
|
102
|
-
@app_details.connect(SIGNAL(:app_changed)) {
|
103
|
-
@main_tabs.app_changed
|
104
|
-
@app_binary.app_changed
|
105
|
-
@menu_item_screenshot.setEnabled(true)
|
106
|
-
}
|
107
|
-
@app_details.connect(SIGNAL(:show_device_status)) {
|
108
|
-
@device_status = DeviceStatusDialog.new
|
109
|
-
@device_status.exec
|
110
|
-
}
|
111
|
-
|
112
|
-
|
113
|
-
@grid.addWidget @app_details, 0,0
|
114
|
-
|
115
|
-
# App Binary Details
|
116
|
-
@app_binary = AppBinaryGroupBox.new @central_widget
|
117
|
-
@grid.addWidget @app_binary, 1,0
|
118
|
-
@app_binary.connect(SIGNAL('binary_analyzed()')) {
|
119
|
-
@main_tabs.refresh_app_binary
|
120
|
-
}
|
121
|
-
|
122
|
-
@spacer = Qt::SpacerItem.new 0,1, Qt::SizePolicy::Fixed, Qt::SizePolicy::Expanding
|
123
|
-
@grid.addItem @spacer, 2,0
|
124
|
-
|
125
101
|
# Main Tab Widget
|
126
102
|
@main_tabs = MainTabWidget.new @central_widget
|
127
|
-
@grid.addWidget @main_tabs, 0,1,
|
103
|
+
@grid.addWidget @main_tabs, 4,0,1,2
|
104
|
+
|
128
105
|
|
129
106
|
# device Details
|
130
107
|
@device_details = DeviceInfoGroupBox.new @central_widget
|
108
|
+
@device_details.setSizePolicy Qt::SizePolicy::Expanding, Qt::SizePolicy::Fixed
|
109
|
+
@device_details.connect(SIGNAL(:connect_clicked)) {
|
110
|
+
@usb_device.trigger
|
111
|
+
}
|
131
112
|
@device_details.connect(SIGNAL :disconnect) {
|
132
113
|
@main_tabs.disable_all
|
133
|
-
@app_binary.clear
|
134
|
-
@app_binary.disable_analyze_binary
|
135
|
-
@app_details.clear
|
136
|
-
@app_details.disable_select_app
|
114
|
+
@main_tabs.app_info.app_binary.clear
|
115
|
+
@main_tabs.app_info.app_binary.disable_analyze_binary
|
116
|
+
@main_tabs.app_info.app_details.clear
|
137
117
|
@usb_device.setChecked(false)
|
118
|
+
@global_app_details.disconnect
|
119
|
+
}
|
120
|
+
@grid.addWidget @device_details, 0,0
|
121
|
+
|
122
|
+
|
123
|
+
# global app details
|
124
|
+
@global_app_details = GlobalAppDetailsGroupBox.new
|
125
|
+
@global_app_details.setSizePolicy Qt::SizePolicy::Expanding, Qt::SizePolicy::Fixed
|
126
|
+
@global_app_details.connect(SIGNAL :app_changed) {
|
127
|
+
@menu_item_screenshot.setEnabled(true)
|
128
|
+
@main_tabs.app_changed
|
138
129
|
}
|
139
|
-
@grid.addWidget @
|
130
|
+
@grid.addWidget @global_app_details, 0, 1
|
131
|
+
|
132
|
+
|
133
|
+
@spacer = Qt::SpacerItem.new 0,5, Qt::SizePolicy::Fixed, Qt::SizePolicy::Fixed
|
134
|
+
@grid.addItem @spacer, 1,0,1,2
|
135
|
+
@grid.addItem @spacer, 3,0,1,2
|
136
|
+
|
137
|
+
line = Qt::Frame.new
|
138
|
+
line.setFrameShape(Qt::Frame::HLine)
|
139
|
+
line.setFrameShadow(Qt::Frame::Sunken)
|
140
|
+
@grid.addWidget line,2,0,1,2
|
141
|
+
|
140
142
|
|
141
143
|
menu
|
142
144
|
|
@@ -161,8 +163,9 @@ module Idb
|
|
161
163
|
}
|
162
164
|
setting.exec
|
163
165
|
}
|
164
|
-
@menu_file =
|
166
|
+
@menu_file = Qt::Menu.new "&File"
|
165
167
|
@menu_file.addAction menu_item_settings
|
168
|
+
menuBar().addAction @menu_file.menuAction()
|
166
169
|
|
167
170
|
@menu_item_screenshot = Qt::Action.new "&Screenshot", self
|
168
171
|
@menu_item_screenshot.setEnabled(false)
|
@@ -175,15 +178,16 @@ module Idb
|
|
175
178
|
ca = CAManagerDialog.new self
|
176
179
|
ca.exec
|
177
180
|
}
|
178
|
-
@menu_tools =
|
181
|
+
@menu_tools = Qt::Menu.new "&Tools"
|
179
182
|
@menu_tools.addAction @menu_item_screenshot
|
180
183
|
@menu_tools.addAction @menu_item_cert
|
184
|
+
menuBar.addAction @menu_tools.menuAction
|
181
185
|
|
182
186
|
|
183
187
|
#Devices
|
184
188
|
@sim_group = Qt::ActionGroup.new @menu_devices
|
185
189
|
|
186
|
-
@menu_devices =
|
190
|
+
@menu_devices = Qt::Menu.new "&Devices"
|
187
191
|
@usb_device = Qt::Action.new "USB Device", self
|
188
192
|
if $settings['device_connection_mode'] == "ssh"
|
189
193
|
@usb_device.setText("SSH Device")
|
@@ -220,11 +224,7 @@ module Idb
|
|
220
224
|
@device_status = DeviceStatusDialog.new
|
221
225
|
@device_status.exec
|
222
226
|
end
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
@app_details.enable_select_app
|
227
|
+
@global_app_details.enable
|
228
228
|
@device_details.update_device
|
229
229
|
@menu_item_cert.setEnabled(true)
|
230
230
|
@main_tabs.enableDeviceFunctions
|
@@ -233,6 +233,8 @@ module Idb
|
|
233
233
|
|
234
234
|
progress.reset
|
235
235
|
}
|
236
|
+
|
237
|
+
|
236
238
|
menu_item = @menu_devices.addAction @usb_device
|
237
239
|
@sim_group.addAction @usb_device
|
238
240
|
|
@@ -254,12 +256,11 @@ module Idb
|
|
254
256
|
@menu_devices.addAction action
|
255
257
|
}
|
256
258
|
|
257
|
-
|
259
|
+
menuBar.addAction @menu_devices.menuAction()
|
258
260
|
|
259
261
|
|
260
262
|
end
|
261
263
|
|
262
|
-
|
263
264
|
def center
|
264
265
|
qdw = Qt::DesktopWidget.new
|
265
266
|
|
@@ -279,9 +280,7 @@ module Idb
|
|
279
280
|
app.setApplicationName("idb")
|
280
281
|
|
281
282
|
idb = Idb.new
|
282
|
-
idb
|
283
|
-
idb.showMaximized
|
284
|
-
idb.raise
|
283
|
+
app.setActiveWindow(idb)
|
285
284
|
app.exec
|
286
285
|
|
287
286
|
$log.info "Performing cleanup before exiting."
|
data/lib/idb/version.rb
CHANGED
data/lib/lib/CgBI.rb
CHANGED
@@ -39,12 +39,15 @@ module Idb
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def self.from_file(file_path)
|
42
|
+
|
42
43
|
self.new(File.open(file_path, 'rb') {|f| f.read})
|
43
44
|
end
|
44
45
|
|
45
46
|
def png
|
46
47
|
return @png if @png
|
47
48
|
|
49
|
+
all_idats = ""
|
50
|
+
|
48
51
|
#Convert from cgbi, set instance var, return
|
49
52
|
data = @cgbi.dup
|
50
53
|
png = ""
|
@@ -89,14 +92,14 @@ module Idb
|
|
89
92
|
#(1..@height).each do |y|
|
90
93
|
# Copy over the filter type byte on each line
|
91
94
|
# TODO: Might not be necessary for all filter types
|
92
|
-
|
95
|
+
all_idats << decompressed.slice!(0,1)
|
93
96
|
(1..@width).each do |x|
|
94
97
|
# BGRA => RGBA
|
95
98
|
b,g,r,a = decompressed.unpack("CCCC")
|
96
99
|
decompressed.slice!(0,4).split(//)
|
97
100
|
|
98
101
|
begin
|
99
|
-
|
102
|
+
all_idats += [r,g,b,a].pack("CCCC")
|
100
103
|
decompressed = nil if decompressed.length == 0
|
101
104
|
rescue => e
|
102
105
|
puts "Left: #{decompressed.inspect}"
|
@@ -104,20 +107,19 @@ module Idb
|
|
104
107
|
end
|
105
108
|
end
|
106
109
|
|
107
|
-
# Deflate the IDAT chunk
|
108
|
-
chunk[:type] = "IDAT"
|
109
|
-
chunk[:data] = Zlib::Deflate.deflate(chunk[:data])
|
110
|
-
chunk[:length] = [chunk[:data].length].pack("N")
|
111
|
-
chunk[:crc] = [Zlib::crc32('IDAT' + chunk[:data])].pack("N")
|
112
|
-
|
113
|
-
# store it away
|
114
|
-
png << chunk[:length]
|
115
|
-
png << chunk[:type]
|
116
|
-
png << chunk[:data]
|
117
|
-
png << chunk[:crc]
|
118
110
|
|
119
111
|
when "IEND"
|
120
112
|
raise "Data after IEND" unless data.empty?
|
113
|
+
|
114
|
+
#first write IDAT
|
115
|
+
# Deflate the IDAT chunk
|
116
|
+
compressed_idats = Zlib::Deflate.deflate(all_idats)
|
117
|
+
png << [compressed_idats.length].pack("N")
|
118
|
+
png << "IDAT"
|
119
|
+
png << compressed_idats
|
120
|
+
png << [Zlib::crc32('IDAT' + compressed_idats)].pack("N")
|
121
|
+
|
122
|
+
|
121
123
|
png << [chunk[:length]].pack("N")
|
122
124
|
png << chunk[:type]
|
123
125
|
png << chunk[:data]
|
@@ -150,4 +152,7 @@ module Idb
|
|
150
152
|
end
|
151
153
|
|
152
154
|
end
|
155
|
+
|
156
|
+
|
153
157
|
end
|
158
|
+
|
data/lib/lib/app.rb
CHANGED
@@ -1,18 +1,34 @@
|
|
1
1
|
require_relative 'plist_util'
|
2
2
|
require_relative 'app_binary'
|
3
3
|
require_relative 'CgBI'
|
4
|
+
require_relative 'ios8_last_launch_services_map_wrapper'
|
4
5
|
|
5
6
|
module Idb
|
6
7
|
class App
|
7
|
-
attr_accessor :uuid, :app_dir, :binary, :cache_dir
|
8
|
+
attr_accessor :uuid, :app_dir, :binary, :cache_dir, :data_dir
|
8
9
|
|
9
10
|
|
10
11
|
def initialize uuid
|
11
12
|
@uuid = uuid
|
12
|
-
@app_dir = "#{$device.apps_dir}/#{@uuid}"
|
13
13
|
@cache_dir = "#{$tmp_path}/#{uuid}"
|
14
14
|
FileUtils.mkdir_p @cache_dir unless Dir.exist? @cache_dir
|
15
|
+
|
16
|
+
@app_dir = "#{$device.apps_dir}/#{@uuid}"
|
15
17
|
parse_info_plist
|
18
|
+
|
19
|
+
if $device.ios_version == 8
|
20
|
+
mapping_file = "/var/mobile/Library/MobileInstallation/LastLaunchServicesMap.plist"
|
21
|
+
local_mapping_file = cache_file mapping_file
|
22
|
+
mapper = IOS8LastLaunchServicesMapWrapper.new local_mapping_file
|
23
|
+
|
24
|
+
@data_dir = mapper.data_path_by_bundle_id @info_plist.bundle_identifier
|
25
|
+
@keychain_access_groups = mapper.keychain_access_groups_by_bundle_id @info_plist.bundle_identifier
|
26
|
+
|
27
|
+
else
|
28
|
+
@data_dir = @app_dir
|
29
|
+
end
|
30
|
+
|
31
|
+
|
16
32
|
end
|
17
33
|
|
18
34
|
def analyze
|
@@ -113,26 +129,41 @@ module Idb
|
|
113
129
|
end
|
114
130
|
|
115
131
|
|
116
|
-
def
|
132
|
+
def find_icon
|
133
|
+
# lets try the easy way first...
|
117
134
|
icon_name = get_raw_plist_value('CFBundleIconFile')
|
135
|
+
if not icon_name.nil?
|
136
|
+
return icon_name
|
137
|
+
end
|
138
|
+
|
139
|
+
# lets try iphone icons
|
140
|
+
icon_name = get_raw_plist_value('CFBundleIcons')
|
141
|
+
unless icon_name.nil?
|
142
|
+
if not icon_name["CFBundlePrimaryIcon"].nil? and not icon_name["CFBundlePrimaryIcon"]["CFBundleIconFiles"].nil?
|
143
|
+
return icon_name["CFBundlePrimaryIcon"]["CFBundleIconFiles"].sort.last
|
144
|
+
end
|
145
|
+
end
|
118
146
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
icon_name
|
123
|
-
|
124
|
-
|
147
|
+
# lets try ipad icons
|
148
|
+
icon_name = get_raw_plist_value('CFBundleIcons~ipad')
|
149
|
+
unless icon_name.nil?
|
150
|
+
if not icon_name["CFBundlePrimaryIcon"].nil? and not icon_name["CFBundlePrimaryIcon"]["CFBundleIconFiles"].nil?
|
151
|
+
return icon_name["CFBundlePrimaryIcon"]["CFBundleIconFiles"].sort.last
|
152
|
+
end
|
125
153
|
end
|
154
|
+
end
|
126
155
|
|
156
|
+
def icon_path
|
127
157
|
app_dir = Shellwords.escape(@app_dir)
|
158
|
+
icon_name = find_icon
|
128
159
|
|
129
160
|
unless (icon_name[-4,4] == ".png")
|
130
161
|
$log.debug "Appending extension to #{icon_name}"
|
131
|
-
icon_name += "
|
162
|
+
icon_name += "*.png"
|
132
163
|
$log.debug "Now: #{icon_name}"
|
133
164
|
end
|
134
165
|
|
135
|
-
icon_file = $device.ops.execute("ls #{app_dir}/*app/#{icon_name}").strip
|
166
|
+
icon_file = $device.ops.execute("ls #{app_dir}/*app/#{icon_name}").split("\n").first.strip
|
136
167
|
|
137
168
|
if not $device.ops.file_exists? icon_file
|
138
169
|
$log.warn "Icon not found: #{icon_file}"
|
@@ -159,6 +190,22 @@ module Idb
|
|
159
190
|
get_raw_plist_value 'CFBundleDisplayName'
|
160
191
|
end
|
161
192
|
|
193
|
+
def keychain_access_groups
|
194
|
+
if @keychain_access_groups.nil?
|
195
|
+
"[iOS 8 specific]"
|
196
|
+
else
|
197
|
+
@keychain_access_groups.join "\n"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def data_directory
|
202
|
+
if $device.ios_version != 8
|
203
|
+
"[iOS 8 specific]"
|
204
|
+
else
|
205
|
+
@data_dir
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
162
209
|
def platform_version
|
163
210
|
get_raw_plist_value 'DTPlatformVersion'
|
164
211
|
end
|
@@ -207,17 +254,37 @@ module Idb
|
|
207
254
|
|
208
255
|
def find_plist_files
|
209
256
|
$log.info "Looking for plist files..."
|
210
|
-
$device.ops.dir_glob(@app_dir, "**/*plist")
|
257
|
+
app_dir_files = $device.ops.dir_glob(@app_dir, "**/*plist")
|
258
|
+
data_dir_files = Array.new
|
259
|
+
|
260
|
+
if app_dir != data_dir
|
261
|
+
data_dir_files = $device.ops.dir_glob(@data_dir, "**/*plist")
|
262
|
+
end
|
263
|
+
app_dir_files + data_dir_files
|
264
|
+
|
211
265
|
end
|
212
266
|
|
213
267
|
def find_sqlite_dbs
|
214
268
|
$log.info "Looking for sqlite files..."
|
215
|
-
$device.ops.dir_glob(@app_dir, "**/*sql**")
|
269
|
+
app_dir_files = $device.ops.dir_glob(@app_dir, "**/*sql**")
|
270
|
+
data_dir_files = Array.new
|
271
|
+
|
272
|
+
if app_dir != data_dir
|
273
|
+
data_dir_files = $device.ops.dir_glob(@data_dir, "**/*sql**")
|
274
|
+
end
|
275
|
+
app_dir_files + data_dir_files
|
276
|
+
|
216
277
|
end
|
217
278
|
|
218
279
|
def find_cache_dbs
|
219
280
|
$log.info "Looking for Cache.db files..."
|
220
|
-
$device.ops.dir_glob(@app_dir, "**/Cache.db")
|
281
|
+
app_dir_files = $device.ops.dir_glob(@app_dir, "**/Cache.db")
|
282
|
+
data_dir_files = Array.new
|
283
|
+
|
284
|
+
if app_dir != data_dir
|
285
|
+
data_dir_files = $device.ops.dir_glob(@data_dir, "**/Cache.db")
|
286
|
+
end
|
287
|
+
app_dir_files + data_dir_files
|
221
288
|
end
|
222
289
|
|
223
290
|
def get_url_handlers
|
data/lib/lib/device.rb
CHANGED
@@ -7,10 +7,11 @@ require_relative 'usb_muxd_wrapper'
|
|
7
7
|
|
8
8
|
module Idb
|
9
9
|
class Device < AbstractDevice
|
10
|
-
attr_accessor :usb_ssh_port, :mode, :tool_port
|
10
|
+
attr_accessor :usb_ssh_port, :mode, :tool_port, :ios_version
|
11
11
|
|
12
12
|
def initialize username, password, hostname, port
|
13
|
-
|
13
|
+
|
14
|
+
|
14
15
|
@username = username
|
15
16
|
@password = password
|
16
17
|
@hostname = hostname
|
@@ -58,6 +59,28 @@ module Idb
|
|
58
59
|
$log.debug "opening tool port #{@tool_port} for internal ssh connection"
|
59
60
|
@usbmuxd.proxy @tool_port, $settings['ssh_port']
|
60
61
|
|
62
|
+
|
63
|
+
|
64
|
+
@apps_dir_ios_pre8 = '/private/var/mobile/Applications'
|
65
|
+
@apps_dir_ios_8 = '/private/var/mobile/Containers/Bundle/Application'
|
66
|
+
@data_dir_ios_8 = '/private/var/mobile/Containers/Data/Application'
|
67
|
+
|
68
|
+
if @ops.directory? @apps_dir_ios_pre8
|
69
|
+
@ios_version = 7 # 7 or earlier
|
70
|
+
@apps_dir = @apps_dir_ios_pre8
|
71
|
+
@data_dir = @apps_dir_ios_pre8
|
72
|
+
|
73
|
+
elsif @ops.directory? @apps_dir_ios_8
|
74
|
+
@ios_version = 8
|
75
|
+
@apps_dir = @apps_dir_ios_8
|
76
|
+
@data_dir = @data_dir_ios_8
|
77
|
+
|
78
|
+
else
|
79
|
+
$log.error "Unsupported iOS Version."
|
80
|
+
raise
|
81
|
+
end
|
82
|
+
|
83
|
+
|
61
84
|
end
|
62
85
|
|
63
86
|
start_port_forwarding
|
@@ -329,23 +352,17 @@ module Idb
|
|
329
352
|
@ops.execute "killall -9 #{process_name}"
|
330
353
|
end
|
331
354
|
|
332
|
-
def
|
355
|
+
def device_id
|
356
|
+
|
333
357
|
$log.error "Not implemented"
|
334
358
|
nil
|
335
359
|
end
|
336
360
|
|
337
361
|
def configured?
|
338
|
-
|
339
|
-
false
|
340
|
-
elsif $settings['devices'][device_id].nil?
|
341
|
-
false
|
342
|
-
else
|
343
|
-
true
|
344
|
-
end
|
362
|
+
apt_get_installed? and open_installed? and openurl_installed? and dumpdecrypted_installed? and pbwatcher_installed? and pcviewer_installed? and keychain_dump_installed? and rsync_installed? and cycript_installed?
|
345
363
|
end
|
346
364
|
|
347
365
|
|
348
|
-
|
349
366
|
def cycript_installed?
|
350
367
|
is_installed? :cycript
|
351
368
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'plist4r'
|
2
|
+
|
3
|
+
class IOS8LastLaunchServicesMapWrapper
|
4
|
+
|
5
|
+
def initialize plist_file
|
6
|
+
@plist_file = plist_file
|
7
|
+
|
8
|
+
@plist_data = Plist4r.open @plist_file
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def data_path_by_bundle_id bundle_id
|
13
|
+
@plist_data.to_hash["User"][bundle_id]["Container"]
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def keychain_access_groups_by_bundle_id bundle_id
|
18
|
+
@plist_data.to_hash["User"][bundle_id]["Entitlements"]["keychain-access-groups"]
|
19
|
+
end
|
20
|
+
end
|
data/lib/lib/plist_util.rb
CHANGED
@@ -13,7 +13,10 @@ module Idb
|
|
13
13
|
|
14
14
|
@plutil = Pathname.new("/usr/bin/plutil")
|
15
15
|
if(!@plutil.exist?)
|
16
|
-
|
16
|
+
@plutil = Pathname.new("/usr/bin/plistutil")
|
17
|
+
if(!@plutil.exist?)
|
18
|
+
raise "plutil not found at #{@plutil}. aborting."
|
19
|
+
end
|
17
20
|
end
|
18
21
|
|
19
22
|
parse_plist_file
|
@@ -31,6 +34,15 @@ module Idb
|
|
31
34
|
puts CodeRay.scan(doc.to_xml(:indent => 2), :xml).terminal
|
32
35
|
end
|
33
36
|
|
37
|
+
def get_with_regex regex
|
38
|
+
ap @plist_data.to_hash
|
39
|
+
a = @plist_data.to_hash.find { |x|
|
40
|
+
not (x =~ regex).nil?
|
41
|
+
}
|
42
|
+
ap a
|
43
|
+
a
|
44
|
+
end
|
45
|
+
|
34
46
|
private
|
35
47
|
def parse_plist_file
|
36
48
|
$log.info 'Parsing plist file..'
|
@@ -68,5 +80,6 @@ module Idb
|
|
68
80
|
|
69
81
|
|
70
82
|
|
83
|
+
|
71
84
|
end
|
72
85
|
end
|
@@ -4,8 +4,7 @@ require 'expect'
|
|
4
4
|
|
5
5
|
module Idb
|
6
6
|
class RsyncGitManager
|
7
|
-
def initialize
|
8
|
-
@remote_path = remote_path
|
7
|
+
def initialize local_path
|
9
8
|
@local_path = local_path
|
10
9
|
FileUtils.mkdir_p @local_path unless Dir.exist? @local_path
|
11
10
|
|
@@ -27,23 +26,15 @@ module Idb
|
|
27
26
|
end
|
28
27
|
end
|
29
28
|
|
30
|
-
def sync_new_revision
|
31
|
-
$log.info "Hard resetting work dir #{@local_path}..."
|
32
|
-
begin
|
33
|
-
@g.reset_hard
|
34
|
-
rescue
|
35
|
-
$log.error "Reset of repo failed. If this is the first time you run rsync+git for this app this may be okay."
|
36
|
-
end
|
37
|
-
|
38
|
-
|
39
29
|
|
30
|
+
def sync_dir remote, local_relative
|
31
|
+
local = @local_path + "/" + local_relative
|
40
32
|
if $settings['device_connection_mode'] == "ssh"
|
41
|
-
cmd = "rsync -avz -e 'ssh -oStrictHostKeyChecking=no -p #{$settings.ssh_port}' #{$settings.ssh_username}@#{$settings.ssh_host}:#{Shellwords.escape(
|
33
|
+
cmd = "rsync -avz -e 'ssh -oStrictHostKeyChecking=no -p #{$settings.ssh_port}' #{$settings.ssh_username}@#{$settings.ssh_host}:#{Shellwords.escape(remote)}/ #{Shellwords.escape(local)}/"
|
42
34
|
else
|
43
|
-
cmd = "rsync -avz -e 'ssh -oStrictHostKeyChecking=no -p #{$device.tool_port}' root@localhost:#{Shellwords.escape(
|
35
|
+
cmd = "rsync -avz -e 'ssh -oStrictHostKeyChecking=no -p #{$device.tool_port}' root@localhost:#{Shellwords.escape(remote)}/ #{Shellwords.escape(local)}/"
|
44
36
|
end
|
45
37
|
|
46
|
-
|
47
38
|
$log.info "Executing rsync command #{cmd}"
|
48
39
|
begin
|
49
40
|
PTY.spawn(cmd) { |rsync_out, rsync_in, pid |
|
@@ -67,15 +58,28 @@ module Idb
|
|
67
58
|
PTY.check
|
68
59
|
}
|
69
60
|
rescue
|
70
|
-
$log.info "Rsync Done. committing to git."
|
71
|
-
@g.add(:all=>true)
|
72
|
-
begin
|
73
|
-
@g.commit_all("Snapshot from #{Time.now.to_s}")
|
74
|
-
rescue
|
75
|
-
end
|
76
61
|
end
|
77
62
|
|
78
63
|
end
|
79
64
|
|
65
|
+
|
66
|
+
def commit_new_revision
|
67
|
+
$log.info "Rsync Done. committing to git."
|
68
|
+
@g.add(:all=>true)
|
69
|
+
begin
|
70
|
+
@g.commit_all("Snapshot from #{Time.now.to_s}")
|
71
|
+
rescue
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def start_new_revision
|
76
|
+
$log.info "Hard resetting work dir #{@local_path}..."
|
77
|
+
begin
|
78
|
+
@g.reset_hard
|
79
|
+
rescue
|
80
|
+
$log.error "Reset of repo failed. If this is the first time you run rsync+git for this app this may be okay."
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
80
84
|
end
|
81
85
|
end
|
data/lib/lib/screen_shot_util.rb
CHANGED
@@ -3,9 +3,10 @@ require_relative 'ssh_operations'
|
|
3
3
|
module Idb
|
4
4
|
class ScreenShotUtil
|
5
5
|
|
6
|
-
def initialize
|
7
|
-
@
|
8
|
-
|
6
|
+
def initialize data_path, ops, sim = true
|
7
|
+
@data_path = data_path
|
8
|
+
ap @data_path
|
9
|
+
@snapshot_path = "#{@data_path}/Library/Caches/Snapshots"
|
9
10
|
@ops = ops
|
10
11
|
@sim = sim
|
11
12
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: idb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel A. Mayer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -258,6 +258,7 @@ files:
|
|
258
258
|
- lib/gui/app_details_group_box.rb
|
259
259
|
- lib/gui/app_list_dialog.rb
|
260
260
|
- lib/gui/app_list_widget_item.rb
|
261
|
+
- lib/gui/app_tab_widget.rb
|
261
262
|
- lib/gui/binary_strings_widget.rb
|
262
263
|
- lib/gui/browse_filesystem_widget.rb
|
263
264
|
- lib/gui/ca_manager_dialog.rb
|
@@ -270,6 +271,7 @@ files:
|
|
270
271
|
- lib/gui/device_status_dialog.rb
|
271
272
|
- lib/gui/file_system_events_widget.rb
|
272
273
|
- lib/gui/fs_viewer_tab_widget.rb
|
274
|
+
- lib/gui/global_app_details_group_box.rb
|
273
275
|
- lib/gui/i_device_syslog_thread.rb
|
274
276
|
- lib/gui/images/check.png
|
275
277
|
- lib/gui/images/folder.ico
|
@@ -318,6 +320,7 @@ files:
|
|
318
320
|
- lib/lib/device_ca_interface.rb
|
319
321
|
- lib/lib/host_file_wrapper.rb
|
320
322
|
- lib/lib/i_device_diagnostics_wrapper.rb
|
323
|
+
- lib/lib/ios8_last_launch_services_map_wrapper.rb
|
321
324
|
- lib/lib/keychain_plist_parser.rb
|
322
325
|
- lib/lib/local_operations.rb
|
323
326
|
- lib/lib/otool_wrapper.rb
|