def test_track_detail_app_removed_tracker(self): tracker1 = Tracker( id=1, name='Teemo', ) tracker1.save() application_handle1 = "com.handle.one" report1 = Report() report1.save() application1 = Application( handle=application_handle1, report=report1 ) application1.save() report1.found_trackers = [tracker1.id] report1.save() report2 = Report() report2.save() application2 = Application( handle=application_handle1, report=report2 ) application2.save() # Removing trackers in the version of the app report2.found_trackers = [] report2.save() c = Client() url = self.TRACKER_DETAIL_PATH.format(tracker1.id) response = c.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(response.context['tracker'].id, tracker1.id) self.assertEqual(len(response.context['reports']), 0)
def test_track_detail_app_multiple_reports(self): tracker2 = Tracker( id=2, name='Exodus Super Tracker', ) tracker2.save() application_handle2 = "com.handle.two" report2 = Report() report2.save() application2 = Application( handle=application_handle2, report=report2 ) application2.save() report2.found_trackers = [tracker2.id] report2.save() report3 = Report() report3.save() application3 = Application( handle=application_handle2, report=report3 ) application3.save() report3.found_trackers = [tracker2.id] report3.save() c = Client() url = self.TRACKER_DETAIL_PATH.format(tracker2.id) response = c.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(response.context['tracker'].id, tracker2.id) self.assertEqual(len(response.context['reports']), 1) self.assertEqual(response.context['reports'][0].application.handle, application_handle2) self.assertEqual(response.context['reports'][0], report3)
def test_should_return_stats_with_multiple_reports_multiple_application(self): tracker1 = Tracker( id=1, name='Teemo', ) tracker1.save() tracker2 = Tracker( id=2, name='Exodus Super Tracker', ) tracker2.save() application_handle1 = "com.handle.one" application_handle2 = "com.handle.two" report1 = Report() report1.save() application1 = Application( handle=application_handle1, report=report1 ) application1.save() report1.found_trackers = [tracker2.id] report1.save() report2 = Report() report2.save() application2 = Application( handle=application_handle2, report=report2 ) application2.save() report2.found_trackers = [] report2.save() report3 = Report() report3.save() application3 = Application( handle=application_handle2, report=report3 ) application3.save() report3.found_trackers = [tracker1.id, tracker2.id] report3.save() c = Client() response = c.get(self.STATS_PATH) self.assertEqual(response.status_code, 200) self.assertContains(response, tracker1.name, 1) self.assertContains(response, tracker2.name, 1) self.assertEqual(response.context['trackers'][0].name, tracker2.name) # Only recent for an application is considered self.assertEqual(response.context['trackers'][0].count, 2) self.assertEqual(response.context['trackers'][0].score, 100) self.assertEqual(response.context['trackers'][1].name, tracker1.name) self.assertEqual(response.context['trackers'][1].count, 1) self.assertEqual(response.context['trackers'][1].score, 50)
def test_should_return_stats_with_multiple_trackers_found(self): tracker1 = Tracker( id=1, name='Teemo', ) tracker1.save() tracker2 = Tracker( id=2, name='Exodus Super Tracker', ) tracker2.save() report1 = Report() report1.save() report1.found_trackers = [tracker2.id] report1.save() report2 = Report() report2.save() report2.found_trackers = [] report2.save() report3 = Report() report3.save() report3.found_trackers = [tracker1.id, tracker2.id] report3.save() c = Client() response = c.get(self.STATS_PATH) self.assertEqual(response.status_code, 200) self.assertContains(response, tracker1.name, 1) self.assertContains(response, tracker2.name, 1) self.assertEqual(response.context['trackers'][0].name, tracker2.name) self.assertEqual(response.context['trackers'][0].count, 2) self.assertEqual(response.context['trackers'][0].score, 66) self.assertEqual(response.context['trackers'][1].name, tracker1.name) self.assertEqual(response.context['trackers'][1].count, 1) self.assertEqual(response.context['trackers'][1].score, 33)
def test_should_return_stats_with_1_tracker_found(self): tracker = Tracker( id=1, name='Teemo', ) tracker.save() report = Report() report.save() report.found_trackers = [tracker.id] report.save() c = Client() response = c.get(self.STATS_PATH) self.assertEqual(response.status_code, 200) self.assertContains(response, tracker.name, 1) self.assertEqual(response.context['trackers'][0].name, tracker.name) self.assertEqual(response.context['trackers'][0].count, 1) self.assertEqual(response.context['trackers'][0].score, 100)
def test_should_not_include_more_than_X_trackers(self): tracker_limit = 21 for x in range(0, tracker_limit): tracker = Tracker(name='Tracker{}.'.format(x)) tracker.save() extra_tracker = Tracker(name='Exodus Super Tracker') extra_tracker.save() first_trackers = Tracker.objects.exclude(name=extra_tracker.name) report = Report() report.save() report.found_trackers = [t.id for t in first_trackers] report.save() c = Client() response = c.get(self.STATS_PATH) self.assertEqual(response.status_code, 200) self.assertNotContains(response, extra_tracker.name) for t in first_trackers: self.assertContains(response, t.name, 1)
def start_static_analysis(analysis): """ Compute the entire static analysis :param analysis: a StaticAnalysis instance """ request = AnalysisRequest.objects.get(pk=analysis.query.id) request.description = _('Your request is running') request.save() storage_helper = RemoteStorageHelper(analysis.bucket) # Download APK and put it on Minio storage dl_r = download_apk(storage_helper, request.handle, analysis.tmp_dir, analysis.apk_name, analysis.apk_tmp) if not dl_r: msg = _('Unable to download the APK') exit_code = save_error(storage_helper, analysis, request, msg) return exit_code change_description(request, _('Download APK: success')) # Decode the APK file try: static_analysis = StaticAnalysis(analysis.apk_tmp) static_analysis.load_apk() except Exception as e: logging.info(e) msg = _('Unable to decode the APK') exit_code = save_error(storage_helper, analysis, request, msg) return exit_code change_description(request, _('Decode APK: success')) # List and save embedded classes try: with tempfile.NamedTemporaryFile(delete=True) as fp: static_analysis.save_embedded_classes_in_file(fp.name) storage_helper.put_file(fp.name, analysis.class_list_file) except Exception as e: logging.info(e) msg = _('Unable to compute the class list') exit_code = save_error(storage_helper, analysis, request, msg) return exit_code change_description(request, _('List embedded classes: success')) # APK shasum = static_analysis.get_sha256() # Application handle = static_analysis.get_package() version = static_analysis.get_version() version_code = static_analysis.get_version_code() # If a report exists for the same handle, version & version_code, return it existing_report = Report.objects.filter( application__handle=handle, application__version=version, application__version_code=version_code ).order_by('-creation_date').first() if existing_report is not None: clear_analysis_files(storage_helper, analysis.tmp_dir, analysis.bucket, True) request.description = _('A report already exists for this application version') request.processed = True request.report_id = existing_report.id request.save() return existing_report.id # APK try: certificates = static_analysis.get_certificates() except Exception as e: logging.info(e) msg = _('Unable to get certificates') exit_code = save_error(storage_helper, analysis, request, msg) return exit_code # Fingerprint try: perms = static_analysis.get_permissions() app_uid = static_analysis.get_application_universal_id() if len(app_uid) < 16: raise Exception('Unable to compute the Universal Application ID') icon_file, icon_phash = static_analysis.get_icon_and_phash(storage_helper, analysis.icon_name) if len(str(icon_phash)) < 16: raise Exception('Unable to compute the icon perceptual hash') except Exception as e: logging.info(e) msg = _('Unable to compute APK fingerprint') exit_code = save_error(storage_helper, analysis, request, msg) return exit_code # Application details try: app_info = static_analysis.get_app_info() except Exception as e: logging.info(e) msg = _('Unable to get application details from Google Play') exit_code = save_error(storage_helper, analysis, request, msg) return exit_code change_description(request, _('Get application details: success')) # Find trackers trackers = static_analysis.detect_trackers() change_description(request, _('Tracker analysis: success')) report = Report( apk_file=analysis.apk_name, storage_path='', bucket=request.bucket, class_list_file=analysis.class_list_file ) report.save() net_analysis = NetworkAnalysis(report=report) net_analysis.save() app = Application( report=report, handle=handle, version=version, version_code=version_code, name=static_analysis.get_app_name(), icon_phash=icon_phash, app_uid=app_uid ) if app_info is not None: app.name = app_info['title'] app.creator = app_info['creator'] app.downloads = app_info['downloads'] if icon_file != '': app.icon_path = analysis.icon_name app.save(force_insert=True) apk = Apk( application=app, name=analysis.apk_name, sum=shasum ) apk.save(force_insert=True) for certificate in certificates: c = Certificate( apk=apk, issuer=certificate.issuer, fingerprint=certificate.fingerprint, subject=certificate.subject, serial_number=certificate.serial ) c.save(force_insert=True) for perm in perms: p = Permission( application=app, name=perm ) p.save(force_insert=True) report.found_trackers = trackers report.save() change_description(request, _('Static analysis complete')) clear_analysis_files(storage_helper, analysis.tmp_dir, analysis.bucket, False) request.processed = True request.report_id = report.id request.save() return report.id