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.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +65 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/bin/idb +5 -0
- data/idb.gemspec +41 -0
- data/lib/LICENSE +20 -0
- data/lib/README.md +54 -0
- data/lib/config/.dummy +0 -0
- data/lib/config/settings.yml +8 -0
- data/lib/gui/app_binary_tab_widget.rb +45 -0
- data/lib/gui/app_details_group_box.rb +213 -0
- data/lib/gui/app_list_dialog.rb +67 -0
- data/lib/gui/app_list_widget_item.rb +9 -0
- data/lib/gui/binary_strings_widget.rb +33 -0
- data/lib/gui/browse_filesystem_widget.rb +4 -0
- data/lib/gui/ca_manager_dialog.rb +137 -0
- data/lib/gui/cache_db_widget.rb +61 -0
- data/lib/gui/certificate_item.rb +5 -0
- data/lib/gui/console_widget.rb +163 -0
- data/lib/gui/cycript_console_widget.rb +68 -0
- data/lib/gui/cycript_thread.rb +81 -0
- data/lib/gui/device_info_group_box.rb +55 -0
- data/lib/gui/device_status_dialog.rb +351 -0
- data/lib/gui/file_system_events_widget.rb +4 -0
- data/lib/gui/fs_viewer_tab_widget.rb +245 -0
- data/lib/gui/i_device_syslog_thread.rb +47 -0
- data/lib/gui/images/check.png +0 -0
- data/lib/gui/images/folder.ico +0 -0
- data/lib/gui/images/iphone.ico +0 -0
- data/lib/gui/images/screenshot.png +0 -0
- data/lib/gui/key_chain_widget.rb +86 -0
- data/lib/gui/local_storage_tab_widget.rb +37 -0
- data/lib/gui/log_plain_text_edit.rb +18 -0
- data/lib/gui/log_widget.rb +71 -0
- data/lib/gui/main_tab_widget.rb +179 -0
- data/lib/gui/pasteboard_monitor_widget.rb +116 -0
- data/lib/gui/path_list_widget_item.rb +5 -0
- data/lib/gui/pb_watcher_thread.rb +63 -0
- data/lib/gui/plist_file_widget.rb +66 -0
- data/lib/gui/qt_ruby_variant.rb +16 -0
- data/lib/gui/screenshot_wizard.rb +169 -0
- data/lib/gui/settings_dialog.rb +69 -0
- data/lib/gui/settings_tab_widget.rb +149 -0
- data/lib/gui/shared_libraries_widget.rb +47 -0
- data/lib/gui/snoop_it_fs_events_widget.rb +150 -0
- data/lib/gui/snoop_it_keychain_widget.rb +172 -0
- data/lib/gui/snoop_it_sensitive_api_widget.rb +128 -0
- data/lib/gui/snoop_it_tab_widget.rb +27 -0
- data/lib/gui/snoop_it_update_thread.rb +48 -0
- data/lib/gui/sqlite_widget.rb +73 -0
- data/lib/gui/ssh_port_forward_tab_widget.rb +209 -0
- data/lib/gui/tool_widget.rb +94 -0
- data/lib/gui/url_handler_widget.rb +26 -0
- data/lib/gui/url_scheme_fuzz_widget.rb +103 -0
- data/lib/gui/url_scheme_widget.rb +60 -0
- data/lib/gui/weak_class_dump_widget.rb +89 -0
- data/lib/helper/ssh_port_forwarder.rb +72 -0
- data/lib/idb.rb +295 -0
- data/lib/idb/version.rb +3 -0
- data/lib/lib/CgBI.rb +153 -0
- data/lib/lib/abstract_device.rb +31 -0
- data/lib/lib/app.rb +286 -0
- data/lib/lib/app_binary.rb +57 -0
- data/lib/lib/ca_interface.rb +151 -0
- data/lib/lib/configuration.rb +0 -0
- data/lib/lib/console_launcher.rb +24 -0
- data/lib/lib/device.rb +438 -0
- data/lib/lib/device_ca_interface.rb +36 -0
- data/lib/lib/host_file_wrapper.rb +27 -0
- data/lib/lib/i_device_diagnostics_wrapper.rb +90 -0
- data/lib/lib/keychain_plist_parser.rb +15 -0
- data/lib/lib/local_operations.rb +67 -0
- data/lib/lib/otool_wrapper.rb +116 -0
- data/lib/lib/plist_util.rb +72 -0
- data/lib/lib/qt_thread_fix.rb +29 -0
- data/lib/lib/rsync_git_manager.rb +81 -0
- data/lib/lib/screen_shot_util.rb +59 -0
- data/lib/lib/settings.rb +67 -0
- data/lib/lib/simulator.rb +60 -0
- data/lib/lib/simulator_ca_interface.rb +16 -0
- data/lib/lib/snoop_it_wrapper.rb +80 -0
- data/lib/lib/ssh_operations.rb +136 -0
- data/lib/lib/ssh_port_forwarder.rb +43 -0
- data/lib/lib/tools.rb +11 -0
- data/lib/lib/url_scheme_fuzzer.rb +98 -0
- data/lib/lib/usb_muxd_wrapper.rb +32 -0
- data/lib/lib/weak_class_dump_wrapper.rb +62 -0
- data/lib/utils/dumpdecrypted/README +4 -0
- data/lib/utils/dumpdecrypted/dumpdecrypted_armv6.dylib +0 -0
- data/lib/utils/dumpdecrypted/dumpdecrypted_armv7.dylib +0 -0
- data/lib/utils/ios-ssl-kill-switch/com.isecpartners.nabla.sslkillswitch_v0.5-iOS_6.1.deb +0 -0
- data/lib/utils/keychain_dump/README +2 -0
- data/lib/utils/keychain_dump/keychain_dump +0 -0
- data/lib/utils/pbwatcher/pbwatcher +0 -0
- data/lib/utils/pcviewer/protectionclassviewer +0 -0
- data/lib/utils/weak_class_dump/README +5 -0
- data/lib/utils/weak_class_dump/weak_classdump.cy +726 -0
- metadata +412 -0
data/lib/idb/version.rb
ADDED
data/lib/lib/CgBI.rb
ADDED
|
@@ -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
|
data/lib/lib/app.rb
ADDED
|
@@ -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
|