idb 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
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