Compare commits
21 Commits
Author | SHA1 | Date |
---|---|---|
|
9a3ce60629 | |
|
56e99b2138 | |
|
9e75f6bca3 | |
|
56737ae57c | |
|
8b5b5332fd | |
|
850a38efd2 | |
|
c5eff3b063 | |
|
64b58d1c3e | |
|
9850158401 | |
|
2363a00550 | |
|
2405c99d17 | |
|
8a47ae4ff8 | |
|
35a749f270 | |
|
f88043a222 | |
|
160a6e7419 | |
|
a39c11e38c | |
|
b2581409b1 | |
|
a9b9c9fbf5 | |
|
187446d3c1 | |
|
71499f4d91 | |
|
e53e81ecc3 |
|
@ -1,10 +1,11 @@
|
||||||
# frida-ios-dump
|
# frida-ios-dump
|
||||||
Pull a decrypted IPA from a jailbroken device
|
Pull a decrypted IPA from a jailbroken device
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
1. Install [frida](http://www.frida.re/) on device
|
1. Install [frida](http://www.frida.re/) on device
|
||||||
2. `sudo pip install -r requirements.txt --upgrade` (Python 2.7)
|
2. `sudo pip install -r requirements.txt --upgrade`
|
||||||
3. Run usbmuxd/iproxy SSH forwarding over USB (Default 2222 -> 22). e.g. `iproxy 2222 22`
|
3. Run usbmuxd/iproxy SSH forwarding over USB (Default 2222 -> 22). e.g. `iproxy 2222 22`
|
||||||
4. Run ./dump.py `Display name` or `Bundle identifier`
|
4. Run ./dump.py `Display name` or `Bundle identifier`
|
||||||
|
|
||||||
|
@ -39,6 +40,11 @@ Congratulations!!! You've got a decrypted IPA file.
|
||||||
|
|
||||||
Drag to [MonkeyDev](https://github.com/AloneMonkey/MonkeyDev), Happy hacking!
|
Drag to [MonkeyDev](https://github.com/AloneMonkey/MonkeyDev), Happy hacking!
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
Python 2.x and 3.x
|
||||||
|
|
||||||
|
|
||||||
### issues
|
### issues
|
||||||
|
|
||||||
If the following error occurs:
|
If the following error occurs:
|
||||||
|
|
95
dump.js
95
dump.js
|
@ -129,14 +129,15 @@ function getExportFunction(type, name, ret, args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NSSearchPathForDirectoriesInDomains = getExportFunction("f", "NSSearchPathForDirectoriesInDomains", "pointer", ["int", "int", "int"]);
|
var NSSearchPathForDirectoriesInDomains = getExportFunction("f", "NSSearchPathForDirectoriesInDomains", "pointer", ["int", "int", "int"]);
|
||||||
wrapper_open = getExportFunction("f", "open", "int", ["pointer", "int", "int"]);
|
var wrapper_open = getExportFunction("f", "open", "int", ["pointer", "int", "int"]);
|
||||||
read = getExportFunction("f", "read", "int", ["int", "pointer", "int"]);
|
var read = getExportFunction("f", "read", "int", ["int", "pointer", "int"]);
|
||||||
write = getExportFunction("f", "write", "int", ["int", "pointer", "int"]);
|
var write = getExportFunction("f", "write", "int", ["int", "pointer", "int"]);
|
||||||
lseek = getExportFunction("f", "lseek", "int64", ["int", "int64", "int"]);
|
var lseek = getExportFunction("f", "lseek", "int64", ["int", "int64", "int"]);
|
||||||
close = getExportFunction("f", "close", "int", ["int"]);
|
var close = getExportFunction("f", "close", "int", ["int"]);
|
||||||
remove = getExportFunction("f", "remove", "int", ["pointer"]);
|
var remove = getExportFunction("f", "remove", "int", ["pointer"]);
|
||||||
access = getExportFunction("f", "access", "int", ["pointer", "int"]);
|
var access = getExportFunction("f", "access", "int", ["pointer", "int"]);
|
||||||
|
var dlopen = getExportFunction("f", "dlopen", "pointer", ["pointer", "int"]);
|
||||||
|
|
||||||
function getDocumentDir() {
|
function getDocumentDir() {
|
||||||
var NSDocumentDirectory = 9;
|
var NSDocumentDirectory = 9;
|
||||||
|
@ -154,13 +155,11 @@ function open(pathname, flags, mode) {
|
||||||
|
|
||||||
var modules = null;
|
var modules = null;
|
||||||
function getAllAppModules() {
|
function getAllAppModules() {
|
||||||
if (modules == null) {
|
modules = new Array();
|
||||||
modules = new Array();
|
var tmpmods = Process.enumerateModulesSync();
|
||||||
var tmpmods = Process.enumerateModulesSync();
|
for (var i = 0; i < tmpmods.length; i++) {
|
||||||
for (var i = 0; i < tmpmods.length; i++) {
|
if (tmpmods[i].path.indexOf(".app") != -1) {
|
||||||
if (tmpmods[i].path.indexOf(".app") != -1) {
|
modules.push(tmpmods[i]);
|
||||||
modules.push(tmpmods[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return modules;
|
return modules;
|
||||||
|
@ -314,15 +313,75 @@ function dumpModule(name) {
|
||||||
return newmodpath
|
return newmodpath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadAllDynamicLibrary(app_path) {
|
||||||
|
var defaultManager = ObjC.classes.NSFileManager.defaultManager();
|
||||||
|
var errorPtr = Memory.alloc(Process.pointerSize);
|
||||||
|
Memory.writePointer(errorPtr, NULL);
|
||||||
|
var filenames = defaultManager.contentsOfDirectoryAtPath_error_(app_path, errorPtr);
|
||||||
|
for (var i = 0, l = filenames.count(); i < l; i++) {
|
||||||
|
var file_name = filenames.objectAtIndex_(i);
|
||||||
|
var file_path = app_path.stringByAppendingPathComponent_(file_name);
|
||||||
|
if (file_name.hasSuffix_(".framework")) {
|
||||||
|
var bundle = ObjC.classes.NSBundle.bundleWithPath_(file_path);
|
||||||
|
if (bundle.isLoaded()) {
|
||||||
|
console.log("[frida-ios-dump]: " + file_name + " has been loaded. ");
|
||||||
|
} else {
|
||||||
|
if (bundle.load()) {
|
||||||
|
console.log("[frida-ios-dump]: Load " + file_name + " success. ");
|
||||||
|
} else {
|
||||||
|
console.log("[frida-ios-dump]: Load " + file_name + " failed. ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (file_name.hasSuffix_(".bundle") ||
|
||||||
|
file_name.hasSuffix_(".momd") ||
|
||||||
|
file_name.hasSuffix_(".strings") ||
|
||||||
|
file_name.hasSuffix_(".appex") ||
|
||||||
|
file_name.hasSuffix_(".app") ||
|
||||||
|
file_name.hasSuffix_(".lproj") ||
|
||||||
|
file_name.hasSuffix_(".storyboardc")) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
var isDirPtr = Memory.alloc(Process.pointerSize);
|
||||||
|
Memory.writePointer(isDirPtr,NULL);
|
||||||
|
defaultManager.fileExistsAtPath_isDirectory_(file_path, isDirPtr);
|
||||||
|
if (Memory.readPointer(isDirPtr) == 1) {
|
||||||
|
loadAllDynamicLibrary(file_path);
|
||||||
|
} else {
|
||||||
|
if (file_name.hasSuffix_(".dylib")) {
|
||||||
|
var is_loaded = 0;
|
||||||
|
for (var j = 0; j < modules.length; j++) {
|
||||||
|
if (modules[j].path.indexOf(file_name) != -1) {
|
||||||
|
is_loaded = 1;
|
||||||
|
console.log("[frida-ios-dump]: " + file_name + " has been dlopen.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_loaded) {
|
||||||
|
if (dlopen(allocStr(file_path.UTF8String()), 9)) {
|
||||||
|
console.log("[frida-ios-dump]: dlopen " + file_name + " success. ");
|
||||||
|
} else {
|
||||||
|
console.log("[frida-ios-dump]: dlopen " + file_name + " failed. ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleMessage(message) {
|
function handleMessage(message) {
|
||||||
//start dump
|
modules = getAllAppModules();
|
||||||
|
var app_path = ObjC.classes.NSBundle.mainBundle().bundlePath();
|
||||||
|
loadAllDynamicLibrary(app_path);
|
||||||
|
// start dump
|
||||||
modules = getAllAppModules();
|
modules = getAllAppModules();
|
||||||
for (var i = 0; i < modules.length; i++) {
|
for (var i = 0; i < modules.length; i++) {
|
||||||
console.log("start dump " + modules[i].path);
|
console.log("start dump " + modules[i].path);
|
||||||
result = dumpModule(modules[i].path);
|
var result = dumpModule(modules[i].path);
|
||||||
send({ dump: result, path: modules[i].path});
|
send({ dump: result, path: modules[i].path});
|
||||||
}
|
}
|
||||||
send({app: ObjC.classes.NSBundle.mainBundle().bundlePath().toString()});
|
send({app: app_path.toString()});
|
||||||
send({done: "ok"});
|
send({done: "ok"});
|
||||||
recv(handleMessage);
|
recv(handleMessage);
|
||||||
}
|
}
|
||||||
|
|
114
dump.py
114
dump.py
|
@ -4,26 +4,28 @@
|
||||||
# Author : AloneMonkey
|
# Author : AloneMonkey
|
||||||
# blog: www.alonemonkey.com
|
# blog: www.alonemonkey.com
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
import sys
|
import sys
|
||||||
import codecs
|
import codecs
|
||||||
import frida
|
import frida
|
||||||
import threading
|
import threading
|
||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
import time
|
import time
|
||||||
import argparse
|
import argparse
|
||||||
import tempfile
|
import tempfile
|
||||||
import subprocess
|
import subprocess
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import paramiko
|
import paramiko
|
||||||
from paramiko import SSHClient
|
from paramiko import SSHClient
|
||||||
from scp import SCPClient
|
from scp import SCPClient
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
reload(sys)
|
IS_PY2 = sys.version_info[0] < 3
|
||||||
sys.setdefaultencoding('utf8')
|
if IS_PY2:
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
|
||||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
@ -33,6 +35,7 @@ User = 'root'
|
||||||
Password = 'alpine'
|
Password = 'alpine'
|
||||||
Host = 'localhost'
|
Host = 'localhost'
|
||||||
Port = 2222
|
Port = 2222
|
||||||
|
KeyFileName = None
|
||||||
|
|
||||||
TEMP_DIR = tempfile.gettempdir()
|
TEMP_DIR = tempfile.gettempdir()
|
||||||
PAYLOAD_DIR = 'Payload'
|
PAYLOAD_DIR = 'Payload'
|
||||||
|
@ -43,6 +46,9 @@ finished = threading.Event()
|
||||||
|
|
||||||
|
|
||||||
def get_usb_iphone():
|
def get_usb_iphone():
|
||||||
|
Type = 'usb'
|
||||||
|
if int(frida.__version__.split('.')[0]) < 12:
|
||||||
|
Type = 'tether'
|
||||||
device_manager = frida.get_device_manager()
|
device_manager = frida.get_device_manager()
|
||||||
changed = threading.Event()
|
changed = threading.Event()
|
||||||
|
|
||||||
|
@ -53,9 +59,9 @@ def get_usb_iphone():
|
||||||
|
|
||||||
device = None
|
device = None
|
||||||
while device is None:
|
while device is None:
|
||||||
devices = [dev for dev in device_manager.enumerate_devices() if dev.type == 'tether']
|
devices = [dev for dev in device_manager.enumerate_devices() if dev.type == Type]
|
||||||
if len(devices) == 0:
|
if len(devices) == 0:
|
||||||
print 'Waiting for USB device...'
|
print('Waiting for USB device...')
|
||||||
changed.wait()
|
changed.wait()
|
||||||
else:
|
else:
|
||||||
device = devices[0]
|
device = devices[0]
|
||||||
|
@ -68,23 +74,25 @@ def get_usb_iphone():
|
||||||
def generate_ipa(path, display_name):
|
def generate_ipa(path, display_name):
|
||||||
ipa_filename = display_name + '.ipa'
|
ipa_filename = display_name + '.ipa'
|
||||||
|
|
||||||
print 'Generating "{}"'.format(ipa_filename)
|
print('Generating "{}"'.format(ipa_filename))
|
||||||
try:
|
try:
|
||||||
app_name = file_dict['app']
|
app_name = file_dict['app']
|
||||||
|
|
||||||
for key, value in file_dict.items():
|
for key, value in file_dict.items():
|
||||||
from_dir = os.path.join(path, key)
|
from_dir = os.path.join(path, key)
|
||||||
to_dir = os.path.join(path, app_name, value)
|
to_dir = os.path.join(path, app_name, value)
|
||||||
if key != 'app':
|
if key != 'app':
|
||||||
shutil.move(from_dir, to_dir)
|
try:
|
||||||
|
os.rename(from_dir, to_dir)
|
||||||
|
except FileExistsError:
|
||||||
|
os.remove(to_dir)
|
||||||
|
os.rename(from_dir, to_dir)
|
||||||
target_dir = './' + PAYLOAD_DIR
|
target_dir = './' + PAYLOAD_DIR
|
||||||
zip_args = ('zip', '-qr', os.path.join(os.getcwd(), ipa_filename), target_dir)
|
zip_args = ("7z", "a", "-r", f"{os.getcwd()}/{ipa_filename}.zip", "-w", f"{target_dir}", "-mem=AES256")
|
||||||
subprocess.check_call(zip_args, cwd=TEMP_DIR)
|
subprocess.check_call(zip_args, cwd=TEMP_DIR)
|
||||||
shutil.rmtree(PAYLOAD_PATH)
|
os.rename(f"{os.getcwd()}/{ipa_filename}.zip", f"{os.getcwd()}/{ipa_filename}")
|
||||||
print
|
os.system('rmdir /S /Q "{}"'.format(PAYLOAD_PATH))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print e
|
print(f"{type(e)}: {e}")
|
||||||
finished.set()
|
finished.set()
|
||||||
|
|
||||||
def on_message(message, data):
|
def on_message(message, data):
|
||||||
|
@ -92,7 +100,11 @@ def on_message(message, data):
|
||||||
last_sent = [0]
|
last_sent = [0]
|
||||||
|
|
||||||
def progress(filename, size, sent):
|
def progress(filename, size, sent):
|
||||||
t.desc = os.path.basename(filename)
|
baseName = os.path.basename(filename)
|
||||||
|
if IS_PY2 or isinstance(baseName, bytes):
|
||||||
|
t.desc = baseName.decode("utf-8")
|
||||||
|
else:
|
||||||
|
t.desc = baseName
|
||||||
t.total = size
|
t.total = size
|
||||||
t.update(sent - last_sent[0])
|
t.update(sent - last_sent[0])
|
||||||
last_sent[0] = 0 if size == sent else sent
|
last_sent[0] = 0 if size == sent else sent
|
||||||
|
@ -104,17 +116,19 @@ def on_message(message, data):
|
||||||
dump_path = payload['dump']
|
dump_path = payload['dump']
|
||||||
|
|
||||||
scp_from = dump_path
|
scp_from = dump_path
|
||||||
scp_to = PAYLOAD_PATH + u'/'
|
scp_to = PAYLOAD_PATH + '/'
|
||||||
|
|
||||||
with SCPClient(ssh.get_transport(), progress = progress, socket_timeout = 60) as scp:
|
with SCPClient(ssh.get_transport(), progress = progress, socket_timeout = 60) as scp:
|
||||||
scp.get(scp_from, scp_to)
|
scp.get(scp_from, scp_to)
|
||||||
|
|
||||||
chmod_dir = os.path.join(PAYLOAD_PATH, os.path.basename(dump_path))
|
chmod_dir = os.path.join(PAYLOAD_PATH, os.path.basename(dump_path))
|
||||||
chmod_args = ('chmod', '655', chmod_dir)
|
chmod_args = ('chmod', '655', chmod_dir)
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(chmod_args)
|
subprocess.check_call(chmod_args)
|
||||||
except subprocess.CalledProcessError as err:
|
except subprocess.CalledProcessError as err:
|
||||||
print err
|
print(err)
|
||||||
|
"""
|
||||||
|
|
||||||
index = origin_path.find('.app/')
|
index = origin_path.find('.app/')
|
||||||
file_dict[os.path.basename(dump_path)] = origin_path[index + 5:]
|
file_dict[os.path.basename(dump_path)] = origin_path[index + 5:]
|
||||||
|
@ -123,17 +137,18 @@ def on_message(message, data):
|
||||||
app_path = payload['app']
|
app_path = payload['app']
|
||||||
|
|
||||||
scp_from = app_path
|
scp_from = app_path
|
||||||
scp_to = PAYLOAD_PATH + u'/'
|
scp_to = PAYLOAD_PATH + '/'
|
||||||
with SCPClient(ssh.get_transport(), progress = progress, socket_timeout = 60) as scp:
|
with SCPClient(ssh.get_transport(), progress = progress, socket_timeout = 60) as scp:
|
||||||
scp.get(scp_from, scp_to, recursive=True)
|
scp.get(scp_from, scp_to, recursive=True)
|
||||||
|
|
||||||
chmod_dir = os.path.join(PAYLOAD_PATH, os.path.basename(app_path))
|
chmod_dir = os.path.join(PAYLOAD_PATH, os.path.basename(app_path))
|
||||||
chmod_args = ('chmod', '755', chmod_dir)
|
chmod_args = ('chmod', '755', chmod_dir)
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(chmod_args)
|
subprocess.check_call(chmod_args)
|
||||||
except subprocess.CalledProcessError as err:
|
except subprocess.CalledProcessError as err:
|
||||||
print err
|
print(err)
|
||||||
|
"""
|
||||||
file_dict['app'] = os.path.basename(app_path)
|
file_dict['app'] = os.path.basename(app_path)
|
||||||
|
|
||||||
if 'done' in payload:
|
if 'done' in payload:
|
||||||
|
@ -188,8 +203,7 @@ def get_applications(device):
|
||||||
try:
|
try:
|
||||||
applications = device.enumerate_applications()
|
applications = device.enumerate_applications()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print 'Failed to enumerate applications: %s' % e
|
sys.exit('Failed to enumerate applications: %s' % e)
|
||||||
return
|
|
||||||
|
|
||||||
return applications
|
return applications
|
||||||
|
|
||||||
|
@ -208,15 +222,15 @@ def list_applications(device):
|
||||||
|
|
||||||
header_format = '%' + str(pid_column_width) + 's ' + '%-' + str(name_column_width) + 's ' + '%-' + str(
|
header_format = '%' + str(pid_column_width) + 's ' + '%-' + str(name_column_width) + 's ' + '%-' + str(
|
||||||
identifier_column_width) + 's'
|
identifier_column_width) + 's'
|
||||||
print header_format % ('PID', 'Name', 'Identifier')
|
print(header_format % ('PID', 'Name', 'Identifier'))
|
||||||
print '%s %s %s' % (pid_column_width * '-', name_column_width * '-', identifier_column_width * '-')
|
print('%s %s %s' % (pid_column_width * '-', name_column_width * '-', identifier_column_width * '-'))
|
||||||
line_format = '%' + str(pid_column_width) + 's ' + '%-' + str(name_column_width) + 's ' + '%-' + str(
|
line_format = '%' + str(pid_column_width) + 's ' + '%-' + str(name_column_width) + 's ' + '%-' + str(
|
||||||
identifier_column_width) + 's'
|
identifier_column_width) + 's'
|
||||||
for application in sorted(applications, key=cmp_to_key(compare_applications)):
|
for application in sorted(applications, key=cmp_to_key(compare_applications)):
|
||||||
if application.pid == 0:
|
if application.pid == 0:
|
||||||
print line_format % ('-', application.name, application.identifier)
|
print(line_format % ('-', application.name, application.identifier))
|
||||||
else:
|
else:
|
||||||
print line_format % (application.pid, application.name, application.identifier)
|
print(line_format % (application.pid, application.name, application.identifier))
|
||||||
|
|
||||||
|
|
||||||
def load_js_file(session, filename):
|
def load_js_file(session, filename):
|
||||||
|
@ -234,15 +248,15 @@ def create_dir(path):
|
||||||
path = path.strip()
|
path = path.strip()
|
||||||
path = path.rstrip('\\')
|
path = path.rstrip('\\')
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
shutil.rmtree(path)
|
os.system('rmdir /S /Q "{}"'.format(path))
|
||||||
try:
|
try:
|
||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
except os.error as err:
|
except os.error as err:
|
||||||
print err
|
print(err)
|
||||||
|
|
||||||
|
|
||||||
def open_target_app(device, name_or_bundleid):
|
def open_target_app(device, name_or_bundleid):
|
||||||
print 'Start the target app {}'.format(name_or_bundleid)
|
print('Start the target app {}'.format(name_or_bundleid))
|
||||||
|
|
||||||
pid = ''
|
pid = ''
|
||||||
session = None
|
session = None
|
||||||
|
@ -262,13 +276,13 @@ def open_target_app(device, name_or_bundleid):
|
||||||
else:
|
else:
|
||||||
session = device.attach(pid)
|
session = device.attach(pid)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print e
|
print(e)
|
||||||
|
|
||||||
return session, display_name, bundle_identifier
|
return session, display_name, bundle_identifier
|
||||||
|
|
||||||
|
|
||||||
def start_dump(session, ipa_name):
|
def start_dump(session, ipa_name):
|
||||||
print 'Dumping {} to {}'.format(display_name, TEMP_DIR)
|
print('Dumping {} to {}'.format(display_name, TEMP_DIR))
|
||||||
|
|
||||||
script = load_js_file(session, DUMP_JS)
|
script = load_js_file(session, DUMP_JS)
|
||||||
script.post('dump')
|
script.post('dump')
|
||||||
|
@ -284,25 +298,45 @@ if __name__ == '__main__':
|
||||||
parser = argparse.ArgumentParser(description='frida-ios-dump (by AloneMonkey v2.0)')
|
parser = argparse.ArgumentParser(description='frida-ios-dump (by AloneMonkey v2.0)')
|
||||||
parser.add_argument('-l', '--list', dest='list_applications', action='store_true', help='List the installed apps')
|
parser.add_argument('-l', '--list', dest='list_applications', action='store_true', help='List the installed apps')
|
||||||
parser.add_argument('-o', '--output', dest='output_ipa', help='Specify name of the decrypted IPA')
|
parser.add_argument('-o', '--output', dest='output_ipa', help='Specify name of the decrypted IPA')
|
||||||
|
parser.add_argument('-H', '--host', dest='ssh_host', help='Specify SSH hostname')
|
||||||
|
parser.add_argument('-p', '--port', dest='ssh_port', help='Specify SSH port')
|
||||||
|
parser.add_argument('-u', '--user', dest='ssh_user', help='Specify SSH username')
|
||||||
|
parser.add_argument('-P', '--password', dest='ssh_password', help='Specify SSH password')
|
||||||
|
parser.add_argument('-K', '--key_filename', dest='ssh_key_filename', help='Specify SSH private key file path')
|
||||||
parser.add_argument('target', nargs='?', help='Bundle identifier or display name of the target app')
|
parser.add_argument('target', nargs='?', help='Bundle identifier or display name of the target app')
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
exit_code = 0
|
exit_code = 0
|
||||||
ssh = None
|
ssh = None
|
||||||
|
|
||||||
|
if not len(sys.argv[1:]):
|
||||||
|
parser.print_help()
|
||||||
|
sys.exit(exit_code)
|
||||||
|
|
||||||
device = get_usb_iphone()
|
device = get_usb_iphone()
|
||||||
|
|
||||||
if len(sys.argv[1:]) == 0:
|
if args.list_applications:
|
||||||
parser.print_help()
|
|
||||||
elif args.list_applications:
|
|
||||||
list_applications(device)
|
list_applications(device)
|
||||||
else:
|
else:
|
||||||
name_or_bundleid = args.target
|
name_or_bundleid = args.target
|
||||||
output_ipa = args.output_ipa
|
output_ipa = args.output_ipa
|
||||||
|
# update ssh args
|
||||||
|
if args.ssh_host:
|
||||||
|
Host = args.ssh_host
|
||||||
|
if args.ssh_port:
|
||||||
|
Port = int(args.ssh_port)
|
||||||
|
if args.ssh_user:
|
||||||
|
User = args.ssh_user
|
||||||
|
if args.ssh_password:
|
||||||
|
Password = args.ssh_password
|
||||||
|
if args.ssh_key_filename:
|
||||||
|
KeyFileName = args.ssh_key_filename
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ssh = paramiko.SSHClient()
|
ssh = paramiko.SSHClient()
|
||||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
ssh.connect(Host, port=Port, username=User, password=Password)
|
ssh.connect(Host, port=Port, username=User, password=Password, key_filename=KeyFileName)
|
||||||
|
|
||||||
create_dir(PAYLOAD_PATH)
|
create_dir(PAYLOAD_PATH)
|
||||||
(session, display_name, bundle_identifier) = open_target_app(device, name_or_bundleid)
|
(session, display_name, bundle_identifier) = open_target_app(device, name_or_bundleid)
|
||||||
|
@ -312,10 +346,12 @@ if __name__ == '__main__':
|
||||||
if session:
|
if session:
|
||||||
start_dump(session, output_ipa)
|
start_dump(session, output_ipa)
|
||||||
except paramiko.ssh_exception.NoValidConnectionsError as e:
|
except paramiko.ssh_exception.NoValidConnectionsError as e:
|
||||||
print e
|
print(e)
|
||||||
|
print('Try specifying -H/--hostname and/or -p/--port')
|
||||||
exit_code = 1
|
exit_code = 1
|
||||||
except paramiko.AuthenticationException as e:
|
except paramiko.AuthenticationException as e:
|
||||||
print e
|
print(e)
|
||||||
|
print('Try specifying -u/--username and/or -P/--password')
|
||||||
exit_code = 1
|
exit_code = 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('*** Caught exception: %s: %s' % (e.__class__, e))
|
print('*** Caught exception: %s: %s' % (e.__class__, e))
|
||||||
|
@ -326,6 +362,6 @@ if __name__ == '__main__':
|
||||||
ssh.close()
|
ssh.close()
|
||||||
|
|
||||||
if os.path.exists(PAYLOAD_PATH):
|
if os.path.exists(PAYLOAD_PATH):
|
||||||
shutil.rmtree(PAYLOAD_PATH)
|
os.system('rmdir /S /Q "{}"'.format(PAYLOAD_PATH))
|
||||||
|
|
||||||
sys.exit(exit_code)
|
sys.exit(exit_code)
|
||||||
|
|
|
@ -4,7 +4,7 @@ cffi
|
||||||
colorama
|
colorama
|
||||||
cryptography
|
cryptography
|
||||||
enum34
|
enum34
|
||||||
frida
|
frida-tools
|
||||||
idna
|
idna
|
||||||
ipaddress
|
ipaddress
|
||||||
paramiko
|
paramiko
|
||||||
|
|
Loading…
Reference in New Issue