idb 2.9.0 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +30 -0
  3. data/Gemfile.lock +5 -0
  4. data/idb.gemspec +1 -0
  5. data/lib/gui/app_binary_tab_widget.rb +7 -14
  6. data/lib/gui/app_details_group_box.rb +63 -88
  7. data/lib/gui/app_list_dialog.rb +29 -35
  8. data/lib/gui/app_list_widget_item.rb +1 -5
  9. data/lib/gui/app_tab_widget.rb +17 -22
  10. data/lib/gui/binary_strings_widget.rb +7 -15
  11. data/lib/gui/ca_manager_dialog.rb +32 -54
  12. data/lib/gui/cache_db_widget.rb +21 -26
  13. data/lib/gui/certificate_item.rb +2 -2
  14. data/lib/gui/default_protection_class_group_widget.rb +7 -12
  15. data/lib/gui/device_info_group_box.rb +26 -23
  16. data/lib/gui/main_tab_widget.rb +2 -21
  17. data/lib/gui/shared_libraries_widget.rb +1 -1
  18. data/lib/gui/sqlite_widget.rb +1 -3
  19. data/lib/gui/weak_class_dump_widget.rb +1 -1
  20. data/lib/idb.rb +3 -3
  21. data/lib/idb/version.rb +1 -1
  22. data/lib/lib/abstract_device.rb +7 -11
  23. data/lib/lib/app.rb +49 -59
  24. data/lib/lib/app_binary.rb +18 -29
  25. data/lib/lib/ca_interface.rb +46 -59
  26. data/lib/lib/device.rb +68 -155
  27. data/lib/lib/device_ca_interface.rb +7 -13
  28. data/lib/lib/host_file_wrapper.rb +6 -8
  29. data/lib/lib/ios8_last_launch_services_map_wrapper.rb +11 -18
  30. data/lib/lib/local_operations.rb +24 -32
  31. data/lib/lib/otool_wrapper.rb +30 -33
  32. data/lib/lib/rsync_git_manager.rb +26 -22
  33. data/lib/lib/screen_shot_util.rb +20 -28
  34. data/lib/lib/settings.rb +14 -17
  35. data/lib/lib/simulator.rb +11 -16
  36. data/lib/lib/simulator_ca_interface.rb +1 -3
  37. data/lib/lib/ssh_operations.rb +49 -65
  38. data/lib/lib/ssh_port_forwarder.rb +9 -13
  39. data/lib/lib/tools.rb +3 -3
  40. data/lib/lib/url_scheme_fuzzer.rb +41 -49
  41. data/lib/lib/usb_muxd_wrapper.rb +6 -8
  42. data/lib/lib/weak_class_dump_wrapper.rb +15 -16
  43. metadata +19 -9
  44. data/lib/gui/console_widget.rb +0 -163
  45. data/lib/gui/cycript_console_widget.rb +0 -68
  46. data/lib/gui/cycript_thread.rb +0 -81
  47. data/lib/lib/console_launcher.rb +0 -24
  48. data/lib/lib/i_device_diagnostics_wrapper.rb +0 -90
  49. 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 cert
23
- FileUtils.copy_file @db_path, "#{@db_path}-#{Time.now.to_s}"
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 cert_file
29
- FileUtils.copy_file @db_path, "#{@db_path}-#{Time.now.to_s}"
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 text
17
+ def save(text)
19
18
  # upload
20
- File.open(@cache_path,"w") { |f|
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 bundle_id
12
- begin
13
- @plist_data.to_hash["User"][bundle_id]["Entitlements"]
14
- rescue
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
- def keychain_access_groups_by_bundle_id bundle_id
26
- begin
27
- @plist_data.to_hash["User"][bundle_id]["Entitlements"]["keychain-access-groups"]
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
@@ -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
- def download a, b
11
- FileUtils.copy_file(a,b)
12
- return true
7
+ def download(a, b)
8
+ FileUtils.copy_file(a, b)
9
+ true
13
10
  end
14
11
 
15
-
16
- def directory? path
17
- File.directory? path
12
+ def directory?(path)
13
+ File.directory? path
18
14
  end
19
15
 
20
- def mtime path
16
+ def mtime(path)
21
17
  File.mtime path
22
18
  end
23
19
 
24
- def open path
25
- begin
26
- Launchy.open path
27
- return true
28
- rescue Exception => e
29
- $log.error "Could not open file #{path}: #{e.message}"
30
- $log.error e.backtrace
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 path
29
+ def list_dir(path)
36
30
  Dir.entries path
37
31
  end
38
32
 
39
- def list_dir_full path
33
+ def list_dir_full(path)
40
34
  Dir.entries path
41
35
  end
42
36
 
43
- def dir_glob path, pattern
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? file
49
- File.exists? file
42
+ def file_exists?(file)
43
+ File.exist? file
50
44
  end
51
45
 
52
- def execute cmd
46
+ def execute(cmd)
53
47
  `#{cmd}`
54
48
  end
55
49
 
56
- def execute_fork cmd
50
+ def execute_fork(cmd)
57
51
  (pid = fork) ? Process.detach(pid) : exec(cmd)
58
52
  end
59
53
 
60
- def launch_app command, app
54
+ def launch_app(command, app)
61
55
  $log.info "Executing #{command} #{app}"
62
- self.execute_fork("#{command} \"#{app}\"")
56
+ execute_fork("#{command} \"#{app}\"")
63
57
  end
64
-
65
-
66
58
  end
67
- end
59
+ end
@@ -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 binary
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
- error.setInformativeText("This feature requires otool to be installed on the host running idb. This is the default on OS X but it may not be available for other platforms.")
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 = Array.new
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{ |x| x.strip} unless lines.nil?
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? "stack_chk_fail" or symbols.include? "stack_chk_guard"
48
- @canaries = true
49
- else
50
- @canaries = false
51
- end
52
-
53
- if symbols.include? "_objc_release"
54
- @arc = true
55
- else
56
- @arc = false
57
- end
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 == "" or line.include?(@binary)}
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
- @pie = true
99
- else
100
- @pie = false
101
- end
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 = Hash.new
113
+ @load_commands = {}
116
114
 
117
- @raw_load_output.split("\n").each {|line|
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 = Hash.new
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 local_path
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, :log => $log)
12
+ @g = Git.open(local_path, log: $log)
13
13
  rescue
14
- $log.debug "Repository could not be opened. This is likely the first clone. Creating empty repo."
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, :log => $log)
17
+ @g = Git.open(local_path, log: $log)
17
18
  FileUtils.touch "#{local_path}/idb_dummy.placeholder"
18
- @g.add(:all=>true)
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}' #{$settings.ssh_username}@#{$settings.ssh_host}:#{Shellwords.escape(remote)}/ #{Shellwords.escape(local)}/"
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 -p #{$device.tool_port}' root@localhost:#{Shellwords.escape(remote)}/ #{Shellwords.escape(local)}/"
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) { |rsync_out, rsync_in, pid |
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: /) { |x|
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 { |x|
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(:all=>true)
71
+ @g.add(all: true)
69
72
  begin
70
- @g.commit_all("Snapshot from #{Time.now.to_s}")
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 run rsync+git for this app this may be okay."
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