idb 1.3.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 (103) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.gitignore +19 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +65 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +2 -0
  9. data/bin/idb +5 -0
  10. data/idb.gemspec +41 -0
  11. data/lib/LICENSE +20 -0
  12. data/lib/README.md +54 -0
  13. data/lib/config/.dummy +0 -0
  14. data/lib/config/settings.yml +8 -0
  15. data/lib/gui/app_binary_tab_widget.rb +45 -0
  16. data/lib/gui/app_details_group_box.rb +213 -0
  17. data/lib/gui/app_list_dialog.rb +67 -0
  18. data/lib/gui/app_list_widget_item.rb +9 -0
  19. data/lib/gui/binary_strings_widget.rb +33 -0
  20. data/lib/gui/browse_filesystem_widget.rb +4 -0
  21. data/lib/gui/ca_manager_dialog.rb +137 -0
  22. data/lib/gui/cache_db_widget.rb +61 -0
  23. data/lib/gui/certificate_item.rb +5 -0
  24. data/lib/gui/console_widget.rb +163 -0
  25. data/lib/gui/cycript_console_widget.rb +68 -0
  26. data/lib/gui/cycript_thread.rb +81 -0
  27. data/lib/gui/device_info_group_box.rb +55 -0
  28. data/lib/gui/device_status_dialog.rb +351 -0
  29. data/lib/gui/file_system_events_widget.rb +4 -0
  30. data/lib/gui/fs_viewer_tab_widget.rb +245 -0
  31. data/lib/gui/i_device_syslog_thread.rb +47 -0
  32. data/lib/gui/images/check.png +0 -0
  33. data/lib/gui/images/folder.ico +0 -0
  34. data/lib/gui/images/iphone.ico +0 -0
  35. data/lib/gui/images/screenshot.png +0 -0
  36. data/lib/gui/key_chain_widget.rb +86 -0
  37. data/lib/gui/local_storage_tab_widget.rb +37 -0
  38. data/lib/gui/log_plain_text_edit.rb +18 -0
  39. data/lib/gui/log_widget.rb +71 -0
  40. data/lib/gui/main_tab_widget.rb +179 -0
  41. data/lib/gui/pasteboard_monitor_widget.rb +116 -0
  42. data/lib/gui/path_list_widget_item.rb +5 -0
  43. data/lib/gui/pb_watcher_thread.rb +63 -0
  44. data/lib/gui/plist_file_widget.rb +66 -0
  45. data/lib/gui/qt_ruby_variant.rb +16 -0
  46. data/lib/gui/screenshot_wizard.rb +169 -0
  47. data/lib/gui/settings_dialog.rb +69 -0
  48. data/lib/gui/settings_tab_widget.rb +149 -0
  49. data/lib/gui/shared_libraries_widget.rb +47 -0
  50. data/lib/gui/snoop_it_fs_events_widget.rb +150 -0
  51. data/lib/gui/snoop_it_keychain_widget.rb +172 -0
  52. data/lib/gui/snoop_it_sensitive_api_widget.rb +128 -0
  53. data/lib/gui/snoop_it_tab_widget.rb +27 -0
  54. data/lib/gui/snoop_it_update_thread.rb +48 -0
  55. data/lib/gui/sqlite_widget.rb +73 -0
  56. data/lib/gui/ssh_port_forward_tab_widget.rb +209 -0
  57. data/lib/gui/tool_widget.rb +94 -0
  58. data/lib/gui/url_handler_widget.rb +26 -0
  59. data/lib/gui/url_scheme_fuzz_widget.rb +103 -0
  60. data/lib/gui/url_scheme_widget.rb +60 -0
  61. data/lib/gui/weak_class_dump_widget.rb +89 -0
  62. data/lib/helper/ssh_port_forwarder.rb +72 -0
  63. data/lib/idb.rb +295 -0
  64. data/lib/idb/version.rb +3 -0
  65. data/lib/lib/CgBI.rb +153 -0
  66. data/lib/lib/abstract_device.rb +31 -0
  67. data/lib/lib/app.rb +286 -0
  68. data/lib/lib/app_binary.rb +57 -0
  69. data/lib/lib/ca_interface.rb +151 -0
  70. data/lib/lib/configuration.rb +0 -0
  71. data/lib/lib/console_launcher.rb +24 -0
  72. data/lib/lib/device.rb +438 -0
  73. data/lib/lib/device_ca_interface.rb +36 -0
  74. data/lib/lib/host_file_wrapper.rb +27 -0
  75. data/lib/lib/i_device_diagnostics_wrapper.rb +90 -0
  76. data/lib/lib/keychain_plist_parser.rb +15 -0
  77. data/lib/lib/local_operations.rb +67 -0
  78. data/lib/lib/otool_wrapper.rb +116 -0
  79. data/lib/lib/plist_util.rb +72 -0
  80. data/lib/lib/qt_thread_fix.rb +29 -0
  81. data/lib/lib/rsync_git_manager.rb +81 -0
  82. data/lib/lib/screen_shot_util.rb +59 -0
  83. data/lib/lib/settings.rb +67 -0
  84. data/lib/lib/simulator.rb +60 -0
  85. data/lib/lib/simulator_ca_interface.rb +16 -0
  86. data/lib/lib/snoop_it_wrapper.rb +80 -0
  87. data/lib/lib/ssh_operations.rb +136 -0
  88. data/lib/lib/ssh_port_forwarder.rb +43 -0
  89. data/lib/lib/tools.rb +11 -0
  90. data/lib/lib/url_scheme_fuzzer.rb +98 -0
  91. data/lib/lib/usb_muxd_wrapper.rb +32 -0
  92. data/lib/lib/weak_class_dump_wrapper.rb +62 -0
  93. data/lib/utils/dumpdecrypted/README +4 -0
  94. data/lib/utils/dumpdecrypted/dumpdecrypted_armv6.dylib +0 -0
  95. data/lib/utils/dumpdecrypted/dumpdecrypted_armv7.dylib +0 -0
  96. data/lib/utils/ios-ssl-kill-switch/com.isecpartners.nabla.sslkillswitch_v0.5-iOS_6.1.deb +0 -0
  97. data/lib/utils/keychain_dump/README +2 -0
  98. data/lib/utils/keychain_dump/keychain_dump +0 -0
  99. data/lib/utils/pbwatcher/pbwatcher +0 -0
  100. data/lib/utils/pcviewer/protectionclassviewer +0 -0
  101. data/lib/utils/weak_class_dump/README +5 -0
  102. data/lib/utils/weak_class_dump/weak_classdump.cy +726 -0
  103. metadata +412 -0
