class DynamicAnalysis(object): """DynamicAnalysis""" def __init__(self, device_name, apk_path, n_runs=RUNS_PER_APP, emulator=False): if not os.path.isfile(apk_path): raise DynamicAnalysisError('File not found {0}'.format(apk_path)) self.n_runs = n_runs self.max_trials = n_runs + 3 self.emulator = emulator self.apk_path = apk_path self.apk_name = os.path.basename(apk_path) self.device_name = device_name self.start_ts = None self.stop_ts = None def start_analysis(self): self.start_ts = int(time()) logger.info('Starting analysis') ip_address = self.device_name.split(':')[0] # ADBDriver.get_device_ipaddress(self.device_name) print ip_address self.proxy_port = int('40' + ip_address.split('.')[-1]) # set proxy iptables logger.debug('Setting proxy iptables') set_iptables(ip_address, self.proxy_port) success_runs = 0 total_runs = 0 while success_runs < self.n_runs and total_runs < self.max_trials: logger.info('APK: {0} Run #{1}'.format(self.apk_name, success_runs)) if success_runs == 0: # firts run, record ts status = self.run_apk(first=True) else: status = self.run_apk() if status: success_runs += 1 logger.info('Run completed') else: logger.info('Run failed') total_runs += 1 if total_runs == self.max_trials: logger.error('Reached max number of trials') # change all success_runs = 0 total_runs = 0 while success_runs < 1 and total_runs < 2: logger.info('APK: {0} Final Run'.format(self.apk_name)) status = self.run_apk(final=True, field='all') if status: success_runs += 1 logger.info('Final Run (all) completed') else: logger.info('Final Run (all) failed') total_runs += 1 leaks = whitelist_analysis(self.apk_name, field='all') sensitive_fields = data_default.keys() if leaks: for field in sensitive_fields: success_runs = 0 total_runs = 0 while success_runs < 1 and total_runs < 2: logger.info('APK: {0} Final Run'.format(self.apk_name)) status = self.run_apk(final=True, field=field) if status: success_runs += 1 logger.info('Final Run ({0}) completed'.format(field)) else: logger.info('Final Run ({0}) failed'.format(field)) total_runs += 1 self.stop_ts = int(time()) elapsed_time = self.stop_ts - self.start_ts # delete proxy iptables logger.debug('Deleting proxy iptables') delete_iptables(ip_address, self.proxy_port) logger.info('Analysis completed, {0}'.format(self.apk_name)) logger.info('Elapsed time: {0} seconds'.format(elapsed_time)) def run_apk(self, first=False, final=False, field=None): logger.debug('Preparing to run apk {0}'.format(self.apk_name)) # Setting up folders try: os.stat(FLOWS_FOLDER) except: os.mkdir(FLOWS_FOLDER) if final: output_dir = os.path.join(FLOWS_FOLDER, self.apk_name + '_final') else: output_dir = os.path.join(FLOWS_FOLDER, self.apk_name) try: os.stat(output_dir) except: os.mkdir(output_dir) try: os.stat(CRYPTOHOOKER_LOGS_FOLDER) except: os.mkdir(CRYPTOHOOKER_LOGS_FOLDER) if final: hooked_data_dir = os.path.join(CRYPTOHOOKER_LOGS_FOLDER, self.apk_name + '_final') else: hooked_data_dir = os.path.join(CRYPTOHOOKER_LOGS_FOLDER, self.apk_name) try: os.stat(hooked_data_dir) except: os.mkdir(hooked_data_dir) self.proxy = Proxy(port=self.proxy_port) ts = int(time()) self.adb = ADBDriver(self.device_name, emulator=self.emulator) if self.emulator: self.adb.start() package = get_APK_package_name(self.apk_path) activity = get_APK_main_activity(self.apk_path) if final: flow_name = '{0}_{1}.flow_{2}'.format(self.apk_name, ts, field) else: flow_name = '{0}_{1}.flow'.format(self.apk_name, ts) flow_file = os.path.join(output_dir, flow_name) self.proxy.start(flow_file) if self.emulator: self.adb.completeboot() sleep(OPERATIONS_SLEEPTIME) self.adb.install_cert() self.adb.create_writeble_folder(CHANGER_FOLDER) self.adb.write_file(CHANGER_PACKAGENAME_FILE, package) self.set_sensitive_field(field) # self.adb.flush_logcat() self.adb.delete_folder(CRYPTOHOOKER_FOLDER) self.adb.create_writeble_folder(CRYPTOHOOKER_FOLDER) self.adb.set_logfile(CRYPTOHOOKER_LOG_DEVICE) self.adb.write_file(CRYPTOHOOKER_PACKAGENAME_FILE, package) self.adb.adb_cmd(['push', RANDOM_NUM_FILE, CRYPTOHOOKER_RANDOMNUM_FILE]) if first: self.adb.set_record_ts(True) else: self.adb.set_record_ts(False) if not self.emulator: self.adb.turn_on_screen() self.adb.unlock() sleep(OPERATIONS_SLEEPTIME) try: self.adb.install(self.apk_path) except ADBDriverError: self.finish_run() # remove flow file if os.path.isfile(flow_file): os.remove(flow_file) return False if not self.emulator: self.adb.set_iptables(package) sleep(OPERATIONS_SLEEPTIME) try: self.adb.start_activity(package, activity) except ADBDriverError: self.finish_run() # remove flow file if os.path.isfile(flow_file): os.remove(flow_file) return False sleep(OPERATIONS_SLEEPTIME) try: self.adb.start_monkey(package=package, seed=SEED) except ADBDriverError: logger.warning('Monkey execution hit timeout') self.adb.kill_monkey() # wait the end of the analysis sleep(ANALYSIS_TIMEOUT) if final: log_name = '{0}_{1}.log_{2}'.format(self.apk_name, ts, field) else: log_name = '{0}_{1}.log'.format(self.apk_name, ts) cryptohookerlog = os.path.join(hooked_data_dir, log_name) self.adb.get_file(CRYPTOHOOKER_LOG_DEVICE, cryptohookerlog) self.finish_run() return True # check run results # return self.check_run([flow_file, cryptohookerlog]) def finish_run(self): if self.emulator: self.adb.stop() self.adb.destroy() else: package = get_APK_package_name(self.apk_path) self.adb.del_iptables(package) try: self.adb.uninstall(package) except ADBDriverError: logger.warning('Uninstall FAILED') self.adb.delete_folder('/data/data/' + package) self.adb.delete_folder(CRYPTOHOOKER_FOLDER) self.proxy.stop() def check_run(self, output_files): status = True for f in output_files: if not os.path.isfile(f) or os.path.getsize(f) == 0: status = False # delete files if (part of) the analysis failed if not status: for f in output_files: if os.path.isfile(f): os.remove(f) return status def set_sensitive_field(self, field): if field is None: data = deepcopy(data_default) elif field == 'all': data = deepcopy(data_special) else: data = deepcopy(data_default) data[field] = data_special[field] self.set_sensitive_data(data) def set_sensitive_data(self, data): if 'location' in data: lat, lon = data['location'] self.adb.set_mock_location(lat, lon) if 'phone_number' in data: self.adb.set_phone_number(data['phone_number']) if 'mac_addr' in data: self.adb.set_mac_addr(data['mac_addr']) if 'sim_serial_num' in data: self.adb.set_sim_serial_num(data['sim_serial_num']) if 'subscriber_id' in data: self.adb.set_subscriber_id(data['subscriber_id']) if 'device_id' in data: self.adb.set_device_id(data['device_id']) if 'email' in data: self.adb.set_email(data['email']) if 'gender' in data: self.adb.set_gender(data['gender']) if 'contacts' in data: self.adb.set_contacts(data['contacts']) if 'android_id' in data: self.adb.set_android_id(data['android_id'])
class FalsePositivesAnalysis(object): """FalsePositivesAnalysis""" def __init__(self, device_name, apk_path, n_runs=RUNS_PER_APP, randomness=False, emulator=False): if not os.path.isfile(apk_path): raise DynamicAnalysisError('File not found {0}'.format(apk_path)) self.n_runs = n_runs self.max_trials = n_runs + 3 self.emulator = emulator self.apk_path = apk_path self.apk_name = os.path.basename(apk_path) self.device_name = device_name self.randomness = randomness self.start_ts = None self.stop_ts = None def start_analysis(self): self.start_ts = int(time()) logger.info('Starting analysis') ip_address = ADBDriver.get_device_ipaddress(self.device_name) self.proxy_port = int('40' + ip_address.split('.')[-1]) # set proxy iptables logger.debug('Setting proxy iptables') set_iptables(ip_address, self.proxy_port) success_runs = 0 total_runs = 0 while success_runs < self.n_runs and total_runs < self.max_trials: logger.info('APK: {0} Run #{1}'.format(self.apk_name, success_runs)) if success_runs == 0: # firts run, record ts status = self.run_apk(first=True) else: status = self.run_apk() if status: success_runs += 1 logger.info('Run completed') else: logger.info('Run failed') total_runs += 1 if total_runs == self.max_trials: logger.error('Reached max number of trials') success_runs = 0 total_runs = 0 while success_runs < 1 and total_runs < 2: logger.info('APK: {0} Final Run'.format(self.apk_name)) status = self.run_apk(final=True) if status: success_runs += 1 logger.info('Final Run (all) completed') else: logger.info('Final Run (all) failed') total_runs += 1 self.stop_ts = int(time()) elapsed_time = self.stop_ts - self.start_ts # delete proxy iptables logger.debug('Deleting proxy iptables') delete_iptables(ip_address, self.proxy_port) logger.info('Analysis completed, {0}'.format(self.apk_name)) logger.info('Elapsed time: {0} seconds'.format(elapsed_time)) def run_apk(self, first=False, final=False): logger.debug('Preparing to run apk {0}'.format(self.apk_name)) # Setting up folders try: os.stat(FLOWS_FOLDER) except: os.mkdir(FLOWS_FOLDER) if final: output_dir = os.path.join(FLOWS_FOLDER, self.apk_name + '_final') else: output_dir = os.path.join(FLOWS_FOLDER, self.apk_name) try: os.stat(output_dir) except: os.mkdir(output_dir) try: os.stat(CRYPTOHOOKER_LOGS_FOLDER) except: os.mkdir(CRYPTOHOOKER_LOGS_FOLDER) if final: hooked_data_dir = os.path.join(CRYPTOHOOKER_LOGS_FOLDER, self.apk_name + '_final') else: hooked_data_dir = os.path.join(CRYPTOHOOKER_LOGS_FOLDER, self.apk_name) try: os.stat(hooked_data_dir) except: os.mkdir(hooked_data_dir) self.proxy = Proxy(port=self.proxy_port) ts = int(time()) self.adb = ADBDriver(self.device_name, emulator=self.emulator) if self.emulator: self.adb.start() package = get_APK_package_name(self.apk_path) activity = get_APK_main_activity(self.apk_path) flow_name = '{0}_{1}.flow'.format(self.apk_name, ts) flow_file = os.path.join(output_dir, flow_name) self.proxy.start(flow_file) if self.emulator: self.adb.completeboot() sleep(OPERATIONS_SLEEPTIME) self.adb.install_cert() # self.adb.flush_logcat() self.adb.delete_folder(CRYPTOHOOKER_FOLDER) self.adb.create_writeble_folder(CRYPTOHOOKER_FOLDER) self.adb.set_logfile(CRYPTOHOOKER_LOG_DEVICE) if self.randomness: self.adb.write_file(CRYPTOHOOKER_PACKAGENAME_FILE, 'wrongpackage') else: self.adb.write_file(CRYPTOHOOKER_PACKAGENAME_FILE, package) self.adb.adb_cmd( ['push', RANDOM_NUM_FILE, CRYPTOHOOKER_RANDOMNUM_FILE]) if first: self.adb.set_record_ts(True) else: self.adb.set_record_ts(False) if not self.emulator: self.adb.turn_on_screen() self.adb.unlock() sleep(OPERATIONS_SLEEPTIME) try: self.adb.install(self.apk_path) except ADBDriverError as e: self.finish_run() # remove flow file if os.path.isfile(flow_file): os.remove(flow_file) return False if not self.emulator: self.adb.set_iptables(package) sleep(OPERATIONS_SLEEPTIME) try: self.adb.start_activity(package, activity) except ADBDriverError as e: self.finish_run() # remove flow file if os.path.isfile(flow_file): os.remove(flow_file) return False sleep(OPERATIONS_SLEEPTIME) try: self.adb.start_monkey(package=package, seed=SEED) except ADBDriverError as e: logger.warning('Monkey execution hit timeout') self.adb.kill_monkey() # wait the end of the analysis sleep(ANALYSIS_TIMEOUT) self.finish_run() return True def finish_run(self): if self.emulator: self.adb.stop() self.adb.destroy() else: package = get_APK_package_name(self.apk_path) self.adb.del_iptables(package) try: self.adb.uninstall(package) except ADBDriverError as e: logger.warning('Uninstall FAILED') self.adb.delete_folder('/data/data/' + package) self.adb.delete_folder(CRYPTOHOOKER_FOLDER) self.proxy.stop() def check_run(self, output_files): status = True for f in output_files: if not os.path.isfile(f) or os.path.getsize(f) == 0: status = False # delete files if (part of) the analysis failed if not status: for f in output_files: if os.path.isfile(f): os.remove(f) return status