idb 2.1.0 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/idb.svg)](http://badge.fury.io/rb/idb)
|
2
|
+
[![Dependency Status](https://gemnasium.com/dmayer/idb.png)](https://gemnasium.com/dmayer/idb)
|
3
|
+
[![Code Climate](https://codeclimate.com/github/dmayer/idb.png)](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
|