def push_and_start_frida_server(adb: ADB): """ Parameters ---------- adb Returns ------- """ frida_server = os.path.join(os.getcwd(), "resources", "frida-server", "frida-server") try: adb.execute(['root']) adb.connect() except Exception as e: adb.kill_server() logger.error("Error on adb {}".format(e)) logger.info("Push frida server") try: adb.push_file(frida_server, "/data/local/tmp") except Exception as e: logger.error("Push frida error as {}".format(e)) pass logger.info("Add execution permission to frida-server") chmod_frida = ["chmod 755 /data/local/tmp/frida-server"] adb.shell(chmod_frida) logger.info("Start frida server") start_frida = ["cd /data/local/tmp/ && ./frida-server &"] adb.shell(start_frida, is_async=True)
def start_analysis(list_apps: list, timeout_privacy: int, max_actions: int, type: str, emulator_name: str): logger.info("Start Analysis of {} apps".format(len(list_apps))) start = time.time() stats = Statistic(type) if type == "random": type = start_appium_node(type) logger.info("Upload model p3 detector") # upload model pdetector = PredictionModel() logger.info("P3detector model uploaded") # start analysis count = 0 tentative = 0 num_log = len(glob.glob(os.path.join(os.getcwd(), "logs", "log_analysis_*"))) log_analysis_file = os.path.join(os.getcwd(), "logs", "log_analysis_{}.json".format(num_log + 1)) log_permission_file = os.path.join(os.getcwd(), "logs", "permissions_stats_{}.json".format(num_log + 1)) log_trackers_file = os.path.join(os.getcwd(), "logs", "tracker_stats_{}.json".format(num_log + 1)) while count < len(list_apps): app = list_apps[count] dict_analysis_app = {} md5_app = md5(app) dir_result = os.path.join(os.getcwd(), "logs", md5_app) if not os.path.exists(dir_result): os.makedirs(dir_result) try: dict_analysis_app["md5"] = md5_app apk_object = APK(app) dict_analysis_app["package_name"] = apk_object.get_package() if not check_app_already_analyzed_md5(md5_app) or tentative > 0: logger.info("3PDroid start Analysis {}".format(app)) write_package_name_and_md5(apk_object.get_package(), md5_app, os.path.join(os.getcwd(), "logs", "package_md5.txt")) # start emulator r_start_emulator = requests.get("{}/start/{}".format(LOCAL_URL_EMULATOR, emulator_name)) # if the emulator star ok if r_start_emulator.status_code == 200: # get trackers libraries and list permissions logger.info("Start emulator ok") logger.info("Get application information") app_trackers, app_permissions_list, api_to_monitoring_trackers, application, dict_analysis_app = app_analyzer. \ analyze_apk_androguard(app, md5_app, dict_analysis_app) # get permissions privacy relevant logger.info("Package name {}".format(application.get_package())) dict_analysis_app["package_name"] = application.get_package() logger.info("MD5 {}".format(md5_app)) logger.info("Get permission-api mapping") permissions_api_mapping = app_analyzer.get_api_related_to_permission_privacy_relevant() logger.info("Creation list api to be monitored during dynamic analysis") list_api_to_monitoring = app_analyzer.create_list_api_to_monitoring_from_file( permissions_api_mapping, app_permissions_list, app_trackers) # if API == 0 --> app is cleaned if len(list_api_to_monitoring) == 0: logger.info("Application does not need privacy policy page, " "close the emulator and " "pass to the next application") # write on file file_name = md5_app dir_result = os.path.join(os.getcwd(), "logs", file_name) dict_analysis_app["dynamic_analysis_needed"] = False with open(os.path.join(dir_result, "{}.json".format(file_name)), "w") as json_file: json.dump(dict_analysis_app, json_file, indent=4) count += 1 r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name)) # UPDATE STATS logger.info("Update stats") stats.update_stats_permission(app_permissions_list) stats.update_stats_trackers(app_trackers) stats.add_app_cleaned() # STORE INFORMATION logger.info(stats.stats_trackers) logger.info(stats.stats_permission) # write on file stats.write_on_file(log_analysis_file, count) stats.write_stats_permissions(log_permission_file) stats.write_stats_trackers(log_trackers_file) shutil.move(app, os.path.join(os.getcwd(), "apps_analyzed")) continue # APP should be analyzed in a dynamic way logger.info("Number of APIs to monitoring: {}".format(len(list_api_to_monitoring))) file_name = md5_app dir_result = os.path.join(os.getcwd(), "logs", file_name) dict_analysis_app["api_to_monitoring_all"] = len(list_api_to_monitoring) with open(os.path.join(dir_result, "{}.json".format(file_name)), "w") as json_file: json.dump(dict_analysis_app, json_file, indent=4) # disable verify installer and set correct time time.sleep(5) logger.info("Set correct time on emulator") adb = ADB() adb.kill_server() adb.connect() time.sleep(2) try: command_settings_verify = ["settings put global verifier_verify_adb_installs 0"] adb.shell(command_settings_verify) date_command = ['su 0 date {0}; am broadcast -a android.intent.action.TIME_SET'. format(time.strftime('%m%d%H%M%Y.%S'))] adb.shell(date_command) except Exception as e: logger.error("Exception as e {}, restart and re-connect to emulator".format(e)) adb.kill_server() adb.connect() command_settings_verify = ["settings put global verifier_verify_adb_installs 0"] adb.shell(command_settings_verify) date_command = ['su 0 date {0}; am broadcast -a android.intent.action.TIME_SET'. format(time.strftime('%m%d%H%M%Y.%S'))] adb.shell(date_command) dir_hook_file = os.path.join(os.getcwd(), "hook", md5_app) logger.info("Creation hook dir frida") if not os.path.exists(dir_hook_file): os.makedirs(dir_hook_file) hook_is_created = app_analyzer.create_api_list_frida(list_api_to_monitoring, os.path.join(dir_hook_file, "frida_api.txt")) frida_monitoring.push_and_start_frida_server(adb) frida_monitoring.set_file_log_frida(os.path.join(os.getcwd(), "logs", md5_app, "monitoring_api_{}.json".format(md5_app))) frida_monitoring.clean_list_json_api_invoked() signal.signal(signal.SIGALRM, handler_timeout) signal.alarm(MAX_TIME_ANALYSIS) result_app, dict_analysis_app = dynamic_testing_environment.start_analysis(type_analysis=type, app=app, max_actions=max_actions, timeout_privacy=timeout_privacy, pdetector=pdetector, md5_app=md5_app, frida_monitoring=frida_monitoring, dict_analysis_app=dict_analysis_app) # END DYNAMIC ANALYSIS NOW STORE DATA result_directory = os.path.join(os.getcwd(), "logs", md5_app) if not os.path.exists(result_directory): os.makedirs(result_directory) logger.info("Analysis api invoked during dynamic analysis") # Get API Invoked list_json_api_invoked = frida_monitoring.get_list_api_invoked() # set_list_json_api_invoked = list(set(list_json_api_invoked)) logger.info("Api invoked during dynamic analysis {}".format(len(list_json_api_invoked))) # store on json file the api invoked if len(list_json_api_invoked) > 0: file_log_frida = frida_monitoring.get_file_log_frida() with open(file_log_frida, "w") as outfile_api: json.dump(list_json_api_invoked, outfile_api, indent=4) # Action not needed # DETECT IF THE APP IS COMPLIANT OR NOT WITH GOOGLE PLAY STORE app_is_compliant = result_app.detected and not (result_app.back_button_change_page or result_app.home_button_change_page or len(list_json_api_invoked) > 0 ) dict_analysis_app["api_invoked_during_dynamic_analysis"] = len(list_json_api_invoked) if app_is_compliant: stats.add_app_compliant() else: stats.add_app_not_compliant() dict_analysis_app["app_is_compliant_with_google_play_store"] = app_is_compliant dict_analysis_app["app_analyzed"] = True dict_analysis_app["num_tentative"] = tentative + 1 write_json_file_log(md5_app, dict_analysis_app) stats.add_api_privacy_relevant_invoked(len(list_json_api_invoked)) # r_reset_emulator = requests.get("{}/reset/{}".format(LOCAL_URL_EMULATOR, emulator_name)) r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name)) # UPDATE stats analysis logger.info("Update stats") stats.list_max_actions.append(result_app.max_actions) stats.update_value_dynamic_analysis(result_app) stats.update_stats_permission(app_permissions_list) stats.update_stats_trackers(app_trackers) # debug logger.info(stats.stats_trackers) logger.info(stats.stats_permission) # write on file count += 1 tentative = 0 stats.write_on_file(log_analysis_file, count) stats.write_stats_permissions(log_permission_file) stats.write_stats_trackers(log_trackers_file) logger.info("End update stats") logger.info("3PDroid end analysis") str_end_file = "*" * 20 logger.info("{}\n\n".format(str_end_file)) shutil.move(app, os.path.join(os.getcwd(), "apps_analyzed")) else: tentative += 1 if tentative < MAX_TENTATIVE: logger.error("Unable to start emulator, try again this app") str_end_file = "*" * 20 logger.info("{}\n\n".format(str_end_file)) r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name)) else: tentative = 0 count += 1 r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name)) stats.add_app_not_analyzed() dict_analysis_app["app_analyzed"] = False write_json_file_log(md5_app, dict_analysis_app) logger.error("Unable to start emulator, pass to next app") str_end_file = "*" * 20 logger.info("{}\n\n".format(str_end_file)) shutil.move(app, os.path.join(os.getcwd(), "apps_analyzed")) else: logger.info("App already analyzed, pass to next app") shutil.move(app, os.path.join(os.getcwd(), "apps_analyzed")) count += 1 except MyTimeoutExcpetion as e: tentative += 1 if tentative < MAX_TENTATIVE: logger.error("Exception stop emulator, Exception: {}".format(e)) str_end_file = "*" * 20 logger.info("{}\n\n".format(str_end_file)) r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name)) else: tentative = 0 count += 1 r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name)) stats.add_app_not_analyzed() logger.error("Exception stop emulator pass to next apps, Exception: {}".format(e)) dict_analysis_app["app_analyzed"] = False write_json_file_log(md5_app, dict_analysis_app) str_end_file = "*" * 20 logger.info("{}\n\n".format(str_end_file)) shutil.move(app, os.path.join(os.getcwd(), "apps_analyzed")) except Exception as e: tentative += 1 if tentative < MAX_TENTATIVE: logger.error("Exception stop emulator, Exception: {}".format(e)) str_end_file = "*" * 20 logger.info("{}\n\n".format(str_end_file)) r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name)) else: tentative = 0 count += 1 r_stop_emulator = requests.get("{}/stop/{}".format(LOCAL_URL_EMULATOR, emulator_name)) stats.add_app_not_analyzed() logger.error("Exception stop emulator pass to next apps, Exception: {}".format(e)) dict_analysis_app["app_analyzed"] = False write_json_file_log(md5_app, dict_analysis_app) str_end_file = "*" * 20 logger.info("{}\n\n".format(str_end_file)) shutil.move(app, os.path.join(os.getcwd(), "apps_analyzed")) end = time.time() logger.info("\n\n") logger.info("Execution time: {}, mean: {}".format(end - start, (end - start) / count))