@@ -0,0 +1,3 @@
1
+ module Idb
2
+ VERSION = "1.3.1"
3
+ end
@@ -0,0 +1,153 @@
1
+ require 'zlib'
2
+
3
+ # By Jeff Jarmoc (jeff@jarmoc.com)
4
+
5
+ # Simplified usage
6
+ # ---------------
7
+ # require './CGBI.rb'
8
+ # CGBI.from_file('./test.png').to_png_file('./outfile.png')
9
+
10
+ module Idb
11
+ class CGBI
12
+ # http://iphonedevwiki.net/index.php/CgBI_file_format
13
+ PNGHEADER = "\x89PNG\r\n\x1A\n".force_encoding('ASCII-8BIT')
14
+
15
+ # Places to hold data
16
+ @cgbi
17
+ @png
18
+
19
+ # Places to store header info..
20
+ attr_accessor :width, :height, :depth, :filter
21
+
22
+ #Stores the input format
23
+ @orig_format
24
+
25
+ def initialize(string)
26
+ unless string[0,8] == PNGHEADER
27
+ raise "Not a PNG"
28
+ end
29
+
30
+ if string.match(/CgBI/)
31
+ #puts "Input is CGBI"
32
+ @cgbi = string
33
+ @orig_format = "CGBI"
34
+ else
35
+ #puts "Input is PNG"
36
+ @png = string
37
+ @orig_format = "PNG"
38
+ end
39
+ end
40
+
41
+ def self.from_file(file_path)
42
+ self.new(File.open(file_path, 'rb') {|f| f.read})
43
+ end
44
+
45
+ def png
46
+ return @png if @png
47
+
48
+ #Convert from cgbi, set instance var, return
49
+ data = @cgbi.dup
50
+ png = ""
51
+ png = data.slice!(0,8) #Copy header
52
+
53
+ loop do
54
+ # Parse chunks... fixup as needed.
55
+ chunk = {}
56
+ chunk[:length] = data.slice!(0,4).unpack("N")[0]
57
+ chunk[:type] = data.slice!(0,4)
58
+
59
+ chunk[:data] = data.slice!(0,chunk[:length] || nil)
60
+ chunk[:crc] = data.slice!(0,4)
61
+
62
+ #puts "#{chunk[:length]} : #{chunk[:type]} : #{chunk[:crc].inspect}"
63
+
64
+ case chunk[:type]
65
+ when "CgBI"
66
+ #puts "Skipping CgBI Chunk"
67
+
68
+ when "IHDR"
69
+ self.width = chunk[:data][0, 4].unpack("L>").first
70
+ self.height = chunk[:data][4, 4].unpack("L>").first
71
+ self.depth = chunk[:data][8, 1].unpack("C").first
72
+ self.filter = chunk[:data][11, 1].unpack("C").first
73
+
74
+ #puts "Image: #{width}x#{height} #{depth}bit - Filter: #{filter}"
75
+
76
+ png << [chunk[:length]].pack("N")
77
+ png << chunk[:type]
78
+ png << chunk[:data]
79
+ png << chunk[:crc]
80
+
81
+ when "IDAT"
82
+ #Inflate the IDAT chunk
83
+ inflate = Zlib::Inflate.new(-15)
84
+ decompressed = inflate.inflate(chunk[:data])
85
+
86
+ # Re-order pixels to RGBA
87
+ chunk[:data] = ""
88
+ while (decompressed) do
89
+ #(1..@height).each do |y|
90
+ # Copy over the filter type byte on each line
91
+ # TODO: Might not be necessary for all filter types
92
+ chunk[:data] << decompressed.slice!(0,1)
93
+ (1..@width).each do |x|
94
+ # BGRA => RGBA
95
+ b,g,r,a = decompressed.unpack("CCCC")
96
+ decompressed.slice!(0,4).split(//)
97
+
98
+ begin
99
+ chunk[:data] += [r,g,b,a].pack("CCCC")
100
+ decompressed = nil if decompressed.length == 0
101
+ rescue => e
102
+ puts "Left: #{decompressed.inspect}"
103
+ end
104
+ end
105
+ end
106
+
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
+
119
+ when "IEND"
120
+ raise "Data after IEND" unless data.empty?
121
+ png << [chunk[:length]].pack("N")
122
+ png << chunk[:type]
123
+ png << chunk[:data]
124
+ png << chunk[:crc]
125
+ # do stuff
126
+ #puts "#{chunk[:length]} : #{chunk[:type]} : #{chunk[:crc].inspect}"
127
+ break
128
+ else
129
+ # For any chunk we don't modify, copy it through.
130
+ png << [chunk[:length]].pack("N")
131
+ png << chunk[:type]
132
+ png << chunk[:data]
133
+ png << chunk[:crc]
134
+ end
135
+ ######
136
+ #binding.pry
137
+ end
138
+
139
+ @png = png
140
+ end
141
+
142
+ def to_png_file(file)
143
+ File.open(file, 'w') { |f| f.write(self.png)}
144
+ end
145
+
146
+ def cgbi
147
+ return @cgbi
148
+
149
+ #TODO: Convert from png, set local var, return
150
+ end
151
+
152
+ end
153
+ end
@@ -0,0 +1,31 @@
1
+ module Idb
2
+ class AbstractDevice
3
+ attr_accessor :apps_dir
4
+ attr_accessor :ops
5
+
6
+
7
+ def get_app_uuids
8
+ if not @ops.file_exists? @apps_dir
9
+ puts "Application directory #{@apps_dir} not found."
10
+ raise "Application directory #{@apps_dir} not found."
11
+ end
12
+
13
+ puts '[*] Retrieving list of applications...'
14
+
15
+ dirs = @ops.list_dir "#{@apps_dir}"
16
+ dirs.select! { |x| x != "." and x != ".." }
17
+
18
+ if dirs.length == 0
19
+ puts "No applications found in #{@apps_dir}."
20
+ raise "No applications found in #{@apps_dir}."
21
+ end
22
+ return dirs
23
+ end
24
+
25
+ def close
26
+
27
+ end
28
+
29
+
30
+ end
31
+ end
@@ -0,0 +1,286 @@
1
+ require_relative 'plist_util'
2
+ require_relative 'app_binary'
3
+ require_relative 'CgBI'
4
+
5
+ module Idb
6
+ class App
7
+ attr_accessor :uuid, :app_dir, :binary, :cache_dir
8
+
9
+
10
+ def initialize uuid
11
+ @uuid = uuid
12
+ @app_dir = "#{$device.apps_dir}/#{@uuid}"
13
+ @cache_dir = "#{$tmp_path}/#{uuid}"
14
+ FileUtils.mkdir_p @cache_dir unless Dir.exist? @cache_dir
15
+ parse_info_plist
16
+ end
17
+
18
+ def analyze
19
+ local_binary_path = cache_file binary_path
20
+ @binary = AppBinary.new local_binary_path
21
+ if @binary.is_encrypted?
22
+ $log.info "Binary is encrypted. Decrypting for further analysis."
23
+ decrypt_binary!
24
+ else
25
+ $log.info "Binary is not encrypted."
26
+ @local_decrypted_binary = local_binary_path
27
+ end
28
+ end
29
+
30
+ def strings
31
+ data = `strings '#{@local_decrypted_binary}'`
32
+ end
33
+
34
+ def decrypt_binary!
35
+ unless $device.dumpdecrypted_installed?
36
+ $log.error "dumpdecrypted not installed."
37
+ return false
38
+ end
39
+
40
+ dylib = "dumpdecrypted_#{$device.arch}.dylib"
41
+
42
+ $log.info "Running '#{binary_path}'"
43
+ full_remote_path = binary_path
44
+ decrypted_path = "/var/root/#{File.basename full_remote_path}.decrypted"
45
+
46
+ $device.ops.execute "cd /var/root/"
47
+ $device.ops.execute "DYLD_INSERT_LIBRARIES=dumpdecrypted_armv7.dylib \"#{full_remote_path}\""
48
+ $log.info "Checking if decrypted file #{decrypted_path} was created..."
49
+ if not $device.ops.file_exists? decrypted_path
50
+ $log.error "Decryption failed. Trying armv6 build for iOS 6 and earlier..."
51
+ $device.ops.execute "DYLD_INSERT_LIBRARIES=dumpdecrypted_armv6.dylib \"#{full_remote_path}\""
52
+ $log.info "Checking if decrypted file #{decrypted_path} was created..."
53
+ end
54
+
55
+ if not $device.ops.file_exists? decrypted_path
56
+ $log.error "Decryption failed. File may not be encrypted."
57
+ return
58
+ end
59
+
60
+ $log.info "Decrypted file found. Downloading..."
61
+
62
+ @local_decrypted_binary = "#{cache_dir}/#{File.basename full_remote_path}.decrypted"
63
+ @binary.setDecryptedPath @local_decrypted_binary
64
+
65
+ local_path = $device.ops.download decrypted_path, @local_decrypted_binary
66
+
67
+ $log.info "Decrypted binary downloaded to #{@local_decrypted_binary}"
68
+ @local_decrypted_binary
69
+
70
+ end
71
+
72
+ def decrypt_binary_clutch!
73
+ # not in use since Stefan Esser updated dumpdecrypted
74
+ unless $device.clutch_installed?
75
+ $log.error "clutch not installed."
76
+ return false
77
+ end
78
+
79
+ $log.info "Binary name is: '#{binary_name}'"
80
+
81
+ $device.ops.execute "cd /var/root/"
82
+ output = $device.ops.execute "#{$device.clutch_path} #{binary_name}"
83
+ puts output
84
+
85
+ decrypted_path = "/var/root/Documents/Cracked/#{binary_name}*.ipa"
86
+ $log.info "Checking if decrypted file #{decrypted_path} was created..."
87
+ if not $device.ops.file_exists? decrypted_path
88
+ $log.error "Decryption / Cracking failed."
89
+ return
90
+ end
91
+
92
+ $log.info "Decrypted file found. Downloading..."
93
+
94
+ @local_decrypted_binary = "#{cache_dir}/#{File.basename full_remote_path}.decrypted"
95
+ @binary.setDecryptedPath @local_decrypted_binary
96
+
97
+ local_path = $device.ops.download decrypted_path, @local_decrypted_binary
98
+
99
+ $log.info "Decrypted binary downloaded to #{@local_decrypted_binary}"
100
+ @local_decrypted_binary
101
+
102
+ end
103
+
104
+
105
+
106
+
107
+ def get_raw_plist_value val
108
+ begin
109
+ @info_plist.plist_data[val]
110
+ rescue
111
+ "[error]"
112
+ end
113
+ end
114
+
115
+
116
+ def icon_path
117
+ icon_name = get_raw_plist_value('CFBundleIconFile')
118
+
119
+ unless icon_name
120
+ # If there's no icon specified, grab the first one from the array.
121
+ # If it's large, this could make the app nonresponsive.
122
+ icon_name = get_raw_plist_value('CFBundleIconFiles').first
123
+ # NOTE: This still fails to find the icon for some apps that store it in odd places,
124
+ # Like Netflix' plist_data['CFBundleIcons~ipad']['CFBundlePrimaryIcon']['CFBundleIconFiles']
125
+ end
126
+
127
+ app_dir = Shellwords.escape(@app_dir)
128
+
129
+ unless (icon_name[-4,4] == ".png")
130
+ $log.debug "Appending extension to #{icon_name}"
131
+ icon_name += ".png"
132
+ $log.debug "Now: #{icon_name}"
133
+ end
134
+
135
+ icon_file = $device.ops.execute("ls #{app_dir}/*app/#{icon_name}").strip
136
+
137
+ if not $device.ops.file_exists? icon_file
138
+ $log.warn "Icon not found: #{icon_file}"
139
+ return nil
140
+ end
141
+ $log.info "Icon found at #{icon_file}"
142
+ return icon_file
143
+ end
144
+
145
+ def get_icon_file
146
+ path = icon_path
147
+
148
+ unless path.nil?
149
+ local_path = cache_file path
150
+ new_local_path = "#{local_path}.png"
151
+ CGBI.from_file(local_path).to_png_file(new_local_path)
152
+ new_local_path
153
+ else
154
+ nil
155
+ end
156
+ end
157
+
158
+ def bundle_name
159
+ get_raw_plist_value 'CFBundleDisplayName'
160
+ end
161
+
162
+ def platform_version
163
+ get_raw_plist_value 'DTPlatformVersion'
164
+ end
165
+
166
+ def sdk_version
167
+ get_raw_plist_value 'DTSDKName'
168
+ end
169
+
170
+ def minimum_os_version
171
+ get_raw_plist_value 'MinimumOSVersion'
172
+ end
173
+
174
+ def bundle_id
175
+ begin
176
+ @info_plist.bundle_identifier
177
+ rescue
178
+ "[error]"
179
+ end
180
+ end
181
+
182
+ def launch
183
+ $device.app_launch self
184
+ end
185
+
186
+ def binary_path
187
+ $log.info "Locating application binary..."
188
+ dirs = $device.ops.dir_glob("#{@app_dir}/","**")
189
+ dirs.select! { |f|
190
+ $device.ops.file_exists? "#{f}/#{binary_name}"
191
+ }
192
+
193
+ "#{dirs.first}/#{binary_name}"
194
+ end
195
+
196
+ def binary_name
197
+ begin
198
+ @info_plist.binary_name
199
+ rescue
200
+ "[error]"
201
+ end
202
+ end
203
+
204
+ def sync_app_dir
205
+ `#{rsync} avc -e ssh TKTK #{} `
206
+ end
207
+
208
+ def find_plist_files
209
+ $log.info "Looking for plist files..."
210
+ $device.ops.dir_glob(@app_dir, "**/*plist")
211
+ end
212
+
213
+ def find_sqlite_dbs
214
+ $log.info "Looking for sqlite files..."
215
+ $device.ops.dir_glob(@app_dir, "**/*sql**")
216
+ end
217
+
218
+ def find_cache_dbs
219
+ $log.info "Looking for Cache.db files..."
220
+ $device.ops.dir_glob(@app_dir, "**/Cache.db")
221
+ end
222
+
223
+ def get_url_handlers
224
+ @info_plist.schemas
225
+ end
226
+
227
+ def cache_dir
228
+ "#{$tmp_path}/#{@uuid}/"
229
+ end
230
+
231
+
232
+ def cache_file f
233
+ relative_file = f.sub(@app_dir,'')
234
+ relative_dir = File.dirname relative_file
235
+ cache_dir = "#{$tmp_path}/#{@uuid}/#{relative_dir}"
236
+ FileUtils.mkdir_p(cache_dir) unless Dir.exist?(cache_dir)
237
+ cached_file_path = "#{cache_dir}/#{File.basename(f)}"
238
+
239
+ if $device.ops.download f, cached_file_path
240
+ return cached_file_path
241
+ else
242
+ return nil
243
+ end
244
+ end
245
+ private
246
+
247
+ def parse_info_plist
248
+ begin
249
+ plist_file = cache_file(info_plist_path)
250
+ rescue Exception => ex
251
+ $log.error "Error getting plist file #{info_plist_path}."
252
+ $log.debug "Exception Details: #{ex.message}."
253
+ $log.debug "Backtrace: #{ex.backtrace.join("\n")}."
254
+ return
255
+ end
256
+
257
+ begin
258
+ @info_plist = PlistUtil.new plist_file
259
+ @info_plist.parse_info_plist
260
+ rescue Exception => ex
261
+ $log.error "Error parsing plist file #{plist_file}."
262
+ $log.debug "Exception Details: #{ex.message}."
263
+ $log.debug "Backtrace: #{ex.backtrace.join("\n")}."
264
+ return
265
+ end
266
+
267
+ end
268
+
269
+
270
+
271
+ def info_plist_path
272
+ app_dir = Shellwords.escape(@app_dir)
273
+ plist_file = $device.ops.execute("ls #{app_dir}/*app/Info.plist").strip
274
+
275
+ # the following works but is terribly slow.
276
+ #plist_file = (@if.ops.dir_glob "#{@app_dir}/","*app/Info.plist").first
277
+
278
+ if not $device.ops.file_exists? plist_file
279
+ $log.error "Info.plist not found."
280
+ return nil
281
+ end
282
+ $log.info "Info.plist found at #{plist_file}"
283
+ return plist_file
284
+ end
285
+ end
286
+ end