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 |
13
README.md
13
README.md
|
@ -1,13 +1,13 @@
|
|||
# frida-ios-dump
|
||||
Pull a decrypted IPA from a jailbroken device
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
1. Install [frida](http://www.frida.re/) on device
|
||||
2. `sudo pip install -r requirements.txt --upgrade` (Python 2.7)
|
||||
3. `sudo pip3 install -r requirements.txt --upgrade` (Python 3.x)
|
||||
4. Run usbmuxd/iproxy SSH forwarding over USB (Default 2222 -> 22). e.g. `iproxy 2222 22`
|
||||
5. Run ./dump.py `Display name` or `Bundle identifier`
|
||||
2. `sudo pip install -r requirements.txt --upgrade`
|
||||
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`
|
||||
|
||||
For SSH/SCP make sure you have your public key added to the target device's ~/.ssh/authorized_keys file.
|
||||
|
||||
|
@ -40,6 +40,11 @@ Congratulations!!! You've got a decrypted IPA file.
|
|||
|
||||
Drag to [MonkeyDev](https://github.com/AloneMonkey/MonkeyDev), Happy hacking!
|
||||
|
||||
## Support
|
||||
|
||||
Python 2.x and 3.x
|
||||
|
||||
|
||||
### issues
|
||||
|
||||
If the following error occurs:
|
||||
|
|
67
dump.py
67
dump.py
|
@ -1,27 +1,32 @@
|
|||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Author : AloneMonkey
|
||||
# blog: www.alonemonkey.com
|
||||
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import sys
|
||||
import codecs
|
||||
import frida
|
||||
import threading
|
||||
import os
|
||||
import shutil
|
||||
import time
|
||||
import argparse
|
||||
import tempfile
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
import paramiko
|
||||
from paramiko import SSHClient
|
||||
from scp import SCPClient
|
||||
from tqdm import tqdm
|
||||
import traceback
|
||||
|
||||
IS_PY2 = sys.version_info[0] < 3
|
||||
if IS_PY2:
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf8')
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
DUMP_JS = os.path.join(script_dir, 'dump.js')
|
||||
|
@ -30,6 +35,7 @@ User = 'root'
|
|||
Password = 'alpine'
|
||||
Host = 'localhost'
|
||||
Port = 2222
|
||||
KeyFileName = None
|
||||
|
||||
TEMP_DIR = tempfile.gettempdir()
|
||||
PAYLOAD_DIR = 'Payload'
|
||||
|
@ -71,19 +77,22 @@ def generate_ipa(path, display_name):
|
|||
print('Generating "{}"'.format(ipa_filename))
|
||||
try:
|
||||
app_name = file_dict['app']
|
||||
|
||||
for key, value in file_dict.items():
|
||||
from_dir = os.path.join(path, key)
|
||||
to_dir = os.path.join(path, app_name, value)
|
||||
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
|
||||
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)
|
||||
shutil.rmtree(PAYLOAD_PATH)
|
||||
os.rename(f"{os.getcwd()}/{ipa_filename}.zip", f"{os.getcwd()}/{ipa_filename}")
|
||||
os.system('rmdir /S /Q "{}"'.format(PAYLOAD_PATH))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print(f"{type(e)}: {e}")
|
||||
finished.set()
|
||||
|
||||
def on_message(message, data):
|
||||
|
@ -91,7 +100,11 @@ def on_message(message, data):
|
|||
last_sent = [0]
|
||||
|
||||
def progress(filename, size, sent):
|
||||
t.desc = os.path.basename(filename).decode("utf-8")
|
||||
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.update(sent - last_sent[0])
|
||||
last_sent[0] = 0 if size == sent else sent
|
||||
|
@ -110,10 +123,12 @@ def on_message(message, data):
|
|||
|
||||
chmod_dir = os.path.join(PAYLOAD_PATH, os.path.basename(dump_path))
|
||||
chmod_args = ('chmod', '655', chmod_dir)
|
||||
"""
|
||||
try:
|
||||
subprocess.check_call(chmod_args)
|
||||
except subprocess.CalledProcessError as err:
|
||||
print(err)
|
||||
"""
|
||||
|
||||
index = origin_path.find('.app/')
|
||||
file_dict[os.path.basename(dump_path)] = origin_path[index + 5:]
|
||||
|
@ -128,11 +143,12 @@ def on_message(message, data):
|
|||
|
||||
chmod_dir = os.path.join(PAYLOAD_PATH, os.path.basename(app_path))
|
||||
chmod_args = ('chmod', '755', chmod_dir)
|
||||
"""
|
||||
try:
|
||||
subprocess.check_call(chmod_args)
|
||||
except subprocess.CalledProcessError as err:
|
||||
print(err)
|
||||
|
||||
"""
|
||||
file_dict['app'] = os.path.basename(app_path)
|
||||
|
||||
if 'done' in payload:
|
||||
|
@ -232,7 +248,7 @@ def create_dir(path):
|
|||
path = path.strip()
|
||||
path = path.rstrip('\\')
|
||||
if os.path.exists(path):
|
||||
shutil.rmtree(path)
|
||||
os.system('rmdir /S /Q "{}"'.format(path))
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except os.error as err:
|
||||
|
@ -282,7 +298,13 @@ if __name__ == '__main__':
|
|||
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('-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')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
exit_code = 0
|
||||
|
@ -299,11 +321,22 @@ if __name__ == '__main__':
|
|||
else:
|
||||
name_or_bundleid = args.target
|
||||
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:
|
||||
ssh = paramiko.SSHClient()
|
||||
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)
|
||||
(session, display_name, bundle_identifier) = open_target_app(device, name_or_bundleid)
|
||||
|
@ -313,10 +346,12 @@ if __name__ == '__main__':
|
|||
if session:
|
||||
start_dump(session, output_ipa)
|
||||
except paramiko.ssh_exception.NoValidConnectionsError as e:
|
||||
print(e)
|
||||
print(e)
|
||||
print('Try specifying -H/--hostname and/or -p/--port')
|
||||
exit_code = 1
|
||||
except paramiko.AuthenticationException as e:
|
||||
print(e)
|
||||
print(e)
|
||||
print('Try specifying -u/--username and/or -P/--password')
|
||||
exit_code = 1
|
||||
except Exception as e:
|
||||
print('*** Caught exception: %s: %s' % (e.__class__, e))
|
||||
|
@ -327,6 +362,6 @@ if __name__ == '__main__':
|
|||
ssh.close()
|
||||
|
||||
if os.path.exists(PAYLOAD_PATH):
|
||||
shutil.rmtree(PAYLOAD_PATH)
|
||||
os.system('rmdir /S /Q "{}"'.format(PAYLOAD_PATH))
|
||||
|
||||
sys.exit(exit_code)
|
||||
|
|
Loading…
Reference in New Issue