Skip to content

Commit 6b88fb8

Browse files
authored
Merge pull request #94 from alright21/master
Add patchmultiple functionality to patch bundled apks
2 parents 5ecbabb + 3cd5396 commit 6b88fb8

File tree

1 file changed

+92
-52
lines changed

1 file changed

+92
-52
lines changed

libraries/libmango.py

Lines changed: 92 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
APKTOOL = os.path.abspath(os.path.join(BASE, '../dependencies/apktool.jar'))
2525
MEDUSA_AGENT = os.path.abspath(os.path.join(BASE, '../dependencies/agent.apk'))
2626
DEBUGGABLE_APK = os.getcwd() + "/debuggable.apk"
27-
ALLIGNED_APK = os.getcwd() + "/debuggable_alligned_signed.apk"
27+
ALIGNED_APK = os.getcwd() + "/debuggable_aligned_signed.apk"
2828
TMP_FOLDER = os.getcwd() + "/tmp_dir"
2929
SIGNATURE = os.path.abspath(os.path.join(BASE, '../dependencies/common.jks'))
3030
PLAYSTORE_VERSION_PATTERN_0 = re.compile(r'\[\[\["([0-9]+\.[0-9]+\.[0-9]+)"\]\],\[\[\[33\]\],\[\[\[23,"[0-9]+\.[0-9]+"\]\]\]\]')
@@ -601,62 +601,28 @@ def do_notify(self, line):
601601

602602
def do_patch(self, line):
603603
"""Usage: patch /full/path/to/foo.apk
604-
Changes the debuggable flage of the AndroidManifest.xml to true for a given apk.
605-
The command requires apksigner and zipallign to have been installed."""
604+
Changes the debuggable flag of the AndroidManifest.xml to true for a given apk.
605+
The command requires apksigner and zipalign to have been installed."""
606606

607-
text_to_search = "<application"
608-
replacement_text = '<application android:debuggable="true" '
609-
file = line.split(' ')[0]
610-
611-
if os.path.exists(file):
612-
try:
613-
if not self.does_exist("apksigner"):
614-
print("[!] apksigner is not installed, quiting !")
615-
return
616-
if not self.does_exist("zipalign"):
617-
print("[!] zipalign is not installed, quiting !")
618-
return
619-
if not os.path.exists(APKTOOL):
620-
if Polar('[?] apktool has not been downloaded, do you want to do it now ?').ask():
621-
self.download_file(APKTOOL_URL, APKTOOL)
622-
623-
print(GREEN + '[+] Unpacking the apk....' + RESET)
624-
subprocess.run('java -jar ' + APKTOOL + f' d {file} -o {TMP_FOLDER}', shell=True)
625-
626-
print(GREEN + '[+] Extracting the manifest....' + RESET)
627-
with open(TMP_FOLDER + '/AndroidManifest.xml', 'rt') as f:
628-
data = f.read()
629-
630-
print(GREEN + '[+] Setting the debug flag to true...')
631-
632-
if 'android:debuggable="true"' in data:
633-
print(RED + "[!] Application is already debuggable !" + RESET)
634-
else:
635-
data = data.replace(text_to_search, replacement_text)
607+
if len(line.arg_list) > 0:
608+
self.patch_apk(line.arg_list[0])
609+
else:
610+
logger.error("[!] Usage: patch /full/path/to/foo.apk")
611+
636612

637-
with open(TMP_FOLDER + '/AndroidManifest.xml', 'wt') as f:
638-
f.write(data)
639-
print(GREEN + '[+] Repacking the app...' + RESET)
640-
subprocess.run('java -jar ' + APKTOOL + f' b {TMP_FOLDER} -o {DEBUGGABLE_APK}', shell=True)
641-
print(GREEN + '[+] Alligning the apk file.....' + RESET)
642-
subprocess.run(f'zipalign -p -v 4 {DEBUGGABLE_APK} {ALLIGNED_APK}', shell=True)
643-
print(GREEN + '[+] Signing the apk.....' + RESET)
644-
subprocess.run(
645-
f'apksigner sign --ks {SIGNATURE} -ks-key-alias common --ks-pass pass:password --key-pass pass:password {ALLIGNED_APK}',
646-
shell=True)
647-
print(GREEN + '[+] Removing the unsigned apk.....' + RESET)
648-
os.remove(DEBUGGABLE_APK)
649-
print(GREEN + '[+] Backing up the original...' + RESET)
650-
shutil.move(file, 'original_' + file)
651-
shutil.move(ALLIGNED_APK, file)
652613

653-
if not Polar('[?] Do you want to keep the extracted resources ?').ask():
654-
shutil.rmtree(TMP_FOLDER)
655-
except Exception as e:
656-
print(e)
614+
def do_patchmultiple(self, line):
615+
"""Usage: patchmultiple /full/path/to/foo.apk /full/path/to/split_config.en.apk ...
616+
Changes the debuggable flag of the AndroidManifest.xml to true for a given apks. It is used for bundled apk patching.
617+
The command requires apksigner and zipalign to have been installed."""
657618

619+
if len(line.arg_list)>1:
620+
for file in line.arg_list:
621+
self.patch_apk(file)
658622
else:
659-
print("[!] File doesn't exist.")
623+
logger.error("[!] Usage: patchmultiple /full/path/to/foo.apk /full/path/to/split_config.en.apk ...")
624+
625+
660626

661627
def do_playstore(self, line):
662628
"""Usage: playstore package_name
@@ -1206,6 +1172,11 @@ def complete_spawn(self, text, line, begidx, endidx):
12061172

