Skip to content

Instantly share code, notes, and snippets.

@YungRaj
Created October 31, 2023 22:35
Show Gist options
  • Save YungRaj/d12a5178f66483f104a1caf83973008a to your computer and use it in GitHub Desktop.
Save YungRaj/d12a5178f66483f104a1caf83973008a to your computer and use it in GitHub Desktop.
import sys, os, re, subprocess, select, plistlib, frida
def print_usage():
print('python3 install_ios_app.py app_ids')
argv = sys.argv;
argc = len(sys.argv)
if argc < 2:
print_usage();
env = os.environ.copy()
env['IPATOOL_EMAIL'] = ''
env['IPATOOL_PASSWORD'] = ''
env['IPATOOL_2FA_CODE'] = ''
command = ['ipatool','auth', 'login']
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, env=env)
output, error = process.communicate()
output = output.decode('utf-8')
stream = output.split('\n')
for i in range(1, argc):
app_id = argv[i]
command = ['ipatool','search', app_id]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, env=env)
output, error = process.communicate()
output = output.decode('utf-8')
stream = output.split('\n')
bundle_id = None
print('Installing app with app id %s' %(app_id))
for line in stream:
regex = re.compile(r'\b(?![A-Z])[\w-]+(?:\.[\w-]+)+\b')
result = regex.findall(line)
if result:
result = result[0].strip().split(' ')
if result is not None and len(result) != 0:
bundle_id = result[0]
else:
continue
if bundle_id is None:
print_usage()
print(bundle_id)
command = ['ipatool','purchase', '--bundle-identifier', bundle_id, '--device-family', 'iPhone']
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, env=env)
output, error = process.communicate()
output = output.decode('utf-8')
stream = output.split('\n')
command = ['ipatool','download', '--bundle-identifier', bundle_id, '--device-family', 'iPhone']
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, env=env)
output, error = process.communicate()
output = output.decode('utf-8')
stream = output.split('\n')
ipa_file = None
for line in stream:
if bundle_id in line and '.ipa' in line:
ipa_file = line[line.find(bundle_id):line.find('.ipa') + len('.ipa')]
if ipa_file is None:
print_usage()
print('ipa = %s' % (ipa_file))
command = ['ideviceinstaller','-i', ipa_file]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)
output, error = process.communicate()
output = output.decode('utf-8')
stream = output.split('\n')
if error is not None:
exit(-1)
num_failures = 0
complete = False
while(not complete and num_failures < 10):
env = os.environ.copy()
env['SSH_PORT'] = '2222'
env['SSH_USERNAME'] = 'root'
env['SSH_PASSWORD'] = 'ilhan123'
command = ['bagbak','-U', bundle_id]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
stdout = []
stderr = []
while True:
reads = [process.stdout.fileno(), process.stderr.fileno()]
ret = select.select(reads, [], [])
for fd in ret[0]:
if fd == process.stdout.fileno():
read = process.stdout.readline()
sys.stdout.write(read.decode("utf-8") )
stdout.append(read.decode("utf-8") )
if fd == process.stderr.fileno():
read = process.stderr.readline()
sys.stderr.write(read.decode("utf-8") )
stderr.append(read.decode("utf-8") )
if process.poll() != None:
break
process.wait()
output, error = process.communicate()
output = "".join(stdout)
error = "".join(stderr)
stream = output.split('\n')
print(output)
print(error)
if 'Saved to' in output:
complete = True
else:
complete = False
num_failures += 1
if(num_failures >= 10):
continue
localized_app_ipa = None
for line in stream:
if '.ipa' in line and 'Saved to':
localized_app_ipa = line.split(' ')[2]
break
if localized_app_ipa is None:
print_usage()
decrypt_folder = './dump/' + bundle_id
payload_folder = decrypt_folder + '/Payload'
command = ['unzip', localized_app_ipa, '-d', decrypt_folder]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)
output, error = process.communicate()
output = output.decode('utf-8')
command = ['ls', '-1', payload_folder]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)
output, error = process.communicate()
output = output.decode('utf-8')
stream = output.split('\n')
for line in stream:
if '.app' in line:
localized_name = line[:line.find('.app')]
break
app_bundle = payload_folder + '/' + localized_name + '.app'
app_binary = app_bundle + '/' + localized_name
app_frameworks = app_bundle + '/' + 'Frameworks'
command = ['codesign', '-fs', '-', '--preserve-metadata=entitlements', app_binary, '--deep']
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)
output, error = process.communicate()
output = output.decode('utf-8')
command = ['ls', '-1', app_frameworks]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)
output, error = process.communicate()
output = output.decode('utf-8')
stream = output.split('\n')
for line in stream:
to_sign = app_frameworks + '/' + line
command = ['codesign', '-fs', '-', '--preserve-metadata=entitlements', to_sign, '--deep']
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)
output, error = process.communicate()
output = output.decode('utf-8')
new_ipa = decrypt_folder + '/' + localized_name + '.ipa'
command = ['ditto', '-c', '-k', '--sequesterRsrc', '--keepParent', payload_folder, new_ipa]
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)
output, error = process.communicate()
output = output.decode('utf-8')
command = ['rm', './*.ipa']
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None)
output, error = process.communicate()
output = output.decode('utf-8')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment