lib/lib/device.rb
# encoding: utf-8
require_relative 'abstract_device'
require_relative 'ssh_port_forwarder'
require_relative 'device_ca_interface'
require_relative 'usb_muxd_wrapper'
require 'json'
module Idb
class Device < AbstractDevice
attr_accessor :usb_ssh_port, :mode, :tool_port, :ios_version
attr_reader :data_dir
def initialize(username, password, hostname, port)
@username = username
@password = password
@hostname = hostname
@port = port
@app = nil
@device_app_paths = {}
@device_app_paths[:cycript] = ["/usr/bin/cycript"]
@device_app_paths[:rsync] = ["/usr/bin/rsync"]
@device_app_paths[:open] = ["/usr/bin/open"]
@device_app_paths[:openurl] = ["/usr/bin/uiopen",
"/usr/bin/openurl",
"/usr/bin/openURL"]
@device_app_paths[:aptget] = ["/usr/bin/apt-get", "/usr/bin/aptitude"]
@device_app_paths[:keychaineditor] = ["/var/root/keychaineditor"]
@device_app_paths[:pcviewer] = ["/var/root/protectionclassviewer"]
@device_app_paths[:pbwatcher] = ["/var/root/pbwatcher"]
@device_app_paths[:dumpdecrypted_armv7] = ["/usr/lib/dumpdecrypted_armv7.dylib"]
@device_app_paths[:dumpdecrypted_armv6] = ["/usr/lib/dumpdecrypted_armv6.dylib"]
if $settings['device_connection_mode'] == "ssh"
$log.debug "Connecting via SSH"
@mode = 'ssh'
@ops = SSHOperations.new username, password, hostname, port
else
$log.debug "Connecting via USB"
@mode = 'usb'
@usbmuxd = USBMuxdWrapper.new
proxy_port = @usbmuxd.find_available_port
$log.debug "Using port #{proxy_port} for SSH forwarding"
@usbmuxd.proxy proxy_port, $settings['ssh_port']
sleep 1
@ops = SSHOperations.new username, password, 'localhost', proxy_port
@usb_ssh_port = $settings['manual_ssh_port']
$log.debug "opening port #{proxy_port} for manual ssh connection"
@usbmuxd.proxy @usb_ssh_port, $settings['ssh_port']
@tool_port = @usbmuxd.find_available_port
$log.debug "opening tool port #{@tool_port} for internal ssh connection"
@usbmuxd.proxy @tool_port, $settings['ssh_port']
end
@apps_dir_ios_pre8 = '/private/var/mobile/Applications'
@apps_dir_ios_8 = '/private/var/mobile/Containers/Bundle/Application'
@data_dir_ios_8 = '/private/var/mobile/Containers/Data/Application'
@apps_dir_ios_9 = '/private/var/containers/Bundle/Application'
@data_dir_ios_9 = @data_dir_ios_8
@application_state_ios_10 = "/User/Library/FrontBoard/applicationState.db"
$log.info "Checking iOS version"
@ops.execute"touch /tmp/daniel"
if @ops.file_exists? @application_state_ios_10
$log.info "iOS Version: 10 or newer"
@ios_version = 10
@apps_dir = @apps_dir_ios_9
@data_dir = @data_dir_ios_9
elsif @ops.directory? @apps_dir_ios_9
$log.info "iOS Version: 9"
@ios_version = 9
@apps_dir = @apps_dir_ios_9
@data_dir = @data_dir_ios_9
elsif @ops.directory? @apps_dir_ios_8
$log.info "iOS Version: 8"
@ios_version = 8
@apps_dir = @apps_dir_ios_8
@data_dir = @data_dir_ios_8
elsif @ops.directory? @apps_dir_ios_pre8
$log.info "iOS Version: 7 or earlier"
@ios_version = 7 # 7 or earlier
@apps_dir = @apps_dir_ios_pre8
@data_dir = @apps_dir_ios_pre8
else
$log.error "Unsupported iOS Version."
raise
end
$log.info "iOS Version: #{@ios_version} with apps dir: #{@apps_dir} and data dir: #{@data_dir}"
start_port_forwarding
end
def ssh
@ops.ssh
end
def disconnect
@ops.disconnect
end
def device?
true
end
def arch
"armv7"
end
def start_port_forwarding
command = "#{RbConfig.ruby} #{Idb.root}/lib/helper/ssh_port_forwarder.rb"
@port_forward_pid = Process.spawn(command)
end
def restart_port_forwarding
$log.info "Restarting SSH port forwarding"
Process.kill("INT", @port_forward_pid)
start_port_forwarding
end
def protection_class(file)
@ops.execute "#{pcviewer_path} '#{file}'"
end
def simulator?
false
end
def app_launch(app)
@ops.launch_app(open_path, app.bundle_id)
end
def is_installed?(tool)
$log.info "Checking if #{tool} is installed..."
if path_for(tool).nil?
$log.warn "#{tool} not found."
false
else
$log.info "#{tool} found at #{path_for(tool)}."
true
end
end
def path_for(tool)
@device_app_paths[tool].each do |device_app_path|
return device_app_path if @ops.file_exists? device_app_path
end
nil
end
def install_dumpdecrypted
upload_dumpdecrypted
# Change permissions as this needs to be run as the mobile user
@ops.chmod dumpdecrypted_path, 0755
@ops.chmod dumpdecrypted_path_armv6, 0755
end
def upload_dumpdecrypted
$log.info "Uploading dumpdecrypted library..."
@ops.upload("#{Idb.root}/lib/utils/dumpdecrypted/dumpdecrypted_armv6.dylib",
@device_app_paths[:dumpdecrypted_armv6].first)
@ops.upload("#{Idb.root}/lib/utils/dumpdecrypted/dumpdecrypted_armv7.dylib",
@device_app_paths[:dumpdecrypted_armv7].first)
$log.info "'dumpdecrypted' installed successfully."
end
def install_keychain_editor
keychaineditor_path = "#{Idb.root}/lib/utils/keychain_editor/keychaineditor"
if File.exist? keychaineditor_path
upload_keychain_editor
else
$log.error "keychain_editor not found at '#{keychaineditor_path}'."
false
end
end
def install_pcviewer
pcviewer_path = "#{Idb.root}/lib/utils/pcviewer/protectionclassviewer"
if File.exist? pcviewer_path
upload_pcviewer
else
$log.error "protectionclassviewer not found at '#{pcviewer_path}'."
false
end
end
def install_pbwatcher
pbwatcher_path = "#{Idb.root}/lib/utils/pbwatcher/pbwatcher"
if File.exist? pbwatcher_path
upload_pbwatcher
else
$log.error "pbwatcher not found at '#{pbwatcher_path}'."
false
end
end
def upload_pcviewer
local_pcviewer_path = "#{Idb.root}/lib/utils/pcviewer/protectionclassviewer"
$log.info "Uploading pcviewer..."
@ops.upload local_pcviewer_path, "/var/root/protectionclassviewer"
@ops.chmod "/var/root/protectionclassviewer", 0744
$log.info "'pcviewer' installed successfully."
end
def upload_keychain_editor
local_keychaineditor_path = "#{Idb.root}/lib/utils/keychain_editor/keychaineditor"
$log.info "Uploading keychain_editor..."
@ops.upload local_keychaineditor_path, "/var/root/keychaineditor"
@ops.chmod "/var/root/keychaineditor", 0744
$log.info "'keychain_editor' installed successfully."
end
def upload_pbwatcher
local_pbwatcher_path = "#{Idb.root}/lib/utils/pbwatcher/pbwatcher"
$log.info "Uploading pbwatcher..."
@ops.upload local_pbwatcher_path, "/var/root/pbwatcher"
@ops.chmod "/var/root/pbwatcher", 0744
$log.info "'pbwatcher' installed successfully."
end
def install_from_cydia(package)
if apt_get_installed?
$log.info "Updating package repo..."
@ops.execute("#{apt_get_path} -y update")
$log.info "Installing #{package}..."
@ops.execute("#{apt_get_path} -y install #{package}")
return true
else
$log.error "apt-get or aptitude not found on the device"
return false
end
end
def install_open
install_from_cydia "com.conradkramer.open"
end
def install_rsync
install_from_cydia "rsync"
end
def install_cycript
install_from_cydia "cycript"
end
def close
$log.info "Terminating port forwarding helper..."
Process.kill("INT", @port_forward_pid)
$log.info "Stopping any SSH via USB forwarding"
@usbmuxd.stop_all if $settings['device_connection_mode'] != "ssh"
end
def open_url(url)
command = "#{openurl_path} \"#{url.gsub('&', '\&')}\""
$log.info "Executing: #{command}"
@ops.execute command
end
def ca_interface
DeviceCAInterface.new self
end
def kill_by_name(process_name)
@ops.execute "killall -9 #{process_name}"
end
def device_id
$log.error "Not implemented"
nil
end
def configured?
apt_get_installed? &&
open_installed? &&
openurl_installed? &&
dumpdecrypted_installed? &&
pbwatcher_installed? &&
pcviewer_installed? &&
keychain_editor_installed? &&
rsync_installed? &&
cycript_installed?
end
def cycript_installed?
is_installed? :cycript
end
def keychain_editor_installed?
is_installed? :keychaineditor
end
def pcviewer_installed?
is_installed? :pcviewer
end
def pbwatcher_installed?
is_installed? :pbwatcher
end
def dumpdecrypted_installed?
is_installed?(:dumpdecrypted_armv6) && is_installed?(:dumpdecrypted_armv7)
end
def rsync_installed?
is_installed? :rsync
end
def open_installed?
is_installed? :open
end
def openurl_installed?
is_installed? :openurl
end
def apt_get_installed?
is_installed? :aptget
end
def keychain_editor_path
path_for :keychaineditor
end
def pcviewer_path
path_for :pcviewer
end
def pbwatcher_path
path_for :pbwatcher
end
def dumpdecrypted_path
path_for :dumpdecrypted_armv7
end
def dumpdecrypted_path_armv6
path_for :dumpdecrypted_armv6
end
def rsync_path
path_for :rsync
end
def open_path
path_for :open
end
def openurl_path
path_for :openurl
end
def apt_get_path
path_for :aptget
end
def cycript_path
path_for :cycript
end
end
end