idb 2.9.0 → 2.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +30 -0
- data/Gemfile.lock +5 -0
- data/idb.gemspec +1 -0
- data/lib/gui/app_binary_tab_widget.rb +7 -14
- data/lib/gui/app_details_group_box.rb +63 -88
- data/lib/gui/app_list_dialog.rb +29 -35
- data/lib/gui/app_list_widget_item.rb +1 -5
- data/lib/gui/app_tab_widget.rb +17 -22
- data/lib/gui/binary_strings_widget.rb +7 -15
- data/lib/gui/ca_manager_dialog.rb +32 -54
- data/lib/gui/cache_db_widget.rb +21 -26
- data/lib/gui/certificate_item.rb +2 -2
- data/lib/gui/default_protection_class_group_widget.rb +7 -12
- data/lib/gui/device_info_group_box.rb +26 -23
- data/lib/gui/main_tab_widget.rb +2 -21
- data/lib/gui/shared_libraries_widget.rb +1 -1
- data/lib/gui/sqlite_widget.rb +1 -3
- data/lib/gui/weak_class_dump_widget.rb +1 -1
- data/lib/idb.rb +3 -3
- data/lib/idb/version.rb +1 -1
- data/lib/lib/abstract_device.rb +7 -11
- data/lib/lib/app.rb +49 -59
- data/lib/lib/app_binary.rb +18 -29
- data/lib/lib/ca_interface.rb +46 -59
- data/lib/lib/device.rb +68 -155
- data/lib/lib/device_ca_interface.rb +7 -13
- data/lib/lib/host_file_wrapper.rb +6 -8
- data/lib/lib/ios8_last_launch_services_map_wrapper.rb +11 -18
- data/lib/lib/local_operations.rb +24 -32
- data/lib/lib/otool_wrapper.rb +30 -33
- data/lib/lib/rsync_git_manager.rb +26 -22
- data/lib/lib/screen_shot_util.rb +20 -28
- data/lib/lib/settings.rb +14 -17
- data/lib/lib/simulator.rb +11 -16
- data/lib/lib/simulator_ca_interface.rb +1 -3
- data/lib/lib/ssh_operations.rb +49 -65
- data/lib/lib/ssh_port_forwarder.rb +9 -13
- data/lib/lib/tools.rb +3 -3
- data/lib/lib/url_scheme_fuzzer.rb +41 -49
- data/lib/lib/usb_muxd_wrapper.rb +6 -8
- data/lib/lib/weak_class_dump_wrapper.rb +15 -16
- metadata +19 -9
- data/lib/gui/console_widget.rb +0 -163
- data/lib/gui/cycript_console_widget.rb +0 -68
- data/lib/gui/cycript_thread.rb +0 -81
- data/lib/lib/console_launcher.rb +0 -24
- data/lib/lib/i_device_diagnostics_wrapper.rb +0 -90
- data/lib/lib/snoop_it_wrapper.rb +0 -80
@@ -2,35 +2,29 @@ require_relative 'ca_interface'
|
|
2
2
|
|
3
3
|
module Idb
|
4
4
|
class DeviceCAInterface < CAInterface
|
5
|
-
|
6
|
-
def initialize device
|
5
|
+
def initialize(device)
|
7
6
|
@device = device
|
8
7
|
@device_store_path = "/private/var/Keychains/TrustStore.sqlite3"
|
9
8
|
base_path = "#{$tmp_path}/device"
|
10
9
|
FileUtils.mkdir_p base_path
|
11
10
|
@db_path = "#{base_path}/TrustStore.sqlite3"
|
12
|
-
|
13
|
-
|
14
11
|
end
|
15
12
|
|
16
|
-
|
17
|
-
def get_certs
|
13
|
+
def certs
|
18
14
|
@device.ops.download @device_store_path, @db_path
|
19
15
|
super
|
20
16
|
end
|
21
17
|
|
22
|
-
def remove_cert
|
23
|
-
FileUtils.copy_file @db_path, "#{@db_path}-#{Time.now
|
18
|
+
def remove_cert(cert)
|
19
|
+
FileUtils.copy_file @db_path, "#{@db_path}-#{Time.now}"
|
24
20
|
super cert
|
25
21
|
@device.ops.upload @db_path, @device_store_path
|
26
22
|
end
|
27
23
|
|
28
|
-
def add_cert
|
29
|
-
FileUtils.copy_file @db_path, "#{@db_path}-#{Time.now
|
24
|
+
def add_cert(cert_file)
|
25
|
+
FileUtils.copy_file @db_path, "#{@db_path}-#{Time.now}"
|
30
26
|
super cert_file
|
31
27
|
@device.ops.upload @db_path, @device_store_path
|
32
28
|
end
|
33
|
-
|
34
|
-
|
35
29
|
end
|
36
|
-
end
|
30
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Idb
|
2
2
|
class HostFileWrapper
|
3
|
-
|
4
3
|
def initialize
|
5
4
|
@cache_path = "#{$tmp_path}/device/hosts"
|
6
5
|
end
|
@@ -9,19 +8,18 @@ module Idb
|
|
9
8
|
FileUtils.mkpath "#{$tmp_path}/device" unless File.directory? "#{$tmp_path}/device"
|
10
9
|
$device.ops.download "/etc/hosts", @cache_path
|
11
10
|
begin
|
12
|
-
File.open(@cache_path,"r").read
|
11
|
+
File.open(@cache_path, "r").read
|
13
12
|
rescue
|
14
|
-
|
13
|
+
$log.error "Could not open #{@cache_path}"
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
18
|
-
def save
|
17
|
+
def save(text)
|
19
18
|
# upload
|
20
|
-
File.open(@cache_path,"w")
|
19
|
+
File.open(@cache_path, "w") do |f|
|
21
20
|
f.puts text
|
22
|
-
|
21
|
+
end
|
23
22
|
$device.ops.upload(@cache_path, "/etc/hosts")
|
24
|
-
|
25
23
|
end
|
26
24
|
end
|
27
|
-
end
|
25
|
+
end
|
@@ -1,32 +1,25 @@
|
|
1
1
|
require 'plist4r'
|
2
2
|
|
3
3
|
class IOS8LastLaunchServicesMapWrapper
|
4
|
-
|
5
|
-
def initialize plist_file
|
4
|
+
def initialize(plist_file)
|
6
5
|
@plist_file = plist_file
|
7
6
|
|
8
7
|
@plist_data = Plist4r.open @plist_file
|
9
8
|
end
|
10
9
|
|
11
|
-
def entitlements_by_bundle_id
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
$log.error "Could not read entitlements.."
|
16
|
-
end
|
10
|
+
def entitlements_by_bundle_id(bundle_id)
|
11
|
+
@plist_data.to_hash["User"][bundle_id]["Entitlements"]
|
12
|
+
rescue
|
13
|
+
$log.error "Could not read entitlements.."
|
17
14
|
end
|
18
15
|
|
19
|
-
|
20
|
-
def data_path_by_bundle_id bundle_id
|
16
|
+
def data_path_by_bundle_id(bundle_id)
|
21
17
|
@plist_data.to_hash["User"][bundle_id]["Container"]
|
22
18
|
end
|
23
19
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
rescue
|
29
|
-
""
|
30
|
-
end
|
20
|
+
def keychain_access_groups_by_bundle_id(bundle_id)
|
21
|
+
@plist_data.to_hash["User"][bundle_id]["Entitlements"]["keychain-access-groups"]
|
22
|
+
rescue
|
23
|
+
""
|
31
24
|
end
|
32
|
-
end
|
25
|
+
end
|
data/lib/lib/local_operations.rb
CHANGED
@@ -1,67 +1,59 @@
|
|
1
1
|
module Idb
|
2
2
|
class LocalOperations
|
3
|
-
|
4
|
-
|
5
|
-
def file? path
|
3
|
+
def file?(path)
|
6
4
|
File.file? path
|
7
5
|
end
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
return true
|
7
|
+
def download(a, b)
|
8
|
+
FileUtils.copy_file(a, b)
|
9
|
+
true
|
13
10
|
end
|
14
11
|
|
15
|
-
|
16
|
-
|
17
|
-
File.directory? path
|
12
|
+
def directory?(path)
|
13
|
+
File.directory? path
|
18
14
|
end
|
19
15
|
|
20
|
-
def mtime
|
16
|
+
def mtime(path)
|
21
17
|
File.mtime path
|
22
18
|
end
|
23
19
|
|
24
|
-
def open
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
return false
|
32
|
-
end
|
20
|
+
def open(path)
|
21
|
+
Launchy.open path
|
22
|
+
return true
|
23
|
+
rescue StandardError => e
|
24
|
+
$log.error "Could not open file #{path}: #{e.message}"
|
25
|
+
$log.error e.backtrace
|
26
|
+
return false
|
33
27
|
end
|
34
28
|
|
35
|
-
def list_dir
|
29
|
+
def list_dir(path)
|
36
30
|
Dir.entries path
|
37
31
|
end
|
38
32
|
|
39
|
-
def list_dir_full
|
33
|
+
def list_dir_full(path)
|
40
34
|
Dir.entries path
|
41
35
|
end
|
42
36
|
|
43
|
-
def dir_glob
|
37
|
+
def dir_glob(path, pattern)
|
44
38
|
full_path = "#{path}/#{pattern}"
|
45
39
|
Dir.glob(full_path)
|
46
40
|
end
|
47
41
|
|
48
|
-
def file_exists?
|
49
|
-
File.
|
42
|
+
def file_exists?(file)
|
43
|
+
File.exist? file
|
50
44
|
end
|
51
45
|
|
52
|
-
def execute
|
46
|
+
def execute(cmd)
|
53
47
|
`#{cmd}`
|
54
48
|
end
|
55
49
|
|
56
|
-
def execute_fork
|
50
|
+
def execute_fork(cmd)
|
57
51
|
(pid = fork) ? Process.detach(pid) : exec(cmd)
|
58
52
|
end
|
59
53
|
|
60
|
-
def launch_app
|
54
|
+
def launch_app(command, app)
|
61
55
|
$log.info "Executing #{command} #{app}"
|
62
|
-
|
56
|
+
execute_fork("#{command} \"#{app}\"")
|
63
57
|
end
|
64
|
-
|
65
|
-
|
66
58
|
end
|
67
|
-
end
|
59
|
+
end
|
data/lib/lib/otool_wrapper.rb
CHANGED
@@ -4,12 +4,14 @@ module Idb
|
|
4
4
|
class OtoolWrapper
|
5
5
|
attr_accessor :load_commands, :shared_libraries, :pie, :arc, :canaries
|
6
6
|
|
7
|
-
def initialize
|
7
|
+
def initialize(binary)
|
8
8
|
@otool_path = "/usr/bin/otool"
|
9
9
|
unless File.exist? @otool_path.to_s
|
10
10
|
$log.error "otool not available. Some functions will not work properly."
|
11
11
|
error = Qt::MessageBox.new
|
12
|
-
|
12
|
+
msg = "This feature requires otool to be installed on the host running idb." \
|
13
|
+
" This is the default on OS X but it may not be available for other platforms."
|
14
|
+
error.setInformativeText(msg)
|
13
15
|
error.setIcon(Qt::MessageBox::Critical)
|
14
16
|
error.exec
|
15
17
|
@otool_path = nil
|
@@ -24,17 +26,17 @@ module Idb
|
|
24
26
|
process_symbol_table
|
25
27
|
end
|
26
28
|
|
27
|
-
|
28
29
|
private
|
30
|
+
|
29
31
|
def parse_shared_libraries
|
30
32
|
if @otool_path.nil?
|
31
|
-
@shared_libraries =
|
33
|
+
@shared_libraries = []
|
32
34
|
@shared_libraries << "Error; otool not available"
|
33
35
|
return
|
34
36
|
end
|
35
37
|
@raw_shared_libraries_output = `#{@otool_path} -L '#{@binary}'`
|
36
38
|
lines = @raw_shared_libraries_output.split("\n")
|
37
|
-
@shared_libraries = lines[1,lines.size].map
|
39
|
+
@shared_libraries = lines[1, lines.size].map(&:strip) unless lines.nil?
|
38
40
|
end
|
39
41
|
|
40
42
|
def process_symbol_table
|
@@ -44,20 +46,19 @@ module Idb
|
|
44
46
|
return
|
45
47
|
end
|
46
48
|
symbols = `#{@otool_path} -I -v '#{@binary}'`
|
47
|
-
if symbols.include?
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
if symbols.include? "_objc_release"
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
49
|
+
@canaries = if symbols.include?("stack_chk_fail") || symbols.include?("stack_chk_guard")
|
50
|
+
true
|
51
|
+
else
|
52
|
+
false
|
53
|
+
end
|
54
|
+
|
55
|
+
@arc = if symbols.include? "_objc_release"
|
56
|
+
true
|
57
|
+
else
|
58
|
+
false
|
59
|
+
end
|
58
60
|
end
|
59
61
|
|
60
|
-
|
61
62
|
def hashify_otool_output(otool_output)
|
62
63
|
# otool output may contain multiple mach headers
|
63
64
|
mach_headers = otool_output.split("Mach header\n").map(&:strip)
|
@@ -65,7 +66,7 @@ module Idb
|
|
65
66
|
# The newest otool version no longer echos the path of the binary being
|
66
67
|
# inspected. Here we reject that line if it shows up in the output of
|
67
68
|
# otool as well as any blank lines
|
68
|
-
mach_headers.reject!{|line| line == ""
|
69
|
+
mach_headers.reject! { |line| (line == "") || line.include?(@binary) }
|
69
70
|
|
70
71
|
# convert otool output to a hash
|
71
72
|
mach_headers.map do |mach_header|
|
@@ -78,7 +79,6 @@ module Idb
|
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
81
|
-
|
82
82
|
def parse_header
|
83
83
|
if @otool_path.nil?
|
84
84
|
@pie = "Error"
|
@@ -87,18 +87,17 @@ module Idb
|
|
87
87
|
pie_flag = 0x00200000
|
88
88
|
@raw_load_output = `#{@otool_path} -h '#{@binary}'`
|
89
89
|
|
90
|
-
|
91
90
|
mach_hashes = hashify_otool_output(@raw_load_output)
|
92
91
|
$log.info "Mach Hashes: #{mach_hashes}"
|
93
92
|
|
94
93
|
# extract the Position Independent Executable (PIE) flag from the flags
|
95
94
|
# value.
|
96
95
|
mach_hashes.each do |mach_hash|
|
97
|
-
if (mach_hash["flags"].to_i(16) & pie_flag) == pie_flag
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
96
|
+
@pie = if (mach_hash["flags"].to_i(16) & pie_flag) == pie_flag
|
97
|
+
true
|
98
|
+
else
|
99
|
+
false
|
100
|
+
end
|
102
101
|
end
|
103
102
|
end
|
104
103
|
|
@@ -108,24 +107,22 @@ module Idb
|
|
108
107
|
return
|
109
108
|
end
|
110
109
|
@raw_load_output = `#{@otool_path} -l '#{@binary}'`
|
111
|
-
delim = "Load command"
|
112
110
|
regex_cmd = /Load command (\d+)/
|
113
111
|
regex_parse_key_vals = /\s*(cmd|cryptid)\s(.+)/
|
114
112
|
|
115
|
-
@load_commands =
|
113
|
+
@load_commands = {}
|
116
114
|
|
117
|
-
@raw_load_output.split("\n").each
|
118
|
-
|
119
|
-
if match = regex_cmd.match(line)
|
115
|
+
@raw_load_output.split("\n").each do |line|
|
116
|
+
if (match = regex_cmd.match(line))
|
120
117
|
@load_commands[@cmd] = @command unless @cmd.nil?
|
121
118
|
@cmd = match[1]
|
122
|
-
@command =
|
119
|
+
@command = {}
|
123
120
|
end
|
124
121
|
|
125
|
-
if match = regex_parse_key_vals.match(line)
|
122
|
+
if (match = regex_parse_key_vals.match(line))
|
126
123
|
@command[match[1]] = match[2]
|
127
124
|
end
|
128
|
-
|
125
|
+
end
|
129
126
|
end
|
130
127
|
end
|
131
128
|
end
|
@@ -4,18 +4,19 @@ require 'expect'
|
|
4
4
|
|
5
5
|
module Idb
|
6
6
|
class RsyncGitManager
|
7
|
-
def initialize
|
7
|
+
def initialize(local_path)
|
8
8
|
@local_path = local_path
|
9
9
|
FileUtils.mkdir_p @local_path unless Dir.exist? @local_path
|
10
10
|
|
11
11
|
begin
|
12
|
-
@g = Git.open(local_path, :
|
12
|
+
@g = Git.open(local_path, log: $log)
|
13
13
|
rescue
|
14
|
-
$log.debug "Repository could not be opened.
|
14
|
+
$log.debug "Repository could not be opened." \
|
15
|
+
" This is likely the first clone. Creating empty repo."
|
15
16
|
Git.init(local_path)
|
16
|
-
@g = Git.open(local_path, :
|
17
|
+
@g = Git.open(local_path, log: $log)
|
17
18
|
FileUtils.touch "#{local_path}/idb_dummy.placeholder"
|
18
|
-
@g.add(:
|
19
|
+
@g.add(all: true)
|
19
20
|
$log.debug "Committing placeholder to initialize the repo."
|
20
21
|
begin
|
21
22
|
@g.commit_all("Initial commit. Initializing the repo.")
|
@@ -26,49 +27,52 @@ module Idb
|
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
-
def sync_dir remote, local_relative
|
30
|
+
def sync_dir(remote, local_relative)
|
31
31
|
local = @local_path + "/" + local_relative
|
32
32
|
if $settings['device_connection_mode'] == "ssh"
|
33
|
-
cmd = "rsync -avz -e 'ssh -oStrictHostKeyChecking=no -p #{$settings.ssh_port}'
|
33
|
+
cmd = "rsync -avz -e 'ssh -oStrictHostKeyChecking=no -p #{$settings.ssh_port}'" \
|
34
|
+
" #{$settings.ssh_username}@#{$settings.ssh_host}:#{Shellwords.escape(remote)}/" \
|
35
|
+
" #{Shellwords.escape(local)}/"
|
34
36
|
else
|
35
|
-
cmd = "rsync -avz -e 'ssh -oStrictHostKeyChecking=no
|
37
|
+
cmd = "rsync -avz -e 'ssh -oStrictHostKeyChecking=no" \
|
38
|
+
" -p #{$device.tool_port}' root@localhost:#{Shellwords.escape(remote)}/" \
|
39
|
+
" #{Shellwords.escape(local)}/"
|
36
40
|
end
|
37
41
|
|
38
42
|
$log.info "Executing rsync command #{cmd}"
|
39
43
|
begin
|
40
|
-
PTY.spawn(cmd)
|
44
|
+
PTY.spawn(cmd) do |rsync_out, rsync_in, _pid|
|
41
45
|
STDOUT.flush
|
42
46
|
rsync_out.sync = true
|
43
47
|
rsync_in.sync = true
|
44
48
|
$expect_verbose = true
|
45
49
|
|
46
|
-
rsync_out.expect(/assword: /)
|
50
|
+
rsync_out.expect(/assword: /) do |_x|
|
47
51
|
begin
|
48
52
|
$log.info "Supplying password for rsync if required..."
|
49
53
|
rsync_in.printf("#{$settings.ssh_password}\n")
|
50
54
|
rescue
|
51
55
|
$log.info "No password required for rsync...."
|
52
56
|
end
|
53
|
-
|
57
|
+
end
|
54
58
|
|
55
|
-
rsync_out.each
|
59
|
+
rsync_out.each do |x|
|
56
60
|
$log.info x
|
57
|
-
|
61
|
+
end
|
58
62
|
PTY.check
|
59
|
-
|
63
|
+
end
|
60
64
|
rescue
|
65
|
+
$log.error "Something went wrong"
|
61
66
|
end
|
62
|
-
|
63
67
|
end
|
64
68
|
|
65
|
-
|
66
69
|
def commit_new_revision
|
67
70
|
$log.info "Rsync Done. committing to git."
|
68
|
-
@g.add(:
|
71
|
+
@g.add(all: true)
|
69
72
|
begin
|
70
|
-
@g.commit_all("Snapshot from #{Time.now
|
73
|
+
@g.commit_all("Snapshot from #{Time.now}")
|
71
74
|
rescue
|
75
|
+
$log.error "Something went wrong"
|
72
76
|
end
|
73
77
|
end
|
74
78
|
|
@@ -77,9 +81,9 @@ module Idb
|
|
77
81
|
begin
|
78
82
|
@g.reset_hard
|
79
83
|
rescue
|
80
|
-
$log.error "Reset of repo failed. If this is the first time you
|
84
|
+
$log.error "Reset of repo failed. If this is the first time you" \
|
85
|
+
" run rsync+git for this app this may be okay."
|
81
86
|
end
|
82
87
|
end
|
83
|
-
|
84
88
|
end
|
85
|
-
end
|
89
|
+
end
|