12071173
def complete_uninstall(self, text, line, begidx, endidx):
12081174
return self.get_packages_starting_with(text)
1175+
1176+
complete_install = cmd2.Cmd.path_complete
1177+
complete_installmultiple = cmd2.Cmd.path_complete
1178+
complete_patch = cmd2.Cmd.path_complete
1179+
complete_patchmultiple = cmd2.Cmd.path_complete
12091180

12101181
###################################################### print defs start ############################################################
12111182

@@ -1809,3 +1780,72 @@ def transproxy(self, ip, port):
18091780
self.print_proxy()
18101781
except Exception as e:
18111782
logger.error(e)
1783+
1784+
1785+
def patch_apk(self, file: str):
1786+
"""Patches an apk to make it debuggable"""
1787+
text_to_search = "<application"
1788+
replacement_text = '<application android:debuggable="true" '
1789+
APP_FOLDER = os.path.join(TMP_FOLDER, os.path.basename(file))
1790+
1791+
if os.path.exists(file):
1792+
file_name, extension = os.path.splitext(file)
1793+
ALIGNED_APK = file_name + '_debuggable' + extension
1794+
try:
1795+
if not self.does_exist("apksigner"):
1796+
logger.error("[!] apksigner is not installed, quitting !")
1797+
return
1798+
if not self.does_exist("zipalign"):
1799+
logger.error("[!] zipalign is not installed, quitting !")
1800+
return
1801+
if not os.path.exists(APKTOOL):
1802+
if Polar('[?] apktool has not been downloaded, do you want to do it now ?').ask():
1803+
logger.info("[+] Downloading apktool from " + APKTOOL_URL + " to " +APKTOOL)
1804+
self.download_file(APKTOOL_URL, APKTOOL)
1805+
1806+
logger.info("[+] Unpacking the apk...")
1807+
if os.path.exists(APP_FOLDER):
1808+
if Polar('[?] Folder' + APP_FOLDER + ' already exists. Do you want to remove the old resources?').ask():
1809+
logger.info("[+] Removing old resources...")
1810+
shutil.rmtree(APP_FOLDER)
1811+
else:
1812+
logger.info("[!] The application will use the existing directory")
1813+
1814+
subprocess.run('java -jar ' + APKTOOL + f' d {file} -o {APP_FOLDER}', shell=True)
1815+
1816+
logger.info("[+] Extracting the manifest...")
1817+
with open(APP_FOLDER + '/AndroidManifest.xml', 'rt') as f:
1818+
data = f.read()
1819+
1820+
logger.info("[+] Setting the debug flag to true...")
1821+
1822+
if 'android:debuggable="true"' in data:
1823+
logger.error("[!] Application is already debuggable !")
1824+
else:
1825+
data = data.replace(text_to_search, replacement_text)
1826+
1827+
with open(APP_FOLDER + '/AndroidManifest.xml', 'wt') as f:
1828+
f.write(data)
1829+
logger.info("[+] Repacking the app...")
1830+
subprocess.run('java -jar ' + APKTOOL + f' b {APP_FOLDER} -o {DEBUGGABLE_APK}', shell=True)
1831+
logger.info("[+] Aligning the apk file...")
1832+
subprocess.run(f'zipalign -p -v 4 {DEBUGGABLE_APK} {ALIGNED_APK}', shell=True)
1833+
logger.info("[+] Signing the apk...")
1834+
subprocess.run(
1835+
f'apksigner sign --ks {SIGNATURE} -ks-key-alias common --ks-pass pass:password --key-pass pass:password {ALIGNED_APK}',
1836+
shell=True)
1837+
logger.info("[+] Removing the unsigned apk...")
1838+
os.remove(DEBUGGABLE_APK)
1839+
logger.info("[+] Original file: " + file)
1840+
logger.info("[+] Debuggable file: " + ALIGNED_APK)
1841+
1842+
if not Polar('[?] Do you want to keep the extracted resources ?').ask():
1843+
shutil.rmtree(APP_FOLDER)
1844+
if len(os.listdir(TMP_FOLDER)) == 0:
1845+
logger.info(f"[+] {TMP_FOLDER} is empty, removing it...")
1846+
shutil.rmtree(TMP_FOLDER)
1847+
except Exception as e:
1848+
logger.error(e)
1849+
1850+
else:
1851+
logger.error("[!] File doesn't exist.")

0 commit comments

Comments
 (0)