Source code for bbarchivist.scripts.droidlookup

#!/usr/bin/env python3
"""Check Android autoloader files."""

import sys  # load arguments

import requests  # session
from bbarchivist import argutils  # arguments
from bbarchivist import decorators  # Ctrl+C wrapping
from bbarchivist import jsonutils  # json
from bbarchivist import networkutils  # lookup
from bbarchivist import utilities  # argument filters

__author__ = "Thurask"
__license__ = "WTFPL v2"
__copyright__ = "2015-2018 Thurask"


[docs]def grab_args(): """ Parse arguments from argparse/questionnaire. Invoke :func:`droidlookup.droidlookup_main` with those arguments. """ if len(sys.argv) > 1: parser = argutils.default_parser("bb-droidlookup", "Get Android autoloaders") parser.add_argument( "branch", help="OS branch, 3 letters") parser.add_argument( "floor", help="Start of search range", default=0, nargs="?", type=int, choices=range(0, 999), metavar="floor") parser.add_argument( "-d", "--device", dest="device", help="Device to check", nargs="?", type=argutils.droidlookup_devicetype, default=None) parser.add_argument( "-c", "--ceiling", dest="ceil", help="End of search range", default=999, nargs="?", type=int, choices=range(1, 1000), metavar="ceil") parser.add_argument( "-t", "--type", help="Check SHA256/512 hashes instead", default=None, type=argutils.droidlookup_hashtype) parser.add_argument( "-s", "--single", dest="single", help="Only scan one OS build", action="store_true", default=False) parser.add_argument( "-a", "--all-devices", dest="alldevices", help="Scan all devices, not just known ones", action="store_true", default=False) args = parser.parse_args(sys.argv[1:]) parser.set_defaults() execute_args(args) else: questionnaire()
[docs]def execute_args(args): """ Get args and decide what to do with them. :param args: Arguments. :type args: argparse.Namespace """ if args.single: args.ceil = args.floor # range(x, x+1) == x famlist = jsonutils.load_json("droidfamilies") cleanlist = famlist[:4] # Priv/DTEK50/DTEK60/KEYone if args.device is None: if not args.alldevices: famlist = cleanlist droidlookup_main(famlist, args.branch, args.floor, args.ceil, args.type) elif args.device not in cleanlist: print("Selected device {0} has unknown autoloader scheme!".format(args.device)) else: droidlookup_main(args.device, args.branch, args.floor, args.ceil, args.type)
[docs]def questionnaire_single(): """ What to ask if only one lookup is needed. """ while True: scanos = input("OS (ex. AAD250): ") branch = scanos[:3] floor = scanos[3:6] quants = [len(scanos) == 6, branch.isalpha(), floor.isdigit()] if not all(quants): print("OS MUST BE 3 LETTERS AND 3 NUMBERS, TRY AGAIN") continue else: floor = int(floor) ceil = floor break return branch, floor, ceil
[docs]def questionnaire_branch(): """ Ask about lookup branch. """ while True: branch = input("BRANCH (ex. AAD): ") if len(branch) != 3 or not branch.isalpha(): print("BRANCH MUST BE 3 LETTERS, TRY AGAIN") continue else: break return branch
[docs]def parse_floor(floor): """ Check if floor value is OK. :param floor: Starting OS version. :type floor: int """ return parse_extreme(floor, 0, 998, "INITIAL < 0, TRY AGAIN", "INITIAL > 998, TRY AGAIN")
[docs]def parse_ceiling(ceil, floor): """ Check if ceiling value is OK. :param ceil: Ending OS version. :type ceil: int :param floor: Starting OS version. :type floor: int """ return parse_extreme(ceil, floor, 999, "FINAL < INITIAL, TRY AGAIN", "FINAL > 999, TRY AGAIN")
[docs]def questionnaire_initial(): """ Ask about lookup start. """ while True: try: floor = int(input("INITIAL OS (0-998): ")) except ValueError: continue else: if parse_floor(floor): break else: continue return floor
[docs]def parse_extreme(starter, minim, maxim, mintext, maxtext): """ Check if floor/ceiling value is OK. :param starter: Minimum/maximum OS version. :type starter: int :param minim: Minimum value for starter. :type minim: int :param maxim: Maximum value for starter. :type maxim: int :param mintext: What to print if starter < minim. :type mintext: str :param maxtext: What to print if starter > maxim. :type maxtext: str """ okay = False if starter < minim: print(mintext) elif starter > maxim: print(maxtext) else: okay = True return okay
[docs]def questionnaire_final(floor): """ Ask about lookup end. :param floor: Starting OS version. :type floor: int """ while True: try: ceil = int(input("FINAL OS (1-999): ")) except ValueError: ceil = 999 else: if parse_ceiling(ceil, floor): break else: continue return ceil
[docs]def questionnaire(): """ Questions to ask if no arguments given. """ single = utilities.i2b("SINGLE OS (Y/N)?: ") if single: branch, floor, ceil = questionnaire_single() else: branch = questionnaire_branch() floor = questionnaire_initial() ceil = questionnaire_final(floor) famlist = jsonutils.load_json("droidfamilies") # same here droidlookup_main(famlist[:2], branch, floor, ceil) decorators.enter_to_exit(True)
@decorators.wrap_keyboard_except def droidlookup_main(device, branch, floor=0, ceil=999, method=None): """ Check the existence of Android factory images, in a range. :param device: Device to check. :type device: str :param branch: OS version, 3 letters. :type branch: str :param floor: Starting OS version, padded to 3 numbers. Default is 0. :type floor: int :param ceil: Ending OS version, padded to 3 numbers. Default is 999. :type ceil: int :param method: None for regular OS links, "hash256/512" for SHA256 or 512 hash. :type method: str """ argutils.slim_preamble("DROIDLOOKUP") text = "DEVICE: ALL" if isinstance(device, list) else "DEVICE: {0}".format(device.upper()) print(text) sess = requests.Session() for ver in range(floor, ceil + 1): build = "{0}{1}".format(branch.upper(), str(ver).zfill(3)) print("NOW SCANNING: {0}".format(build), end="\r") results = networkutils.droid_scanner(build, device, method, sess) if results is not None: for result in results: print("{0} AVAILABLE! {1}\n".format(build, result), end="\r") if __name__ == "__main__": grab_args()