def screenshot(desc_file): try: shell("shell screencap -p sdcard/screen.png") result = pull("sdcard/screen.png", desc_file) Logs.instance().info("Result screenshot = " + result) return True if "1 file pulled" in result else False except: return False
def file_get_contents(filename): contents = None try: with open(filename) as f: contents = f.read() except: Logs.instance().error('No such file or directory: ' + filename) return contents
def analyse(self, software, install_packages): """ Start software analysis. :param software: Software information (retrieve by adb shell getprop) :param install_packages: installed packages list of the software :return: None """ # report_manager = ReportManager(self._context.get_root_path()) Logs.instance().warning("\tImplement your SCA Plugin algorithm here!")
def make_dirs(filename): dir_name = os.path.dirname(filename) if not os.path.exists(dir_name): try: os.makedirs(dir_name) return True except OSError as exc: # Guard against race condition Logs.instance().error(exc) errors.log_exception_to_file(exc) return False return False
def uiautomator_dump(): for i in range(0, 30): result = shell("uiautomator dump") time.sleep(1.5) Logs.instance().info('\tUIAutomator dumping..' + '.' * i) if 'window_dump.xml' in result: result = cat_file("/sdcard/window_dump.xml") if "hierarchy" in result: return result
def execute(cmd, args=None, display_cmd=False, disable_out=False, disable_error=False, no_wait=False, is_shell=False): if cmd is None: return None cmd_args = [cmd] if args is not None: for arg in args: cmd_args.append(str(arg)) if display_cmd: str_cmd = None for arg in cmd_args: if str_cmd is None: str_cmd = str(arg) else: str_cmd = str_cmd + " " + str(arg) Logs.instance().debug(str_cmd) std_out = subprocess.PIPE if disable_out: std_out = DEVNULL # std_out = open(os.devnull, 'wb') if no_wait: subprocess.Popen(cmd_args, stdin=None, stdout=None, stderr=None, shell=is_shell) return None elif disable_error: p = subprocess.Popen(cmd_args, stdout=std_out, stderr=DEVNULL, shell=is_shell) else: p = subprocess.Popen(cmd_args, stdout=std_out, stderr=subprocess.STDOUT, shell=is_shell) if disable_out: return None else: out = p.stdout.read().decode('utf-8') return out
def list_packages(root_path, package_pattern=None, last_version=False): """ list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER] Prints all packages; optionally only those whose name contains the text in FILTER. Options: -f: see their associated file -d: filter to only show disabled packages -e: filter to only show enabled packages -s: filter to only show system packages -3: filter to only show third party packages -i: see the installer for the packages -u: also include uninstalled packages """ result = shell("pm list packages -f") _display_adb_error(result) # users = android_users.get_android_users_list(root_path) users = 1 lines = result.split("\n") packages = [] for line in lines: if line: name = strings.extract_regex_value( line, '(?:=([a-zA-Z0-9\\-\\._ ]{3,}))') path = line.replace(name, '').replace('package:', '').replace('.apk=', '.apk').strip() if (package_pattern is None) or utils.is_matching_package( name, package_pattern): # Determine if it's system app: system = ('/vendor/app/' in path or '/system/priv-app/' in path or '/system/app/' in path) Logs.instance().info('\tDumping package info: ' + name) info = _get_package_info(name, path, system, users, last_version) # Logs.instance().info('\tDone !\n') if info is not None: p = {'name': name, 'path': path, 'system': system} package = utils.merge_dicts(p, info) packages.append(package) # exit() return packages
def download_file(url, dest, credentials=None): """ Downloads a file using a given config :param url: URL of the file to download :param dest: Path of the downloaded file :param credentials: Credentials to use to download the file, should be of the form {'user':'******', 'password':'******'} :return: None """ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) if credentials is not None: basic_auth = credentials['user'] + ':' + credentials['password'] headers = urllib3.util.make_headers(basic_auth=basic_auth, disable_cache=True) else: headers = urllib3.util.make_headers(disable_cache=True) http = urllib3.PoolManager() r = http.request('GET', url, headers=headers, preload_content=False) chunk_size = 4096 header_items = dict(r.headers) if 'Content-Length' not in header_items.keys(): Logs.instance().debug(r.headers) Logs.instance().warning('Response has no Content-Length!') return None total_length = int(header_items['Content-Length']) content_filename = url[url.rfind("/") + 1:] # check cache: if file_exists(dest): file_size = os.path.getsize(dest) if file_size == total_length: Logs.instance().info("File already downloaded in cache!") return content_filename else: delete_file_if_exists(dest) Logs.instance().info("Download in progress, please wait...") dl = 0 with open(dest, 'wb') as out: while True: data = r.read(chunk_size) if not data: break out.write(data) dl += len(data) done = int(50 * dl / total_length) sys.stdout.write("\r[%s%s]" % ('=' * done, ' ' * (50 - done))) sys.stdout.flush() r.release_conn() print("\r") return content_filename
def unzip(zip_path, destination): # Remove existing source: fast_rm_file_if_exists(destination) Logs.instance().info("Unzip archive in progress... ") try: archive = zipfile.ZipFile(zip_path) for f in archive.namelist(): archive.extract(f, destination) return True except zipfile.BadZipfile: msg = "Zip file corrupted: " + str(zip_path) Logs.instance().error(msg) errors.log_error_to_file(msg) return False
def find_files(files, dirs=[], extensions=[]): new_dirs = [] for d in dirs: try: if os.path.isfile(d): if extensions is None or os.path.splitext(d)[1] in extensions: files.append(d) else: new_dirs += [os.path.join(d, f) for f in os.listdir(d)] except OSError: pass except TypeError: Logs.instance().warning("Could not reach below " + d + ", skipping to next directory...") if new_dirs: find_files(files, new_dirs, extensions) else: return
def device_awake_and_unlocked(): # adb shell dumpsys power result = shell("dumpsys power | grep 'mHolding'") _display_adb_error(result) # Logs.instance().debug(result) # mHoldingWakeLockSuspendBlocker=true wake_lock_suspend_blocker = utils.to_boolean( strings.extract_regex_value( result, r"(?:mHoldingWakeLockSuspendBlocker=([a-zA-Z]{4,5}))")) # Logs.instance().debug("mHoldingWakeLockSuspendBlocker = " + str(wake_lock_suspend_blocker)) # mHoldingDisplaySuspendBlocker=true display_suspend_blocker = utils.to_boolean( strings.extract_regex_value( result, r"(?:mHoldingDisplaySuspendBlocker=([a-zA-Z]{4,5}))")) # Logs.instance().debug("mHoldingDisplaySuspendBlocker = " + str(display_suspend_blocker)) if not wake_lock_suspend_blocker and not display_suspend_blocker: Logs.instance().warning("Screen if not awake!") if not wake_lock_suspend_blocker and display_suspend_blocker: Logs.instance().warning("Screen awake but locked!") if wake_lock_suspend_blocker and display_suspend_blocker: Logs.instance().info("Screen awake and unlocked!") return True return False
def initial_wifi(self, *args): wifi_state = adb.shell("settings get global wifi_on") self.result = wifi_state == self.BT_Initial_state if not self.result: Logs.instance().info("wifi is disable") return
def initial_bluetooth(self, *args): bluetooth_state = adb.shell("settings get global bluetooth_on") self.result = bluetooth_state == self.BT_Initial_state if not self.result: Logs.instance().info("BT is disable") return
def delete_file(path): result = command.execute("adb", ["shell", "rm", path]).strip() # Logs.instance().debug("Result delete = " + result) if result.find("rm: " + path + ":") > -1: Logs.instance().info("Couldn't remove file from device: " + result)
def _get_package_info(package_name, package_path, system, users, latest_version): result = shell("dumpsys package " + package_name) _display_adb_error(result) index = result.find("Hidden system packages:") if latest_version and index > -1: result = result[:index] if not latest_version and index > -1: result = result[index:] if result is None or strings.contains_regex(result, 'Unable to find'): Logs.instance().warning('Dumpsys failed for package: ' + package_name) return None flag = False info = _get_default_package_info() info['manifest'] = None info['name'] = package_name info['path'] = package_path info['system'] = system info['user_id'] = utils.str_to_int( strings.extract_regex_value(result, r"(?:userId=([0-9]*))", flag)) info['user'] = resolve_user(users, info['user_id']) info['version_code'] = utils.str_to_int( strings.extract_regex_value(result, r"(?:versionCode=([0-9]*))", flag)) info['version_name'] = strings.extract_regex_value( result, r"(?:versionName=([0-9a-zA-Z\-\(\)\.\_\[\]]*))", flag) info['min_sdk'] = utils.str_to_int( strings.extract_regex_value(result, r"(?:minSdk=([0-9]*))", flag)) info['target_sdk'] = utils.str_to_int( strings.extract_regex_value(result, r"(?:targetSdk=([0-9]*))", flag)) flags = [] pkg_lags = strings.extract_regex_value(result, r"(?:pkgFlags=\[([\sA-Z\_]*)\])", flag) if pkg_lags is not None: flags = pkg_lags.strip().split() for flag in flags: if flag == 'SYSTEM': info['system'] = True info['pkg_flags'].append(flag.strip()) info['code_path'] = strings.extract_regex_value( result, r"(?:codePath=([0-9a-zA-Z\/\-\_\.=]+))", flag) info['odex'] = None # retro compatibility (Android 6) if info['odex'] is None and info['system']: items = list_files_extension('odex', info['code_path']) if len(items) > 0 and items[0].endswith('.odex'): info['odex'] = items[0] # Fix Package path (O MR1) if not package_path.startswith(info['code_path']): items = list_files_extension('apk', info['code_path']) if len(items) > 0 and items[0].endswith('.apk'): info['old_path'] = package_path info['path'] = items[0] else: info['old_path'] = package_path info['path'] = strings.extract_regex_value( result, r"(?:path:\s*([0-9a-zA-Z\/\-\_\=\.]+))", True) return info
def _display_adb_error(result): if result is not None and (result.startswith('adb: error:') or result.startswith('error:')): Logs.instance().error(result.strip()) return True return False