├── LICENSE ├── README.txt ├── abe.jar └── backHack.py /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016 Kirk Hayes (l0gan) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | 2 | /$$ /$$ /$$ /$$ /$$ 3 | | $$ | $$ | $$ | $$ | $$ 4 | | $$$$$$$ /$$$$$$ /$$$$$$$| $$ /$$| $$ | $$ /$$$$$$ /$$$$$$$| $$ /$$ 5 | | $$__ $$ |____ $$ /$$_____/| $$ /$$/| $$$$$$$$ |____ $$ /$$_____/| $$ /$$/ 6 | | $$ \ $$ /$$$$$$$| $$ | $$$$$$/ | $$__ $$ /$$$$$$$| $$ | $$$$$$/ 7 | | $$ | $$ /$$__ $$| $$ | $$_ $$ | $$ | $$ /$$__ $$| $$ | $$_ $$ 8 | | $$$$$$$/| $$$$$$$| $$$$$$$| $$ \ $$| $$ | $$| $$$$$$$| $$$$$$$| $$ \ $$ 9 | |_______/ \_______/ \_______/|__/ \__/|__/ |__/ \_______/ \_______/|__/ \__/ 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | backHack 3.1 19 | v3.1: Download APK from device 20 | v3.0: iOS Backup Parsing! 21 | v2.5: Allow for easier app selection. 22 | v2.0: Run straight from the command line! 23 | v1.6: WINDOWS Support has been added! 24 | 25 | by: Kirk Hayes(l0gan) 26 | Twitter: @kirkphayes 27 | 28 | To run from command line (new in v2.0): 29 | 30 | command: python backHack.py --app com.app.android 31 | --app APPNAME, -a APPNAME (name of app to backup/analyze/restore) 32 | --listapps, -l (List apps installed on device) 33 | 34 | iOS Mode (1): 35 | python backHack.py --ios --app appname (iOS mode. Specify app name and backHack will parse all backups from iTunes for which files may be of interest) 36 | 37 | NEW: To download APK: 38 | python backHack.py --app appname --apk (will save the apk with the name of the app you enter) 39 | 40 | To run interactively: 41 | 42 | command: python backHack.py 43 | 44 | 45 | 1 Select App Package 46 | 2 Backup and Extract App 47 | 3 Repack and Restore App 48 | 99 Exit 49 | Please select an option: 50 | 51 | SUBMENU 1: 52 | 1 List Apps on Device 53 | 2 Search for App 54 | 3 Type in App Name 55 | 99 Go Back 56 | Please select an option: 57 | 58 | (1): Have not tested encrypted backups yet.... 59 | 60 | ** adb must be installed and set in your PATH. 61 | *** If using a password on your backups, you must have Java JCE Unlimited Strength Jurisdiction Policy installed (http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html) 62 | **** On Google Pixel you may HAVE to use encryption. 63 | 64 | Use at your own risk!! 65 | -------------------------------------------------------------------------------- /abe.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/l0gan/backHack/561ec8684665652935e5ee6a6aa7713789fc347c/abe.jar -------------------------------------------------------------------------------- /backHack.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | import os 3 | from os.path import expanduser 4 | import tarfile 5 | from distutils.version import LooseVersion 6 | import subprocess 7 | from subprocess import check_output 8 | from argparse import ArgumentParser 9 | import platform 10 | import time 11 | from datetime import datetime 12 | #import pytz 13 | import glob 14 | import sqlite3 15 | 16 | 17 | parser = ArgumentParser(description='Hacking some Android apps! Use backHack to perform Android Application File System Analysis on non-rooted devices. Running without arguments will run in interactive mode.') 18 | parser.add_argument('--app', '-a', help='Application name (e.g. com.niantic.pokemongo)') 19 | parser.add_argument('--listapps', '-l', action="store_true", help='List apps on device') 20 | parser.add_argument('--backup', '-b', action="store_true", help='Backup app') 21 | parser.add_argument('--restore', '-r', action="store_true", help='Restore app') 22 | parser.add_argument('--ios', '-i', action="store_true", help='iOS mode. Uses a iTunes backup file to extract data from the specified app.') 23 | parser.add_argument('--apk', action="store_true", help='Download App APK') 24 | 25 | ver = "3.1" 26 | 27 | def cls(): 28 | os.system('cls' if os.name == 'nt' else 'clear') 29 | 30 | def logo(): 31 | print(""" 32 | /$$ /$$ /$$ /$$ /$$ 33 | | $$ | $$ | $$ | $$ | $$ 34 | | $$$$$$$ /$$$$$$ /$$$$$$$| $$ /$$| $$ | $$ /$$$$$$ /$$$$$$$| $$ /$$ 35 | | $$__ $$ |____ $$ /$$_____/| $$ /$$/| $$$$$$$$ |____ $$ /$$_____/| $$ /$$/ 36 | | $$ \ $$ /$$$$$$$| $$ | $$$$$$/ | $$__ $$ /$$$$$$$| $$ | $$$$$$/ 37 | | $$ | $$ /$$__ $$| $$ | $$_ $$ | $$ | $$ /$$__ $$| $$ | $$_ $$ 38 | | $$$$$$$/| $$$$$$$| $$$$$$$| $$ \ $$| $$ | $$| $$$$$$$| $$$$$$$| $$ \ $$ 39 | |_______/ \_______/ \_______/|__/ \__/|__/ |__/ \_______/ \_______/|__/ \__/ 40 | 41 | Version: """ + ver + """ 42 | 43 | 44 | 45 | 46 | 47 | """) 48 | 49 | def mainmenu(): 50 | appName = '' 51 | andVer = '' 52 | mainMenu = {} 53 | mainMenu['1']="Select App Package" 54 | mainMenu['2']="Backup and Extract App" 55 | mainMenu['3']="Repack and Restore App" 56 | mainMenu['99']="Exit" 57 | cls() 58 | while True: 59 | logo() 60 | options=mainMenu.keys() 61 | #options.sort() 62 | for entry in options: 63 | print(entry, mainMenu[entry]) 64 | 65 | selection=input("[*] Please select an option: ") 66 | if selection == "1": 67 | cls() 68 | appSelectMenu = {} 69 | appSelectMenu['1']="List Apps on Device" 70 | appSelectMenu['2']="Search for App" 71 | appSelectMenu['3']="Type in App Name" 72 | appSelectMenu['99']="Go Back" 73 | while True: 74 | logo() 75 | options=appSelectMenu.keys() 76 | #options.sort() 77 | for entry in options: 78 | print(entry, appSelectMenu[entry]) 79 | 80 | selection=input("[*] Please select an option: ") 81 | if selection == "1": 82 | cls() 83 | packs = listApps() 84 | appnumber = input("[*] Enter number corresponding with the app you want to use: ") 85 | appName = packs[int(appnumber)] 86 | cls() 87 | print("[!] Your chosen app: " + appName) 88 | break 89 | elif selection == "2": 90 | cls() 91 | appSearch=input("[*] Type in part of the name to search for: ") 92 | print("") 93 | packs = check_output('adb shell pm list packages | find /I "' + appSearch + '"' if os.name == 'nt' else "adb shell pm list packages | grep -i " + appSearch + " | cut -d: -f2", shell=True) 94 | packs = packs.split(":") 95 | packs = [i.split('\r\n', 1)[0] for i in packs] 96 | i = 0 97 | for pack in packs: 98 | print(str(i) + ": " + pack) 99 | i = i+1 100 | print("") 101 | appnumber = input("[*] Enter number corresponding with the app you want to use: ") 102 | appName = packs[int(appnumber)] 103 | appName = appName.strip("\n") 104 | cls() 105 | print("[!] Your chosen app: " + appName) 106 | break 107 | elif selection == "3": 108 | cls() 109 | appName=input("[*] Please type in the package name:") 110 | cls() 111 | print("[!] Your chosen app: " + appName) 112 | break 113 | elif selection == "99": 114 | cls() 115 | break 116 | else: 117 | cls() 118 | print("[-] Invalid Selection") 119 | elif selection == "2": 120 | cls() 121 | if appName: 122 | backupApp(appName) 123 | else: 124 | print("[-] You have not selected an app. Please use option 1 to set your app.") 125 | 126 | elif selection == "3": 127 | cls() 128 | andVer = andVerCheck() 129 | if appName: 130 | restoreApp(andVer, appName) 131 | else: 132 | print("[-] You have not selected an app. Please use option 1 to set your app.") 133 | elif selection =="99": 134 | cls() 135 | cleanup(appName) 136 | break 137 | else: 138 | cls() 139 | print("[-] Invalid Selection") 140 | 141 | def apkDownloader(appName): 142 | apkLoc = check_output('adb shell pm list packages -f | find /I "' + appName + '"' if os.name == 'nt' else "adb shell pm list packages -f | grep -i " + appName , shell=True) 143 | apkLoc = (apkLoc.split(':')[1]).split('=')[0] 144 | os.system('adb pull ' + apkLoc + ' ' + appName + '.apk') 145 | 146 | def andVerCheck(): 147 | andVerNum = subprocess.check_output("adb.exe shell getprop ro.build.version.release" if os.name == 'nt' else "adb shell getprop ro.build.version.release", shell=True) 148 | andVerNum = str(andVerNum)[:5] 149 | if LooseVersion(str(andVerNum)) > LooseVersion("4.4.2"): 150 | andVer = "pack-kk" 151 | else: 152 | andVer = "pack" 153 | return andVer 154 | 155 | def restoreApp(andVer, appName): 156 | print("[*] Repacking " + appName) 157 | tar = tarfile.open(appName + "-rest.tar", "w", format=tarfile.USTAR_FORMAT) 158 | retar = open("fileList.txt", 'r') 159 | for name in retar.readlines(): 160 | tar.add(name.strip('\n')) 161 | retar.close() 162 | tar.close() 163 | os.system("java -jar abe.jar "+ andVer + " " + appName + "-rest.tar " + appName + "-rest.ab") 164 | cls() 165 | print("[*] Repacking complete.") 166 | print("[*] Restoring " + appName) 167 | os.system("adb.exe restore " + appName + "-rest.ab" if os.name == 'nt' else "adb restore " + appName + "-rest.ab") 168 | 169 | def cleanup(appName): 170 | print("[*] Cleaning Up") 171 | os.system("del fileList.txt "+ appName + ".* " + appName + "-* " if os.name == 'nt' else "rm fileList.txt "+ appName + ".* " + appName + "-* " if appName != '' else "echo Nothing to remove") 172 | os.system("rd /S /Q apps" if os.name == 'nt' else "rm -rf apps") 173 | 174 | def listApps(): 175 | packs = check_output("adb.exe shell pm list packages" if os.name == 'nt' else "adb shell pm list packages", shell=True) 176 | print(packs) 177 | #packs = os.popen("adb.exe shell pm list packages" if os.name == 'nt' else "adb shell pm list packages").read() 178 | packs = str(packs).split(":") 179 | packs = [i.replace('\\r\\npackage', '', 1000) for i in packs] 180 | packs = [i.replace('\\r\\n', '', 1000) for i in packs] 181 | i = 0 182 | for pack in packs: 183 | print(str(i) + ": " + pack) 184 | i = i+1 185 | return packs 186 | 187 | 188 | def backupApp(appName): 189 | print("[*] Backing up " + appName) 190 | os.system("adb.exe backup -f " + appName + ".ab " + appName if os.name == 'nt' else "adb backup -f " + appName + ".ab " + appName) 191 | print("[*] Extracting " + appName + ".") 192 | try: 193 | os.system("java -jar abe.jar unpack " + appName + ".ab " + appName + ".tar") 194 | tar = tarfile.open(appName + ".tar") 195 | tar.extractall() 196 | tarList = open("fileList.txt", 'w') 197 | for member in tar.getmembers(): 198 | tarList.write(str(member.name) + '\n') 199 | tarList.close() 200 | statinfo = os.stat('fileList.txt') 201 | if statinfo.st_size == 0: 202 | print("[-] Extraction failed. Did the backup complete properly? Try again but use a password to encrypt.") 203 | else: 204 | print("[*] Extraction Complete. Please review files under apps folder.") 205 | except Exception as e: 206 | print("[-] An error occured. Are you encrpyting? ") 207 | print(e) 208 | 209 | def main(): 210 | cls() 211 | mainmenu() 212 | 213 | def iosBackup(itunesdir): 214 | try: 215 | newest = max(glob.iglob(itunesdir + '/*'), key=os.path.getctime) 216 | conn = sqlite3.connect(newest + '/Manifest.db') 217 | c = conn.cursor() 218 | print("[+] Files accessible: (" + newest + ")") 219 | print("+" + "-" * 120 + "+") 220 | print("| " + "GUID".ljust(50) + "| " + "LocalDB".ljust(65) + "|") 221 | print("+" + "-" * 120 + "+") 222 | sqlcmd = "SELECT DISTINCT fileID, domain, relativePath from Files WHERE domain LIKE '%" + args.app + "%';" 223 | #sqlcmd = "SELECT * from Files" 224 | for row in c.execute(sqlcmd): 225 | if "." in row[2]: 226 | filename = newest + "/" + row[0][:2] 227 | total_size = 0 228 | for dirpath, dirnames, filenames in os.walk(filename): 229 | for f in filenames: 230 | fp = os.path.join(dirpath, f) 231 | total_size += os.path.getsize(fp) 232 | if total_size > 65: 233 | print("|",row[0].ljust(50), "|", row[2].ljust(65), "|") 234 | print("+" + "-" * 120 + "+") 235 | except ValueError: 236 | print("[-] No Backups found. Have you performed a backup with iTunes?") 237 | 238 | if __name__ == '__main__': 239 | args = parser.parse_args() 240 | parser.set_defaults(listapps=False) 241 | parser.set_defaults(backup=False) 242 | parser.set_defaults(restore=False) 243 | osType = platform.system() 244 | home = expanduser("~") 245 | if args.ios: 246 | cls() 247 | logo() 248 | print("[*] Let's try some iOS fun....") 249 | macDir = home + '/Library/Application Support/MobileSync/Backup/' 250 | winDir = home + r'\AppData\Roaming\Apple Computer\MobileSync\Backup' 251 | if osType == "Darwin": 252 | print("[*] Running on a Mac huh?") 253 | print("[*] Looking for backup data at: " + macDir) 254 | itunesdir = macDir 255 | iosBackup(itunesdir) 256 | elif osType == "Windows": 257 | print("[*] Ugh, Windows huh?") 258 | print("[*] Looking for backup data at: " + winDir) 259 | itunesdir = winDir 260 | iosBackup(itunesdir) 261 | elif osType == "Linux": 262 | print("[-] iOS on Linux? Are you nuts? iTunes doesn't work on Linux! Go grab a Mac or a Windows system...") 263 | else: 264 | print("[-] I don't know what this is: " + osType) 265 | elif args.app: 266 | if args.backup: 267 | backupApp(args.app) 268 | elif args.restore: 269 | andVer = andVerCheck() 270 | restoreApp(andVer, args.app) 271 | cleanup = input("[*] Would you like to cleanup? WARNING: This will DELETE all folders associated with the application backup/restore process. (y/n)") 272 | if cleanup == "y": 273 | cleanup(args.app) 274 | else: 275 | print("[-] Leaving artifacts as they are. Manually cleanup if you need.") 276 | elif args.apk: 277 | apkDownloader(args.app) 278 | else: 279 | print("[-] Missing backup or restore argument.") 280 | elif args.listapps == True: 281 | listApps() 282 | else: 283 | main() 284 | --------------------------------------------------------------------------------