|
24 | 24 | APKTOOL = os.path.abspath(os.path.join(BASE, '../dependencies/apktool.jar'))
|
25 | 25 | MEDUSA_AGENT = os.path.abspath(os.path.join(BASE, '../dependencies/agent.apk'))
|
26 | 26 | DEBUGGABLE_APK = os.getcwd() + "/debuggable.apk"
|
27 |
| -ALLIGNED_APK = os.getcwd() + "/debuggable_alligned_signed.apk" |
| 27 | +ALIGNED_APK = os.getcwd() + "/debuggable_aligned_signed.apk" |
28 | 28 | TMP_FOLDER = os.getcwd() + "/tmp_dir"
|
29 | 29 | SIGNATURE = os.path.abspath(os.path.join(BASE, '../dependencies/common.jks'))
|
30 | 30 | 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):
|
601 | 601 |
|
602 | 602 | def do_patch(self, line):
|
603 | 603 | """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.""" |
606 | 606 |
|
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 | + |
636 | 612 |
|
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) |
652 | 613 |
|
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.""" |
657 | 618 |
|
| 619 | + if len(line.arg_list)>1: |
| 620 | + for file in line.arg_list: |
| 621 | + self.patch_apk(file) |
658 | 622 | 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 | + |
660 | 626 |
|
661 | 627 | def do_playstore(self, line):
|
662 | 628 | """Usage: playstore package_name
|
@@ -1206,6 +1172,11 @@ def complete_spawn(self, text, line, begidx, endidx):
|
1206 | 1172 |
|
1207 | 1173 | def complete_uninstall(self, text, line, begidx, endidx):
|
1208 | 1174 | 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 |
1209 | 1180 |
|
1210 | 1181 | ###################################################### print defs start ############################################################
|
1211 | 1182 |
|
@@ -1809,3 +1780,72 @@ def transproxy(self, ip, port):
|
1809 | 1780 | self.print_proxy()
|
1810 | 1781 | except Exception as e:
|
1811 | 1782 | 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