frida-ios-dump/dump.py

272 lines
7.7 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Author : AloneMonkey
#blog: www.alonemonkey.com
import sys
import codecs
import frida
import threading
import os
import shutil
import time
import getopt
reload(sys)
sys.setdefaultencoding('utf8')
DUMP_JS = './dump.js'
APP_JS = './app.js'
OUTPUT = "Payload"
file_dict = {}
opened = threading.Event()
finished = threading.Event()
global session
global name
#show usage
def usage():
print '-------------------------frida-ios-dump(by AloneMonkey v2.0)----------------------------'
print '\t%-20s\t%s' % ('-h,--help','Show help menu.');
print '\t%-20s\t%s' % ('displayname','Decrypt the application of the specified display name. ps: ./dump.py 微信');
print '\t%-20s\t%s' % ('-l','List the app has been installed.');
print '\t%-20s\t%s' % ('-b bundleid','Decrypt the application of the specified bundleid. ps: ./dump.py com.tencent.xin');
exit(0)
def get_usb_iphone():
dManager = frida.get_device_manager();
changed = threading.Event()
def on_changed():
changed.set()
dManager.on('changed',on_changed)
device = None
while device is None:
devices = [dev for dev in dManager.enumerate_devices() if dev.type == 'tether']
if len(devices) == 0:
print 'Waiting for usb device...'
changed.wait()
else:
device = devices[0]
dManager.off('changed',on_changed)
return device
def gen_ipa(target):
try:
app_name = file_dict["app"]
for key, value in file_dict.items():
if key != "app":
shutil.move(target +"/"+ key, target + "/" + app_name + "/" + value);
(shotname,extension) = os.path.splitext(app_name)
os.system(u''.join(("zip -qr ", name.replace(" ", "\\ "), ".ipa ./Payload")).encode('utf-8').strip());
os.system("rm -rf ./Payload");
except Exception as e:
print e
finished.set();
def on_message(message,data):
global name;
if message.has_key('payload'):
payload = message['payload']
if payload.has_key("opened"):
name = payload["opened"]
opened.set();
if payload.has_key("dump"):
orign_path = payload["path"]
dumppath = payload["dump"]
os.system(u''.join(("scp -P 2222 root@localhost:", dumppath.replace(" ", "\\\\\ "), u" ./" + OUTPUT + u"/")).encode('utf-8').strip())
os.system(u''.join(("chmod 655 ", u'./' + OUTPUT + u'/', os.path.basename(dumppath.replace(" ", "\\ ")))).encode('utf-8').strip())
index = orign_path.find(".app/")
file_dict[os.path.basename(dumppath)] = orign_path[index+5:]
if payload.has_key("app"):
apppath = payload["app"]
os.system(u''.join(("scp -r -P 2222 root@localhost:", apppath.replace(" ", "\\\\\ "), u" ./" + OUTPUT + u"/")).encode('utf-8').strip())
os.system(u''.join(("chmod 755 ", u'./' + OUTPUT + u'/', os.path.basename(apppath.replace(" ", "\\ ")))).encode('utf-8').strip())
file_dict["app"] = os.path.basename(apppath)
if payload.has_key("done"):
gen_ipa(os.getcwd()+"/"+OUTPUT)
finished.set();
def compare_applications(a, b):
a_is_running = a.pid != 0
b_is_running = b.pid != 0
if a_is_running == b_is_running:
if a.name > b.name:
return 1
elif a.name < b.name:
return -1
else:
return 0
elif a_is_running:
return -1
else:
return 1
def cmp_to_key(mycmp):
"Convert a cmp= function into a key= function"
class K:
def __init__(self, obj, *args):
self.obj = obj
def __lt__(self, other):
return mycmp(self.obj, other.obj) < 0
def __gt__(self, other):
return mycmp(self.obj, other.obj) > 0
def __eq__(self, other):
return mycmp(self.obj, other.obj) == 0
def __le__(self, other):
return mycmp(self.obj, other.obj) <= 0
def __ge__(self, other):
return mycmp(self.obj, other.obj) >= 0
def __ne__(self, other):
return mycmp(self.obj, other.obj) != 0
return K
def get_applications():
device = get_usb_iphone()
try:
applications = device.enumerate_applications()
except Exception as e:
print "Failed to enumerate applications: %s" % e
exit(1)
return
return applications
def list_applications():
applications = get_applications()
if len(applications) > 0:
pid_column_width = max(map(lambda app: len("%d" % app.pid), applications))
name_column_width = max(map(lambda app: len(app.name), applications))
identifier_column_width = max(map(lambda app: len(app.identifier), applications))
else:
pid_column_width = 0
name_column_width = 0
identifier_column_width = 0
header_format = "%" + str(pid_column_width) + "s " + "%-" + str(name_column_width) + "s " + "%-" + str(identifier_column_width) + "s"
print header_format % ("PID", "Name", "Identifier")
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(identifier_column_width) + "s"
for app in sorted(applications, key=cmp_to_key(compare_applications)):
if app.pid == 0:
print line_format % ("-", app.name, app.identifier)
else:
print line_format % (app.pid, app.name, app.identifier)
def get_pid_by_bundleid(bundleid):
applications = get_applications()
return [app.pid for app in applications if app.identifier == bundleid][0]
def find_target_app(isbundleid, value):
applications = get_applications()
if not isbundleid:
return [app for app in applications if app.name == value]
else:
return [app for app in applications if app.identifier == value]
def load_js_file(session, filename):
source = ''
with codecs.open(filename,'r','utf-8') as f:
source = source + f.read();
script = session.create_script(source);
script.on("message",on_message)
script.load()
return script
def clear_and_quit(session):
if session:
session.detach()
sys.exit(0)
def create_dir(path):
path = path.strip()
path = path.rstrip("\\")
if not os.path.exists(path):
os.makedirs(path)
else:
print path + u" is existed!";
def open_target_app(isbundleid, value):
global session;
device = get_usb_iphone();
name = u'SpringBoard';
print "open target app......"
session = device.attach(name);
script = load_js_file(session, APP_JS);
if not isbundleid:
script.post({'name': value})
else:
script.post({'bundleid': value})
opened.wait();
session.detach();
create_dir(os.getcwd()+"/"+OUTPUT)
print 'Waiting for the application to open......'
time.sleep(5);
def start_dump(target):
global session;
print "start dump target app......"
device = get_usb_iphone();
session = device.attach(target);
script = load_js_file(session, DUMP_JS);
script.post("dump");
finished.wait();
clear_and_quit(session);
def dump_by_display_name(display_name):
open_target_app( 0, display_name)
start_dump(display_name);
def dump_by_bundleid(bundleid):
open_target_app( 1, bundleid)
start_dump(get_pid_by_bundleid(bundleid));
def check_args():
if len(sys.argv) < 2:
usage()
sys.exit(1)
try:
opts,args = getopt.getopt(sys.argv[1:],"hlb:",["help"]);
except getopt.GetoptError:
usage()
sys.exit(2)
for opt,value in opts:
if opt in ("-h","--help"):
usage()
if opt in ("-l"):
list_applications()
if opt in ("-b"):
if not find_target_app(1, value):
print "can not find target app '%s'" % value
else:
dump_by_bundleid(value)
if len(opts) == 0 and len(sys.argv) == 2:
name = sys.argv[1].decode('utf8');
if not find_target_app(0, name):
print "can not find target app '%s'" % name
else:
dump_by_display_name(name)
sys.exit(0)
if __name__ == "__main__":
try:
check_args()
pass
except KeyboardInterrupt:
if session:
session.detach()
sys.exit()
except:
pass