From 41347d4e5b674a0086b4d539bd210418d8298570 Mon Sep 17 00:00:00 2001 From: Ajin Abraham Date: Thu, 18 Jul 2019 16:48:59 -0400 Subject: [PATCH] flake8 linting and code QA --- .travis.yml | 5 +- DynamicAnalyzer/admin.py | 3 - DynamicAnalyzer/models.py | 3 - DynamicAnalyzer/tests.py | 3 - DynamicAnalyzer/views/android/analysis.py | 270 ++--- DynamicAnalyzer/views/android/avd.py | 98 -- DynamicAnalyzer/views/android/dynamic.py | 957 +++++++++-------- DynamicAnalyzer/views/android/shared.py | 130 ++- .../views/android/virtualbox_vm.py | 27 +- MalwareAnalyzer/admin.py | 3 - MalwareAnalyzer/models.py | 3 - MalwareAnalyzer/tests.py | 3 - MalwareAnalyzer/trackersdb/exodus_trackers | 2 +- MalwareAnalyzer/views/Trackers.py | 98 +- MalwareAnalyzer/views/VirusTotal.py | 99 +- MalwareAnalyzer/views/apkid.py | 15 +- MalwareAnalyzer/views/domain_check.py | 127 +-- MobSF/forms.py | 5 +- MobSF/models.py | 1 - MobSF/settings.py | 306 +++--- MobSF/urls.py | 55 +- MobSF/utils.py | 549 +++++----- MobSF/views/api/rest_api.py | 138 +-- MobSF/views/api/rest_api_middleware.py | 25 +- MobSF/views/helpers.py | 32 +- MobSF/views/home.py | 172 ++- MobSF/views/scanning.py | 77 +- MobSF/wsgi.py | 9 +- StaticAnalyzer/admin.py | 3 - StaticAnalyzer/forms.py | 52 +- StaticAnalyzer/models.py | 2 +- StaticAnalyzer/tests.py | 307 +++--- StaticAnalyzer/tools/strings.py | 25 +- StaticAnalyzer/views/android/android_apis.py | 131 +-- .../views/android/android_manifest_desc.py | 975 +++++++++++++----- StaticAnalyzer/views/android/android_rules.py | 232 +++-- .../views/android/binary_analysis.py | 160 +-- StaticAnalyzer/views/android/cert_analysis.py | 136 +-- StaticAnalyzer/views/android/code_analysis.py | 71 +- StaticAnalyzer/views/android/converter.py | 162 +-- .../views/android/db_interaction.py | 93 +- .../views/android/dvm_permissions.py | 428 ++++---- StaticAnalyzer/views/android/find.py | 56 +- StaticAnalyzer/views/android/icon_analysis.py | 55 +- StaticAnalyzer/views/android/java.py | 69 +- .../views/android/manifest_analysis.py | 604 ++++++----- StaticAnalyzer/views/android/manifest_view.py | 36 +- StaticAnalyzer/views/android/playstore.py | 13 +- StaticAnalyzer/views/android/smali.py | 48 +- .../views/android/static_analyzer.py | 299 +++--- StaticAnalyzer/views/android/strings.py | 33 +- StaticAnalyzer/views/android/view_source.py | 44 +- StaticAnalyzer/views/android/win_fixes.py | 39 +- StaticAnalyzer/views/comparer.py | 145 +-- StaticAnalyzer/views/ios/appstore.py | 24 +- StaticAnalyzer/views/ios/binary_analysis.py | 396 ++++--- StaticAnalyzer/views/ios/code_analysis.py | 60 +- StaticAnalyzer/views/ios/db_interaction.py | 412 ++++---- StaticAnalyzer/views/ios/ios_apis.py | 33 +- StaticAnalyzer/views/ios/ios_rules.py | 121 ++- StaticAnalyzer/views/ios/plist_analysis.py | 292 +++--- StaticAnalyzer/views/ios/static_analyzer.py | 283 ++--- StaticAnalyzer/views/ios/view_source.py | 128 ++- StaticAnalyzer/views/shared_func.py | 472 +++++---- StaticAnalyzer/views/windows.py | 332 +++--- install/windows/rpc_client.py | 110 +- install/windows/setup.py | 175 ++-- manage.py | 5 +- scripts/check_android_permissions.py | 21 +- scripts/clean.sh | 2 +- scripts/cloud/cloud_server.py | 77 +- scripts/mass_static_analysis.py | 75 +- scripts/mobsfy.py | 195 ++-- scripts/mobsfy_AVD.py | 318 ------ scripts/qcow2.py | 87 -- scripts/start_avd.py | 199 ---- templates/dynamic_analysis/start_test.html | 11 +- tox.ini | 82 ++ 78 files changed, 5738 insertions(+), 5605 deletions(-) delete mode 100644 DynamicAnalyzer/views/android/avd.py delete mode 100755 scripts/mobsfy_AVD.py delete mode 100644 scripts/qcow2.py delete mode 100644 scripts/start_avd.py create mode 100644 tox.ini diff --git a/.travis.yml b/.travis.yml index 76d06b12..597298c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,9 +52,8 @@ addons: - sqlite3 install: - export PYTHONIOENCODING=UTF8 -- pip install coveralls before_script: - - pip install flake8 -r requirements.txt + - pip install tox -r requirements.txt script: - - flake8 . --count --select=E9,F63,F72,F82 --exclude .git,__pycache__,venv --show-source --statistics + - tox -e lint - python manage.py test diff --git a/DynamicAnalyzer/admin.py b/DynamicAnalyzer/admin.py index ea5d68b7..e69de29b 100755 --- a/DynamicAnalyzer/admin.py +++ b/DynamicAnalyzer/admin.py @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/DynamicAnalyzer/models.py b/DynamicAnalyzer/models.py index fd18c6ea..e69de29b 100755 --- a/DynamicAnalyzer/models.py +++ b/DynamicAnalyzer/models.py @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/DynamicAnalyzer/tests.py b/DynamicAnalyzer/tests.py index de8bdc00..e69de29b 100755 --- a/DynamicAnalyzer/tests.py +++ b/DynamicAnalyzer/tests.py @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/DynamicAnalyzer/views/android/analysis.py b/DynamicAnalyzer/views/android/analysis.py index d045a7fe..feb818a7 100644 --- a/DynamicAnalyzer/views/android/analysis.py +++ b/DynamicAnalyzer/views/android/analysis.py @@ -1,34 +1,28 @@ -""" -Perform Analysis on Dynamic Analysis Data -""" -import os -import io -import re -import json +"""Perform Analysis on Dynamic Analysis Data.""" import base64 -import tarfile -import shutil +import io +import json import logging - +import os +import re +import shutil +import tarfile from pathlib import Path from django.utils.html import escape from MalwareAnalyzer.views.domain_check import malware_check -from MobSF.utils import ( - python_list, - isBase64, - PrintException -) + +from MobSF.utils import is_base64, log_exception, python_list logger = logging.getLogger(__name__) def api_analysis(package, location): - """API Analysis""" + """API Analysis.""" api_analysis_result = {} - logger.info("Dynamic API Analysis") - dat = "" + logger.info('Dynamic API Analysis') + dat = '' api_base64 = [] api_fileio = [] api_reflect = [] @@ -43,99 +37,119 @@ def api_analysis(package, location): api_cmd = [] api_sms = [] try: - with open(location, "r", encoding="utf-8") as flip: + with open(location, 'r', encoding='utf-8') as flip: dat = flip.readlines() - res_id = "Droidmon-apimonitor-" + package + ":" + res_id = 'Droidmon-apimonitor-' + package + ':' for line in dat: if res_id in line: - # print "LINE: " + line _, value = line.split(res_id, 1) - # print "PARAM is :" + param - # print "Value is :"+ value try: apis = json.loads(value, strict=False) ret = '' args = '' - mtd = str(apis["method"]) - clss = str(apis["class"]) - # print "Called Class: " + CLS - # print "Called Method: " + MTD + mtd = str(apis['method']) + clss = str(apis['class']) if apis.get('return'): - ret = str(apis["return"]) - # print "Return Data: " + RET + ret = str(apis['return']) else: - # print "No Return Data" - ret = "No Return Data" + ret = 'No Return Data' if apis.get('args'): - args = str(apis["args"]) - # print "Passed Arguments" + ARGS + args = str(apis['args']) else: - # print "No Arguments Passed" - args = "No Arguments Passed" + args = 'No Arguments Passed' # XSS Safe - call_data = "
METHOD: " + \ - escape(mtd) + "
ARGUMENTS: " + escape(args) + \ - "
RETURN DATA: " + escape(ret) + call_data = ('
METHOD: {}' + '
ARGUMENTS: {}' + '
RETURN DATA: {}').format( + escape(mtd), + escape(args), + escape(ret)) - if re.findall("android.util.Base64", clss): + if re.findall('android.util.Base64', clss): # Base64 Decode - if "decode" in mtd: + if 'decode' in mtd: args_list = python_list(args) - if isBase64(args_list[0]): - call_data += '
' +\ - 'Decoded String: ' + \ - escape(base64.b64decode(args_list[0])) + if is_base64(args_list[0]): + call_data += ('
' + 'Decoded String' + ': {}').format( + escape(base64.b64decode( + args_list[0]))) api_base64.append(call_data) - if re.findall('libcore.io|android.app.SharedPreferencesImpl\$EditorImpl', clss): + if re.findall('libcore.io|' + 'android.app.SharedP' + 'referencesImpl\\$EditorImpl', clss): api_fileio.append(call_data) if re.findall('java.lang.reflect', clss): api_reflect.append(call_data) - if re.findall('android.content.ContentResolver|android.location.Location|android.media.AudioRecord|android.media.MediaRecorder|android.os.SystemProperties', clss): + if re.findall('android.content.ContentResolver|' + 'android.location.Location|' + 'android.media.AudioRecord|' + 'android.media.MediaRecorder|' + 'android.os.SystemProperties', clss): api_sysprop.append(call_data) - if re.findall('android.app.Activity|android.app.ContextImpl|android.app.ActivityThread', clss): + if re.findall('android.app.Activity|' + 'android.app.ContextImpl|' + 'android.app.ActivityThread', clss): api_binder.append(call_data) - if re.findall('javax.crypto.spec.SecretKeySpec|javax.crypto.Cipher|javax.crypto.Mac', clss): + if re.findall('javax.crypto.spec.SecretKeySpec|' + 'javax.crypto.Cipher|' + 'javax.crypto.Mac', clss): api_crypto.append(call_data) - if re.findall('android.accounts.AccountManager|android.app.ApplicationPackageManager|android.app.NotificationManager|android.net.ConnectivityManager|android.content.BroadcastReceiver', clss): + if re.findall('android.accounts.AccountManager|' + 'android.app.ApplicationPackageManager|' + 'android.app.NotificationManager|' + 'android.net.ConnectivityManager|' + 'android.content.BroadcastReceiver', clss): api_acntmnger.append(call_data) - if re.findall('android.telephony.TelephonyManager|android.net.wifi.WifiInfo|android.os.Debug', clss): + if re.findall('android.telephony.TelephonyManager|' + 'android.net.wifi.WifiInfo|' + 'android.os.Debug', clss): api_deviceinfo.append(call_data) - if re.findall('dalvik.system.BaseDexClassLoader|dalvik.system.DexFile|dalvik.system.DexClassLoader|dalvik.system.PathClassLoader', clss): + if re.findall('dalvik.system.BaseDexClassLoader|' + 'dalvik.system.DexFile|' + 'dalvik.system.DexClassLoader|' + 'dalvik.system.PathClassLoader', clss): api_dexloader.append(call_data) - if re.findall('java.lang.Runtime|java.lang.ProcessBuilder|java.io.FileOutputStream|java.io.FileInputStream|android.os.Process', clss): + if re.findall('java.lang.Runtime|java.lang.ProcessBuilder|' + 'java.io.FileOutputStream|' + 'java.io.FileInputStream|' + 'android.os.Process', clss): api_cmd.append(call_data) if re.findall('android.content.ContentValues', clss): api_cntvl.append(call_data) if re.findall('android.telephony.SmsManager', clss): api_sms.append(call_data) - if re.findall('java.net.URL|org.apache.http.impl.client.AbstractHttpClient', clss): + if re.findall('java.net.URL|org.apache.http.' + 'impl.client.AbstractHttpClient', clss): api_net.append(call_data) - except: - PrintException("Parsing JSON Failed for: " + value) - except: - PrintException("Dynamic API Analysis") - api_analysis_result["api_net"] = list(set(api_net)) - api_analysis_result["api_base64"] = list(set(api_base64)) - api_analysis_result["api_fileio"] = list(set(api_fileio)) - api_analysis_result["api_binder"] = list(set(api_binder)) - api_analysis_result["api_crypto"] = list(set(api_crypto)) - api_analysis_result["api_deviceinfo"] = list(set(api_deviceinfo)) - api_analysis_result["api_cntvl"] = list(set(api_cntvl)) - api_analysis_result["api_sms"] = list(set(api_sms)) - api_analysis_result["api_sysprop"] = list(set(api_sysprop)) - api_analysis_result["api_dexloader"] = list(set(api_dexloader)) - api_analysis_result["api_reflect"] = list(set(api_reflect)) - api_analysis_result["api_acntmnger"] = list(set(api_acntmnger)) - api_analysis_result["api_cmd"] = list(set(api_cmd)) + except Exception: + log_exception('Parsing JSON Failed for: ' + value) + except Exception: + log_exception('Dynamic API Analysis') + api_analysis_result['api_net'] = list(set(api_net)) + api_analysis_result['api_base64'] = list(set(api_base64)) + api_analysis_result['api_fileio'] = list(set(api_fileio)) + api_analysis_result['api_binder'] = list(set(api_binder)) + api_analysis_result['api_crypto'] = list(set(api_crypto)) + api_analysis_result['api_deviceinfo'] = list(set(api_deviceinfo)) + api_analysis_result['api_cntvl'] = list(set(api_cntvl)) + api_analysis_result['api_sms'] = list(set(api_sms)) + api_analysis_result['api_sysprop'] = list(set(api_sysprop)) + api_analysis_result['api_dexloader'] = list(set(api_dexloader)) + api_analysis_result['api_reflect'] = list(set(api_reflect)) + api_analysis_result['api_acntmnger'] = list(set(api_acntmnger)) + api_analysis_result['api_cmd'] = list(set(api_cmd)) return api_analysis_result def run_analysis(apk_dir, md5_hash, package): - """Run Dynamic File Analysis""" + """Run Dynamic File Analysis.""" analysis_result = {} - logger.info("Dynamic File Analysis") - capfuzz_home = os.path.join(str(Path.home()), ".capfuzz") - web = os.path.join(capfuzz_home, 'flows', package + ".flows.txt") + logger.info('Dynamic File Analysis') + capfuzz_home = os.path.join(str(Path.home()), '.capfuzz') + web = os.path.join(capfuzz_home, 'flows', package + '.flows.txt') logcat = os.path.join(apk_dir, 'logcat.txt') xlogcat = os.path.join(apk_dir, 'x_logcat.txt') traffic = '' @@ -144,28 +158,30 @@ def run_analysis(apk_dir, md5_hash, package): domains = {} logcat_data = [] clipboard = [] - clip_tag = "I/CLIPDUMP-INFO-LOG" + clip_tag = 'I/CLIPDUMP-INFO-LOG' try: - with io.open(web, mode='r', encoding="utf8", errors="ignore") as flip: + with io.open(web, mode='r', encoding='utf8', errors='ignore') as flip: web_data = flip.read() - except: + except Exception: pass - with io.open(logcat, mode='r', encoding="utf8", errors="ignore") as flip: + with io.open(logcat, mode='r', encoding='utf8', errors='ignore') as flip: logcat_data = flip.readlines() traffic = ''.join(logcat_data) - with io.open(xlogcat, mode='r', encoding="utf8", errors="ignore") as flip: + with io.open(xlogcat, mode='r', encoding='utf8', errors='ignore') as flip: xlg = flip.read() traffic = web_data + traffic + xlg for log_line in logcat_data: if log_line.startswith(clip_tag): - clipboard.append(log_line.replace(clip_tag, "Process ID ")) + clipboard.append(log_line.replace(clip_tag, 'Process ID ')) urls = [] # URLs My Custom regex url_pattern = re.compile( - r'((?:https?://|s?ftps?://|file://|javascript:|data:|www\d{0,3}[.])[\w().=/;,#:@?&~*+!$%\'{}-]+)', re.UNICODE) + r'((?:https?://|s?ftps?://|file://|' + r'javascript:|data:|www\d{0,3}' + r'[.])[\w().=/;,#:@?&~*+!$%\'{}-]+)', re.UNICODE) urllist = re.findall(url_pattern, traffic.lower()) # Domain Extraction and Malware Check - logger.info("Performing Malware Check on extracted Domains") + logger.info('Performing Malware Check on extracted Domains') domains = malware_check(urllist) for url in urllist: if url not in urls: @@ -173,10 +189,10 @@ def run_analysis(apk_dir, md5_hash, package): # Email Etraction Regex emails = [] - regex = re.compile(r"[\w.-]+@[\w-]+\.[\w.]+") + regex = re.compile(r'[\w.-]+@[\w-]+\.[\w.]+') for email in regex.findall(traffic.lower()): if (email not in emails) and (not email.startswith('//')): - if email == "yodleebanglore@gmail.com": + if email == 'yodleebanglore@gmail.com': pass else: emails.append(email) @@ -189,10 +205,10 @@ def run_analysis(apk_dir, md5_hash, package): with tarfile.open(tar_loc) as tar: try: tar.extractall(untar_dir) - except: + except Exception: pass - except: - PrintException("TAR EXTRACTION FAILED") + except Exception: + log_exception('TAR EXTRACTION FAILED') # Do Static Analysis on Data from Device xmlfiles = '' sqlite_db = '' @@ -205,57 +221,67 @@ def run_analysis(apk_dir, md5_hash, package): for dir_name, _, files in os.walk(untar_dir): for jfile in files: file_path = os.path.join(untar_dir, dir_name, jfile) - if "+" in file_path: - shutil.move(file_path, file_path.replace("+", "x")) - file_path = file_path.replace("+", "x") + if '+' in file_path: + shutil.move(file_path, file_path.replace('+', 'x')) + file_path = file_path.replace('+', 'x') fileparam = file_path.replace(untar_dir, '') if jfile == 'lib': pass else: if jfile.endswith('.xml'): typ = 'xml' - xmlfiles += "" + escape(fileparam) + "" + xmlfiles += ('{}' + '').format( + escape(fileparam), + md5_hash, + typ, + escape(fileparam)) else: - with io.open(file_path, mode='r', encoding="utf8", errors="ignore") as flip: + with open(file_path, 'r') as flip: file_cnt_sig = flip.read(6) - if file_cnt_sig == "SQLite": + if file_cnt_sig == 'SQLite': typ = 'db' - sqlite_db += "" + \ - escape(fileparam) + "" + sqlite_db += ('{}' + '').format( + escape(fileparam), + md5_hash, + typ, + escape(fileparam)) elif not jfile.endswith('.DS_Store'): typ = 'others' - other_files += "" + \ - escape(fileparam) + "" - except: - PrintException("Dynamic File Analysis") - analysis_result["urls"] = urls - analysis_result["domains"] = domains - analysis_result["emails"] = emails - analysis_result["clipboard"] = clipboard - analysis_result["web_data"] = web_data - analysis_result["xmlfiles"] = xmlfiles - analysis_result["sqlite_db"] = sqlite_db - analysis_result["other_files"] = other_files + other_files += ('{}' + '').format( + escape(fileparam), + md5_hash, + typ, + escape(fileparam)) + except Exception: + log_exception('Dynamic File Analysis') + analysis_result['urls'] = urls + analysis_result['domains'] = domains + analysis_result['emails'] = emails + analysis_result['clipboard'] = clipboard + analysis_result['web_data'] = web_data + analysis_result['xmlfiles'] = xmlfiles + analysis_result['sqlite_db'] = sqlite_db + analysis_result['other_files'] = other_files return analysis_result def download(md5_hash, download_dir, apk_dir, package): - """Generating Downloads""" - logger.info("Generating Downloads") + """Generating Downloads.""" + logger.info('Generating Downloads') try: - capfuzz_home = os.path.join(str(Path.home()), ".capfuzz") + capfuzz_home = os.path.join(str(Path.home()), '.capfuzz') logcat = os.path.join(apk_dir, 'logcat.txt') xlogcat = os.path.join(apk_dir, 'x_logcat.txt') dumpsys = os.path.join(apk_dir, 'dump.txt') sshot = os.path.join(apk_dir, 'screenshots-apk/') - web = os.path.join(capfuzz_home, 'flows', package + ".flows.txt") + web = os.path.join(capfuzz_home, 'flows', package + '.flows.txt') star = os.path.join(apk_dir, package + '.tar') dlogcat = os.path.join(download_dir, md5_hash + '-logcat.txt') @@ -278,15 +304,15 @@ def download(md5_hash, download_dir, apk_dir, package): shutil.copyfile(dumpsys, ddumpsys) try: shutil.copytree(sshot, dsshot) - except: + except Exception: pass try: shutil.copyfile(web, dweb) - except: + except Exception: pass try: shutil.copyfile(star, dstar) - except: + except Exception: pass - except: - PrintException("Generating Downloads") + except Exception: + log_exception('Generating Downloads') diff --git a/DynamicAnalyzer/views/android/avd.py b/DynamicAnalyzer/views/android/avd.py deleted file mode 100644 index 1fa23f54..00000000 --- a/DynamicAnalyzer/views/android/avd.py +++ /dev/null @@ -1,98 +0,0 @@ -""" -Android Dynamic Analyzer for Android AVD (ARM) VM -""" -import os -import time -import platform -import subprocess -import logging -from DynamicAnalyzer.views.android.shared import adb_command -from MobSF.utils import PrintException -from django.conf import settings -from scripts.start_avd import main as start_avd_cold -logger = logging.getLogger(__name__) - - -def stop_avd(): - """Stop AVD""" - logger.info("Stopping MobSF Emulator") - try: - adb_command(['emu', 'kill'], silent=True) - except: - PrintException("Stopping MobSF Emulator") - - -def start_avd_from_snapshot(): - """Start AVD""" - logger.info("Starting MobSF Emulator") - try: - if platform.system() == 'Darwin': - # There is a strage error in mac with the dyld one in a while.. - # this should fix it.. - if 'DYLD_FALLBACK_LIBRARY_PATH' in list(os.environ.keys()): - del os.environ['DYLD_FALLBACK_LIBRARY_PATH'] - - args = [ - settings.AVD_EMULATOR, - '-avd', - settings.AVD_NAME, - "-writable-system", - "-snapshot", - settings.AVD_SNAPSHOT, - "-netspeed", - "full", - "-netdelay", - "none", - "-port", - str(settings.AVD_ADB_PORT), - ] - subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - # Give a few seconds and check if the snapshot load succeed - time.sleep(5) - result = adb_command(["getprop", "init.svc.bootanim"], True) - - if result: - if result.strip() == b"stopped": - return True - - # Snapshot failed, stop the avd and return an error - adb_command(["emu", "kill"]) - return False - except: - PrintException("Starting MobSF Emulator") - return False - - -def refresh_avd(): - """Refresh AVD""" - - # Before we load the AVD, check paths - for path in [settings.AVD_EMULATOR, - settings.ADB_BINARY]: - if not path: - logger.error("AVD binaries not configured, please refer to the official documentation") - return False - - logger.info("Refreshing MobSF Emulator") - try: - # Stop existing emulator - stop_avd() - - # Check if configuration specifies cold or warm boot - if settings.AVD_COLD_BOOT: - if start_avd_cold(): - logger.info("AVD has been started successfully") - return True - else: - if not settings.AVD_SNAPSHOT: - logger.error("AVD not configured properly - AVD_SNAPSHOT is missing") - return False - if start_avd_from_snapshot(): - logger.info("AVD has been loaded from snapshot successfully") - return True - return False - - except: - PrintException("Refreshing MobSF VM") - return False diff --git a/DynamicAnalyzer/views/android/dynamic.py b/DynamicAnalyzer/views/android/dynamic.py index d0f50cd5..7864692f 100755 --- a/DynamicAnalyzer/views/android/dynamic.py +++ b/DynamicAnalyzer/views/android/dynamic.py @@ -1,58 +1,37 @@ -"""Core Functions of Android Dynamic Analysis""" # -*- coding: utf_8 -*- -import os -import re -import ntpath -import io +"""Core Functions of Android Dynamic Analysis.""" import json -import random -import time -import socket -import shutil -import threading -import sqlite3 as sq -from django.shortcuts import render -from django.conf import settings -from django.template.defaulttags import register -from django.http import HttpResponseRedirect, HttpResponse -from django.utils.html import escape import logging +import ntpath +import os +import random +import re +import shutil +import socket +import sqlite3 as sq +import threading +import time + +from django.conf import settings +from django.http import HttpResponse, HttpResponseRedirect +from django.shortcuts import render +from django.template.defaulttags import register +from django.utils.html import escape + +from DynamicAnalyzer.tools.webproxy import (get_ca_dir, start_fuzz_ui, + start_proxy, stop_capfuzz) +from DynamicAnalyzer.views.android.analysis import (api_analysis, download, + run_analysis) +from DynamicAnalyzer.views.android.shared import (adb_command, connect, + get_identifier, get_res, + install_and_run, wait) +from DynamicAnalyzer.views.android.virtualbox_vm import refresh_vm + +from MobSF.utils import (get_adb, is_number, log_exception, + print_n_send_error_response, python_list) + from StaticAnalyzer.models import StaticAnalyzerAndroid -from DynamicAnalyzer.tools.webproxy import ( - start_proxy, - stop_capfuzz, - start_fuzz_ui, - get_ca_dir, -) -from DynamicAnalyzer.views.android.avd import ( - refresh_avd, - stop_avd -) - -from DynamicAnalyzer.views.android.analysis import ( - api_analysis, - run_analysis, - download -) -from DynamicAnalyzer.views.android.virtualbox_vm import ( - refresh_vm -) -from DynamicAnalyzer.views.android.shared import ( - connect, - install_and_run, - get_res, - get_identifier, - wait, - adb_command, -) -from MobSF.utils import ( - PrintException, - is_number, - python_list, - getADB, - print_n_send_error_response -) logger = logging.getLogger(__name__) # =========================================== @@ -66,25 +45,27 @@ TCP Connnection to screenshot service needs to be secured. Globals! """ -TCP_SERVER_MODE = "off" # ScreenCast TCP Service Status +TCP_SERVER_MODE = 'off' # ScreenCast TCP Service Status @register.filter def key(d, key_name): - """To get dict element by key name in template""" + """To get dict element by key name in template.""" return d.get(key_name) def android_dynamic_analyzer(request): - """Android Dynamic Analyzer View""" - logger.info("Dynamic Analysis Started") + """Android Dynamic Analyzer View.""" + logger.info('Dynamic Analysis Started') try: if request.method == 'POST': md5_hash = request.POST['md5'] package = request.POST['pkg'] launcher = request.POST['lng'] - if re.findall(r';|\$\(|\|\||&&', package) or re.findall(r';|\$\(|\|\||&&', launcher): - return print_n_send_error_response(request, "Possible RCE Attack") + if (re.findall(r';|\$\(|\|\||&&', package) + or re.findall(r';|\$\(|\|\||&&', launcher)): + return print_n_send_error_response(request, + 'Possible RCE Attack') if re.match('^[0-9a-f]{32}$', md5_hash): # Delete ScreenCast Cache screen_file = os.path.join(settings.SCREEN_DIR, 'screen.png') @@ -99,552 +80,630 @@ def android_dynamic_analyzer(request): os.makedirs(screen_dir) # Start DM stop_capfuzz(settings.PORT) - adb = getADB() - is_avd = False - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": + if settings.ANDROID_DYNAMIC_ANALYZER == 'MobSF_REAL_DEVICE': logger.info( - "MobSF will perform Dynamic Analysis on real Android Device") - elif settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": - # adb, avd_path, reference_name, dup_name, emulator - is_avd = True - if not os.path.exists(settings.AVD_EMULATOR): - return print_n_send_error_response(request, "Cannot Find AVD Emulator") - if not refresh_avd(): - return print_n_send_error_response(request, "Cannot Refresh AVD") + 'MobSF Dynamic Analysis on Real Android Device') else: # Refersh VM refresh_vm(settings.UUID, settings.SUUID, settings.VBOX) context = {'md5': md5_hash, 'pkg': package, 'lng': launcher, - 'title': 'Start Testing', - 'AVD': is_avd, } - template = "dynamic_analysis/start_test.html" + 'title': 'Start Testing'} + template = 'dynamic_analysis/start_test.html' return render(request, template, context) else: - return print_n_send_error_response(request, "Invalid Scan Hash") + return print_n_send_error_response(request, + 'Invalid Scan Hash') else: - return print_n_send_error_response(request, "Only POST allowed") - except: - PrintException("DynamicAnalyzer") - return print_n_send_error_response(request, "Dynamic Analysis Failed.") + return print_n_send_error_response(request, + 'Only POST allowed') + except Exception: + log_exception('DynamicAnalyzer') + return print_n_send_error_response(request, + 'Dynamic Analysis Failed.') # AJAX def get_env(request): - """Get Dynamic Analysis Environment for Android""" - logger.info("Setting up Dynamic Analysis Environment") + """Get Dynamic Analysis Environment for Android.""" + logger.info('Setting up Dynamic Analysis Environment') try: if request.method == 'POST': data = {} md5_hash = request.POST['md5'] package = request.POST['pkg'] launcher = request.POST['lng'] - if re.findall(r";|\$\(|\|\||&&", package) or re.findall(r";|\$\(|\|\||&&", launcher): - return print_n_send_error_response(request, "Possible RCE Attack", True) + if (re.findall(r';|\$\(|\|\||&&', package) + or re.findall(r';|\$\(|\|\||&&', launcher)): + return print_n_send_error_response(request, + 'Possible RCE Attack', + True) if re.match('^[0-9a-f]{32}$', md5_hash): - base_dir = settings.BASE_DIR app_dir = os.path.join( settings.UPLD_DIR, md5_hash + '/') # APP DIRECTORY app_file = md5_hash + '.apk' # NEW FILENAME app_path = app_dir + app_file # APP PATH - adb = getADB() - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": - proxy_ip = '127.0.0.1' - else: - proxy_ip = settings.PROXY_IP # Proxy IP start_proxy(settings.PORT, package) # vm needs the connect function try: - if not settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": - connect() + connect() except Exception as exp: data = {'ready': 'no', 'msg': 'Cannot Connect to the VM/Device.', 'error': str(exp)} - return HttpResponse(json.dumps(data), content_type='application/json') + return HttpResponse(json.dumps(data), + content_type='application/json') # Change True to support non-activity components install_and_run(app_path, package, launcher, True) screen_width, screen_width = get_res() data = {'ready': 'yes', 'screen_witdth': screen_width, - 'screen_height': screen_width, } - return HttpResponse(json.dumps(data), content_type='application/json') + 'screen_height': screen_width} + return HttpResponse(json.dumps(data), + content_type='application/json') else: - return print_n_send_error_response(request, "Invalid Scan Hash", True) + return print_n_send_error_response(request, + 'Invalid Scan Hash', + True) else: - return print_n_send_error_response(request, "Only POST allowed", True) - except: - PrintException("Setting up Dynamic Analysis Environment") - return print_n_send_error_response(request, "Environment Setup Failed", True) + return print_n_send_error_response(request, + 'Only POST allowed', + True) + except Exception: + log_exception('Setting up Dynamic Analysis Environment') + return print_n_send_error_response(request, + 'Environment Setup Failed', + True) # AJAX def take_screenshot(request): - """Take Screenshot""" - logger.info("Taking Screenshot") + """Take Screenshot.""" + logger.info('Taking Screenshot') try: if request.method == 'POST': md5_hash = request.POST['md5'] if re.match('^[0-9a-f]{32}$', md5_hash): data = {} rand_int = random.randint(1, 1000000) - base_dir = settings.BASE_DIR # make sure that list only png from this directory screen_dir = os.path.join( settings.UPLD_DIR, md5_hash + '/screenshots-apk/') if not os.path.exists(screen_dir): os.makedirs(screen_dir) adb_command( - ["screencap", "-p", "/data/local/screen.png"], True) - adb_command(["pull", "/data/local/screen.png", - screen_dir + "screenshot-" + str(rand_int) + ".png"]) - logger.info("Screenshot Taken") + ['screencap', '-p', '/data/local/screen.png'], True) + adb_command(['pull', + '/data/local/screen.png', + '{}creenshot-{}.png'.fomat( + screen_dir, + str(rand_int))]) + logger.info('Screenshot Taken') data = {'screenshot': 'yes'} - return HttpResponse(json.dumps(data), content_type='application/json') + return HttpResponse(json.dumps(data), + content_type='application/json') else: - return print_n_send_error_response(request, "Invalid Scan Hash", True) + return print_n_send_error_response(request, + 'Invalid Scan Hash', + True) else: - return print_n_send_error_response(request, "Only POST allowed", True) - except: - PrintException("Taking Screenshot") - return print_n_send_error_response(request, "Error Taking Screenshot", True) + return print_n_send_error_response(request, + 'Only POST allowed', + True) + except Exception: + log_exception('Taking Screenshot') + return print_n_send_error_response(request, + 'Error Taking Screenshot', + True) # AJAX def screen_cast(request): - """Start or Stop ScreenCast Feature""" - logger.info("Invoking ScreenCast Service in VM/Device") + """Start or Stop ScreenCast Feature.""" + logger.info('Invoking ScreenCast Service in VM/Device') try: global TCP_SERVER_MODE data = {} if request.method == 'POST': mode = request.POST['mode'] - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": - ip_address = '10.0.2.2' - else: - ip_address = settings.SCREEN_IP + ip_address = settings.SCREEN_IP port = str(settings.SCREEN_PORT) - if mode == "on": - args = ["am", - "startservice", - "-a", - ip_address + ":" + port, - "opensecurity.screencast/.StartScreenCast"] + if mode == 'on': + args = ['am', + 'startservice', + '-a', + ip_address + ':' + port, + 'opensecurity.screencast/.StartScreenCast'] data = {'status': 'on'} - TCP_SERVER_MODE = "on" - elif mode == "off": - args = ["am", - "force-stop", - "opensecurity.screencast"] + TCP_SERVER_MODE = 'on' + elif mode == 'off': + args = ['am', + 'force-stop', + 'opensecurity.screencast'] data = {'status': 'off'} - TCP_SERVER_MODE = "off" - if (mode in ["on", "off"]): + TCP_SERVER_MODE = 'off' + if (mode in ['on', 'off']): try: adb_command(args, True) screen_trd = threading.Thread(target=screencast_service) screen_trd.setDaemon(True) screen_trd.start() - except: - PrintException("Casting Screen") + except Exception: + log_exception('Casting Screen') data = {'status': 'error'} - return HttpResponse(json.dumps(data), content_type='application/json') + return HttpResponse(json.dumps(data), + content_type='application/json') else: data = {'status': 'failed'} else: data = {'status': 'failed'} - return HttpResponse(json.dumps(data), content_type='application/json') - except: - PrintException("Casting Screen") - return print_n_send_error_response(request, "Error Casting Screen", True) + return HttpResponse(json.dumps(data), + content_type='application/json') + except Exception: + log_exception('Casting Screen') + return print_n_send_error_response(request, + 'Error Casting Screen', + True) # AJAX def clip_dump(request): - """Dump Android ClipBoard""" - logger.info("Starting Clipboard Dump Service in VM/Device") + """Dump Android Clipboard.""" + logger.info('Starting Clipboard Dump Service in VM/Device') try: data = {} if request.method == 'POST': - adb = getADB() - args = ["am", - "startservice", - "opensecurity.clipdump/.ClipDumper"] + args = ['am', + 'startservice', + 'opensecurity.clipdump/.ClipDumper'] try: adb_command(args, True) data = {'status': 'success'} - except: - PrintException("Dumping Clipboard") + except Exception: + log_exception('Dumping Clipboard') data = {'status': 'error'} else: data = {'status': 'failed'} - return HttpResponse(json.dumps(data), content_type='application/json') - except: - PrintException("Dumping Clipboard") - return print_n_send_error_response(request, "Error Dumping Clipboard", True) + return HttpResponse(json.dumps(data), + content_type='application/json') + except Exception: + log_exception('Dumping Clipboard') + return print_n_send_error_response(request, + 'Error Dumping Clipboard', + True) # AJAX def touch(request): - """Sending Touch Events""" - logger.info("Sending Touch Events") + """Sending Touch Events.""" + logger.info('Sending Touch Events') try: data = {} - if (request.method == 'POST') and (is_number(request.POST['x'])) and (is_number(request.POST['y'])): + if (request.method == 'POST' + and is_number(request.POST['x']) + and is_number(request.POST['y'])): x_axis = request.POST['x'] y_axis = request.POST['y'] - adb = getADB() - args = ["input", - "tap", + args = ['input', + 'tap', x_axis, y_axis] data = {'status': 'success'} try: adb_command(args, True) - except: + except Exception: data = {'status': 'error'} - PrintException("Performing Touch Action") + log_exception('Performing Touch Action') else: data = {'status': 'failed'} - return HttpResponse(json.dumps(data), content_type='application/json') - except: - PrintException("Sending Touch Events") - return print_n_send_error_response(request, "Error Sending Touch Events", True) + return HttpResponse(json.dumps(data), + content_type='application/json') + except Exception: + log_exception('Sending Touch Events') + return print_n_send_error_response(request, + 'Error Sending Touch Events', + True) # AJAX def execute_adb(request): - """Execute ADB Commands""" - logger.info("Executing ADB Commands") + """Execute ADB Commands.""" + logger.info('Executing ADB Commands') try: if request.method == 'POST': data = {} cmd = request.POST['cmd'] - resp = "error" + resp = 'error' try: resp = adb_command(cmd.split(' ')) - except: - PrintException("Executing ADB Commands") - data = {'cmd': 'yes', 'resp': resp.decode("utf8", "ignore")} - return HttpResponse(json.dumps(data), content_type='application/json') + except Exception: + log_exception('Executing ADB Commands') + data = {'cmd': 'yes', 'resp': resp.decode('utf8', 'ignore')} + return HttpResponse(json.dumps(data), + content_type='application/json') else: - return print_n_send_error_response(request, "Only POST allowed", True) - except: - PrintException("Executing ADB Commands") - return print_n_send_error_response(request, "Error running ADB commands", True) + return print_n_send_error_response(request, + 'Only POST allowed', + True) + except Exception: + log_exception('Executing ADB Commands') + return print_n_send_error_response(request, + 'Error running ADB commands', + True) # AJAX def mobsf_ca(request): - """Install and Remove MobSF Proxy RootCA""" + """Install and Remove MobSF Proxy RootCA.""" try: if request.method == 'POST': data = {} act = request.POST['action'] rootca = get_ca_dir() - adb = getADB() - if act == "install": - logger.info("Installing MobSF RootCA") + if act == 'install': + logger.info('Installing MobSF RootCA') adb_command( - ["push", rootca, "/data/local/tmp/" + settings.ROOT_CA]) - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": - # For some reason, avd emulator does not have cp binary - adb_command(["/data/local/tmp/busybox", "cp", - "/data/local/tmp/" + settings.ROOT_CA, - "/system/etc/security/cacerts/" + settings.ROOT_CA], True) - adb_command(["chmod", "644", - "/system/etc/security/cacerts/" + settings.ROOT_CA], True) - else: - adb_command(["su", - "-c", - "cp", - "/data/local/tmp/" + settings.ROOT_CA, - "/system/etc/security/cacerts/" + settings.ROOT_CA], True) - adb_command(["su", - "-c", - "chmod", - "644", - "/system/etc/security/cacerts/" + settings.ROOT_CA], True) - adb_command( - ["rm", "/data/local/tmp/" + settings.ROOT_CA], True) + ['push', rootca, '/data/local/tmp/' + settings.ROOT_CA]) + ca_file = '/system/etc/security/cacerts/' + settings.ROOT_CA + adb_command(['su', + '-c', + 'cp', + '/data/local/tmp/' + settings.ROOT_CA, + ca_file], True) + adb_command(['su', + '-c', + 'chmod', + '644', + ca_file], True) + adb_command(['rm', + '/data/local/tmp/' + settings.ROOT_CA], True) data = {'ca': 'installed'} - elif act == "remove": - logger.info("Removing MobSF RootCA") - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": - adb_command( - ["rm", "/system/etc/security/cacerts/" + settings.ROOT_CA], True) - else: - adb_command(["su", - "-c", - "rm", - "/system/etc/security/cacerts/" + settings.ROOT_CA], True) + elif act == 'remove': + logger.info('Removing MobSF RootCA') + adb_command( + ['su', + '-c', + 'rm', + ca_file], True) data = {'ca': 'removed'} - return HttpResponse(json.dumps(data), content_type='application/json') + return HttpResponse(json.dumps(data), + content_type='application/json') else: - return print_n_send_error_response(request, "Only POST allowed", True) - except: - PrintException("MobSF RootCA Handler") - return print_n_send_error_response(request, "Error in RootCA Handler", True) + return print_n_send_error_response(request, + 'Only POST allowed', + True) + except Exception: + log_exception('MobSF RootCA Handler') + return print_n_send_error_response(request, + 'Error in RootCA Handler', + True) # AJAX def final_test(request): - """Collecting Data and Cleanup""" + """Collecting Data and Cleanup.""" global TCP_SERVER_MODE - logger.info("Collecting Data and Cleaning Up") + logger.info('Collecting Data and Cleaning Up') try: if request.method == 'POST': data = {} md5_hash = request.POST['md5'] package = request.POST['pkg'] - if re.findall(r";|\$\(|\|\||&&", package): - return print_n_send_error_response(request, "Possible RCE Attack", True) + if re.findall(r';|\$\(|\|\||&&', package): + return print_n_send_error_response(request, + 'Possible RCE Attack', + True) if re.match('^[0-9a-f]{32}$', md5_hash): # Stop ScreenCast Client if it is running - TCP_SERVER_MODE = "off" - base_dir = settings.BASE_DIR + TCP_SERVER_MODE = 'off' apk_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') - adb = getADB() + adb = get_adb() # Change to check output of subprocess when analysis is done # Can't RCE - os.system(adb + ' -s ' + get_identifier() + - ' logcat -d dalvikvm:W ActivityManager:I > "' + apk_dir + 'logcat.txt"') - logger.info("Downloading Logcat logs") - adb_command(["pull", "/data/data/de.robv.android.xposed.installer/log/error.log", - apk_dir + "x_logcat.txt"]) - - logger.info("Downloading Droidmon API Monitor Logcat logs") + cmd = ('{} -s {} logcat -d dalvikvm:' + 'W ActivityManager:I > "{}logact.txt"').format( + adb, + get_identifier(), + apk_dir) + os.system(cmd) + logger.info('Downloading Logcat logs') + xposed_out = ('/data/data/' + 'de.robv.android.xposed.installer' + '/log/error.log') + adb_command(['pull', + xposed_out, + apk_dir + 'x_logcat.txt']) + logger.info('Downloading Droidmon API Monitor Logcat logs') # Can't RCE - os.system(adb + ' -s ' + get_identifier() + - ' shell dumpsys > "' + apk_dir + 'dump.txt"') - logger.info("Downloading Dumpsys logs") + cmd = '{} -s {} shell dumpsys > "{}dump.txt"'.format( + adb, + get_identifier(), + apk_dir) + os.system(cmd) + logger.info('Downloading Dumpsys logs') - adb_command(["am", "force-stop", package], True) - logger.info("Stopping Application") + adb_command(['am', 'force-stop', package], True) + logger.info('Stopping Application') adb_command( - ["am", "force-stop", "opensecurity.screencast"], True) - logger.info("Stopping ScreenCast Service") + ['am', 'force-stop', 'opensecurity.screencast'], True) + logger.info('Stopping ScreenCast Service') data = {'final': 'yes'} - return HttpResponse(json.dumps(data), content_type='application/json') + return HttpResponse(json.dumps(data), + content_type='application/json') else: - return print_n_send_error_response(request, "Invalid Scan Hash", True) + return print_n_send_error_response(request, + 'Invalid Scan Hash', + True) else: - return print_n_send_error_response(request, "Only POST allowed", True) - except: - PrintException("Data Collection & Clean Up") - return print_n_send_error_response(request, "Data Collection & Clean Up failed", True) + return print_n_send_error_response(request, + 'Only POST allowed', + True) + except Exception: + err = 'Data Collection & Clean Up failed' + log_exception(err) + return print_n_send_error_response(request, + err, + True) # AJAX def dump_data(request): - """Downloading Application Data from Device""" - logger.info("Downloading Application Data from Device") + """Downloading Application Data from Device.""" + logger.info('Downloading Application Data from Device') try: if request.method == 'POST': data = {} package = request.POST['pkg'] md5_hash = request.POST['md5'] if re.match('^[0-9a-f]{32}$', md5_hash): - if re.findall(r";|\$\(|\|\||&&", package): - return print_n_send_error_response(request, "Possible RCE Attack", True) - base_dir = settings.BASE_DIR + if re.findall(r';|\$\(|\|\||&&', package): + return print_n_send_error_response(request, + 'Possible RCE Attack', + True) apk_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') # Let's try to close Proxy a bit early as we don't have much # control on the order of thread execution stop_capfuzz(settings.PORT) - logger.info("Deleting Dump Status File") - adb_command(["rm", "/sdcard/mobsec_status"], True) - logger.info("Creating TAR of Application Files.") - adb_command(["am", "startservice", "-a", package, - "opensecurity.ajin.datapusher/.GetPackageLocation"], True) - logger.info("Waiting for TAR dump to complete...") - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": + logger.info('Deleting Dump Status File') + adb_command(['rm', '/sdcard/mobsec_status'], True) + logger.info('Creating TAR of Application Files.') + dp = 'opensecurity.ajin.datapusher/.GetPackageLocation' + adb_command(['am', + 'startservice', + '-a', + package, + dp], True) + logger.info('Waiting for TAR dump to complete...') + if settings.ANDROID_DYNAMIC_ANALYZER == 'MobSF_REAL_DEVICE': timeout = settings.DEVICE_TIMEOUT else: timeout = settings.VM_TIMEOUT start_time = time.time() while True: current_time = time.time() - if b"MOBSEC-TAR-CREATED" in adb_command(["cat", "/sdcard/mobsec_status"], shell=True): + out = adb_command( + ['cat', '/sdcard/mobsec_status'], shell=True) + if b'MOBSEC-TAR-CREATED' in out: break if (current_time - start_time) > timeout: logger.error( - "TAR Generation Failed. Process timed out.") + 'TAR Generation Failed. Process timed out.') break - logger.info("Dumping Application Files from Device/VM") - adb_command(["pull", "/data/local/" + package + - ".tar", apk_dir + package + ".tar"]) - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": - logger.info("Removing package") - adb_command(["uninstall", package]) - stop_avd() - logger.info("Stopping ADB") - adb_command(["kill-server"]) + logger.info('Dumping Application Files from Device/VM') + adb_command(['pull', + '/data/local/' + package + '.tar', + apk_dir + package + '.tar']) + logger.info('Stopping ADB') + adb_command(['kill-server']) data = {'dump': 'yes'} - return HttpResponse(json.dumps(data), content_type='application/json') + return HttpResponse(json.dumps(data), + content_type='application/json') else: - return print_n_send_error_response(request, "Invalid Scan Hash", True) + return print_n_send_error_response(request, + 'Invalid Scan Hash', + True) else: - return print_n_send_error_response(request, "Only POST allowed", True) - except: - PrintException("Downloading Application Data from Device") - return print_n_send_error_response(request, "Application Data Dump from Device failed", True) + return print_n_send_error_response(request, + 'Only POST allowed', + True) + except Exception: + log_exception('Downloading Application Data from Device') + err = 'Application Data Dump from Device failed' + return print_n_send_error_response(request, + err, + True) # AJAX def exported_activity_tester(request): - """Exported Activity Tester""" - logger.info("Exported Activity Tester") + """Exported Activity Tester.""" + logger.info('Exported Activity Tester') try: md5_hash = request.POST['md5'] package = request.POST['pkg'] if re.match('^[0-9a-f]{32}$', md5_hash): - if re.findall(r";|\$\(|\|\||&&", package): - return print_n_send_error_response(request, "Possible RCE Attack", True) + if re.findall(r';|\$\(|\|\||&&', package): + return print_n_send_error_response(request, + 'Possible RCE Attack', + True) if request.method == 'POST': - base_dir = settings.BASE_DIR app_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') screen_dir = os.path.join(app_dir, 'screenshots-apk/') if not os.path.exists(screen_dir): os.makedirs(screen_dir) data = {} - adb = getADB() - static_android_db = StaticAnalyzerAndroid.objects.filter( MD5=md5_hash) if static_android_db.exists(): - logger.info("Fetching Exported Activity List from DB") + logger.info('Fetching Exported Activity List from DB') exported_act = python_list( static_android_db[0].EXPORTED_ACT) if exported_act: exp_act_no = 0 - logger.info("Starting Exported Activity Tester...") - logger.info("" + str(len(exported_act)) + - " Exported Activities Identified") + logger.info('Starting Exported Activity Tester...') + logger.info('%s Exported Activities Identified', + str(len(exported_act))) for line in exported_act: try: exp_act_no += 1 - logger.info("Launching Exported Activity - " + - str(exp_act_no) + ". " + line) - adb_command( - ["am", "start", "-n", package + "/" + line], True) - # AVD is much slower, it should get extra time - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": - wait(8) - else: - wait(4) - adb_command( - ["screencap", "-p", "/data/local/screen.png"], True) - #? get appended from Air :-() if activity names are used - adb_command(["pull", "/data/local/screen.png", - screen_dir + "expact-" + str(exp_act_no) + ".png"]) - logger.info("Activity Screenshot Taken") - adb_command( - ["am", "force-stop", package], True) - logger.info("Stopping App") - except: - PrintException( - "Exported Activity Tester") + expa = 'Launching Exported Activity' + logger.info('%s - %s. %s', + expa, + str(exp_act_no), + line) + adb_command(['am', + 'start', + '-n', + package + '/' + line], True) + wait(4) + adb_command(['screencap', + '-p', + '/data/local/screen.png'], True) + # ? get appended from Air :-() + # if activity names are used + outfile = '{}expact-{}.png'.format( + screen_dir, str(exp_act_no)) + adb_command(['pull', + '/data/local/screen.png', + outfile]) + logger.info('Activity Screenshot Taken') + adb_command(['am', + 'force-stop', + package], True) + logger.info('Stopping App') + except Exception: + log_exception( + 'Exported Activity Tester') data = {'expacttest': 'done'} else: logger.info( - "Exported Activity Tester - No Activity Found!") + 'Exported Activity Tester - No Activity Found!') data = {'expacttest': 'noact'} - return HttpResponse(json.dumps(data), content_type='application/json') + return HttpResponse(json.dumps(data), + content_type='application/json') else: - return print_n_send_error_response(request, "Entry does not exist in DB", True) + err = 'Entry does not exist in DB' + return print_n_send_error_response(request, + err, + True) else: - return print_n_send_error_response(request, "Only POST allowed", True) + return print_n_send_error_response(request, + 'Only POST allowed', + True) else: - return print_n_send_error_response(request, "Invalid Scan Hash", True) - except: - PrintException("ERROR] Exported Activity Tester") - return print_n_send_error_response(request, "Error Running Exported Activity Tests", True) + return print_n_send_error_response(request, + 'Invalid Scan Hash', + True) + except Exception: + err = 'Error Running Exported Activity Tests' + log_exception('ERROR] Exported Activity Tester') + return print_n_send_error_response(request, + err, + True) # AJAX def activity_tester(request): - """Activity Tester""" - logger.info("Activity Tester") + """Activity Tester.""" + logger.info('Activity Tester') try: md5_hash = request.POST['md5'] package = request.POST['pkg'] if re.match('^[0-9a-f]{32}$', md5_hash): - if re.findall(r";|\$\(|\|\||&&", package): - return print_n_send_error_response(request, "Possible RCE Attack", True) + if re.findall(r';|\$\(|\|\||&&', package): + return print_n_send_error_response(request, + 'Possible RCE Attack', + True) if request.method == 'POST': - base_dir = settings.BASE_DIR app_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') screen_dir = os.path.join(app_dir, 'screenshots-apk/') if not os.path.exists(screen_dir): os.makedirs(screen_dir) data = {} - adb = getADB() static_android_db = StaticAnalyzerAndroid.objects.filter( MD5=md5_hash) if static_android_db.exists(): - logger.info("Fetching Activity List from DB") + logger.info('Fetching Activity List from DB') activities = python_list(static_android_db[0].ACTIVITIES) if activities: act_no = 0 - logger.info("Starting Activity Tester...") - logger.info("" + str(len(activities)) + - " Activities Identified") + logger.info('Starting Activity Tester...') + logger.info('%s Activities Identified', + str(len(activities))) for line in activities: try: act_no += 1 - logger.info("Launching Activity - " + - str(act_no) + ". " + line) + logger.info( + 'Launching Activity - %s. %s', + str(act_no), + line) + adb_command(['am', + 'start', + '-n', + package + '/' + line], True) + wait(4) adb_command( - ["am", "start", "-n", package + "/" + line], True) - # AVD is much slower, it should get extra time - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": - wait(8) - else: - wait(4) + ['screencap', + '-p', + '/data/local/screen.png'], True) + # ? get appended from Air :-() + # if activity names are used + outfile = ('{}act-{}.png'.format( + screen_dir, + act_no)) + adb_command(['pull', + '/data/local/screen.png', + outfile]) + logger.info('Activity Screenshot Taken') adb_command( - ["screencap", "-p", "/data/local/screen.png"], True) - #? get appended from Air :-() if activity names are used - adb_command(["pull", "/data/local/screen.png", - screen_dir + "act-" + str(act_no) + ".png"]) - logger.info("Activity Screenshot Taken") - adb_command( - ["am", "force-stop", package], True) - logger.info("Stopping App") - except: - PrintException("Activity Tester") + ['am', 'force-stop', package], True) + logger.info('Stopping App') + except Exception: + log_exception('Activity Tester') data = {'acttest': 'done'} else: - logger.info("Activity Tester - No Activity Found!") + logger.info('Activity Tester - No Activity Found!') data = {'acttest': 'noact'} - return HttpResponse(json.dumps(data), content_type='application/json') + return HttpResponse(json.dumps(data), + content_type='application/json') else: - return print_n_send_error_response(request, "Entry does not exist in DB", True) + err = 'Entry does not exist in DB' + return print_n_send_error_response(request, + err, + True) else: - return print_n_send_error_response(request, "Only POST allowed", True) + return print_n_send_error_response(request, + 'Only POST allowed', + True) else: - return print_n_send_error_response(request, "Invalid Scan Hash", True) - except: - PrintException("Activity Tester") - return print_n_send_error_response(request, "Error Running Activity Tester", True) + return print_n_send_error_response(request, + 'Invalid Scan Hash', + True) + except Exception: + log_exception('Activity Tester') + return print_n_send_error_response(request, + 'Error Running Activity Tester', + True) def report(request): - """Dynamic Analysis Report Generation""" - logger.info("Dynamic Analysis Report Generation") + """Dynamic Analysis Report Generation.""" + logger.info('Dynamic Analysis Report Generation') try: if request.method == 'GET': md5_hash = request.GET['md5'] package = request.GET['pkg'] - if re.findall(r";|\$\(|\|\||&&", package): - return print_n_send_error_response(request, "Possible RCE Attack") + if re.findall(r';|\$\(|\|\||&&', package): + return print_n_send_error_response(request, + 'Possible RCE Attack') if re.match('^[0-9a-f]{32}$', md5_hash): app_dir = os.path.join( settings.UPLD_DIR, md5_hash + '/') # APP DIRECTORY @@ -659,27 +718,30 @@ def report(request): act = {} expact_imgs = [] exp_act = {} - if os.path.exists(os.path.join(download_dir, md5_hash + "-screenshots-apk/")): + if os.path.exists(os.path.join( + download_dir, + md5_hash + '-screenshots-apk/')): try: imp_path = os.path.join( - download_dir, md5_hash + "-screenshots-apk/") + download_dir, md5_hash + '-screenshots-apk/') for img in os.listdir(imp_path): - if img.endswith(".png"): - if img.startswith("act"): + if img.endswith('.png'): + if img.startswith('act'): act_imgs.append(img) - elif img.startswith("expact"): + elif img.startswith('expact'): expact_imgs.append(img) else: imgs.append(img) - static_android_db = StaticAnalyzerAndroid.objects.filter( + sadb = StaticAnalyzerAndroid.objects.filter( MD5=md5_hash) - if static_android_db.exists(): + if sadb.exists(): logger.info( - "\nFetching Exported Activity & Activity List from DB") + '\nFetching Exported Activity' + ' & Activity List from DB') exported_act = python_list( - static_android_db[0].EXPORTED_ACT) + sadb[0].EXPORTED_ACT) act_desc = python_list( - static_android_db[0].ACTIVITIES) + sadb[0].ACTIVITIES) if act_imgs: if len(act_imgs) == len(act_desc): act = dict(list(zip(act_imgs, act_desc))) @@ -688,82 +750,88 @@ def report(request): exp_act = dict( list(zip(expact_imgs, exported_act))) else: - logger.warning("Entry does not exists in the DB.") - except: - PrintException("Screenshot Sorting") + logger.warning('Entry does not exists in the DB.') + except Exception: + log_exception('Screenshot Sorting') context = {'md5': md5_hash, - 'emails': analysis_result["emails"], - 'urls': analysis_result["urls"], - 'domains': analysis_result["domains"], - 'clipboard': analysis_result["clipboard"], - 'http': analysis_result["web_data"], - 'xml': analysis_result["xmlfiles"], - 'sqlite': analysis_result["sqlite_db"], - 'others': analysis_result["other_files"], + 'emails': analysis_result['emails'], + 'urls': analysis_result['urls'], + 'domains': analysis_result['domains'], + 'clipboard': analysis_result['clipboard'], + 'http': analysis_result['web_data'], + 'xml': analysis_result['xmlfiles'], + 'sqlite': analysis_result['sqlite_db'], + 'others': analysis_result['other_files'], 'imgs': imgs, 'acttest': act, 'expacttest': exp_act, - 'net': api_analysis_result["api_net"], - 'base64': api_analysis_result["api_base64"], - 'crypto': api_analysis_result["api_crypto"], - 'fileio': api_analysis_result["api_fileio"], - 'binder': api_analysis_result["api_binder"], - 'divinfo': api_analysis_result["api_deviceinfo"], - 'cntval': api_analysis_result["api_cntvl"], - 'sms': api_analysis_result["api_sms"], - 'sysprop': api_analysis_result["api_sysprop"], - 'dexload': api_analysis_result["api_dexloader"], - 'reflect': api_analysis_result["api_reflect"], - 'sysman': api_analysis_result["api_acntmnger"], - 'process': api_analysis_result["api_cmd"], + 'net': api_analysis_result['api_net'], + 'base64': api_analysis_result['api_base64'], + 'crypto': api_analysis_result['api_crypto'], + 'fileio': api_analysis_result['api_fileio'], + 'binder': api_analysis_result['api_binder'], + 'divinfo': api_analysis_result['api_deviceinfo'], + 'cntval': api_analysis_result['api_cntvl'], + 'sms': api_analysis_result['api_sms'], + 'sysprop': api_analysis_result['api_sysprop'], + 'dexload': api_analysis_result['api_dexloader'], + 'reflect': api_analysis_result['api_reflect'], + 'sysman': api_analysis_result['api_acntmnger'], + 'process': api_analysis_result['api_cmd'], 'pkg': package, 'title': 'Dynamic Analysis'} - template = "dynamic_analysis/dynamic_analysis.html" + template = 'dynamic_analysis/dynamic_analysis.html' return render(request, template, context) else: - return print_n_send_error_response(request, "Invalid Scan Hash") + return print_n_send_error_response(request, + 'Invalid Scan Hash') else: - return print_n_send_error_response(request, "Only GET allowed") - except: - PrintException("Dynamic Analysis Report Generation") - return print_n_send_error_response(request, "Error Geneating Dynamic Analysis Report") + return print_n_send_error_response(request, + 'Only GET allowed') + except Exception: + log_exception('Dynamic Analysis Report Generation') + err = 'Error Geneating Dynamic Analysis Report' + return print_n_send_error_response(request, err) def handle_sqlite(sfile): - """SQLite Dump - Readable Text""" - logger.info("SQLite DB Extraction") + """Sqlite Dump - Readable Text.""" + logger.info('SQLite DB Extraction') try: data = '' con = sq.connect(sfile) cur = con.cursor() - cur.execute("SELECT name FROM sqlite_master WHERE type='table';") + cur.execute('SELECT name FROM sqlite_master WHERE type=\'table\';') tables = cur.fetchall() for table in tables: - data += "\nTABLE: " + table[0] + \ - " \n=====================================================\n" - cur.execute("PRAGMA table_info('%s')" % table) + data += ('\nTABLE: {}' + ' \n===============' + '===================' + '===================\n'.fomat(table[0])) + cur.execute('PRAGMA table_info(\'%s\')' % table) rows = cur.fetchall() head = '' for sq_row in rows: elm_data = sq_row[1] - head += elm_data + " | " - data += head + " \n============================================" + \ - "=========================\n" - cur.execute("SELECT * FROM '%s'" % table) + head += elm_data + ' | ' + data += ('{} \n================' + '============================' + '=========================\n'.format(head)) + cur.execute('SELECT * FROM \'%s\'' % table) rows = cur.fetchall() for sq_row in rows: dat = '' for each_row in sq_row: - dat += str(each_row) + " | " - data += dat + "\n" + dat += str(each_row) + ' | ' + data += dat + '\n' return data - except: - PrintException("SQLite DB Extraction") + except Exception: + log_exception('SQLite DB Extraction') def view(request): - """View File""" - logger.info("Viewing File") + """View File.""" + logger.info('Viewing File') try: typ = '' fil = '' @@ -773,14 +841,19 @@ def view(request): fil = request.GET['file'] md5_hash = request.GET['md5'] typ = request.GET['type'] - src = os.path.join(settings.UPLD_DIR, - md5_hash + '/DYNAMIC_DeviceData/') + src = os.path.join( + settings.UPLD_DIR, + md5_hash + '/DYNAMIC_DeviceData/') sfile = os.path.join(src, fil) # Prevent Directory Traversal Attacks - if ("../" in fil) or ("%2e%2e" in fil) or (".." in fil) or ("%252e" in fil): - return print_n_send_error_response(request, "Path Traversal Attack Detected") + if (('../' in fil) + or ('%2e%2e' in fil) + or ('..' in fil) + or ('%252e' in fil)): + err = 'Path Traversal Attack Detected' + return print_n_send_error_response(request, err) else: - with io.open(sfile, mode='r', encoding="utf8", errors="ignore") as flip: + with open(sfile, 'r') as flip: dat = flip.read() if (fil.endswith('.xml')) and (typ == 'xml'): rtyp = 'xml' @@ -790,63 +863,69 @@ def view(request): elif typ == 'others': rtyp = 'asciidoc' else: - return print_n_send_error_response(request, "File Type not supported") - context = {'title': escape(ntpath.basename(fil)), 'file': escape( - ntpath.basename(fil)), 'dat': dat, 'type': rtyp, } - template = "general/view.html" + err = 'File Type not supported' + return print_n_send_error_response(request, err) + context = {'title': escape(ntpath.basename(fil)), + 'file': escape(ntpath.basename(fil)), + 'dat': dat, + 'type': rtyp} + template = 'general/view.html' return render(request, template, context) else: - return print_n_send_error_response(request, "Invalid Scan Hash") - except: - PrintException("Viewing File") - return print_n_send_error_response(request, "ERROR Viewing File") + return print_n_send_error_response(request, 'Invalid Scan Hash') + except Exception: + log_exception('Viewing File') + return print_n_send_error_response(request, 'ERROR Viewing File') def capfuzz_start(request): - """Start CapFuzz UI""" - logger.info("Starting CapFuzz Web UI") + """Start CapFuzz UI.""" + logger.info('Starting CapFuzz Web UI') try: stop_capfuzz(settings.PORT) start_fuzz_ui(settings.PORT) time.sleep(3) - logger.info("CapFuzz UI Started") + logger.info('CapFuzz UI Started') if request.GET['project']: project = request.GET['project'] else: - project = "" - return HttpResponseRedirect('http://localhost:' + str(settings.PORT) + "/dashboard/" + project) - except: - PrintException("Starting CapFuzz Web UI") - return print_n_send_error_response(request, "Error Starting CapFuzz UI") + project = '' + url = ('http://localhost:{}' + '/dashboard/{}'.fomat( + str(settings.PORT), + project)) + return HttpResponseRedirect(url) + except Exception: + log_exception('Starting CapFuzz Web UI') + err = 'Error Starting CapFuzz UI' + return print_n_send_error_response(request, err) def screencast_service(): - """Start or Stop ScreenCast Services""" + """Start or Stop ScreenCast Services.""" global TCP_SERVER_MODE - logger.info("ScreenCast Service Status: " + TCP_SERVER_MODE) + logger.info('ScreenCast Service Status: %s', TCP_SERVER_MODE) try: screen_dir = settings.SCREEN_DIR if not os.path.exists(screen_dir): os.makedirs(screen_dir) screen_socket = socket.socket() - if TCP_SERVER_MODE == "on": + if TCP_SERVER_MODE == 'on': screen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": - addr = ('127.0.0.1', settings.SCREEN_PORT) - else: - addr = (settings.SCREEN_IP, settings.SCREEN_PORT) + addr = (settings.SCREEN_IP, settings.SCREEN_PORT) screen_socket.bind(addr) screen_socket.listen(10) - while TCP_SERVER_MODE == "on": + while TCP_SERVER_MODE == 'on': screens, address = screen_socket.accept() - logger.info("Got Connection from: %s", address[0]) - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": + logger.info('Got Connection from: %s', address[0]) + if settings.ANDROID_DYNAMIC_ANALYZER == 'MobSF_REAL_DEVICE': ip_address = settings.DEVICE_IP else: ip_address = settings.VM_IP if address[0] in [ip_address, '127.0.0.1']: - # Very Basic Check to ensure that only MobSF VM/Device/Emulator + # Very Basic Check to ensure + # that only MobSF VM/Device/Emulator # is allowed to connect to MobSF ScreenCast Service. with open(screen_dir + 'screen.png', 'wb') as flip: while True: @@ -855,10 +934,12 @@ def screencast_service(): break flip.write(data) else: - logger.warning("\n[ATTACK] An unknown client :" + address[0] + " is trying " + - "to make a connection with MobSF ScreenCast Service!") - elif TCP_SERVER_MODE == "off": + logger.warning('\n[ATTACK] An unknown client' + ' :%s is trying ' + 'to make a connection with ' + 'MobSF ScreenCast Service!', address[0]) + elif TCP_SERVER_MODE == 'off': screen_socket.close() - except: + except Exception: screen_socket.close() - PrintException("ScreenCast Server") + log_exception('ScreenCast Server') diff --git a/DynamicAnalyzer/views/android/shared.py b/DynamicAnalyzer/views/android/shared.py index a1620287..ce94b6d5 100755 --- a/DynamicAnalyzer/views/android/shared.py +++ b/DynamicAnalyzer/views/android/shared.py @@ -1,66 +1,65 @@ -"""Shared Functions for Android Dynamic Analyzer""" # -*- coding: utf_8 -*- +"""Shared Functions for Android Dynamic Analyzer.""" +import logging import subprocess import time -import traceback -import logging + from django.conf import settings -from MobSF.utils import PrintException, getADB + +from MobSF.utils import get_adb, log_exception logger = logging.getLogger(__name__) def wait(sec): - """Wait in Seconds""" - logger.info("Waiting for " + str(sec) + " seconds...") + """Wait in Seconds.""" + logger.info('Waiting for %s seconds...', str(sec)) time.sleep(sec) def get_res(): - """Get Screen Resolution or Device or VM""" - logger.info("Getting Screen Resolution") + """Get Screen Resolution or Device or VM.""" + logger.info('Getting Screen Resolution') try: - adb = getADB() + adb = get_adb() resp = subprocess.check_output( - [adb, "-s", get_identifier(), "shell", "dumpsys", "window"]) - resp = resp.decode("utf-8").split("\n") - res = "" + [adb, '-s', get_identifier(), 'shell', 'dumpsys', 'window']) + resp = resp.decode('utf-8').split('\n') + res = '' for line in resp: - if "mUnrestrictedScreen" in line: + if 'mUnrestrictedScreen' in line: res = line break - res = res.split("(0,0)")[1] + res = res.split('(0,0)')[1] res = res.strip() - res = res.split("x") + res = res.split('x') if len(res) == 2: return res[0], res[1] # width, height - return "", "" - except: - PrintException("Getting Screen Resolution") - return "", "" + return '', '' + except Exception: + log_exception('Getting Screen Resolution') + return '', '' def get_identifier(): - """Get Device Type""" + """Get Device Type.""" try: - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": - return settings.DEVICE_IP + ":" + str(settings.DEVICE_ADB_PORT) - elif settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": - return 'emulator-' + str(settings.AVD_ADB_PORT) + if settings.ANDROID_DYNAMIC_ANALYZER == 'MobSF_REAL_DEVICE': + return settings.DEVICE_IP + ':' + str(settings.DEVICE_ADB_PORT) else: - return settings.VM_IP + ":" + str(settings.VM_ADB_PORT) - except: - PrintException( - "Getting ADB Connection Identifier for Device/VM") + return settings.VM_IP + ':' + str(settings.VM_ADB_PORT) + except Exception: + log_exception( + 'Getting ADB Connection Identifier for Device/VM') def adb_command(cmd_list, shell=False, silent=False): emulator = get_identifier() - adb = getADB() + adb = get_adb() args = [adb, - "-s", + '-s', emulator] if shell: args += ['shell'] @@ -69,55 +68,54 @@ def adb_command(cmd_list, shell=False, silent=False): try: result = subprocess.check_output(args) return result - except: + except Exception: if not silent: - PrintException("Running ADB Command") + log_exception('Running ADB Command') return None def connect(): - """Connect to VM/Device""" - logger.info("Connecting to VM/Device") - adb = getADB() - subprocess.call([adb, "kill-server"]) - subprocess.call([adb, "start-server"]) - logger.info("ADB Started") + """Connect to VM/Device.""" + logger.info('Connecting to VM/Device') + adb = get_adb() + subprocess.call([adb, 'kill-server']) + subprocess.call([adb, 'start-server']) + logger.info('ADB Started') wait(5) - logger.info("Connecting to VM/Device") - out = subprocess.check_output([adb, "connect", get_identifier()]) - if b"unable to connect" in out: - raise ValueError("ERROR Connecting to VM/Device. ", - out.decode("utf-8").replace("\n", "")) + logger.info('Connecting to VM/Device') + out = subprocess.check_output([adb, 'connect', get_identifier()]) + if b'unable to connect' in out: + raise ValueError('ERROR Connecting to VM/Device. ', + out.decode('utf-8').replace('\n', '')) try: - subprocess.call([adb, "-s", get_identifier(), "wait-for-device"]) - logger.info("Mounting") - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": - adb_command(["su", "-c", "mount", "-o", - "rw,remount,rw", "/system"], True) + subprocess.call([adb, '-s', get_identifier(), 'wait-for-device']) + logger.info('Mounting') + if settings.ANDROID_DYNAMIC_ANALYZER == 'MobSF_REAL_DEVICE': + adb_command(['su', '-c', 'mount', '-o', + 'rw,remount,rw', '/system'], True) else: - adb_command(["su", "-c", "mount", "-o", - "rw,remount,rw", "/system"], True) + adb_command(['su', '-c', 'mount', '-o', + 'rw,remount,rw', '/system'], True) # This may not work for VMs other than the default MobSF VM - adb_command(["mount", "-o", "rw,remount", "-t", "rfs", - "/dev/block/sda6", "/system"], True) - except: - PrintException("Connecting to VM/Device") + adb_command(['mount', '-o', 'rw,remount', '-t', 'rfs', + '/dev/block/sda6', '/system'], True) + except Exception: + log_exception('Connecting to VM/Device') def install_and_run(apk_path, package, launcher, is_activity): - """Install APK and Run it""" - logger.info("Starting App for Dynamic Analysis") + """Install APK and Run it.""" + logger.info('Starting App for Dynamic Analysis') try: - adb = getADB() - logger.info("Installing APK") - adb_command(["install", "-r", apk_path]) + logger.info('Installing APK') + adb_command(['install', '-r', apk_path]) if is_activity: - run_app = package + "/" + launcher - logger.info("Launching APK Main Activity") - adb_command(["am", "start", "-n", run_app], True) + run_app = package + '/' + launcher + logger.info('Launching APK Main Activity') + adb_command(['am', 'start', '-n', run_app], True) else: - logger.info("App Doesn't have a Main Activity") + logger.info('App Doesn\'t have a Main Activity') # Handle Service or Give Choice to Select in Future. - logger.info("Testing Environment is Ready!") - except: - PrintException("Starting App for Dynamic Analysis") + logger.info('Testing Environment is Ready!') + except Exception: + log_exception('Starting App for Dynamic Analysis') diff --git a/DynamicAnalyzer/views/android/virtualbox_vm.py b/DynamicAnalyzer/views/android/virtualbox_vm.py index a8f28e62..529c0ee3 100755 --- a/DynamicAnalyzer/views/android/virtualbox_vm.py +++ b/DynamicAnalyzer/views/android/virtualbox_vm.py @@ -1,31 +1,36 @@ -import time -import subprocess import logging -from MobSF.utils import PrintException +import subprocess +import time + from django.conf import settings + +from MobSF.utils import log_exception + logger = logging.getLogger(__name__) def refresh_vm(uuid, snapshot_uuid, vbox_exe): - """Refresh VirtualBox based VMs""" - logger.info("Refreshing MobSF VM") + """Refresh VirtualBox based VMs.""" + logger.info('Refreshing MobSF VM') try: if not vbox_exe: - logger.error("VirtualBox not found, Manually set VBOXMANAGE_BINARY in settings.py") + logger.error( + 'VirtualBox not found, Manually' + ' set VBOXMANAGE_BINARY in settings.py') # Close VM args = [vbox_exe, 'controlvm', uuid, 'poweroff'] subprocess.call(args) - logger.info("VM Closed") + logger.info('VM Closed') time.sleep(3) # Restore Snapshot args = [vbox_exe, 'snapshot', uuid, 'restore', snapshot_uuid] subprocess.call(args) - logger.info("VM Restore Snapshot") + logger.info('VM Restore Snapshot') # Start Fresh VM args = [vbox_exe, 'startvm', uuid] if settings.VBOX_HEADLESS: args += ['--type', 'headless'] subprocess.call(args) - logger.info("VM Starting") - except: - PrintException("Refreshing MobSF VM") + logger.info('VM Starting') + except Exception: + log_exception('Refreshing MobSF VM') diff --git a/MalwareAnalyzer/admin.py b/MalwareAnalyzer/admin.py index ea5d68b7..e69de29b 100755 --- a/MalwareAnalyzer/admin.py +++ b/MalwareAnalyzer/admin.py @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/MalwareAnalyzer/models.py b/MalwareAnalyzer/models.py index fd18c6ea..e69de29b 100755 --- a/MalwareAnalyzer/models.py +++ b/MalwareAnalyzer/models.py @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/MalwareAnalyzer/tests.py b/MalwareAnalyzer/tests.py index de8bdc00..e69de29b 100755 --- a/MalwareAnalyzer/tests.py +++ b/MalwareAnalyzer/tests.py @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/MalwareAnalyzer/trackersdb/exodus_trackers b/MalwareAnalyzer/trackersdb/exodus_trackers index 23f52c34..05d11f25 100644 --- a/MalwareAnalyzer/trackersdb/exodus_trackers +++ b/MalwareAnalyzer/trackersdb/exodus_trackers @@ -1 +1 @@ -{"trackers": {"1": {"description": "## Primary Location\r\nFrance (Paris) [Crunchbase, 01](https://www.crunchbase.com/organization/databerries)\r\n\r\n## Website\r\n[https://www.teemo.co](https://www.teemo.co)\r\n\r\n## About\r\nTeemo claims to run the \"World's first and biggest persistent geolocation targeting database\". They provide \"solutions\" for \"retail advertisers\" and \"app publishers\". [Teemo, 01](http://teemo.co). \r\n\r\n## Ownership\r\nTeemo\r\n\r\n## Documentation\r\nhttps://teemo.co/sdkguidelines/\r\n\r\n## Products and Services\r\n\r\n_Retail Advertisers - Real Life Targeting:_ \"We target your prospects based on the places they attend in real life with the geolocation of millions smartphones continuously.\" \r\n\r\n * Exclusive Teemo Data \r\n * SDK accurate collection \r\n * 10 to 15 meters accuracy \r\n * 100k+ points of Interest redefined \r\n * 1,170 billion + geolocation data points \r\n * World's Biggest Real Life Targeting DMP \r\n\r\nOffline measurement & insight: \r\n\r\nTeemo measures the exact number of people who visit your point of sale and give you insights on their habits. \r\n\r\n * 7-day attribution \r\n * Exhaustive data \r\n * Provenance of your customers \r\n * Customer loyalty index \r\n\r\n_App Publishers - We Monetize Your Geolocation Data:_ \"Our SDK: \r\n\r\n * Anonymous collection of IDFA and GAID \r\n * Data collection only \r\n * Only 25 KB \r\n\r\n### Methods\r\n\r\nTeemo utilizes geolocation collection through the Databerries (Teemo) SDK.\r\n\r\n## Privacy Policy\r\n\r\nTeemo states that even without a device identifier, such as Apple's IDFA, they can still identify users: \"without the IDFA, and only with the address and the place of work of a person, to find any French would take 5 seconds to a team of 20 people\", is it added in the article\" (French-English translation; see [L'Expansion, 01](https://lexpansion.lexpress.fr/high-tech/teemo-la-start-up-qui-traque-10-millions-de-francais-en-continu_1937638.html)). \r\n\r\n\"The Databerries / Teemo SDK collects location information, for example precise location using GPS, wireless networks, cell towers, and Wi-Fi access points. You must ensure that all applications that use the Databerries / Teemo SDK comply with all of the Google Play's developer requirements and Apple's App Store requirements (collectively, the **'Requirements'**) including obtaining appropriate consent to the collection of location information... Each application that uses the Databerries / Teemo SDK must (a) notify users of the application's use of location data for third-party advertising purposes via a custom notification window, and (b) provide user of the application the ability to consent or withhold consent through an 'Allow' / 'Don't Allow' option, 'Accept' / 'Don't Accept' option, or similarly-worded option... Each application that uses the Databerries / Teemo SDK must inform users of relevant data collection practices and choices available to them. Users of such applications must consent to the collection of location and device information and the sharing of such information with third parties such as Databerries / Teemo. Applications that use the Databerries / Teemo SDK must be provided with an accurate, current and complete privacy policy that:\r\n\r\na. is available prior to download (i.e. from all applicable app storefronts) and from within the settings of the app; \r\nb. is in compliance with all applicable laws and self-regulatory principles; \r\nc. clearly and truthfully describes what data is collected from the app, how such data is used, and the circumstances under which it is disclosed; \r\nd. discloses that location information and other user information will be shared with third parties for advertising purposes; and \r\ne. explains to users how to opt out of the collection of information about their precise location and how to opt out of the use of information about their app usage for interest-based advertising purposes through the settings available on their Android or iOS device.\" \r\n\r\nThe Databerries / Teemo SDK may not be used in apps designed for use by children below the age of 13 (or the age of consent where offered, if higher than 13) \"or be used to collect information from any user known to be under the age of 13 or under the age of consent where they reside\". [Teemo, 03](https://teemo.co/sdkguidelines) \r\n\r\n_Information Collected Automatically Through the Services:_\r\n\"In order to help advertisers reach their audiences and understand the effect of their advertising, we automatically collect certain information when you access mobile applications that incorporate the Services. This information does not identify you personally, but it does reflect information about the mobile applications you use, your location, and how you interact with our Services. This information includes:\r\n\r\n * Location Information: When you use mobile apps that integrate the Services, we may collect information about your precise location using various technologies, including GPS, wireless networks, cell towers, Wi-Fi access points, and other sensors, such as gyroscopes, accelerometers, compasses, and barometers. For information about how to opt out of the collection of certain location information, please see 'Your Choices' below. \r\n\r\n * Device Information: We collect information about your mobile device, including the advertising identifiers assigned to your device, IP address, device type, operating system, and mobile carrier. \r\n\r\n * Usage Data: We collect information about the mobile apps you use that integrate our Services, including the date and time your device accesses such apps.\" \r\n\r\n_Information Teemo Collects from Other Sources:_\r\n\r\nTeemo \"may also obtain information from other sources and combine that with information we collect through our Services. For example, we may collect information about you from third parties, including our business partners, other advertising companies, and publicly available sources.\"\r\n\r\n_Sharing of Information:_\r\n\r\nTeemo \"may share the information we collect as follows or as otherwise described in this Privacy Policy: \r\n\r\n * With vendors, consultants and other service providers who need access to such information to carry out work or perform services on our behalf; \r\n * In response to a request for information if we believe disclosure is in accordance with, or required by, any applicable law, rule, regulation or legal process; \r\n * If we believe your actions are inconsistent with our user agreements or policies, or to protect the rights, property or safety of Databerries or others; \r\n * In connection with, or during negotiations of, any merger, sale of company assets, financing or acquisition of all or a portion of our business by another company; \r\n * Between and among Databerries and any current or future parent, subsidiary and/or affiliated company; and \r\n * With your consent or at your direction.\" \r\n\r\nTeemo \"may also share aggregated or de-identified information, which cannot reasonably be used to identify you. For example, we may share de-identified information with the partners that use our technology about the users of their apps.\" \r\n\r\n_Your Choices:_ \r\n\r\n\"Location Tracking: You can stop the collection of precise location information by individual apps or by your device as a whole changing the preferences in the settings of your mobile device. \r\n\r\nOpting Out of Teemo Services: You can stop the collection of information from Teemo by opting out of our service. You can opt-out from our service either from our ads or by asking us by contacting us at privacy@teemo.co \r\n\r\nOpting Out of Personalized Ads: You may opt out of the use of information about your mobile app activities to serve ads that are targeted to your interests using the settings available on your mobile device. For information about how to opt out on your Android device, click here. For information about how to opt out on your iOS device, click [here](https://support.apple.com/en-us/HT202074). If you wish to opt out on multiple devices, you must repeat the process on each device where you wish to opt out\" [Teemo, 04](https://teemo.co/privacy)\"\r\n\r\n## Relationships\r\n_Customers:_ Volkswagon / MyMedia / Intersport / Havas / dentsu / OMD / WPP / Publics Groupe / Carrefour / Toys\"R\"Us / McDonald's / Ford / Decathlon / FNAC / Leclerc [Teemo, 01](http://teemo.co)\r\n\r\n## Details\r\n_Financial details:_ Teemo (then Databerries) \"raised $16m (?15m) in a Series A funding round led by new investor Index Ventures with support from existing investors ISAI and Mosaic Ventures and new individual investors Greg Coleman and Pascal Gauthier. The company will use the funds to launch its product in the US and double its workforce.\" [Go4Venture, 01](http://go4venture.com/hti/usd-16m-a-mar-2017-databerries) \r\n\r\n_Background and history:_ Formerly known as Databerries, Teemo \"reinvents offline marketing. Its mobile marketing solution combines user offline behavior understanding and algorithms to drive in-store sales. Its performance-based marketing solution delivers relevant, personalized ads that generate in-store sales it can measure. Co-founded in 2014 by Guillaume Charhon, Fran\u00e7ois Wyss and Benoit Grouchko, Teemo has 50 employees in Paris and New-York.\" [Teemo, 02](https://teemo.co/about) \r\n\r\n\"Founded in 2014, Databerries offers brick and mortar retailers a mobile marketing solution, refferred to as Real Life Targeting, that targets mobile users based on locations they have visited in the past and measures the impact of marketing campaigns on store visits. The solution allows retailers to target users who have visited their stores and those of their competitors. The company\u2019s technology collects geolocation and navigation data from mobile users and targets them with relevant and personalised ads. This allows retailers to generate store visits with a significantly lower cost per physical visit (CPV). Databerries enables retailers to count the cost per visit and therefore measure the impact of a campaign on point-of-sale traffic, offering retailers a solution that works for offline marketing while combining online advertising standards such as accurate targeting, personalisation, performance measurement and return on investment optimisation.\r\n\r\nHeadquartered in Paris, Databerries employs 40 people and plans to double its workforce by the end of 2017. Since its launch, the solution has generated more than one million in-store visits and supports more than 20 prestigious advertisers on a daily basis. It serves more than 100 brick and mortar retailers including Carrefour, Decathlon, FNAC, Leclerc, McDonald's (NYSE: MCD) and Volkswagen (ETR: VOW3).\r\n\r\nAccording to the company, offline retailers spend more than $100bn (\u20ac93.9bn) on advertising every year, relying largely on outdoor and other offline channels to increase store visits with limited ability to track the performance of their advertising campaigns. According to a report by MarketsandMarkets, the cross-platform and mobile advertising market is estimated to grow from $25.2bn (\u20ac23.7bn) in 2015 to $80.5bn (\u20ac75.6bn) by 2020, at a CAGR of 26.1%.\" [Go4Venture, 01](http://go4venture.com/hti/usd-16m-a-mar-2017-databerries)\r\n\r\n_Slogans:_ \r\n* \"Real-life Targeting, Offline Measurement\" \r\n* \"Reinventing offline marketing\"\r\n\r\n_Devices:_ Android (Google Android ID) and Apple (IDFA)\r\n\r\n## References\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/databerries](https://www.crunchbase.com/organization/databerries)\r\n* _Teemo, 01._ [http://teemo.co](http://teemo.co) \r\n* _Teemo, 02._ [https://teemo.co/about](https://teemo.co/about) \r\n* _Teemo, 03._ [https://teemo.co/sdkguidelines](https://teemo.co/sdkguidelines) \r\n* _Teemo, 04._ [https://teemo.co/privacy](https://teemo.co/privacy)\r\n\r\n## External Links\r\n* _Go4Venture, 01:_ [http://go4venture.com/hti/usd-16m-a-mar-2017-databerries](http://go4venture.com/hti/usd-16m-a-mar-2017-databerries) \r\n* _L'Expansion, 01:_ [https://lexpansion.lexpress.fr/high-tech/teemo-la-start-up-qui-traque-10-millions-de-francais-en-continu_1937638.html](https://lexpansion.lexpress.fr/high-tech/teemo-la-start-up-qui-traque-10-millions-de-francais-en-continu_1937638.html)", "id": 1, "code_signature": "com.databerries.|com.geolocstation.", "website": "https://www.teemo.co", "name": "Teemo", "network_signature": "databerries\\.com", "creation_date": "2017-09-24"}, "2": {"description": "## Primary Location\r\nFrance (Paris) [Crunchbase, 01](https://www.crunchbase.com/organization/fidzup)\r\n\r\n## Website\r\n[https://www.fidzup.com/en](https://www.fidzup.com/en)\r\n\r\n## About\r\nFidzup merges online and offline mobile marketing for retailers. Their services include fine-grained location tracking through mobile devices for advertising purposes [Fidzup, 02](https://www.fidzup.com/en/team).\r\n\r\n## Ownership\r\nFidzup\r\n\r\n## Documentation\r\nFidzup SDK not listed, other code available at https://github.com/Fidzup\r\n\r\n## Products and Services\r\nFidzup has two primary services:\r\n\r\n1. Drive to store campaign \r\n2. Retargeting campaign \r\n\r\nTheir service is designed to protect retailers for \"showcasing\" whereby consumers view products in retail stores and look for prices and promotions found elsewhere, especially online. \"Thus,\" Fidzup states, \"those consumers who move to a point of sale but do not buy represent a real 'blind spot' for the brand.\"\r\n\r\nGeofencing technologies make it possible to know precisely the location of the consumer and offer new possibilities to harness data for retailers in stores and leverage the same techniques available to retailers in the online space. This helps retailers:\r\n\r\n* Know when the consumer goes to the store, whether they shop or not\r\n* Target their communication with contextualized promotions, or additional services to better inform the consumer during its purchase process\" [Marketing-Professionnel.fr, 01](http://www.marketing-professionnel.fr/parole-expert/distribution-retail-geofencing-geolocalisation-indooor-201411.html) \r\n\r\nFidzup's technology also helps retailers generate in-store traffic through targeting \"specific mobile audiences in your catchment area having an affinity with your brand.\" \r\n\r\nFidzup's in-store tracking helps retailers retarget customers who physically visited their store, according to their in-store behavior. According to Fidzup, their \"Fidzup Retargeting currently manages to detect 40% of point-of-sale traffic, more than 80% of smartphones... Thanks to point-of-sale technologies, Fidzup Retargeting is able to measure the ROI of all the campaigns sent (store visit, download of the application, etc.) and to report to the company. This marketing tool is therefore much more effective than a classic advertising campaign, because it occurs at the psychological moment when the user considers the purchase and allows to finalize the sale it is done in store or on its m-commerce site\" [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip).\r\n\r\nFidzup's technology helps retailers target competitor prospects to \"Serve ads to customers and prospects of retail/brand competitors\" [Fidzup, 01](https://www.fidzup.com/en).\r\n\r\n_Advertised services for clients:_ \r\n\r\nStores: \r\n1. Encourage impulsive purchasing \r\n2. Direct customers to shelves where discontinued products are placed \r\n3. Boost the use of its mobile application \r\n\r\nShopping malls: \r\n1. Create an attraction in the mall. \r\n2. Promote the release of the mobile application. \r\n3. Attract users of the application to the various shops in the shopping mall (eg, with list of promotions). \r\n\r\nTrade fairs: \r\n1. Provide its exhibitors with a special tool to attract more visitors to their stands. \r\n2. Inform visitors effectively of exhibition conferences and other upcoming events. \r\n\r\nConcerts and museums: \r\nFidzup could allow each visitor to a museum to \"automatically receive information of a work or piece just by being close to it\". At a concert, \"it is possible to send the corresponding clip for the song played, or even send a survey to the crowd to let it choose the next title to be played\" [Fidzup v2, 03](https://web.archive.org/web/20171015030737/http://v2.fidzup.com/en//cas-dusage). \r\n\r\n_Scope:_ \r\nAccording to Viuz, Fidzup has \"more than 250 Fidboxes already installed, more than 5 million unique database clients and more than 150 million covered 'foot traffic'\" [Viuz, 01](https://viuz.com/2015/03/19/fidzup-trophee-espoir-lndr-2015-les-outils-du-web-pour-re-inventer-le-commerce-physique).\r\n\r\n## Privacy Policy\r\n_Data collection and identifiable information:_ Fidzup states it \"collects data from wifi-enabled smartphones. No personal information is ever collected by us. We don't know who you are, we don't have access to your contacts, your messages, etc.\"\r\n\r\n_Retention:_ Collected data \"are stored anonymously on our servers for 12 months.\"\r\n\r\n_Data Use:_ \"Collected data allows: \r\n\r\n1. To enhance your experience while you visit point of sales equipped with our technologies.\r\n2. To provide visitors\u2019 in\u00adstore behavior reports to our customers. Those reports contain point of sales visit trends, made of aggregated data. No personal or individual information is included.\r\n3. To personalize visitors mobile ads on smartphone applications they use.\r\nWe use anonymous visit data to provide a personalized experience on our partners smartphone applications. For example: after visiting a shop you could see a personalized banner for this particular shop instead of a generic one.\"\r\n\r\n_Opt-out:_ Fidzup states, \"The simplest way to prevent data collection from your Wifi is to disable your Wifi connection near places that use it. \r\n\r\nWe also provide a way to delete all data regarding your smartphone with our opt-out form\" [Fidzup, 04](https://www.fidzup.com/en/privacy).\r\n\r\nTheir opt-out form can be located at [https://www.fidzup.com/en/opt-out-en](https://www.fidzup.com/en/opt-out-en).\r\n\r\n## Relationships\r\n_Brands and retailers:_ Gemo / Timberland / Buffalo Grill / Grand Optical / Opel / Renault / Kl\u00e9pierre / Etam / Mercedes / Nissan [Fidzup, 01](https://www.fidzup.com/en) / Hammerson & Les Terrasses du Port shopping center / Vache Noire shopping center (in Arcueil) [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip) / KFC / BMW [BusinessWire, 01](http://www.businesswire.com/news/home/20161130005981/en/Fidzup-Performance-Marketing-Startup-Retailers-Raises-3.7) / Galeries Lafayette / Darty / ITF / La Halle / Peugeot / FDJ Cultura [Tech.eu, 01](http://tech.eu/brief/fidzup-raises-investment) / Kiabi / SNCF [L'Usine Digitale, 01](https://www.usine-digitale.fr/editorial/les-100-du-digital-retail-fidzup-pour-geolocaliser-ses-clients-grace-a-leur-smartphone-et-des-ultrasons.N348982) Paris Region Lab / Petit Poucet / scientipole / oseo / R\u00e9seau Entreprendre [Fidzup, 02](https://www.fidzup.com/en/team)\r\n\r\n_Supporters:_ Mobile Marketing Association France / Electronic Business Group / IAB France / Picom / La Nuit Des Rois [Fidzup, 01](https://www.fidzup.com/en) \r\n\r\n## Details\r\n_Financial details: \"Fidzup was founded in 2011 by two entrepreneurs sharing the same idea: to give a lift to traditional business through technological innovation\" [Fidzup, 02](https://www.fidzup.com/en/team). They raised $3,7 million with venture capitalists CapHorn Invest and Turenne Capital as well as existing investors CapDecisif Management via the FRCI (Fonds R\u00e9gional Co-investissement de la R\u00e9gion Ile de France) and Petit Poucet Participation, the press reported in November 2016 [BusinessWire, 01](http://www.businesswire.com/news/home/20161130005981/en/Fidzup-Performance-Marketing-Startup-Retailers-Raises-3.7); [Tech.eu, 01](http://tech.eu/brief/fidzup-raises-investment). \r\n\r\nFor Product pricing (from old website), see [Fidzup v2, 04](https://web.archive.org/web/20171015030915/http://v2.fidzup.com/en//nos-offres).\r\n\r\n_Awards:_ Fidzup won the 2015 \"Kings of Hope Prize\" [Viuz, 01](https://viuz.com/2015/03/19/fidzup-trophee-espoir-lndr-2015-les-outils-du-web-pour-re-inventer-le-commerce-physique).\r\n\r\n_Fidzup history and ideology:_ Fidzup is \"Aware of the opportunities coming from the use of smartphones in your stores, our teams develop microlocation technologies to help you to reach your goals. Continuous innovation and improvement help us to develop more and more relevant and quicker and quicker solutions to install for our customers\" [Fidzup, 02](https://www.fidzup.com/en/team). Their ambition is to \"Provide physical commerce with the tools that pure players now enjoy\". Where on the web professionals are able to identify a highly qualified target to better send them promotions, no solution existed for retailers to recover these prospects.\r\n\r\nSince its creation in 2011, Fidzup was working on an indoor presence detection technology. The idea was to offer retailers and shopping centers a light technology to deploy and without constraint of use for consumers. This is how Fidzup Microtargeting was created, a platform for sending interactive and location-based content on the mobile of visitors to points of sale. It is the explosion of Criteo, the French giant of online advertising retargeting, which pushed the Fidzup teams to pivot towards a similar solution, but to the brick & mortar business. Since the startup was already able to understand the behavior of consumers in points of sale.\r\n\r\nSpecifically, where Criteo is interested in the behavior of Internet users on e-commerce sites to retarget advertising on partner media pages, Fidzup is interested in the consumer shopper journey in physical stores to address contextualized advertising. on its mobile apps\" [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip). \r\n\r\n_Devices:_ Mobile (Android, Apple) / Fidbox\r\n\r\n_Slogans:_ \r\n\r\n* \"Online Offline: Performance mobile marketing for retailers\" [Fidzup, 01](https://www.fidzup.com/en)\r\n* \"An innovative technology for interior presence detection\" \r\n* \"A mailing platform for geolocalized interactive content\" [Fidzup v2, 01](http://archive.is/kUZGK) \r\n\r\n### Methods\r\nFidzup \"has developed 3 solutions to detect the presence of a consumer in stores: Fidzup Microtargeting, Fidzup Retargeting and Fidzup Analytics. These technologies, easily deployable, are based on the principle of indoor geolocation (operating by wifi, ultrasound or BLE) and broadcast interactive content on smartphone. Thus, Fidzup captures and reactivates the consumer or simple visitor, either directly at the point of sale, or when he leaves the sign\" [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip).\r\n\r\nBig Data / Predictive analytics / Programmatic / RTB \r\n\r\n_Consumer targeting:_ Geographical/store / Digital navigation (on devices) / Habits / Purchase intention \r\n\r\n\"The most accurate in-store tracking technology on the market. Measure your online campaigns ROI with adapted offline KPIs\" \r\n_Fidbox:_ \r\n * Works without any mobile app \r\n * 3 meters accuracy; 4 years of R&D, 2 patents registered \r\n * Autonomous in-store sensor [Fidzup, 01](https://www.fidzup.com/en)\r\n\r\nFidbox is \"compatible with 99.9% of smartphones\". Fidboxes \"capture an encrypted identification key, unique to mobile, that Fidzup Retargeting then found on the ad servers. These captured data will be processed to segment the audience of the target brand to address on AdExchanges. This process will thus make it possible to resort to an advertising retargeting by displaying a personalized banner, according to the offline consumption habits of the mobile user, when he / she consults a third-party application (games, news, sports, etc.).\" Fidzup's \"point-of-sale deployment is lightweight and does not require any particular mobile application.\" \r\n\r\n_Fidzup Retargeting:_ Fidzup's \"Totally innovative process allows the Terrasses du Port not to lose its consumers, increase its customer knowledge and optimize its media buying campaigns by addressing a qualified target. Fidzup Retargeting can also measure the visits of the consumer and know the generated downloads in a logic of measurement of the ROI of the carried out campaigns.\" \r\n\r\n_Fidzup Microtargeting:_ Fidzup's microtargeting is \"based on the principle of indoor geofencing and allows shopping centers & retailers to interact instantly with their customers via their smartphone at their points of sale.\" It \"relies on the use of a sound source to send data to a smartphone that will decode and process the received signal. More concretely, Fidzup broadcasts via point of sale via any audio source (speaker system broadcasting music, sound boxes, televisions, etc.) a signal inaudible to the human ear. This signal has the particularity of having a unique identifier corresponding to a specific location. The detection is done when the smartphone receives the signal and decodes it to know where the consumer is.\r\n\r\nFidzup Microtargeting then automatically triggers the sending of interactive and contextualized content on the mobile of the consumer according to his position. Discount coupons, targeted promotion on a product upon entry into the corresponding department, exceptional opening information, contests triggered as soon as they enter the store ... For example, a brand wishes to launch a promotion on its polos: \"1 polo bought, the 2nd to -50% \u00bbFor this, she will have the choice between sending the promotion on the mobile of the consumer as soon as it enters the store or the entrance of the department concerned by the promotion.\r\n\r\nThe consumer then receives relevant content, at the right place and at the best time on his smartphone. With Fidzup technology, the sales area is 'squared': either at the entrance of the store itself or within a specific radius, it is possible for each manager to choose the right place, where the visitor will receive interactive content. \r\n\r\n...Unlike other solutions that require the deployment of a heavy hardware device, and therefore expensive to install and maintain, the technology developed by Fidzup can be deployed without any hardware installation on site if the audio system used is remotely controllable. Indeed, some companies have specialized in the implementation of audio systems, the distribution of music in point of sale can be controlled online. These players cover a majority of the retail and retail market. If, however, the customer is not equipped, Fidzup has developed a battery of inexpensive hardware solutions that are easy to install.\r\n\r\n- Mobile Compatibility: The software brick developed by Fidzup (the SDK) integrates with applications running on iOS mobile OS (iPhone) and Android. Thus, thanks to Fidzup technology it is possible to reach more than 90% of the global mobile market.\r\n\r\n- Use: In the face of the few players capable of detecting presence at the point of sale, Fidzup chose to specialize in consumer care once it is present. Thus, the startup has developed the lightest solution to send promotional content at the best time to maximize efficiency. The end customer has no action to do (except to download the application of the sign or the mall), it is the content that comes to him automatically and at a time when he will be attentive. Since the media is mobile, it is essential to offer end users a limited number of actions to perform for a simple and fluid use.\" \r\n\r\nThis can result in real-time data mining: \"Since the operations implemented are mainly digital, La Vache Noire has the possibility to follow in real time the impact of its operation (participation rate, winning prizes, etc.).\" This can bring businesses that did not previously data mine into the data mining fold: \"Finally, the marketing department of the center has retained a certain interest from brands that have never participated so much in a digital transaction. Thus, prestigious brands such as Celio, Jules, Yves Rocher or Darjeeling participate each week in the operation 'List of promotions'\" [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip).\r\n\r\n\"Fidzup has developed a means of communication between a sonic emitter and a mobile phone. Thus, by diffusing a tone, inaubible to the human ear, inside a building we can detect the presence of mobile phones and therefore their owners. How does the detection work? Your visitors must have the mobile application already installed on their smartphone. This contains a software layer (a SDK supplied by Fidzup) capable of detecting the signals and decoding them. What kind of sonic emitter can be used? It is possible to use any audio source to diffuse the signals. In fact, Fidzup has come up with a variety of hardware solutions depending on the user\u2019s requirements. \r\n\r\n... We supply you with one or several bespoke sonic signals to diffuse in your establishment. Depending on the type of building and the type of usage you require, Fidzup offers a choice of several hardware and software solutions to simplify and optimize the diffusion of its sonic technology. Depending on the method of emission chosen, a sonic signal can be used to cover a precise zone of a store, the corridors of a shopping mall or even detect a visitor admiring a work of art in an art exhibition.\" \r\n\r\n... \"Installing the SDK into your mobile application: We supply you with a software layer (SDK) to add to your mobile application. this layer detects and decodes the audio signal. The SDK is supplied with full documentation to help you install it swiftly and easily into your mobile application.The SDK is compatible with both iOS (iPhone) and Android operating systems. Minimum requirement for the iOS operating system: iOS version 5; Minimum requirement for the Android operating system: Android 2.3.5 (HTC One X not supported)\" [Fidzup v2, 02](https://web.archive.org/web/20171015025307/http://v2.fidzup.com/en//notre-solution).\r\n\r\n_Fidzup Analytics:_ \"Fidzup Analytics is a technology based on wifi that analyzes the traffic in points of sale, especially for shopping centers and supermarkets. Coupled with the Fidzup Retargeting solution, this technology makes it possible to capture on average 40% of the real traffic, whether the consumers / visitors are carriers of the application of the center or not.\r\n\r\nTo facilitate the handling of its solution, Fidzup gives direct access to the Analytics interface to the shopping center teams. The management can then see the route taken by its visitors from one store to another and analyze the data retrieved by day, week or month. Thus, Fidzup Analytics is able to display the traffic generated in the point of sale, the average duration of a visit, its frequency and to couple all these data to highlight trends or peaks of affluence. For the management of the center, the interest of these crossings of data is of size: to be able to identify the typical course of a customer and thus to define the zones \"cold\" or \"hot\" of the shopping mall (that is to say to say the locations more or less visited). Thanks to Fidzup Analytics, retail professionals can have a perfect knowledge of their customers, their habits in the center, but also know if their rental spaces are properly valued according to the passage of visitors. Finally, with the Analytics solution, shopping centers now have the opportunity to measure the audience generated by their communication devices already in place (promotional video screen, POS, display, totem ...). Indeed, depending on the information provided on these media, Fidzup is able to know the impact on the shopping journey of the customer and sales\" [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip).\r\n\r\n\"Fidzup\u2019s Programmatic & Analytics Platform is made up of DSP, DMP and Tag management solutions, developed in-house for bricks-and-mortar stores. These technologies enable store managers to direct their campaigns while accurately measuring their return on investment\" [BusinessWire, 01](http://www.businesswire.com/news/home/20161130005981/en/Fidzup-Performance-Marketing-Startup-Retailers-Raises-3.7).\r\n\r\nSonice emission solutions: \r\n\r\n- Web player: The web player allows you to emit the Fidzup sonic signal via your computer. This solution is ideal for small spaces with no audio system in place. \r\n- Standalone emitter unit: This mains connected unit allows you to broadcast your sound signal continuously in the manner of a portable and independent speaker enclosure. This solution is ideal for creating an interactive zone in a specific area of your establishment. \r\n- Mixer emitter unit: The mixer unit, also mains connected, can automatically mix your signal sound with the music played through your audio system. This solution is ideal for users wishing to cover all areas of their establishment through their own public address system. \r\n- Custom installation: Your audio system is managed by an external provider? No problem, Fidzup can work with them to simplify the deployment, as it could then be managed remotely, without any hardware installation in situ\" [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip). \r\n\r\n_Web interface:_ \"We give you secure access to an administrative interface that allows you to devise promotional content that will be displayed on visitors\u2019 smartphones as soon as they are detected in your establishment. Adjust the parameters and pre-visualize your content: expiry dates, target zones, message type, image uploads, content descriptions, etc., The interface is intuitive and extensive. From a discount coupon to a simple information bulletin, take advantage of the numerous pre- configured items in the interface to send the right content at the right time to your visitors. \r\n\r\n... Following promotional campaigns: Our administrator\u2019s inferface includes a comprehensive dashboard and accurate statistics that allow you to monitor the performance of your promotional campaigns.The number of detections in your location, number of messages sent and received, CTR (click- through rate)... View the impact of your advertising campaigns at a glance and optimize them swiftly\" [Fidzup v2, 02](https://web.archive.org/web/20171015025307/http://v2.fidzup.com/en//notre-solution). \r\n\r\n_Some of the data collected:_ \r\n\r\n* unique visitors\r\n* duration of visits\r\n* frequency of visits\r\n* hot / cold zone of the store\r\n* customer journey\r\n* fast outputs\r\n* volume of smartphones\r\n* brands and OS terminals [Viuz, 01](https://viuz.com/2015/03/19/fidzup-trophee-espoir-lndr-2015-les-outils-du-web-pour-re-inventer-le-commerce-physique)\r\n\r\n## References\r\n* _Ad-exchange.fr, 01._ http://ad-exchange.fr/fidzup-retargeting-unit-le-ciblage-publicitaire-sur-smartphone-et-le-monde-physique-14297._ http://ad-exchange.fr/fidzup-retargeting-unit-le-ciblage-publicitaire-sur-smartphone-et-le-monde-physique-14297\r\n* _Ad-exchange.fr, 02._ http://ad-exchange.fr/fidzup-veut-booster-ladoption-de-boitiers-du-type-beacon-dans-les-magasins-francais-27156._ http://ad-exchange.fr/fidzup-veut-booster-ladoption-de-boitiers-du-type-beacon-dans-les-magasins-francais-27156 \r\n* _BusinessWire, 01._ http://www.businesswire.com/news/home/20161130005981/en/Fidzup-Performance-Marketing-Startup-Retailers-Raises-3.7\r\n* _Crunchbase, 01._ https://www.crunchbase.com/organization/fidzup\r\n[Fidzup, 01._ https://web.archive.org/web/20171124095315/https://www.fidzup.com/en\r\n* _Fidzup, 02._ https://web.archive.org/web/20171124095424/https://www.fidzup.com/en/team \r\n* _Fidzup, 03, .zip file._ https://web.archive.org/web/20171124095525/http://www.fidzup.com/fidzup-2015.zip\r\n* _Fidzup, 04._ https://web.archive.org/web/20171124095616/https://www.fidzup.com/en/privacy\r\n* _Fidzup v2, 01._ http://archive.is/kUZGK\r\n* _Fidzup v2, 02._ https://web.archive.org/web/20171015025307/http://v2.fidzup.com/en//notre-solution \r\n[Fidzup v2, 03._ https://web.archive.org/web/20171015030737/http://v2.fidzup.com/en//cas-dusage\r\n* _Fidzup v2, 04._ https://web.archive.org/web/20171015030915/http://v2.fidzup.com/en//nos-offres\r\n[L'Usine Digitale, 01._ https://www.usine-digitale.fr/editorial/les-100-du-digital-retail-fidzup-pour-geolocaliser-ses-clients-grace-a-leur-smartphone-et-des-ultrasons.N348982\r\n* _Marketing-Professionnel.fr, 01._ http://www.marketing-professionnel.fr/parole-expert/distribution-retail-geofencing-geolocalisation-indooor-201411.html\r\n* _Tech.eu, 01._ http://tech.eu/brief/fidzup-raises-investment\r\n* _Viuz, 01._ https://viuz.com/2015/03/19/fidzup-trophee-espoir-lndr-2015-les-outils-du-web-pour-re-inventer-le-commerce-physique\r\n\r\n## External Links\r\n* _Crunchbase (Fidzup):_ https://www.crunchbase.com/organization/fidzup._ https://www.crunchbase.com/organization/fidzup\r\n* _Fidzup, 05:_ https://web.archive.o]rg/web/20171123081837/https://fidzup.com/en/live._ https://web.archive.org/web/20171123081837/https://fidzup.com/en/live\r\n* _Fidzup, 06:_ https://web.archive.org/web/20171124000206/https://fidzup.com/en/product._ https://web.archive.org/web/20171124000206/https://fidzup.com/en/product\r\n* _Fidzup, 07 https://web.archive.org/web/20171124094502/https://itunes.apple.com/us/app/fidzup-live/id735938167?mt=8._ https://web.archive.org/web/20171124094502/https://itunes.apple.com/us/app/fidzup-live/id735938167?mt=8\r\n* _Fidzup, 08:_ https://web.archive.org/web/20171124094519/https://play.google.com/store/apps/details?id=com.fidzup.fidzuplive._ https://web.archive.org/web/20171124094519/https://play.google.com/store/apps/details?id=com.fidzup.fidzuplive\r\n* _Fidzup, 09:_ https://web.archive.org/web/20171124094739/https://play.google.com/store/apps/details?id=com.fidzup.spotinstore.diagnostic._ https://web.archive.org/web/20171124094739/https://play.google.com/store/apps/details?id=com.fidzup.spotinstore.diagnostic\r\n* _Fidzup, 10:_ https://web.archive.org/web/20171124094810/https://play.google.com/store/apps/details?id=com.fidzup.petitpoucet._ https://web.archive.org/web/20171124094810/https://play.google.com/store/apps/details?id=com.fidzup.petitpoucet\r\n* _Fidzup, 11:_ https://web.archive.org/web/20171124094853/https://www.fidzup.com/en/use-case/._ https://web.archive.org/web/20171124094853/https://www.fidzup.com/en/use-case/\r\n* _Fidzup, 12:_ https://web.archive.org/web/20171124094955/https://vimeo.com/59666867._ https://web.archive.org/web/20171124094955/https://vimeo.com/59666867\r\n* _Fidzup, 13:_ https://web.archive.org/web/20171124095009/https://vimeo.com/80601084._ https://web.archive.org/web/20171124095009/https://vimeo.com/80601084", "id": 2, "code_signature": "com.fidzup.", "website": "https://www.fidzup.com", "name": "FidZup", "network_signature": "fidzup", "creation_date": "2017-09-24"}, "3": {"description": "## Primary Location\r\nUnited States (San Francisco) [Crunchbase, 01](https://www.crunchbase.com/organization/krux-digital)\r\n\r\n## Website\r\n[https://www.salesforce.com/products/marketing-cloud/data-management](https://www.salesforce.com/products/marketing-cloud/data-management)\r\n\r\n## About\r\nSalesforce DMP is a data management platform that manages data, identifies end users, and cetnralizes user-level data for advertising and content personalization [Salesforce, 24](https://konsole.zendesk.com/hc/en-us/articles/115012398067-What-if-I-just-want-to-import-data-instead-of-using-the-Control-Tag-SDK-or-other-DMP-tracking-)\r\n\r\n## Ownership\r\nSalesforce\r\n\r\n## Documentation\r\n[https://konsole.zendesk.com/hc/en-us/articles/226031268-Android-SDK-Implementation-Guide](https://konsole.zendesk.com/hc/en-us/articles/226031268-Android-SDK-Implementation-Guide)\r\n\r\n## Products and Services\r\n\r\nSalesforce DMP offers a vast array of technologies in its data management platform. These are detailed in the Techology section under Details, below.\r\n\r\nServices provided by Salesforce DMP include: \r\n\r\n* Accerlated Mobile Pages (facilitate mobile-optimized content)\r\n* Cross Device Identity Mangement (identify individuals across devices)\r\n* Salesforce DMP Einstein Segmentation (segment multiple personas in an audience)\r\n* Tracking (re-identify and track users using various methods)\r\n* Hashed device management (tracking used in reaction to Safari 3rd party blocking)\r\n* User matching (match users with various techniques to identify individuals)\r\n* Ad Server analytics (understand and analyze audience segment delivery and yield across all ad impressions)\r\n* Content engagement reports (loyalty report cards, site visits, and more)\r\n* Frequency engagement reports (how many times a user has seen an ad)\r\n* Funnels report (track customer behaviors across their customer journey)\r\n* Look-alike modeling (\r\n* Audience Profile Report (such as age, gender, and household income)\r\n\r\n## Privacy Policy\r\n**Opting out** \r\n_DMP Opt-Out_ \"DMP Opt-Out\r\nhttps://apiservices.krxd.net/consumer/optout is the standard DMP opt-out URL. When called directly, this URL will execute the Opt-out action for a user and it will return the following JSON response:\r\n\r\n{\"code\":\"success\"}\r\n\r\nA user must allow cookies from Salesforce DMP in order to opt-out. Calling the DMP opt-out code (by clicking on an opt-out button placed on the client's page) will result in a persistent 'cookie' placed in the user\u2019s web browser by Salesforce, identifying that user as being on the Salesforce DMP 'do not target' list. Taking this opt-out step won't prevent all tracking and targeting online, but it will ensure the user\u2019s wishes are honored by all Salesforce DMP clients.\r\n\r\nNote: If the user uses more than one computer, the process must be repeated for each one as this information is associated with a cookie unique to each machine.\" [Salesforce, 7](https://konsole.zendesk.com/hc/en-us/articles/217039187-Privacy-Policy-and-Opt-Out-Guide)\r\n\r\n_On Mobile:_ \"Users can reset their IDFA or AdID to receive a new one. This is comparable to deleting cookies.\r\n\r\nThey can also block these completely by opting-out of Ad Track or Ads Personalization. In that case, Salesforce DMP cannot track or target these users.\" [Salesforce, 3](https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ)\r\n\r\n_In Safari FAQ:_ \"Is there any difference in the how 1st-party cookies and Hashed Device IDs treat opt-outs?\r\nYes, if the client is utilizing a first-party cookie and has multiple domains, a dedicated opt-out will need to be configured and maintained for each site. Alternatively, if hashed device management is employed a single opt-out link will be applicable for a given client.\r\n\r\nCan users opt-out of Hashed ID tracking?\r\nAbsolutely \u2013 unlike other providers of so-called Fingerprinting techniques, the Salesforce DMP actually can manage fingerprinting users through an opt-out. \r\n\r\nDoes Fingerprinting adhere to PII rules?\r\nYes, our hashed device management solution is fully compliant with PII protocols.\r\n\r\nDo both approaches lose uses when they clear their cookies?\r\nNo, first-party cookies can be cleared, while the hashed ID will persist even if cookies are emptied. [Salesforce, 4](https://konsole.zendesk.com/hc/en-us/articles/115000428307-Safari-FAQ)\r\n\r\n\"Can users opt-out of tracking in Mobile Apps?\r\nUsers can reset their IDFA or AdID to receive a new one. This is comparable to deleting cookies.\r\n\r\nThey can also block these completely by opting-out of Ad Track or Ads Personalization. In that case, Salesforce DMP cannot track or target these users.\" [Salesforce, 58](https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ)\r\n\r\n**Personally Identifiable Information** \r\n\"Personally Identifiable Information (PII) includes any data that could potentially identify a specific individual and can be used for de-anonymizing data. Salesforce does not collect or store PII.\"\r\n\r\nSome examples of PII include: Full name; Email address; Phone numbers; Credit card numbers; Date of birth; Login/screen name; IP address is considered PII in some countries outside of the US; Home address; etc\" [Salesforce, 8](https://konsole.zendesk.com/hc/en-us/articles/115007222048-PII)\r\n\r\n**Data Privacy and Security Considerations**\r\n\r\nSalesforce DMP does not accept PII data and it is a breach of the MSA to send to us. Onboarding might be a better option if you have data connected to email addresses and are concerned with offline data import user matching. Usage and set up fees apply.\" [Salesforce, 32](https://konsole.zendesk.com/hc/en-us/articles/214918988-First-Party-Data-Import) \r\n\r\n**Data Retention** \r\n\"Data Expiry\r\n\r\nSalesforce DMP stores any data collected through online mechanisms (including user matching data) for a variable period as defined in the contractual agreement between Salesforce and the client. First-party imports remove any data not included in subsequent imports (full refresh). For best user match results, files should be uploaded frequently, or daily, even if the data output has no change.\" [Salesforce, 32](https://konsole.zendesk.com/hc/en-us/articles/214918988-First-Party-Data-Import) \r\n\r\n## Relationships\r\n_Data Onboarding:_\r\ncomScore / LiveRamp / Neustar [Salesforce, 9](https://konsole.zendesk.com/hc/en-us/articles/115010458727-Data-Onboarding-Partners)\r\n\r\n_Data Collection Partners:_\r\n\r\n* Off-Site Ad Servers:_ Conversant / DoubleClick Campaign Manager (DCM) / Flashtalking / Innovid / Medialets / Sizmek\r\n* On-Site Ad Servers:_ DoubleClick for Pulishers - DFP (Data Transfer Files)\r\n* Email Service Providers:_ SalesforceExactTarget\r\n* Data Management Platforms:_ Adobe Audience Manager / Oracle BlueKai DMP\r\n* Analytics & Measurement:_ Adobe Analytics (fkaOminture SiteCatalyst) / Brightcove / comScore Validated Campaign Essentials (vCE) / Google Analytics Standard / Kochava / MOAT / Tune [Salesforce, 10](https://konsole.zendesk.com/hc/en-us/articles/227144948-Data-Collection-Partners)\r\n\r\n**Data Activation Partners** \r\n\r\n_On-Site Ad Servers:_ Adition / Adswizz / AdTech / DoubleClick for Publishers - DFPAudience / DoubleClick for Publishers - DFP Key/Value Pairs / Freewheel / IPONWeb / LKQD / Nativo / OAS / OpenX / SAS/AIMatch / Smart Ad Server\r\n\r\n_On-Site SSP's:_ DoubleClick AdExchange - AdX (via DFP) / Index Exchange (Casale) / OpenX / Pubmatic / Rubicon / Sonobi / Sticky Ads / Tremor\r\n\r\n_Off-Site Ad Servers:_ Flashtalking / Flite / Innovid / Sizmek\r\n\r\n_Off-Site Data Activation:_ ActiveAgent AG / Adara / AdColony / AdForm / AdRoll / AdSquare / A.ki / Amazon Advertising / AOL ONE / AppNexus / Beeswax / Comscore / Criteo / DataXu / DoubleClick Bid Manager - DBM / Dstillery / Exponential / Facebook Custom Audiences / Google AdWords / Google RLSA / IgnitionOne / Infectious Media / InMobi / Instagram (via Facebook Custom Audiences) / Jivox / Lotame / Maxpoint / MediaMath / [m]Platform | GroupM / Netmining / Next Performance / OwnerIQ / Platform161 / Quantcast / RadiumOne / RocketFuel / Run / Simpli.fi / Specific Media (Viant) / SpotXchange / Teads / The Trade Desk / TimeOne / Tradelab / Termore Video / TubeMogul / Turn / Twitter - Tailored Audience / Undertone / VideoAmp / Videology / Yahoo! DataX (replaced RMX pipeline) / Yieldlab / Zebestof\r\n\r\n_Experience Management Systems & A/B Testing Platforms:_ AB Tasty / Acquia / Adobe Target / Maxymiser / Optimizely / Oracle Real-Time Decisions / Teradata Real - Time Interactions Manager / VWO\r\n\r\n_Assorted Data Outputs:_ Adobe Audience Manager / Moat / Oracle BlueKai DMP / Survata / YieldEx [Salesforce, 11](https://konsole.zendesk.com/hc/en-us/articles/226620988-Data-Activation-Partners)\r\n\r\n_Third-Party Data Marketplace:_ Acxiom / AffinityAnswers / ALC / Alliant / AnalyticsIQ / ASL / Audience Partners / AuDIGENT / B2B Targets / Bombora / Cardlytics / comScore / Connexity / Crossix / Cuebiq, Inc / Dataium / Dataline / Datamyx / DataLogix / Datonics / Digital Elements / Dun & Bradstreet / Epsilon / Ethnic Technologies / eXelate / Experian / Eyeota / Factual / Forbes / i360 / InfoGroup / IRI Worldwide / IXI Services/Equifax / Kantar Shopcom / L2 / LiveRamp Data Store / Mastercard Advisors / Maxpoint / MeritDirect / Mobiquity / GfK MRI / Gravy Analytics / #HOME by Vendigi / Navegg / NetWise Data / Neustar AdAdvisor / Nielsen / Nielsen Catalina Solutions (NCS) / NinthDecimal / PlaceIQ / PushSpring / Quantcast / SambaTV / ShareThis / Skydeo - Mobile AppAudiences / Skyhook / Specialists Marketing Services / Stirista / Tivo / TruSignal / Twine / Vertical Mass / Visual DNA / V12 / Webbula / Windfall [Salesforce, 12](https://konsole.zendesk.com/hc/en-us/articles/217592967-Third-Party-Data-Marketplace)\r\n\r\n## Details\r\n\r\n_Origins:_ Krux began as \"a platform for brands to collect all data from digital interactions across devices and use it to better understand their customers\" for better marketing. However, they \"knew that first-party data (customers\u2019 email addresses and purchase histories) was where the puck was headed, so we doubled down on it.\" They are driven by the concept \"people data\" because people, not browsers and mobile devices, are what buy things. [Salesforce, 1](https://www.salesforce.com/blog/2017/05/krux-is-now-salesforce-dmp.html)\r\n\r\n_Philosophy and approach:_ \"...when I am asked, what is the future of DMPs, I say that DMPs will become completely integrated into larger technology stacks offering a layer of data management (for both known and unknown data) for the \u201cright person.\u201d This orchestration layer consists of connected execution systems that seek to answer the \u201cright message, right time\u201d quandary. It also includes an artificial intelligence (AI) layer, which is the \u201cbrains\u201d of the operation trying determine how to stitch billions of individual data points together in real time.\" \"...marketing is much more than ad campaigns. It is every experience a customer has with the brand, and we empower marketers to use data to impact every touchpoint along that journey, all powered by AI.\" [Salesforce, 1](https://www.salesforce.com/blog/2017/05/krux-is-now-salesforce-dmp.html)\r\n\r\n\"Some of the core reasons to use a DMP are to manage Identity and centralize user-level data for advertising and content personalization. Additionally, the DMP includes insights that help inform targeting and personalization use cases as well as campaign and personalization optimization.\" [Salesforce, 24](https://konsole.zendesk.com/hc/en-us/articles/115012398067-What-if-I-just-want-to-import-data-instead-of-using-the-Control-Tag-SDK-or-other-DMP-tracking-)\r\n\r\n_Scope:_ \"Every month, Salesforce DMP interacts with more than 3 billion browsers and devices, supports more than 200 billion data collection events, processes more than 5 billion CRM records, and orchestrates more than 200 billion personalized consumer experiences.\" [Salesforce, 1](https://www.salesforce.com/blog/2017/05/krux-is-now-salesforce-dmp.html)\r\n\r\n\"The Salesforce Data Management Platform (DMP) allows publishers and marketers to collect and organize all of their consumer web data in one central \"big-data\" warehouse. Using Salesforce DMP, organizations can consolidate and reconcile their first-party \"web-behavior\" data that is generated by consumers as they engage with media and/or content with data from various third-party data providers like eXelate, DataLogix, Targus etc. Organizations can also integrate data from their user registration and subscription databases (hereon referred to as \u201cfirst-party data\u201d) into Salesforce DMP and join that data with web behavior and third-party data. \r\n\r\nUser data stored in Salesforce DMP is keyed off a global Krux User ID. The Krux User ID is a third-party cookie and as such is specific to a browser (and corresponding device too). All data that is collected by Salesforce DMP from online environments is automatically keyed off the Krux User ID.\r\n\r\nSalesforce DMP supports the ingestion of first-party data available in client systems like registration or subscription databases and other CRM systems. This data is keyed off the client\u2019s first-party User ID. A User Matching process that maps the client first-party User ID to the corresponding Krux User ID for every applicable user facilitates the onboarding and ingestion of this data. \r\n\r\nAfter the user matching process has been setup clients can send first-party data corresponding to the matched users. Salesforce DMP has a strict data format for the first-party data outlined below.\" [Salesforce, 32](https://konsole.zendesk.com/hc/en-us/articles/214918988-First-Party-Data-Import)\r\n\r\n_Billing Clients:_ Clients are charged for impressions, and a maximum amount for a single impression is calculate: [Salesforce, 34](https://konsole.zendesk.com/hc/en-us/articles/115011719688-How-Data-Costs-are-Billed)\r\n\r\n### Technology\r\n\r\n**AMP for Mobile Tracking** \r\nAMP stands for \u2018Accelerated Mobile Pages\u2019 and is designed to facilitate mobile-optimized content. A notable aspect of the design is that it keeps 3rd party JavaScript out as much as possible to improve performance, however, there are AMP libraries available to provide additional rich content.\" \r\n\r\nSee AMP FAQ for more: [Salesforce, 56](https://konsole.zendesk.com/hc/en-us/articles/115000428507-AMP-FAQ)\r\n\r\n**Cross Device Identity Mangement (Declarative and Predictive)** \r\nPredictive DCIM costs an extra fee. \"The Predictive CDIM report describes all of the devices associated with people already in a given segment. It allows you to identify and map consumers and behavior patterns consistently across all devices, screens, and platforms.\"\r\n\r\n_Key features include_: \"Connects known and unknown devices (declared and predictive) / Create a CDIM segment directly from the report / Aggregate audiences and their data across devices / A choice of similarity levels allows you to consider the trade off between accuracy and scale\". _Key benefits include_: \"Improves reach, relevance, and inventory monetization / Increases your opportunity to sequence ads, at optimal frequency, for consistent messaging and experience across channels, throughout the journey / Delivers accurate analytics for segment profiles and campaign conversions?\r\n\r\n_Probablistic Matching:_ \r\n\"How does the probabilistic matching algorithm work?\r\n\r\nThe core of the model is designed to uncover the devices that stay together in various places over long periods of time. To do this effectively there are three important considerations - scale, training, and validation.\r\n\r\n* Scale - Because the success of the model is predicated on seeing lots of devices and how they move over time, it is essential to have massive reach into the device world. With one of the largest device footprints on the planet, Salesforce DMP has an advantageous position from which to deliver accurate results.\r\n* Training - Salesforce DMP uses deterministic data coming from authenticated events (logins, purchases, etc) to provide a truth set for training the algorithm.\r\n* Validation - From the deterministic data set, Salesforce DMP reserves some data to validate the efficacy of the model.\r\n\r\nBetween these three items we are able to continuously improve the accuracy of the predictions and deliver a better product.\r\n\r\nTo better understand the view of devices over time, consider a user's work and home movement. During the work day, all of the user's devices are likely to be tied to the same IP from work. However, colleagues are also tied to the same IP and in that single snapshot of time, it may be assumed the user and their colleagues are the same person.\r\n\r\nLooking at that same IP address at night, there is likely no activity, as everyone has left the office. When looking at the user's home IP at night, all of the devices that belong to that user and their family are tied to the same IP. That single snapshot might imply that the usr and their family are one \"person\".\r\n\r\n_Predicting with device composition:_ \"Device Composition: Salesforce DMP uses predictive cookie matching to fill in the gaps where cookies may not be present, such as mobile apps, Safari browser, ad blocking software, etc. However, because Google is looking for active audience cookies, the two systems use different logic around device composition. If your segment includes a high volume of non-stable cookies (mobile/Safari/cookie-less devices), that can impact the match rate.\" [Salesforce, 37](https://konsole.zendesk.com/hc/en-us/articles/115010886887-DFP-FAQ)\r\n\r\n\"Each user creates multiple Krux User IDs (KUIDS) - cookies in browsers as well as IDFAs or AdIDs for mobile apps. Once our cross devices algorithm identifies that two of these KUIDs belong to the same person, we increase the count of \"people\" by one and select one of the KUIDs to be the \"leading\" KUID. We call this the one the \"Uber ID\". \r\n\r\nThere are some rules in place to determine which of the KUIDs is elected the Uber ID. This evaluation can change from day to day. If the Uber ID KUID is not active for a couple of days, it loses it's status as Uber ID. In this special case, the Uber ID is removed from the segment population list and shown accordingly as \"deleted\". \r\n\r\nIt is mainly Safari users to contribute to these Uber ID changes, as on Safari each page impression created a unique new KUID.\" [Salesforce, 54](https://konsole.zendesk.com/hc/en-us/articles/115006652948-Segment-Processing-FAQ)\r\n\r\n**Salesforce DMP Einstein** \r\n\"Salesforce DMP Einstein Segmentation, which allows marketers to use machine learning to discover the multiple distinct personas that exist within their audience.\r\n\r\nUsing Einstein AI, on top of unified consumer data from both first and third-party sources, enables us to algorithmically determine the \u201cpersonas\u201d that best define a brand\u2019s audience. Now, companies can personalize marketing and reach each key persona with a message that is going to resonate, rather than blasting a one-size-fits-all retargeting message to everyone that happened to land on a particular webpage. For example, Conagra Brands has seen dramatic results by customizing the messages to different consumer personas for its Hunt\u2019s brand.\r\n\r\nThis is a great example of how our data management layer consisting of first, second, and third-party data can feed our growing AI layer to create tangible value for marketers\" [Salesforce, 1](https://www.salesforce.com/blog/2017/05/krux-is-now-salesforce-dmp.html)\"\r\n\r\n**Tracking** \r\n_Device strategies & KUIDs:_ \"We differentiate between Mobile Web and Mobile App. Mobile work works just like Desktop Web with KUIDs stored as 3rd Party cookies. This has all the benefits and limitations (e.g. Safari) Desktop Web has.\r\n\r\n_Reidentification:_ \"Can I reidentify users in Apps?\r\nYes, the IDFA or AdID stays constant. Users can be reidentified and targeted in Apps with these device IDs. User can reset this ID and receive a new one though. This is comparable to deleting cookies but not widely used.\" [Salesforce, 3](https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ)\r\n\r\n_Mobile Web & Mobile IDs:_ \"Can I connect Mobile Web and Mobile App users?\r\nNatively this is not possible. If the user logs in on Mobile Web and Mobile App using the same credentials, Salesforce DMP can store this login ID to both the Mobile Web cookie and the Mobile App device ID and such create a connection of the profiles. This is treated just like cross-device identification.\" [Salesforce, 3](https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ)\r\n\r\n_Tracking in Safari and 3rd party cookie subversion:_ Uses Hashed Device Management and 1st Party cookies (set by clients) to target Safari users, as well as a proprietary Hashed Device Identification; fingerprinting. **Salesforce can use Google PPID** if in conjunction with client and client shares Google cloud storage location. \r\n\r\nCan you user-match with 3rd-party data providers when utilizing a first-party cookie?\r\n\r\nClients will issue a 1st-party cookie to the Salesforce DMP, which we then take as our ID. Since it's not a 3rd party cookie \u2013 even though we are acting as an agent of our clients \u2013 it means that we are unable to sync those users with a 3rd party data provider unless the 3rd party fires a match pixel.\r\n [Salesforce, 4](https://konsole.zendesk.com/hc/en-us/articles/115000428307-Safari-FAQ)\r\n\r\n_CDIM & Hashing:_ \"What makes Salesforce's Hashed ID different from competitive offerings?\r\nThere are a few vendors outside of Salesforce who provide Hashed Device IDs, however, they do not couple it with a CDIM solution. This enables Salesforce to associate Safari activity within a larger, holistic set of that individual\u2019s data and utilize Safari activity within a larger conversion path.\r\n\r\nHow can you tell if other providers offering Hashed Device Management solutions are accurate or employing CDIM?\r\nIf or when you hear really high numbers of unique users (UUs) reported against Safari, it often means that they are not resolving the browser down to a single user; each page view counts as a UU in Safari if you don't have a CDIM solution.\" [Salesforce, 4](https://konsole.zendesk.com/hc/en-us/articles/115000428307-Safari-FAQ)\r\n\r\n\"Do users have a KUID in Mobile Devices?\r\nWe differentiate between Mobile Web and Mobile App. Mobile work works just like Desktop Web with KUIDs stored as 3rd Party cookies. This has all the benefits and limitations (e.g. Safari) Desktop Web has.\r\n\r\nMobile Apps cannot access cookies. They provide their device IDs IDFA (iOS) or AdID (Android) which are used by Salesforce DMP as unique identifiers instead of a Salesforce DMP cookie.\r\n\r\nCan I reidentify users in Apps?\r\nYes, the IDFA or AdID stays constant. Users can be reidentified and targeted in Apps with these device IDs. User can reset this ID and receive a new one though. This is comparable to deleting cookies but not widely used.\r\n\r\nCan I connect Mobile Web and Mobile App users?\r\nNatively this is not possible. If the user logs in on Mobile Web and Mobile App using the same credentials, Salesforce DMP can store this login ID to both the Mobile Web cookie and the Mobile App device ID and such create a connection of the profiles. This is treated just like cross-device identification.\" [Salesforce, 58](https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ)\r\n\r\n**Hashed Device Management (targeting Safari 3rd party blocking)** \r\nUsed for Safari because Safari has 3rd party blocking [Salesforce, 16](https://konsole.zendesk.com/hc/en-us/articles/115012183888-Hashed-Device-Management)\r\n\r\n\"The Salesforce DMP Hashed Device Management solution allows for targeting users on Safari browsers that block 3rd party cookies. Please open a ticket in the Help Portal if you would like to request Hashed Device Management.\" Details here: [Salesforce, 35](https://konsole.zendesk.com/hc/en-us/articles/115011230687-How-to-verify-Hashed-Device-Management)\r\n\r\n**User matching** \r\n_For a great guide on user matching, see:_ [Salesforce, 32](https://konsole.zendesk.com/hc/en-us/articles/214918988-First-Party-Data-Import)\r\n\r\nSalesforce and 3rd parties each use their own IDs, and match users by firing the _other_ party's pixel when their own pixel fires on a site. Match rate is the percentage of users of party A known by party B. SF DMP match rates exclude Safari and app IDs. Increased match rates create greater scale, and \"Greater audience scale creates more options for managing and optimizing campaign tactics such as segmentation, personalized messaging, frequency, omni channel journey, etc.\" Because of 3rd party blocking, **Safari users can typicaly not be matched to partners at all.** \r\n\r\n\"By default, we run user match pixels on client\u2019s websites through the Control Tag for all partners a client is working with. We fire it on all pages with a frequency cap of 3 times over a 24-hour period for a given user. This will ensure return users are matched, but will not overwhelm client\u2019s sites with unnecessary tag fires. We set the tag to fire \"immediately\" to make sure users are matched before leaving the page. \r\n\r\nIt will take up to 30 days for the match rate to reach its peak after a new user match pixel has been activated.\r\n\r\nUnlike first party data that is exclusively available to the client who owns it, user match tables are shared across all Salesforce DMP clients. This way, each client can benefit from the user match pixels being fired on other client\u2019s websites.\r\n\r\nSalesforce has one of the largest footprints in the industry, thus providing exceptionally high match rates. Match rates can vary from country to country though, depending on both Salesforce's and the partner\u2019s footprint in that market.\r\n\r\nIt is also possible for partners to fire the Salesforce DMP user match pixel across all their inventory to improve the match rate upon request.\" [Salesforce, 23](https://konsole.zendesk.com/hc/en-us/articles/115006072448-User-Matching-and-Match-Rates-FAQ)\r\n\r\nCritically, \"The Client User ID will have a one-to-many relationship with the Krux User ID in the User Match table. Note that in general, there may be multiple Krux User IDs mapped to a given Client User ID because the Krux User ID is browser specific whereas the Client User ID will be the same across multiple browsers (assuming that it is indeed a persistent user ID as opposed to a first-party cookie).\"\r\n\r\n\"For example, if there are 3 columns called Age Group, Gender, and Interest in the client\u2019s registration database that need to be imported into Salesforce DMP, then the following represents a valid data file that can be ingested by Salesforce DMP:\r\n\r\nUser1234^gender:male;age:18-24;interest:fishing\r\nUser2345^gender:female\r\nUser3456^age:35-44\r\nUser4567^gender:male;interest:fishing,boating\r\n\r\nWhen Salesforce DMP processes this file, we will create 3 attributes called Gender, Age, and Interest in the client\u2019s Salesforce DMP account. We will also automatically create the corresponding attribute values: male and female under gender and 18-24, 35-44 under age, and fishing and boating under interest.\r\n\r\nSalesforce DMP supports full-refresh.\" [Salesforce, 32](https://konsole.zendesk.com/hc/en-us/articles/214918988-First-Party-Data-Import)\r\n\r\nEvaluating matched users:\r\n\r\n\"Segment Population is the device population of this segment from the Manage Segments screen. This is a count of all devices that are part of the segment based on the segment's rules.\r\n\r\nMatchable population is the Segment Population minus those devices that cannot be matched to a partner. This includes Safari cookies, as per default Safari deleted all cookies after each page impression. A DSP Safari cookie will never show up again and thus can't be served ads to. Many DSPs also don't accept mobile identifiers (IDFA and AdID). So in those cases we also deduct them.\r\n\r\nSegment Match Rate is the percentage of users from the matchable population that we have matched the DSPs cookie against within the last 30 days. We only send these users as older users are not accepted by the DSPs.\r\n\r\nMore info on user matching can be found here:\r\nhttps://konsole.zendesk.com/hc/en-us/articles/115006072448-User-Matching-and-Match-Rates-FAQ\r\n\r\nCumulative population is the population we expect to see in DSP after all the previous considerations. In reality this can differ due to circumstances outside our control. E.g. Google only counts users that have been active in Google's universe on at least two different days for its population/forecasting. For full refresh connections the cumulative population is the population we send every day.\" [Salesforce, 48](https://konsole.zendesk.com/hc/en-us/articles/115009920168-Partner-Management-Additional-Account-Details-FAQ)\r\n\r\n**Ad Server analytics** \r\n\"Salesforce DMP's Yield Analytics reports allow you to understand and analyze audience segment delivery and yield across all ad impressions, irrespective of whether an ad was targeted to an audience segment or not. The \"raw\" ad impression delivery information is combined with the user audience segment map managed in the Salesforce DMP platform to produce these audience segment delivery and yield reports... The ad impression log file contains a record of every impression delivered, and each impression delivery record must contain the Krux User ID of the user who saw the ad. Note that it is not required for every delivery record to contain the Krux User ID; Salesforce DMP simply ignores the records that don't contain the Krux User ID, but the accuracy of the reports is directly proportional to the number of records that contain the Krux User ID\" [Salesforce, 30](https://konsole.zendesk.com/hc/en-us/articles/218445237-Ad-Server-Integration-for-Yield-Analytics).\r\n\r\n**Content Engagement Reports** \r\nReports allow site metrics like:\r\n\r\n* pageviews and unique visits for both segments and unique users; \r\n* Loyalty report cards (\" records the number of return visits per unique over a selected time period\"; will \"Monitor website engagement over time\"; and \"Highlights your total users (unique devices) per site, as well as return users to that site and the percentage of your total uniques that those return users represent\"); \r\n\r\n* Social Activity reports (\"describes all social sharing you have enabled through direct integration* with Facebook or Twitter\"; allows you to \"Build social influencer segments. These segments can be used to target users who are likely to share on social media: Capture Facebook Shares, Facebook Likes, Facebook Unlikes and Twitter Tweets\"; with features like \"Flexible date ranges\" and \"See the URLs of the top Facebook Likes and Twitter tweets; click-through to the original content\". (NOTE: \" third-party implementations, such as AddThis or ShareThis are not included.\")\r\n* Search keywords report: \"gives a list and population of referral keywords associated with inbound web traffic from top search engines including Google, Bing, and Yahoo\" so you can \"Build segments around search keywords; Identify valuable words to use for search campaigns to increase traffic to your site. This can help to identify good keywords for paid search campaigns; Capture site search terms and link them to your site as a data source\". This \"Lists the source, keyword, and population of referrals over the last thirty days, and is filterable by site and section\" and \"Site results are processed weekly, and all recorded keywords are available in the Segment Builder [Salesforce, 38](https://konsole.zendesk.com/hc/en-us/articles/115010860288-Content-Engagement-Report-FAQ)\r\n\r\n**Frequency Reports** \r\n\"Frequency Reports describe how many times what percentage of your audience has seen your ad. This allows you to assess how to improve conversion. Very high frequency is typically a sign of waste, and as such, a source of cost-saving. Very low frequency can suggest the audience isn\u2019t seeing the campaign enough to spur conversion, in which case it too is wasteful.\" The goal is to have the right amount of exposure for efficient conversions. [Salesforce, 39](https://konsole.zendesk.com/hc/en-us/articles/115010860128-Frequency-Report-FAQ)\r\n\r\n**Funnels Report** \r\n\"The Funnels report tracks the sequence of events on customers\u2019 paths to conversion and allows you to optimize accordingly. Use Funnels to understand at what stage in the conversion process users drop off, then target those users to encourage them to finish their purchase, registration, etc.\r\n\r\nBenefits:\r\n\r\n* Allows you to track individual user actions in a purchase process (or other conversion)\r\n* Monitor conversion success, perform A/B testing, and learn more about converted users with funnel reports based on events and event attributes\" [Salesforce, 40](https://konsole.zendesk.com/hc/en-us/articles/115010690407-Funnels-FAQ)\r\n\r\n**Lookalike Modeling** \r\n\"Lookalike Modeling applies an algorithm to a base audience segment and finds new people with features and characteristics similar to those in the base audience. Similarity and reach metrics will allow you to find the most useful lookalike with the highest similarity at the reach level required.\r\n\r\nBenefits:\r\n\r\n* Find prospects for acquisition campaigns\r\n* Expand reach by finding lookalikes among known users\"\r\n\r\n\"Uses 1st and 3rd party data for modelling\" [Salesforce, 41](https://konsole.zendesk.com/hc/en-us/articles/115010859928-Lookalike-Modeling-FAQ)\r\n\r\n**Audience Profile Report** \r\n\"The Audience Profile report shows demographic information about a specific campaign or segment and the segments with the greatest number of unique impressions.\"\r\n\r\nBenefits:\r\n\r\n* Learn which demographics your segments or campaigns fall into and export to share with clients or colleagues\r\n* Top overlapping segments will show how similar or unique your segments are\r\n\r\nFeatures:\r\n\r\n* The gender, age, and household income profile of your users is determined using information from third-party data providers\" [Salesforce, 44](https://konsole.zendesk.com/hc/en-us/articles/115010859168-Audience-Profile-Report-FAQ)\r\n\r\n\"Does the Loyalty report use devices or people?\r\n\r\nDevices; People are only displayed in the Segment dashboard.\" Safari users are not included because Safari doesn't allow 3rd party cookies. [Salesforce, 52](https://konsole.zendesk.com/hc/en-us/articles/115007354408-Salesforce-DMP-Reporting-FAQ)\r\n\r\n## References and External Links\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/krux-digital](https://www.crunchbase.com/organization/krux-digital)\r\n* _Salesforce, 01._ https://www.salesforce.com/blog/2017/05/krux-is-now-salesforce-dmp.html\r\n* _Salesforce, 02._ https://konsole.zendesk.com/hc/en-us/articles/115000451248-Salesforce-DMP-SDK-FAQ\r\n* _Salesforce, 03._ https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ\r\n* _Salesforce, 04._ https://konsole.zendesk.com/hc/en-us/articles/115000428307-Safari-FAQ\r\n* _Salesforce, 05._ https://secure.sfdcstatic.com/assets/pdf/misc/BCRPublicFAQ.pdf\r\n* _Salesforce, 06._ https://www.salesforce.com/company/privacy/full_privacy.jsp\r\n* _Salesforce, 07._ https://konsole.zendesk.com/hc/en-us/articles/217039187-Privacy-Policy-and-Opt-Out-Guide\r\n* _Salesforce, 08._ https://konsole.zendesk.com/hc/en-us/articles/115007222048-PII\r\n* _Salesforce, 09._ https://konsole.zendesk.com/hc/en-us/articles/115010458727-Data-Onboarding-Partners\r\n* _Salesforce, 10._ https://konsole.zendesk.com/hc/en-us/articles/227144948-Data-Collection-Partners\r\n* _Salesforce, 11._ https://konsole.zendesk.com/hc/en-us/articles/226620988-Data-Activation-Partners\r\n* _Salesforce, 12._ https://konsole.zendesk.com/hc/en-us/articles/217592967-Third-Party-Data-Marketplace\r\n* _Salesforce, 13._ https://konsole.zendesk.com/hc/en-us/articles/115012227268-Data-Sentry-Iris-Video-Tutorial\r\n* _Salesforce, 14._ https://konsole.zendesk.com/hc/en-us/articles/115010652267-Data-Sentry-IRIS-FAQ\r\n* _Salesforce, 15._ https://konsole.zendesk.com/hc/en-us/articles/115010652267-Data-Sentry-IRIS-FAQ\r\n* _Salesforce, 16._ https://konsole.zendesk.com/hc/en-us/articles/115012183888-Hashed-Device-Management\r\n* _Salesforce, 17._ https://konsole.zendesk.com/hc/en-us/articles/115010825168-Media-Tag-Generator-Video-Overview\r\n* _Salesforce, 18._ https://konsole.zendesk.com/hc/en-us/articles/115008240047-How-to-Create-Bulk-Segments\r\n* _Salesforce, 19._ https://konsole.zendesk.com/hc/en-us/articles/115007996507-Events-Overview\r\n* _Salesforce, 20._ https://konsole.zendesk.com/hc/en-us/articles/115005914227-How-to-Create-Platform-Segments-in-Salesforce-DMP\r\n* _Salesforce, 21._ https://konsole.zendesk.com/hc/en-us/articles/225407808-How-to-set-up-the-Salesforce-DMP-ControlTag-Helper\r\n* _Salesforce, 22._ https://konsole.zendesk.com/hc/en-us/articles/218941948-How-to-validate-a-Video-Ad-Unit-on-Video-Suite-Inspector-using-HTTP-Fox\r\n* _Salesforce, 23._ https://konsole.zendesk.com/hc/en-us/articles/115006072448-User-Matching-and-Match-Rates-FAQ\r\n* _Salesforce, 24._ https://konsole.zendesk.com/hc/en-us/articles/115012398067-What-if-I-just-want-to-import-data-instead-of-using-the-Control-Tag-SDK-or-other-DMP-tracking-\r\n* _Salesforce, 25._ https://konsole.zendesk.com/hc/en-us/articles/115012555408-What-does-the-Control-Tag-do-\r\n* _Salesforce, 26._ https://konsole.zendesk.com/hc/en-us/articles/115012367627-Will-the-DMP-Control-Tag-Impact-Page-Load-Performance-\r\n* _Salesforce, 27._ https://konsole.zendesk.com/hc/en-us/articles/115009397188-Cross-Device-Identity-Management-CDIM-FAQ-\r\n* _Salesforce, 28._ https://konsole.zendesk.com/hc/en-us/articles/226951307-How-to-Build-Segments-with-CDIM\r\n* _Salesforce, 29._ https://konsole.zendesk.com/hc/en-us/articles/226951307-How-to-Build-Segments-with-CDIM\r\n* _Salesforce, 30._ https://konsole.zendesk.com/hc/en-us/articles/218445237-Ad-Server-Integration-for-Yield-Analytics\r\n* _Salesforce, 31._ https://konsole.zendesk.com/hc/en-us/articles/115002783508-Data-Transfer-File-2-0-Import\r\n* _Salesforce, 32._ https://konsole.zendesk.com/hc/en-us/articles/214918988-First-Party-Data-Import\r\n* _Salesforce, 33._ https://konsole.zendesk.com/hc/en-us/articles/115012221127-Browser-Support\r\n* _Salesforce, 34._ https://konsole.zendesk.com/hc/en-us/articles/115011719688-How-Data-Costs-are-Billed\r\n* _Salesforce, 35._ https://konsole.zendesk.com/hc/en-us/articles/115011230687-How-to-verify-Hashed-Device-Management\r\n* _Salesforce, 36._ https://konsole.zendesk.com/hc/en-us/articles/115010886887-DFP-FAQ\r\n* _Salesforce, 37._ https://konsole.zendesk.com/hc/en-us/articles/115010886887-DFP-FAQ\r\n* _Salesforce, 38._ https://konsole.zendesk.com/hc/en-us/articles/115010860288-Content-Engagement-Report-FAQ\r\n* _Salesforce, 39._ https://konsole.zendesk.com/hc/en-us/articles/115010860128-Frequency-Report-FAQ\r\n* _Salesforce, 40._ https://konsole.zendesk.com/hc/en-us/articles/115010690407-Funnels-FAQ\r\n* _Salesforce, 41._ https://konsole.zendesk.com/hc/en-us/articles/115010859928-Lookalike-Modeling-FAQ\r\n* _Salesforce, 42._ https://konsole.zendesk.com/hc/en-us/articles/115010859228-Site-Distribution-Report-FAQ\r\n* _Salesforce, 43._ https://konsole.zendesk.com/hc/en-us/articles/115010859208-Segment-Overlap-Report-FAQ\r\n* _Salesforce, 44._ https://konsole.zendesk.com/hc/en-us/articles/115010859168-Audience-Profile-Report-FAQ\r\n* _Salesforce, 45._ https://konsole.zendesk.com/hc/en-us/articles/115010689407-Segment-Summary-FAQ\r\n* _Salesforce, 46._ https://konsole.zendesk.com/hc/en-us/articles/115010518787--Data-Studio-FAQ\r\n* _Salesforce, 47._ https://konsole.zendesk.com/hc/en-us/articles/115010365788-Why-are-top-segments-different-in-Audience-Profile-Reports-\r\n* _Salesforce, 48._ https://konsole.zendesk.com/hc/en-us/articles/115009920168-Partner-Management-Additional-Account-Details-FAQ\r\n* _Salesforce, 49._ https://konsole.zendesk.com/hc/en-us/articles/115009293927-Over-the-top-OTT-FAQ\r\n* _Salesforce, 50._ https://konsole.zendesk.com/hc/en-us/articles/115009151507-Media-Tagging-FAQ\r\n* _Salesforce, 51._ https://konsole.zendesk.com/hc/en-us/articles/115007393368-Data-Collection-FAQ\r\n* _Salesforce, 52._ https://konsole.zendesk.com/hc/en-us/articles/115007354408-Salesforce-DMP-Reporting-FAQ\r\n* _Salesforce, 53._ https://konsole.zendesk.com/hc/en-us/articles/115006780068-Real-time-Segment-FAQ\r\n* _Salesforce, 54._ https://konsole.zendesk.com/hc/en-us/articles/115006652948-Segment-Processing-FAQ\r\n* _Salesforce, 55._ https://konsole.zendesk.com/hc/en-us/articles/115002018607-UTM-Parameters-FAQ <-- in FP glossary only\r\n* _Salesforce, 56._ https://konsole.zendesk.com/hc/en-us/articles/115000428507-AMP-FAQ\r\n* _Salesforce, 57._ https://konsole.zendesk.com/hc/en-us/articles/115000428427-Data-Layer-FAQ\r\n* _Salesforce, 58._ https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ\r\n* _Salesforce, 59._ https://konsole.zendesk.com/hc/en-us/articles/236268468-Reach-Opportunities-Index-Calculation-Chart-Operations\r\n* _Salesforce, 60._ https://konsole.zendesk.com/hc/en-us/articles/227951188-Klever-UI-People-and-Devices\r\n* _Salesforce, 61._ https://konsole.zendesk.com/hc/en-us/articles/228024867-SuperTag-FAQ", "id": 3, "code_signature": "com.krux.androidsdk", "website": "https://www.salesforce.com/products/marketing-cloud/data-management", "name": "Krux", "network_signature": "krxd\\.net", "creation_date": "2017-09-24"}, "4": {"description": "## Primary Location\r\nFrance (Paris). [Crunchbase, 01](https://www.crunchbase.com/organization/ad4screen)\r\n\r\n## Website\r\n[http://www.ad4screen.com](http://www.ad4screen.com)\r\n\r\n## About\r\nAd4Screen is \"a marketing and advertising pioneer on Mobile Net (Smartphones, Tablets...)\". They help companies \"to set up performant Mobile advertising campaigns and to increase App User engagement, retention and conversion.\" [Ad4Screen, 02](http://www.ad4screen.com/en/presentation)\r\n\r\n## Ownership\r\nAd4Screen\r\n\r\n## Documentation\r\nVia Accengage [https://docs.accengage.com/display/AND/Integration](https://docs.accengage.com/display/AND/Integration)\r\n\r\n## Products and Services\r\n\r\nAd4Screen advises clients on \"the best possible strategy to limit your risks and we manage, for you, the establishment and management of your campaigns from A to Z!\" (translated from French) [Ad4Screen, 03](http://www.ad4screen.com/publicite-mobile).\r\n\r\n### Products and Services for Mobile Advertising\r\nBranding Campaign / Promote Mobile Sites / Promote Mobile Apps / Mobile RTB / Mobile Tracking / App Store Optimization / Event Driven Strategy (Drive In-Store) [Ad4Screen, 01](http://www.ad4screen.com/en), [Ad4Screen, 02](http://www.ad4screen.com/en/presentation) \r\n\r\n_Branding Campaigns:_ \"The best sites & APPS available; Many available targeting criteria\u2019s (socio-demographics\u2026); Geo-target campaigns; Thematic packages (CSP+, Media, Finance, Sports...); Innovative formats (interstial ads, rich media, videos\u2026) \r\n\r\n_Promoting Mobile Sites:_ \"Thanks to Mobile advertising key results, Ad4Screen enables you to harness the power of your brand, generate more traffic, leads (CPL) and sales on your Mobile Sites and Tablets. Often the gap between click and real visits might be significantly important. With the objective to maximize performance, Ad4Screen guarantees an effective Cost Per Visit (CPV).\" \r\n\r\nDisplay / Rich Media / Videos: \"Our Ad Hoc Experts select the best formats, supports, publishers and Ad-Exchanges in the marketplace in order to efficiently enhance the key advantages and offers of your Mobile Sites and Tablets.\" \r\n\r\nFacebook & Twitter campaigns: \"Our teams are Experts in setting up specific mobile campaigns on Facebook and Twitter. Share high visibility and drive a Performance Business Model forward! Many available targeting criteria specific for Mobile and for each specific plateform. Ensure an Ongoing Performance\" \r\n\r\n_Promote Mobile Apps:_ \"Thanks to Mobile advertising, Ad4Screen helps you to enhance your brand reputation, gain in-depth visibility and increase your volume of APP downloads. Ad4Screen\u2019s specific business goal lies on the guarantee to capture a growing share of Cost Per Download (CPD).\" Display / Videos: \"Our Experts select the market\u2019s best set of formats, supports and well known players in the market in order to empower your Mobile APP or Tablet, whether iOS or Android. \r\n \r\n * Traditional formats: banners, interstitials\r\n * Banners, interstitials HTML5 \r\n * Interstitials videos \r\n * Pre-roll videos \r\n * Geolocalisation \r\n * Native Formats (referring to Facebook, Viadeo, Twitter). \r\n\r\nFacebook & Twitter App install campaigns: \"Our teams are Experts on monitoring Facebook and Twitter campaigns on Mobile. (Mobile Ad Formats exclusively designed to install; Share high exposure and drive a Performance Model forward; Many targeting & optimization criteria; Possibility to track APP installs). Search: \"All Queries made on Google from Smartphones and Tablets are explode! It is today\u2019s business imperative to benefit from Search Query Data to obtain high quality users. Our Operations Team is in charge of your Mobile Adwords campaigns from beginning to end. \r\n\r\n * Buy with CPC \r\n * Double Click Download \r\n * Track In-APP conversion with keywords \r\n\r\n_Mobile RTB Insights:_ \"Our Media Buying & Planning team uses the best next generation Mobile technologies (DSP) in order to program Mobile RTB campaigns. We work with the main 100% Mobile Ad-Exchanges in the market (MoPub, Flurry, Smaato, La Place M\u00e9dia\u2026). \r\n\r\n * Gain wide access to apps ad inventory (80% ad impressions & non available on Web AdEx) \r\n * Use conversion tracking to see in-app activity \r\n * Leverage intelligent algorithms in real time based on in-app conversion \r\n * Communicating to the best with digital savvy shoppers \r\n * Identify your look-alike best prospects \r\n * Invite your Mobile Site Visitors to download your APP\") \r\n\r\n_Mobile Tracking:_ \"Our main concern is to accurately follow conversion on mobile acquisition campaigns to overall revenue. Our ad hoc experts group has the know-how for the best acquisitions and tracking plateforms in the right private marketplaces. \r\n\r\n * Track where your users come from (lever, design, adWord...) \r\n * Analyse and compare specific conversion rates per sources, operating systems, countries, segments\u2026 \r\n * Track how your users interact with your app \r\n * Improve overall ROI by our Experts \r\n\r\n_App Store Optimization:_ \"Benefit from our Trends Report to optimize your organic SEO on App Store.\" \r\n\r\n * Optimize your ranking on Google Play and iTunes \r\n * Improve your APP Ranking in your own category \r\n * Create strong viral effects (Earned media) \r\n * Generate an increase on your organic installs from 10% to 40% per day!\" \r\n\r\n_Event Driven Strategy:_ \"For today\u2019s consumer, Mobile has become the ultimate Digital Shopping Tool. Ad4Screen Operations Team helps you generate more Drive In-Store traffic and positively impact on sales conversion.\r\nWe use the most pertinent Marketing Drive In-Store Tools: \r\n\r\n * Mobile Retargeting\r\n * Push Notification\r\n * GeoTargeted Mobile Advertising\r\n * iBeacon, Geofencing, QR Code...\r\n\r\nAd4Screen implements contest specific rules:\r\n\r\n * Instant Win Games\r\n * Sweepstake\r\n * In-APP & Mobile Web animations [Ad4Screen, 05](http://www.ad4screen.com/en/mobile-advertising)\r\n\r\n### Products and Services for Mobile CRM\r\nPush Notifications / Customer Loyalty Programs (Relationship Programs) / Mobile Retargeting / Email Responsive (Responsive Email Templates) / Mobile Couponing (Mobile Email Tag) / Passbook [Ad4Screen, 01](http://www.ad4screen.com/en), [Ad4Screen, 02](http://www.ad4screen.com/en/presentation)\r\n\r\n_Support:_ Sales Team / Advisory Board / Mobile CRM Experts / Media Buying & Planning / IT Team / Data Mining Team / Support Team \r\n\r\n_Sales Team:_ \"We analyze with you all your requirements and needs to create adapted and breakthrough projects maximizing your ROI.\" \r\n\r\n_Advisory Board:_ \"The Advisory Services Team covers App Store SEO, ROI Optimization, International Acquisition Campaigns Management\u2026\" \r\n\r\n_Mobile CRM Experts:_ \"Our team of experts will support you with setting up Customer Loyalty Programs.\" \r\n\r\n_Media Buying & Planning_: \"We will identify the best traffic sources, getting the best price (CPC, CPL, CPV, CPD...).\" \r\n\r\n_IT Team:_ \"We choose next generation Mobile Marketing technologies, at the cutting-edge of innovation.\" \r\n\r\n_Data Mining Team:_ \"We manage the extraction, integration and analysis of large volumes of DATA to optimize your targeting.\" \r\n\r\n_Support Team:_ \"We are here to help you planning, implementing SDK, training, preserving, updating...\" [Ad4Screen, 02](http://www.ad4screen.com/en/presentation) \r\n\r\n* (translated from French:) \"Our Experts select the best formats, supports, boards and Ad-Exchanges of the market to effectively highlight the benefits and offers of your mobile site and / or tablet.\" [Ad4Screen, 03](http://www.ad4screen.com/publicite-mobile)\r\n\r\nAd4Screen also helps clients set up trigger marketing campaigns [Ad4Screen, 01](http://www.ad4screen.com/en).\r\n\r\n## Privacy Policy\r\nAd4Screen does not appear to list a privacy policy for End Users; see [Ad4Screen, 07](http://www.ad4screen.com/en/privacy-police).\r\n\r\n## Relationships\r\nAdd4Screen lists 200 customers and 5,000 mobile campaigns [Ad4Screen, 02](http://www.ad4screen.com/en/presentation)\r\n\r\n_\"They Trust Us\":_ Betclic / Bouyges Telecom / Europcar / SFR / numericable / ebookers / La Tribune / Le Figaro / Universal Music / Axa / Airfrance KLM / Danone / Saxo Banque / Capcom / Cadremploi.fr / nexity / pole emploi / Rocket Internet / Cond\u00e9 Nast / Nestle / vente-privee.com / Pages Jaunes / Groupe Casino / Voyages-sncf.com / The Walt Disney Company / Price Minister (Rakuten Group) / Club Med / Century 21 / TF1 / Monoprix / keljob.com / kobojo / Explorimmo / easyflirt / Le Monde / LA Tribune / La Redoute / Malakoff-M\u00e9d\u00e9ric / Le PointNathan / Radio France / Orange S.A. (ex France T\u00e9l\u00e9com S.A.) / P\u00f4le emploi (government agency for unemployed) [Ad4Screen, 02](http://www.ad4screen.com/en/presentation), [Ad4Screen, 05](http://www.ad4screen.com/en/mobile-advertising) OTC Agregator [Ad4Screen, 01](http://www.ad4screen.com/en), [Ad4Screen, 04](http://www.ad4screen.com/en/nos-references) \r\n\r\n_Mobile First Alliance:_ In 2014, Ad4Screen \"split its activities into two separate and independent companies\", Accengage and Ad4Screen. Accengage offers a Mobile CRM technology while Ad4Screen specializes in \"mobile media buying and mobile relationship marketing consulting\". The Mobile First Alliance was formed thereafter, composed of three companies: Accengage, Ad4Screen, and Relatia. (Quotes are translated from French.) [Marketing web mobile, 01](http://marketing-webmobile.fr/2014/09/ad4screen-separe-ses-activites-dediteur-de-logiciels-de-mobile-crm-et-dagence-de-publicite-mobile).\r\n\r\n## Details\r\n_Financial details:_ Ad4Screen was founded in 2010 and has raised $10 million [Ad4Screen, 02](http://www.ad4screen.com/en/presentation); [Crunchbase, 01](https://www.crunchbase.com/organization/ad4screen). They were crowdfunded by OTC Agregator, a big French Insurance Company (MMA) and Web contractors (Business Interactive Founders as WCube, Betclic, Boncoin or Poweo) [Ad4Screen, 02](http://www.ad4screen.com/en/presentation).\r\n\r\n_Devices:_ Mobile and tablet media; iOS and Android [Ad4Screen, 03](http://www.ad4screen.com/publicite-mobile); works with iBeacons [Ad4Screen, 07](http://www.ad4screen.com/ibeacon).\r\n\r\n### Methods\r\nRetargeting / Push Notifications / GeoTargeted Mobile Advertising / iBeacon, Geofencing, QR Code / Mobile tracking (including across apps) / Conversion tracking (including intelligent algorithms for in-app conversion) \r\n\r\n_Mobile Push Notification & In-app Message:_ \"Do you have a smartphone app? Benefit from push notification, the new and efficient communication channel to interact with your app visitors. Communicate in real time, by sending the right message, to the right person, at the right time toward the right place inside the app. Our CRM Mobile Experts help you build customer loyalty programs in order to create more proximity and engagement with your app users.\" \r\n\r\n_Customer Loyalty Programs:_ \"Ad4Screen enables you to set up a True Value added customer loyalty programs with your savvy shoppers to dialog with them at each touchpoint of their life cycle. \r\n\r\n * Set up trigger marketing scenarios (send fully automated follow-ups according to mobile user behavior)\" \r\n * Display a welcome message at first open \r\n * Send out alerq messages tbox messages in an application\u2019s life-cycle (last update, error messages, news feed\u2026) \r\n * Send out good deals to capture a growing share of revenue \r\n * Reactive abandoned shopping carts \r\n\r\n_Mobile Retargeting:_ \"2 retargeting methods roll into action to retarget your digital device users: \r\n\r\n * From opt-in to push notification, mobile users are identified by Ad4Screen as having abandoned their shopping cart and reminded via customized push notifications \r\n * No opt-in to push are retargeted in a display mode through targeted customized banners and interstitials \r\n\r\n_Responsive Email:_ \"Ad4Screen delivers a Customer Seamless Experience to read your newsletter on Smartphone by displaying the email according to the device used by the user. \r\n\r\nNet benefits with responsive email: \r\n\r\n * Email designed according to the screen size of the device \r\n * Make it easier to read and interact with your current and prospective customers \r\n * Optimize Click-Through-Rates (Click-to-Open Rates, Click Conversation Rates) \r\n * Yield a significant ROI \r\n\r\n_Mobile Email Tag:_ \"Discover belong your subscribers who read your newsletters from a smartphone and display them in real time a bespoke banner offering to download your app. \r\n\r\nNet benefits with Mobile Email Tag: \r\n\r\n * Redefine smartphone users to individual profile \r\n * Complete mobile user\u2019s status \r\n * Enrich profiles according to the device used \r\n * Drive more traffic and generate high quality installs! \r\n\r\n_Passbook:_ \"Thanks to Ad4Screen, discover Passbook and boost your in-store traffic. The application is able to stock reward cards, ad spend coupons and other tickets. With Passbook you can:\r\n\r\n * Dematerialize your loyalty reward cards, ad spend coupons, tickets\u2026 without the need to develop an app dedicate for it \r\n * Generate in-store traffic by sending a relevant message or a push based on user\u2019s location \r\n * Plan specific events and remind them the last discount day \r\n * Recommend to install your iPhone app [Ad4Screen, 06](http://www.ad4screen.com/en/push-notifications)\r\n\r\n## References\r\n* Ad4Screen, 01. [http://www.ad4screen.com/en](http://www.ad4screen.com/en) \r\n* Ad4Screen, 02. [http://www.ad4screen.com/en/presentation](http://www.ad4screen.com/en/presentation) \r\n* Ad4Screen, 03. [http://www.ad4screen.com/publicite-mobile](http://www.ad4screen.com/publicite-mobile) \r\n* Ad4Screen, 04. [http://www.ad4screen.com/en/nos-references](http://www.ad4screen.com/en/nos-references) \r\n* Ad4Screen, 05. [http://www.ad4screen.com/en/mobile-advertising](http://www.ad4screen.com/en/mobile-advertising) \r\n* Ad4Screen, 06. [http://www.ad4screen.com/en/push-notifications](http://www.ad4screen.com/en/push-notifications) \r\n* Ad4Screen, 07. [http://www.ad4screen.com/ibeacon](http://www.ad4screen.com/ibeacon)\r\n* Crunchbase, 01. [https://www.crunchbase.com/organization/ad4screen](https://www.crunchbase.com/organization/ad4screen) \r\n* Marketing Web Mobile, 01. [http://marketing-webmobile.fr/2014/09/ad4screen-separe-ses-activites-dediteur-de-logiciels-de-mobile-crm-et-dagence-de-publicite-mobile](http://marketing-webmobile.fr/2014/09/ad4screen-separe-ses-activites-dediteur-de-logiciels-de-mobile-crm-et-dagence-de-publicite-mobile)\r\n\r\n## External links\r\n* _Crunchbase (Ad4Screen)_: [https://www.crunchbase.com/organization/ad4screen](https://www.crunchbase.com/organization/ad4screen) \r\n* _AppBrain_: [https://www.appbrain.com/dev/AD4Screen/](https://archive.is/SgBjU)", "id": 4, "code_signature": "com.ad4screen.sdk", "website": "http://www.ad4screen.com", "name": "Ad4Screen", "network_signature": "a4\\.tl|accengage\\.com|ad4screen\\.com|ad4push\\.com", "creation_date": "2017-09-24"}, "5": {"description": "## Primary Location\r\nUnited States (New York City) [Crunchbase, 01](https://www.crunchbase.com/organization/doubleclick)\r\n\r\n## Website\r\n[https://www.doubleclickbygoogle.com](https://www.doubleclickbygoogle.com)\r\n\r\n## About\r\nDoubleClick offers products and services to publishers and advertisers. Publishers use DoubleClick to display advertisements, and advertisers use DoubleClick to control the displaying of their ads by publishers.\r\n\r\n## Ownership\r\nGoogle\r\n\r\n## Documentation\r\n[https://developers.google.com/doubleclick-publishers/docs/start](https://developers.google.com/doubleclick-publishers/docs/start)\r\n\r\n## Products and Services\r\n\r\n### Identification and Analytics\r\n* Through DoubleClick Campaign Manager (DCM), Google uses mobile device IDs to attribute conversions to mobile devices [DoubleClick, 07](https://developers.google.com/doubleclick-advertisers/guides/conversions_overview#using_mobile_device_id).\r\n* DoubleClick segments audiences for targeted advertising [The Guardian, 01](https://www.theguardian.com/technology/2012/apr/23/doubleclick-tracking-trackers-cookies-web-monitoring).\r\n* Google performs cross-device identification (via Google Attribution) [Search Engine Land, 01](https://searchengineland.com/google-attribution-search-marketers-need-know-275751); [DoubleClick, 01](https://www.doubleclickbygoogle.com/articles/google-debuts-new-ad-attribution-service); [Forbes, 01](https://www.forbes.com/sites/roberthof/2017/05/23/did-that-ad-work-google-debuts-new-ai-driven-ad-attribution-service).\r\n* Google connects data to personally identifiable information [ProPublica, 01](https://www.propublica.org/article/google-has-quietly-dropped-ban-on-personally-identifiable-web-tracking).\r\n* DoubleClick offers analytics services for revenue management [DoubleClick, 05](https://www.doubleclickbygoogle.com/solutions/revenue-management/ad-exchange); [DoubleClick, 06](https://support.google.com/dcm/partner/answer/4568975?hl=en); [Online-behavior.com, 01](http://online-behavior.com/analytics/dfp-audience)\r\n\r\n### Store visit tracking\r\nThrough AdWords, Google offers insights on store-visit conversions: \"In DoubleClick Search, you can report on store visit conversions by adding a custom AdWords store visit conversions column to a report\" [Google, 01](https://support.google.com/ds/answer/6348835?hl=en).\r\n\r\n### Advertising Methods\r\n* DoubleClick loads targeted advertisements [Google, 03](https://support.google.com/dfp_premium/answer/2884033?hl=en); [Google, 05, PDF](http://services.google.com/fh/files/misc/case-study-accuweather-delivers-enhanced-value-to-advertisers-with-doubleclick-for-publishers-and-google-analytics-360.pdf); [The Guardian, 01](https://www.theguardian.com/technology/2012/apr/23/doubleclick-tracking-trackers-cookies-web-monitoring).\r\n* Google Attribution integrates information from several Google ad services, including DoubleClick, to evaluate the effectiveness of ads, from search to store visits [Forbes, 01](https://www.forbes.com/sites/roberthof/2017/05/23/did-that-ad-work-google-debuts-new-ai-driven-ad-attribution-service); [Google, 04](https://support.google.com/richmedia/answer/3399874?hl=en)\r\n* Google is using offline and online data sources to conduct real-world location targeting [Google, 01](https://support.google.com/ds/answer/6348835?hl=en); [Google, 02](https://support.google.com/adwords/answer/6100636?co=ADWORDS.IsAWNCustomer%3Dfalse&hl=en-GB); [TechCrunch, 02](https://techcrunch.com/2017/05/23/google-is-now-using-deep-learning-to-measure-store-visits); [DoubleClick, 02](https://support.google.com/adxseller/answer/6016023?hl=en)\r\n* Google conducts real-time targeting [DoubleClick, 04](https://www.doubleclickbygoogle.com/articles/bt-sport-dynamic-ad-insertion-google)\r\n* Google uses artificial intelligence (via Google Attribution) [Forbes, 01](https://www.forbes.com/sites/roberthof/2017/05/23/did-that-ad-work-google-debuts-new-ai-driven-ad-attribution-service); [TechCrunch, 01](https://techcrunch.com/2017/05/23/google-attribution-is-a-free-and-easy-way-to-evaluate-marketing-efforts); [TechCrunch, 02](https://techcrunch.com/2017/05/23/google-is-now-using-deep-learning-to-measure-store-visits)\r\n* Google targets across devices and channels [Forbes, 01](https://www.forbes.com/sites/roberthof/2017/05/23/did-that-ad-work-google-debuts-new-ai-driven-ad-attribution-service)\r\n* DoubleClick provids bidding services [DoubleClick, 05](https://www.doubleclickbygoogle.com/solutions/revenue-management/ad-exchange)\r\n\r\n### Advertising Networks\r\n* Google conducts data sharing and integration [DoubleClick, 05](https://www.doubleclickbygoogle.com/solutions/revenue-management/ad-exchange); [The Guardian, 01](https://www.theguardian.com/technology/2012/apr/23/doubleclick-tracking-trackers-cookies-web-monitoring); [DoubleClick, 03](https://support.google.com/dfp_premium/answer/6281539?hl=en); [AppsFlyer, 01](https://support.appsflyer.com/hc/en-us/articles/115003213726-DoubleClick-Integration-Guide)\r\n\r\n## Privacy Policy\r\nA Google search for \"DoubleClick Privacy Policy\" brings the user to the general Google privacy policy web page.\r\n\r\n_Cookies:_ Google's privacy policy states that Google uses cookies in web broswers for targeted advertising. They also store a record of the ads they serve in their logs. Log data includes \"your web request, IP address, browser type, browser language, the date and time of your request, and one or more cookies that may uniquely identify your browser.\" They anonymize the log data by \"removing part of the IP address (after 9 months) and cookie information (after 18 months)\". Google services, such as AdWords, AdSense, and a range of DoubleClick-branded services, may send cookies to your bro]]wser when you visit a page or see an ad that uses one of these services. \r\n\r\n_Other technologies:_ Google may \"select advertising based on information about your computer or device, such as your device model, browser type, or sensors in your device like the accelerometer.\" \r\n\r\n_Location:_ Google may infer your location \"from a variety of sources\", including your IP address, search queries, as well as you \"precise location from your mobile device\" and \"websites or apps that you use may send information about your location\" to Google. Google \"uses location information in our ads products to infer demographic information, to improve the relevance of the ads you see, to measure ad performance and to report aggregate statistics to advertiser.\" \r\n\r\n_Mobile tracking:_ When cookies are not available (eg, in mobile devices), Google \"may use technologies that perform similar functions to cookies. Sometimes Google links the identifier used for advertising on mobile applications to an advertising cookie on the same device in order to coordinate ads across your mobile apps and mobile browser. This can happen, for example, when you see an ad within an app that launches a web page in your mobile browser. This also helps us improve the reports we give to our advertisers on the effectiveness of their campaigns.\"\r\n\r\n_Opt-out and user control:_ Users can control cookie tracking through Google Ad Settings, consumer choice tools created under self-regulation programs in many countries, and through the management of cookies in web browser settings. Users can opt out of personalized ads in apps through Android and iOS device settings [Google, 06](https://www.google.com/policies/technologies/ads).\r\n\r\n## Details\r\nDoubleClick was founded in 1995 [Crunchbase, 01](https://www.crunchbase.com/organization/doubleclick).\r\n\r\n## References\r\n* _AppsFlyer, 01._ https://support.appsflyer.com/hc/en-us/articles/115003213726-DoubleClick-Integration-Guide \r\n* _Crunchbase, 01._ https://www.crunchbase.com/organization/doubleclick\r\n* _DoubleClick, 01._ https://www.doubleclickbygoogle.com/articles/google-debuts-new-ad-attribution-service \r\n* _DoubleClick, 02._ https://support.google.com/adxseller/answer/6016023?hl=en \r\n* _DoubleClick, 03._ https://support.google.com/dfp_premium/answer/6281539?hl=en \r\n* _DoubleClick, 04._ https://www.doubleclickbygoogle.com/articles/bt-sport-dynamic-ad-insertion-google \r\n* _DoubleClick, 05._ https://www.doubleclickbygoogle.com/solutions/revenue-management/ad-exchange \r\n* _DoubleClick, 06._ https://support.google.com/dcm/partner/answer/4568975?hl=en \r\n* _DoubleClick, 07._ https://developers.google.com/doubleclick-advertisers/guides/conversions_overview#using_mobile_device_id \r\n* _Forbes, 01._ https://www.forbes.com/sites/roberthof/2017/05/23/did-that-ad-work-google-debuts-new-ai-driven-ad-attribution-service \r\n* _Google, 01._ https://support.google.com/ds/answer/6348835?hl=en \r\n* _Google, 02._ https://support.google.com/adwords/answer/6100636?co=ADWORDS.IsAWNCustomer%3Dfalse&hl=en-GB\r\n* _Google, 03._ https://support.google.com/dfp_premium/answer/2884033?hl=en\r\n* _Google, 04._ https://support.google.com/richmedia/answer/3399874?hl=en \r\n* _Google, 05, PDF._ http://services.google.com/fh/files/misc/case-study-accuweather-delivers-enhanced-value-to-advertisers-with-doubleclick-for-publishers-and-google-analytics-360.pdf\r\n* _Google, 06._ https://www.google.com/policies/technologies/ads\r\n* _Online-behavior.com, 01._ http://online-behavior.com/analytics/dfp-audience \r\n* _ProPublica, 01._ https://www.propublica.org/article/google-has-quietly-dropped-ban-on-personally-identifiable-web-tracking \r\n* _Search Engine Land, 01._ https://searchengineland.com/google-attribution-search-marketers-need-know-275751 \r\n* _TechCrunch, 01._ https://techcrunch.com/2017/05/23/google-attribution-is-a-free-and-easy-way-to-evaluate-marketing-efforts \r\n* _TechCrunch, 02._ https://techcrunch.com/2017/05/23/google-is-now-using-deep-learning-to-measure-store-visits \r\n\r\n## External links\r\n* _Crunchbase (DoubleClick):_ [https://www.crunchbase.com/organization/doubleclick](https://www.crunchbase.com/organization/doubleclick)\r\n* _Wikpedia (DoubleClick):_ [https://en.wikipedia.org/wiki/DoubleClick](https://en.wikipedia.org/wiki/DoubleClick)\r\n* _Ghostery (DoubleClick:_ [https://apps.ghostery.com/apps/doubleclick](https://apps.ghostery.com/apps/doubleclick)", "id": 5, "code_signature": "com.google.android.gms.ads.doubleclick", "website": "https://www.doubleclickbygoogle.com/", "name": "Google DoubleClick", "network_signature": "mng-ads\\.com|doubleclick\\.net|doubleclick\\.com|2mdn\\.net|dmtry\\.com", "creation_date": "2017-09-24"}, "6": {"description": "## Primary Location\r\nFrance (Paris)\r\n\r\n## About\r\nWeborama \"collect, organise, stock, transform and operate data within the advertising ecosystem, thanks to a 400 million profiles database\" [Weborama, 02](https://www.weborama.com/data/presentation); [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf). They provide ad analytics and behavioral targeting services [Crunchbase, 01](https://www.crunchbase.com/organization/weborama).\r\n\r\n## Ownership\r\nWeborama\r\n\r\n## Documentation\r\n[https://be-interactive.atlassian.net/wiki/spaces/SDK/pages/5931037/Integration+with+DFP](https://be-interactive.atlassian.net/wiki/spaces/SDK/pages/5931037/Integration+with+DFP)\r\n\r\n## Products and Services\r\nWeborama \"specializes in creating and delivering targeted online ads. Weborama identifies the content, services and products that are most likely to match the interest of specific user groups according to their browsing history\" [Weborama, 07](https://www.weborama.com/e-privacy/our-commitment).\r\n\r\nWeborama features an audience-driven advertising platform:\r\n\r\n\"The Weborama platform enables advertisers to create audience segments from Media, Site and/or CRM data. These segments can be enhanced using 3rd party data. Advertisers can use these segments to buy ad space and target their campaigns. The Weborama platform analyses the performance of these campaigns and audiences and optimises them in real time\" [Weborama, 02](https://www.weborama.com/data/presentation). \r\n\r\n\"Weborama has been developing solutions in adserving, data Management Platform (DMP), audience analysis, data segmentation and target segments for 15 years\" [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf). \r\n\r\n_Weborama Audience Manager:_ A Data Management Platform; it is a \"data management platform for segmentation of different sources of 1st party (CRM, media and website) data, enriched by 3rd party data using access to data owned by Weborama.\"\r\n\r\n_Weborama Audience Insight:_ A \"tool for analysing audience behavior on internet sites\" \r\n\r\n_Weborama Campaign Manager:_ \"adserving tool for management and optimisation of advertising campaigns\" \r\n\r\n_Weborama Advanced Rich Media:_ A \"tool for managing rich media/video campaigns\" \r\n\r\n_Weborama Audience Exchange:_ A \" premium multi-device audience platform, on two channels (WaX for agency, WaX for trading desk). Classic formats, rich media and in stream\" \r\n\r\nWeborama offers audience analysis and a targeted marketing proposal for publishers [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf).\r\n\r\n## Privacy Policy\r\n\r\nWeborama's website privacy policy was last updated in 2014 and does not mention mobile.\r\n\r\n_Opt out procedure:_ \"Users can choose to opt out of Weborama\u2019s anonymous data collection program. Once users opt out, Weborama does not collect navigation data or create marketing profiles anymore. Opting out does not prevent users from receiving online ads delivered by Weborama, but these ads are delivered randomly. They are not targeted to a user\u2019s modelled interest or demographics, are not delivered in sequence or delivered according to any previous advertising interaction. When users opt out, Weborama stores a specific cookie on their browser. Weborama\u2019s opt-out cookie has to be downloaded on each computer and each browser used by users. If cookies are disabled, erased, or altered, and if browsers or operating systems are modified or upgraded, the opt-out process might need to be performed again.\" [Weborama, 07](https://www.weborama.com/e-privacy/our-commitment)\r\n\r\n_Opting out:_ \"In accordance with current legislation, internet users can unsubscribe at any moment from Weborama\u2019s data collection programme, either by using the opt-out on the group\u2019s website, or via the icon Ad Choices, which can be found on all targeted advertising, and returning it via website YourOnlineChoices at IAB Europe.\" [\r\n\r\n_Personally identifiable information:_ Weborama \"does not collect personally identifiable information (PII) such as name, email address or phone number. Weborama does not profile users according to their political, philosophical, sexual or religious preferences, ethnic or racial origins, trade union membership or health condition.\r\n\r\n_Segmenting and age:_ Weborama does not intentionally profile or target sensitive audience segments such as children under the age of 13 or any other segments considered sensitive by IAB Europe\u2019s Self-regulation Online Behavioural Advertising (OBA) Framework.*\"\r\n\r\n_Data Usage and Security:_ \"Navigation data is used by Weborama to build users\u2019 marketing profiles. These profiles are used to deliver, target and/or analyse online marketing campaigns. These actions are conducted by Weborama on behalf of its clients, or by business partners with whom Weborama synchronises anonymous user profiles. Measures have been implemented to protect information from unauthorized or unlawful access, use or disclosure, and against accidental loss, damage or destruction. Access to data is restricted to authorized individuals. Weborama is a member of the Internet Advertising Bureau (IAB) and complies with all applicable laws and regulations as well as with IAB principles as described in the Online Behavioural Advertising (OBA) Framework.\"\r\n\r\n_Privacy Policy last updated:_ Weborama was last updated 16th of October 2014\" [Weborama, 07](https://www.weborama.com/e-privacy/our-commitment)\r\n\r\n## Relationships\r\n\"Over 300 clients use Weborama\u2019s innovative solutions to drive and optimise their online investments in France, Spain, Italy, Portugal, Holland, UK and Russia\" [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf).\r\n\r\nOdnoklassniki (the first Russian social network) / Move Publishing [Weborama, 01](https://www.weborama.com) / EDF / MAIF / Pernod Ricard / Medela / Endesa / Findus / Yeppon / Moschin [Weborama, 06](https://www.weborama.com/documents/2017/09/weborama-growth-of-the-operating-profit-in-the-first-half-of-2017.pdf)\r\n\r\n## Details\r\n_Financial details:_ Weborama was founded in 1998 (listed on Alternext since June 2006 as ALWEB) [Weborama, 02](https://www.weborama.com/data/presentation); it had a market capitalization of \u20ac28 million as of 2015 [Wikipedia, 01](https://fr.wikipedia.org/wiki/Weborama](https://fr.wikipedia.org/wiki/Weborama). Weborama recorded revenues of 24.3 million Euros in 2012 [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf); revenues \"reached \u20ac29 million in 2016\" [Weborama, 05](https://www.weborama.com/infos-financieres/financial-figures). Operating income was up in early 2017. A recently signed international agreement with \"a leading media/marketing player...will especially enable Weborama to grow its presence in the United States.\" [Weborama, 06](https://www.weborama.com/documents/2017/09/weborama-growth-of-the-operating-profit-in-the-first-half-of-2017.pdf)\r\n\r\n_Growth:_ Weborama had 110 million profiles in 2013; this suggests a growth of 300 million profiles in just 4 years [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf); [Weborama, 07](https://www.weborama.com/e-privacy/our-commitment)\r\n\r\n_Devices:_ Web browsers / Trackers in mobile apps\r\n\r\n### Methods\r\n_Data assets:_ Weborama has \"400 million profiles in the European database\" and \"More than 200 socio-demo, behavioural and intenders criteria\". This is used for \"data solutions\" for advertisers; the Audience Manager gives \"an exclusive and native access to 400 million profiles in Europe\" with a \"360\u00b0 view of behavioural and socio-demographic data\". Audience Insight \"allows viewing the audience structure by age, gender and occupation, along with the distribution of behavioural segments and clusters\", which \"helps publishers to drill down into their audience profile in real time, and thereby to maximise its monetisation\" [Weborama, 04](https://www.weborama.com/data/the-offering).\r\n\r\nWeborama tags placed on a publisher's website allows them to \"collect raw and anonymous navigation data\". They conduct \"Audience analysis, followed by a relevant and targeted marketing proposal\" to be \"conducted within three weeks from the date Weborama tags\" the website [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf)\r\n\r\nWeborama \"collects anonymous user navigation data via a network of several thousands of partner websites. These websites make it possible for Weborama to store cookies on users\u2019 browsers to allow for their anonymous identification and tracking over the Internet. Navigation data collected by Weborama only includes non-personally identifiable information (NPII) such as URL pages, software equipment, keywords used for searching, geographic location (at state or city level), and advertising interaction history\" [Weborama, 07](https://www.weborama.com/e-privacy/our-commitment).\r\n\r\n_Location targeting:_ \"Generate qualified traffic in store thanks geolocation\" [Weborama, 02](https://www.weborama.com/2017/09/retail-which-dmps-use-cases) \r\n\r\n_Big Data:_ \"Data is at the heart of its expertise, thanks to its strategists, data consultants, computer linguists, statisticians, mathematicians and developers. Big Data is the driver of development today at Weborama, and will continue to be in the future. Great cares are taken to collect data anonymously, internet user benefits from more relevant advertising.\" [Weborama, 02](https://www.weborama.com/data/presentation)\r\n\r\n_Semantic processing: Cookies, segmenting, & survey:_ \"the data is sourced anonymously from 300,000 sites, using cookies, then processed instantly. this audience classification is a critical process within each database. thanks to this methodology Weborama has a database of 110 million profiles of behavioural, socio-demographic, and purchasing intent data in Europe, 70 million of which are from France. Today, Weborama has identified almost 200 clusters (centres of interest) based on the behaviour of internet users, divided into 23 segments (a segment being a \u201cfamily\u201d of clusters). Weborama\u2019s socio-demographic database is built from a sample group of 300,000 active internet users in France who responded willingly to a questionnaire giving their age, gender and socio-professional category. by cross-referencing behavioural clusters with Weborama\u2019s socio-demographic sample group, the sample group data are extrapolated from the database as a whole\" [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf).\r\n\r\n_Patented technologies based on algorithms and the automatic processing of language:_ 33 million active URLs; 300,000 sites analysed each day; 110 million active profiles per month; 3.5 million qualified internet users per day; 25 words per day per internet user.\" [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf) \r\n\r\n_Knowledge: 3rd party & 1st party data:_ The Weborama 3rd party database enriches 1st party data. 3rd party data is \"Data from a third party which do not belong to the advertiser or publisher, but are made available to them for deployment in online marketing\", whereas 1st party data is \"Data belonging to an advertiser or publisher.\"\r\n\r\n_Audience Segmentation & Targeted Advertising:_ With big data collections, Weborama can identify \"look-alikes\" of internet users with a similar profile to those who \"transform\" (\"subscriptions to products offered in the campaign\"). \"This allows them to be offered advertising which is personalised to fit their profile\". Audience segmentation in media campaigns was introducted by an advertiser in 2012; the advertiser was looking to increase the level of transformation while reducing loss of media investments, and called upon Weborama to build a mechanism for its commercial catalogue. Weborama creates a database, including from data collected by advertisers, and builds a targeted advertising model, which includes a model training phase and A/B testing. \r\n\r\nData mining is conducted as follows: \"this database is then enriched with socio-demographic and behavioural criteria for internet users whose profile is known to Weborama, thanks to their database of 70 million qualified profiles in France. this data is cross referenced with the data coming from Weborama Campaign Manager. this anonymous information is accessible as a whole using the internet user identifier (a series of characters for each individual contained in the cookies deposited in the internet explorer). this unique identifier allows Weborama to find the complete profile of the internet user in their database, in real time.\" Search and surf data is used; Weborama then views transactions over weeks, and observes outcomes from users in the database which includes 60 million qualified profiles over approximatley 300 columns, including ads viewed, reactions (visit, click), behavior on the website visited, and socio-demographic and behavioral profile. \r\n\r\nTraining the model is conducted as follows: From the database, build graphic representation and create permanent tree segments. The criteria most relevant to each product or service can be extracted, where the criteria is based on transformation of the internet users exposed to ad campaigns and impressions.\r\n\r\nWeborama's database \"is then enriched with socio-demographic and behavioural criteria for internet users whose profile is known to Weborama, thanks to their database of 70 million qualified profiles in France. this data is cross-referenced with the data coming from Weborama Campaign Manager. this anonymous information is accessible as a whole using the internet user identifier (a series of characters for each individual contained in the cookies deposited in the internet explorer). this unique identifier allows Weborama to find the complete profile of the internet user in their database, in real time.\" \r\n\r\nWeborama runs A/B testing to determine if the model is working, based on confidence intervals. Variation can occur for many reasons, such as a calendar event or a holiday. \r\n\r\n_Segmentation for publishers:_ \"Above all, the aim of publishers is to organise their commercial products so that they can offer advertisers and agencies, in addition to the contextual menu, packs of targeted audiences, enriched by 3rd party data. the second challenge is to build specific audience packs using ad hoc target segments based on both socio-demographic and behavioural targeting (taking account of the internet users\u2019 different areas of interest). \"Segmentation of a site\u2019s audience allows visitor profiles \r\nfrom other areas of interest to be seen. It is highly probable that a current affairs site has, among its audience, people who enjoy other sites (finance, beauty, fashion, cookery, travel...). this will offer the publishers the possibility of assessing their content quality, as well as that of their audience, while expanding their client base. \" \r\n\r\n_Two methods of data enrichment from publishers:_ The first method \"includes the synchronisation and propagation of Weborama\u2019s socio-demographic criteria and behavioural clusters on the publisher\u2019s site audience. this is possible by identifying profiles recognised within the site\u2019s audience, which are already part of the Weborama database. In this particular case, the adserver of the publisher calls the Weborama database for each internet user. If the Weborama database recognises the socio-demographic profile or behaviour of the visitor to the site, the visitor is transferred to the publisher\u2019s adserver. the publisher\u2019s adserver therefore now contains the socio-demographic and behavioural profile of the majority of its internet users.\" \r\n\r\nThe second method \"identifies and analyses the website user\u2019s profiles to create ad hoc target users relevant to the advertisers\u2019 areas of activity.\" Here Weborama creates _ad hoc_ profiles, and then there is a \"transfer of ad hoc target users\": \"the transfer of ad hoc users defined above is possible using a list of different adserver pixels. this transfer is done by a call of the pixels generated by the publisher\u2019s adserver. the volume of profiles per target required are then available directly in the adserver\" [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf).\r\n\r\n## References\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/weborama](https://www.crunchbase.com/organization/weborama)\r\n* _Weborama, 01._ [https://www.weborama.com](https://www.weborama.com)\r\n* _Weborama, 02._ [https://www.weborama.com/data/presentation](https://www.weborama.com/data/presentation) \r\n* _Weborama, 03._ [http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf) \r\n* _Weborama, 04._ [https://www.weborama.com/data/the-offering](https://www.weborama.com/data/the-offering) \r\n* _Weborama, 05._ [https://www.weborama.com/infos-financieres/financial-figures](https://www.weborama.com/infos-financieres/financial-figures) \r\n* _Weborama, 06._ [https://www.weborama.com/documents/2017/09/weborama-growth-of-the-operating-profit-in-the-first-half-of-2017.pdf](https://www.weborama.com/documents/2017/09/weborama-growth-of-the-operating-profit-in-the-first-half-of-2017.pdf) \r\n* _Weborama, 07._ [https://www.weborama.com/e-privacy/our-commitment](https://www.weborama.com/e-privacy/our-commitment)\r\n \r\n## External Links\r\n* _Wikipedia (Weborama, French):_ [https://fr.wikipedia.org/wiki/Weborama](https://fr.wikipedia.org/wiki/Weborama) \r\n* _Wikipedia (Weborama, English translation):_ [https://translate.google.com/translate?hl=en&sl=fr&u=https://fr.wikipedia.org/wiki/Weborama&prev=search](https://translate.google.com/translate?hl=en&sl=fr&u=https://fr.wikipedia.org/wiki/Weborama&prev=search)", "id": 6, "code_signature": "com.weborama.", "website": "https://www.weborama.com", "name": "Weborama", "network_signature": "weborama\\.net|weborama\\.fr", "creation_date": "2017-09-24"}, "7": {"description": "## Primary Location\r\nFrance\r\n\r\n## Website\r\n[http://smartadserver.com](http://smartadserver.com)\r\n\r\n## About\r\nSmart uses a \"full stack ad technology\" for digital campaigns [Smart, 03](http://smartadserver.com/request-a-demo). They deliver \"multi-screen and multi-channel advertising\" for clients [Smart, 01](http://smartadserver.com). \r\n\r\n## Ownership\r\nSmart\r\n\r\n## Documentation\r\n[https://github.com/smartadserver/SAS-DFP-Adapter-Android](https://github.com/smartadserver/SAS-DFP-Adapter-Android)\r\n\r\n## Products and Services\r\n_Solutions for publishers:_ Ad Server / Programmatic / Mobile / Video / Ad Formats [Smart, 04](http://smartadserver.com/publisher-platform/holistic-ad-server) \r\n\r\n_Full stack ad technology platform:_ Smart is a full stack ad technology platform: \"We come to work because we want to solve the biggest problem publishers, advertisers and agencies face in online advertising \u2014 control. It\u2019s simple. When other companies sell and resell your ad inventory and data through various parties, you depreciate your company\u2019s value along the way. Smart\u2019s integrated ad server and RTB+ Solution allows you to maintain control over your valuable media assets. We provide you with one robust engine to drive your revenues at any scale. Your ad server is the core of your business. It\u2019s your most important strategic asset. It\u2019s that much more powerful when it is seamlessly integrated with RTB+ and can handle the monetization and delivery of any kind of ads \u2013 display, rich media, video \u2013 on any platform \u2013 web, mobile web or mobile apps\" [Smart, 05](http://smartadserver.com/what-we-do/our-mission). \r\n\r\n_Holistic Ad Server:_ \"One integrated platform to run your entire advertising business, including direct and programmatic campaigns, across all digital formats and screens. Optimize operations without losing time switching between platforms... As the central piece of the puzzle, the ad server gets the big picture. It can optimize the value of each impression by taking absolutely all parameters into account in real time allowing direct sales to compete with programmatic ones. The platform dynamically allocates ads by incorporating all activity on the network: traffic and inventory forecasting, delivery planning, guaranteed campaign commitments, offers, and targeting parameters\" [Smart, 04](http://smartadserver.com/publisher-platform/holistic-ad-server). \r\n\r\n\"The Smart AdServer full stack platform features both an ad server and an SSP. From a single entry point, you can manage all your revenue sources: direct, programmatic and ad network mediation. Our outstanding holistic yield optimization algorithm ensures that each impression is sold through the best sales channel in order to maximize your overall revenue\" [Smart, 06](http://smartadserver.com/publisher-platform/full-stack).\r\n\r\nThe service offers:\r\n \r\n* Cross-platform delivery\r\n* Forecasting \r\n* Ad format builder\r\n* Viewability measurement\r\n* Open and extendable services\r\n* Expert support [Smart, 04](http://smartadserver.com/publisher-platform/holistic-ad-server)\r\n\r\n_Premium Programmatic:_ \"Our cross-platform, cross-device, cross-channel technology is 100% independent, 100% publisher-focused and easy-to-use. Access top quality buyers via an SSP integrated into the ad server.\" This can:\r\n\r\n1. Deliver premium ad campaigns (for rich media, native ads, and video)\r\n2. Manage any type of deal (open auction for unreserved inventory; direct deals of fixed-price unreserved inventory; private auctions for buyers; and guaranteed deals with same options as for direct campaigns)\r\n3. Regain full control of your inventory (granular control over RTB rules, including transparency level of your inventory, setting floor prices, and block-lists; quality monitoring utilizing smart machine learning, 3rd party tools, transparency reports, and a creative control interface)\r\n4. Optimize your advertising revenue (manage all of your revenue sources - direct, programmatic, and ad network mediation - from a single interface). A holistic yield optimization algorithm ensures impressions sold through the best sales channel to maximize revenue; an RTB+ Dashboard offers analytics for insights and revenue decisions; Smart AdServer teams to consult; and Smart Yield+ to optimize rules and price floors [Smart, 08](http://smartadserver.com/publisher-platform/premium-programmatic).\r\n\r\n_RTB Mobile:_ Deliver relevant mobile ad experiences, using rich media templates so \"you can create a campaign even if you don\u2019t have stellar technical skills\" [Smart, 09](http://smartadserver.com/publisher-platform/mobile).\r\n\r\n## Relationships\r\n650+ customers [Smart, 11](http://smartadserver.com/media-buyers) \r\n150+ integrated partners [Smart, 10](http://smartadserver.com/what-we-do/ecosystem) \r\n\r\n_Demand partners:_ Radium one / Turn / AppNexus / DoubleClick bid manager by Google / MediaMath / Adform / criteo (A.I. marketing platform) / nextperf / theTradeDesk / sociomantic / quantcast / Index / BidSwitch / DataXu / AdRoll / Vizury / Sitescout / Liquid M / LDmobile / mediasmart / Trademob / A mob / StikeAd / loopMe / DynAdmic / Zebestof / Pocketmath / adelphic / TLVMedia [Smart, 10](http://smartadserver.com/what-we-do/ecosystem) / himediagroup / aufeminin / Axel Springer / SFR R\u00e9gie / Orange / M-Publicite / L'\u00c9quipe / Clar\u00edn / Genesismedia / Antevenio / [Smart, 13](http://smartadserver.com/company/customers)\r\n\r\n_Others:_ \r\n\r\n* 2nd screen: screenpulse / TVTY Real Time / Visiware International \r\n* 3rd Party Vendors: adform / celtra / DoubleClick by Google / Atlast by Facebook / flashtalking / InMobi / inspired / justAd / MobileAds / S4M / Sizmek / userADgents / weborama / Joule \r\n* Analytics: Keynote / S4M \r\n* Audience Data: AudienceScience / ezakus / Globalfastads.com / navegg / Tail Target / krux \r\n* Brandsafety: adwatchisobar \r\n* Content Delivery Network: Akamai / Level(3) \r\n* Creatives: iab / iab MRAID webTester / iab compliant VAST \r\n* Environment: Android / HTML5 / W3C \r\n* Forecast: Yieldex \r\n* Membership: iab / MMA (Mobile Marketing Association) \r\n* Order management: adlogix.eu / Advendio.com / fivia / nugg.ad \r\n* Privacy: Ghostery / Your Online Choices \r\n* Publishing Networks: Facebook / Google Display Network / msn / Pandora / Q1 Media / The New Yorker / Travel+ Leisure / YouTube \r\n* Video Players: brightcove / Dailymotion / flowplayer / JWPlayer / OOYALA \r\n* Viewability: AppNexus [Smart, 10](http://smartadserver.com/what-we-do/ecosystem)\r\n\r\nAntevenio (ad network that delivers 1.2 billion ad impressions/month to MTV, Paramount, Libertad Digital, Letsbonus, Repsol, BBC, etc. - see [Smart, 07](http://smartadserver.com/uploads/EN_SAS_RTB_Case_study_antevenio_2014_3.pdf)) / access to 50,000 leading global marketer brand buyers through Smart AdServer's Demand Partner Network [Smart, 08](http://smartadserver.com/publisher-platform/premium-programmatic) altitude digital / adikteev [Smart, 11](http://smartadserver.com/media-buyers) / Fraudlogix [Smart, 12](http://smartadserver.com/wp-content/uploads/2017/10/20170606_Brand_Safety_Policy.pdf)\r\n\r\nIn 2012, Smart AdServer teamed up with Rubicon Project for integration into their client base [ExchangeWire, 01](https://www.exchangewire.com/blog/2012/07/23/addressing-the-stack-smart-adserver-teams-up-with-rubicon-project-to-maximise-yield).\r\n\r\n_Industry Affiliations:_ European Interactive Digital Advertising Alliance [Ghostery, 01](https://apps.ghostery.com/apps/smart_adserver)\r\n\r\n## Privacy policy\r\n_Cookies & Web Beacons:_ \"Like most digital marketing solutions, Smart AdServer uses \u201ccookies\u201d and other technologies to enhance users\u2019 experiences on the web, to deliver more relevant ads, and for ad delivery and reporting. We cannot use these technologies to personally identify you, and these technologies do not damage your system or files. Smart AdServer uses these technologies to help recognize a unique computer or device so we are able to deliver relevant advertising and measure the impact of that advertising.\" \r\n\r\n_Cookie Opt-Out:_ The cookie opt-out policy allows users to \"opt out form our advertising network\" and \"ensures you that your browser will not be identify anymore by our system\", see \"http://www.smartadserver.com/diffx/optout/IABOptout.aspx. A blank page will open, confirming the opt-out process has been completed and Smart AdServer will no longer place cookies on your computer.\"\r\n\r\n_Online Behavioral Advertising opt-out via YourOnlineChoices platform:_ \"Smart AdServer is a member of the European Interactive Digital Advertising Alliance (EDAA) and a signatory to the Self-Regulatory Principles for Online Behavioral Advertising (http://www.edaa.eu/european-principles/).\"\r\n\r\nThe EDAA offers a Consumer Choice Page (http://youronlinechoices.eu) (opt-out). To learn more, please visit http://edaa.eu.\" [Smart, 02](http://smartadserver.com/company/privacy-policy)\r\n\r\nSmart promises no personal identity is revealed through their practices: \"Online measurements are compiled and anonymous\"; \"We cannot use [ cookies and other technologies ] to personally identify you\"\r\n\r\n## Details\r\n_Financial Details:_ Smart AdServer was created by Internet portal Aufeminin.com in 2001 [clubic, 01](http://www.clubic.com/actualite-145758-100-clients-francais-smart-adserver.html). In 2007, Axel Springer acquired Aufeminin.com. Smart AdServer became independent from Aufeminin.com when it was acquired by Sino-French private-equity fund Cathay Capital for 37 million \u20ac [Wikipedia, 01](https://en.wikipedia.org/wiki/Smart_Adserver); [JDN, 01](http://www.journaldunet.com/ebusiness/publicite/vente-smart-adserver-cathay-capital.shtml); [Smart, 14](http://smartadserver.com/smart-adserver-officially-becomes-independent-with-the-support-of-cathay-capital); [Cathay, 01](http://www.cathay.fr/en/news/cathay-buy-smart-adserver-e37m). Smart AdServer \"generated turnover of $16 million in 2014\" [Ad Exchanger, 01](https://adexchanger.com/platforms/smart-adserver-goes-independent-via-private-equity-firm). \r\n\r\n## Details\r\n_Financial details:_ Smart was founded in 2001 [Crunchbase, 01](https://www.crunchbase.com/organization/smart-adserver)\r\n\r\n_Scope:_ For programmatic buyers: \r\n* 50 billion auctions per month on desktop 30 billion auctions per month on mobile \r\n* 650+ publishers / 800 million unique visitors \r\n* 30,000 sites and apps [Smart, 11](http://smartadserver.com/media-buyers) \r\n* 150 billion monthly impressions [Smart, 13](http://smartadserver.com/company/customers)\r\n\r\n### Methods\r\nCookies & Web Beacons are used (including pixel tags) [Smart, 02](http://smartadserver.com/company/privacy-policy)\r\n\r\n\"Sites and Advertisers are using the system to manage the delivery of their online advertising campaigns. They can collect anonymous statistical data on their visitors to follow the delivery of their campaign and to increase their performance. We may also collect information including your IP address, your ISP, the browser you used to visit a site, and in some cases, whether you have Flash installed. This is generally used for geotargeting purposes or showing certain ads depending on your browser configuration. Online measurements are compiled and anonymous. They essentially relate to Internet advertising campaign exposure: the number of impression of a banner, the number of clicks or the number of visitors having seen the campaign. Some statistics may relate to the performance of the campaign (\u2018return of investment\u2019). In addition to that, Smart AdServer may use cookies to provide advanced statistical data.\" [Smart, 02](http://smartadserver.com/company/privacy-policy)\r\n\r\n_Mobile:_ \r\n1. _Location targeting based on:_ device type; connection type; location through geotargeting; SDK version; screen size; any sales channel; geofencing (\"Use GPS positioning to pinpoint your target audience based on proximity to a location\"). \r\n\r\n2. Prefetch: Deliver ads to users when offline (eg, during commute)\r\n\r\n3. Viewability: \"Measure the number of viewable impressions and define viewability settings based on parameters such as location and area of ad exposure.\"\r\n\r\n4. Reporting and forecasting: \"Get real-time campaign statistics as well as accurate and reliable forecasts based on date, media type, operator, brand model, location and more.\"\r\n\r\n5. Showcasing: \"Showcase apps by previewing ad on actual devices before it goes live\" [Smart, 09](http://smartadserver.com/publisher-platform/mobile)\r\n\r\n## References\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/smart-adserver](https://www.crunchbase.com/organization/smart-adserver)\r\n* _ExchangeWire, 01._ [https://www.exchangewire.com/blog/2012/07/23/addressing-the-stack-smart-adserver-teams-up-with-rubicon-project-to-maximise-yield](https://www.exchangewire.com/blog/2012/07/23/addressing-the-stack-smart-adserver-teams-up-with-rubicon-project-to-maximise-yield)\r\n* _Ghostery, 01._ [https://apps.ghostery.com/apps/smart_adserver](https://apps.ghostery.com/apps/smart_adserver)\r\n* _Smart, 01._ [http://smartadserver.com](http://smartadserver.com)\r\n* _Smart, 02._ [http://smartadserver.com/company/privacy-policy](http://smartadserver.com/company/privacy-policy)\r\n* _Smart, 03._ [http://smartadserver.com/request-a-demo](http://smartadserver.com/request-a-demo) \r\n* _Smart, 04._ [http://smartadserver.com/publisher-platform/holistic-ad-server](http://smartadserver.com/publisher-platform/holistic-ad-server)\r\n* _Smart, 05._ [http://smartadserver.com/what-we-do/our-mission](http://smartadserver.com/what-we-do/our-mission)\r\n* _Smart, 06._ [http://smartadserver.com/publisher-platform/full-stack](http://smartadserver.com/publisher-platform/full-stack)\r\n* _Smart, 07._ [http://smartadserver.com/uploads/EN_SAS_RTB_Case_study_antevenio_2014_3.pdf](http://smartadserver.com/uploads/EN_SAS_RTB_Case_study_antevenio_2014_3.pdf)\r\n* _Smart, 08._ [http://smartadserver.com/publisher-platform/premium-programmatic](http://smartadserver.com/publisher-platform/premium-programmatic)\r\n* _Smart, 09._ http://smartadserver.com/publisher-platform/mobile](http://smartadserver.com/publisher-platform/mobile)\r\n* _Smart, 10._ [http://smartadserver.com/what-we-do/ecosystem](http://smartadserver.com/what-we-do/ecosystem)\r\n* _Smart, 11._ [http://smartadserver.com/media-buyers](http://smartadserver.com/media-buyers)\r\n* _Smart, 12._ [http://smartadserver.com/wp-content/uploads/2017/10/20170606_Brand_Safety_Policy.pdf](http://smartadserver.com/wp-content/uploads/2017/10/20170606_Brand_Safety_Policy.pdf)\r\n* _Smart, 13._ [http://smartadserver.com/company/customers](http://smartadserver.com/company/customers)\r\n* _Smart, 14._ [http://smartadserver.com/smart-adserver-officially-becomes-independent-with-the-support-of-cathay-capital](http://smartadserver.com/smart-adserver-officially-becomes-independent-with-the-support-of-cathay-capital)\r\n* _Wikipedia, 01._ [https://en.wikipedia.org/wiki/Smart_Adserver](https://en.wikipedia.org/wiki/Smart_Adserver) \r\n\r\n## External Links\r\n* _Ghostery_: [https://apps.ghostery.com/apps/smart_adserver](https://apps.ghostery.com/apps/smart_adserver) \r\n* _Wikipedia_: [https://en.wikipedia.org/wiki/Smart_Adserver](https://en.wikipedia.org/wiki/Smart_Adserver)", "id": 7, "code_signature": "com.smartadserver.", "website": "http://smartadserver.com/", "name": "Smart", "network_signature": "smartadserver\\.com|saspreview\\.com", "creation_date": "2017-09-24"}, "8": {"description": "https://developer.jwplayer.com/android-sdk/", "id": 8, "code_signature": "com.longtailvideo.jwplayer.", "website": "https://jwplayer.com", "name": "JW Player", "network_signature": "jwpltx\\.com|p\\.jwpcdn\\.com|g\\.jwpsrv\\.com", "creation_date": "2017-09-24"}, "9": {"description": "\"Loggly is a San Francisco startup developing the world's most popular cloud based logging platform. We have built a highly scalable log management service as a platform which provides great value for the entire organization.\"\r\n\r\n[Privacy Policy](http://loggly.com/privacy/)\r\n\r\n## Data Collected\r\n * Anonymous (Browser Information, Date/Time, Demographic Data, Page Views )\r\n * Pseudonymous (Search History)\r\n\r\n## Data Sharing\r\nAggregate data is shared with 3rd parties.\r\n\r\n## Data Retention\r\nUndisclosed\r\n\r\n[source Ghostery](https://apps.ghostery.com/en/apps/loggly)", "id": 9, "code_signature": "com.github.tony19.timber.loggly|com.github.tony19.loggly|com.visiware.sync2ad.logger.loggly.", "website": "http://loggly.com/", "name": "Loggly", "network_signature": "loggly\\.com", "creation_date": "2017-09-24"}, "10": {"description": "## Primary Location\r\nFrance (Bordeaux) [Crunchbase, 01](https://www.crunchbase.com/organization/at-internet)\r\n\r\n## Website\r\n[https://www.xiti.com/en](https://www.xiti.com)\r\n\r\n## About\r\nXiTi is \"a free web analytics solution that provides data and performance indicators, making it possible to have an overview of a website\u2019s traffic. Hundreds of thousands of users all over the world use XiTi\u00ae Free.\" XiTi offers \"the Analytics Suite, which helps some of the world\u2019s largest brands to measure, analyse, and visualise their data and digital performance\" [AT Internet, 05](https://www.atinternet.com/en/glossary/xiti-free-2).\r\n\r\n## Ownership\r\nAT Internet\r\n\r\n## Documentation\r\n[https://developers.atinternet-solutions.com/android-en/getting-started-android-en/configuration-android-en](https://developers.atinternet-solutions.com/android-en/getting-started-android-en/configuration-android-en)\r\n\r\n## Products and Services\r\n\"One of the world\u2019s major players in digital intelligence since 1996, AT Internet helps companies measure their audience and optimise their digital performance across all channels. AT Internet\u2019s expertise extends from collecting raw data to treating it in real time and delivering it for analysis and the sharing of insights. Applications in AT Internet\u2019s Analytics Suite provide reliable, contextualised and actionable information. Scalable and completely modular, AT Internet\u2019s offering adapts to businesses in all industries: e-commerce, media, finance/banking, corporate institutions. Easy-to-use and accessible to all individuals within a company, these solutions help address the challenges facing both novices and experts in digital analytics and data mining\" [XiTi, 01](https://www.xiti.com/en).\r\n\r\n_AT Intenet Analytics Suite:_ \"Our Analytics Suite is a digital analytics solution that gives you a unified, real-time view of what users do on your website, mobile site and mobile app. Whether you\u2019re a marketing manager or a data analyst, the Analytics Suite brings together all the tools you need for actionable analysis, dashboarding, reporting, data mining and big data exports. Armed with analytics data that\u2019s accurate, consistent and completely reliable, you\u2019ll be able to make sound, data-backed decisions for your business\" [AT Internet, 01](https://www.atinternet.com/en/products). \r\n\r\n_XiTi:_ XiTi is an audience measuring and statistics service for websites. It provides audience and usage statistics regarding website traffic, including mobile internet. XiTi \"many indicators of visitor activity: audience, navigation, origin of the visit, geolocation. Like similar services for commercial use, it tracks the return on investment (ROI) of marketing campaigns (e-mailing campaigns, sponsored links, contextual advertising) and measures the evolution of the turnover of a online shopping website\". XiTi Free offers personal websites limited analytics for free, whereas XiTi Pro \"is intended for showcases or small sites, especially for SMEs / SMIs. It offers a first professional evaluation of the performance of a website\" [Wikipedia, 01, translated from French](https://fr.wikipedia.org/wiki/XiTi). \r\n\r\n\"To use XiTi on a given page you must add in its source code a marker in the form of a JavaScript script that will allow the company's servers to access the information to be saved (based on the headers of which Cookies , the IP address , and the JavaScript environment). An alternative is to insert a small logo (visible for the free version and invisible for paid versions) on each page to be audited\" [Wikipedia, 01, translated from French](https://fr.wikipedia.org/wiki/XiTi).\r\n\r\n_AT Analytics Dashboard:_ \r\n\r\n* \"Build Dashboards: Understand and drive your business at a glance! Create digital analytics dashboards that can be customised down to the pixel and shared across your company.\" \r\n* Tag with Agility: Take control of your tagging with our modular, customisable SmartTag for web and mobile. Speed up implementation and improve load times.\" \r\n* App Analytics: Get rich mobile analytics, in-app, app store and benchmark data. Track mobile user engagement and retention over time\" [AT Internet, 01](https://www.atinternet.com/en/products). \r\n\r\n_Explorer Service:_ \r\n\r\nExplorer's \"iterative analysis...means giving analysts \u2013 whether they are beginners or experts \u2013 the ability to gradually access data, by first offering an intelligent analysis recommendation system based on machine learning, and then offering the ability to slice and dice the data as much and however they wish. Our objective here is simple: offer these users a tool which will help them find the value in their data, step by step, and then help them share the data so that the most can be made of it. To that end, Explorer offers tools that let you work with and refine your data indefinitely notably via filters, drill-downs, on-the-fly segmentation, and custom cross-calculations. \r\n\r\n...with just one click, the analyst can access Data Query to extract data via our API, and then activate that data by creating relevant retargeting campaigns, for example.\r\n\r\nThe analyst can also transform the analysis into a KPI to be directly displayed in a dashboard, thanks to Explorer\u2019s integration in the Analytics Suite. This KPI will allow business users to understand what\u2019s happening, follow the KPI\u2019s evolution, and potentially implement actions as a result\" [Ad Internet, 03](https://blog.atinternet.com/en/interview-finding-the-value-in-your-data-step-by-step). \r\n\r\n_Mobile developments:_ \r\n\r\n\"There are also mobile features that continue to be developed. For example, we are working on the analysis of the customer journey, which is now done on several devices. This cross-device tracking is simple in theory, because in practice, it's more complicated than just following log-in users ... Above all, unlike others, we are very concerned about the respect of Internet users, and everything must be done with their consent, in accordance with the law. We have many other features in preparation. We will also work on marking and its reliability, a \"smart SDK\" for mobile apps, a tool to know the traffic pages and links by surfing the site, or a benchmark mobile apps using data from the app stores\" [JDN, 01](http://www.journaldunet.com/solutions/analytics/1179294-mathieu-llorens-at-internet-ces-4-millions-d-euros-vont-nous-aider-a-passer-un-nouveau-cap). \r\n\r\nXiTi will \"examine any profiling activities done on their advertising networks, especially when analytics data is being used to establish this profiling\" [At Internet, 02, PDF](https://www.atinternet.com/uploads/Digital-Analytics-the-GDPR-5-Things-You-Must-Know.pdf).\r\n\r\n_Trackers:_ \r\n\r\n* Android initialisation (see [AT Internet, 06](https://developers.atinternet-solutions.com/android-en/getting-started-android-en/tracker-initialisation-android-en)) \r\n* Apple iOS (see [AT Internet, 07](https://developers.atinternet-solutions.com/apple-en/getting-started-apple-en/configuration-apple-en)) \r\n* JavaScript (see [AT Internet, 08](https://developers.atinternet-solutions.com/javascript-en/getting-started-javascript-en/tracker-initialisation-javascript-en))\r\n\r\n## Privacy Policy\r\n\r\n_Personal Data:_ XiTi states, \"By default, AT Internet considers all data related to IP address, GPS location and cookies as personal data. We store all this data within the EU. \r\n\r\nWe only keep: \r\n\r\n* IP address data for 6 months maximum \r\n* [Learn more about how we process and anonymise IP addresses.](https://www.atinternet.com/en/company/data-protection/data-collection-on-our-customers-sites/#geolocation)\r\n* GPS location data for 6 months maximum \r\nDuring collection, we truncate all GPS coordinates to two decimal degrees \u2013 we never collect GPS coordinates in their entirety. Truncated coordinates are then converted into a heatmap graphic providing country-level-only informa-tion. Full details are never displayed. \r\n* Our cookies are active during a fixed period of 13 months, and are then deleted from a user\u2019s computer AT Internet\u2019s cookie only contains a unique alphanumeric ID \u2013 no other data is stored in the cookie.\" \r\n\r\n_Transparency:_ XiTi states, \"The GDPR requires companies and organisations (\u201cdata controllers\u201d) to be completely transparent, \u201cusing clear and plain language\u201d, when informing end users (\u201cdata subjects\u201d) about which personal data is collected, where it is stored, and for how long it is kept (see previous section).\" \r\n\r\n\"... AT Internet has the resources required to retrieve, edit or erase any personal data in a timely manner. We will liaise directly with end users on this matter when necessary. We communicate clearly and transparently about end users\u2019 rights in our privacy policy. We also offer an opt-out option for end users who do not wish their activity to be tracked via our web analytics solution.\" \r\n\r\n_Storage Location:_ \r\n\r\n\"AT Internet processes and stores all personal data within the European Union, with no personal data being transferred outside the EU. This information is clearly accessible in our privacy policy, and in our customer contracts.\" \r\n\r\n_Co-Responsibility:_ \"Under the GDPR, when two different organisations (\u201cdata controllers\u201d) work together to establish the purpose and means of processing personal data, they are considered \u201cjoint controllers\u201d and share responsibility. Joint controllers must together determine the details of their \u201crespective responsibilities\u201d for GDPR compliance, especially as it relates to their duties in responding to data subject requests.\"\r\n\r\n\"... AT Internet\u2019s Analytics Suite is GDPR-compliant. We therefore commit to sharing full responsibility with our customers for any potential privacy breaches and sanctions under the GDPR. We will provide each of our customers with a contract addendum \u2013 a Data Protection Agreement, or DPA \u2013 to precisely define the scope of responsibility. If you work with a different digital analytics provider, we strongly recommend you verify the terms of your contract to ensure that responsibility is not automatically transferred to you (via limitations on liability clauses).\" \r\n\r\n_Purposes of Analytics / Cominations and Correlations with Other Customer Data:_ \"Under the GDPR, personal data must only be \"collected for specified, explicit and legitimate purposes and not further processed in a manner that is incompatible with those purposes.\" In other words, your visitors\u2019 data should only be used to achieve the specific thing(s) you\u2019ve informed them of, such as (in the case of analytics) improving their experience on your site, or providing them with tailored content. Your visitors\u2019 data should NOT be used in other ways for which they have not given consent.\" Data profiling requires a Data Protection Impact Assessment (DPIA) \" to determine how this profiling affects the protection of your users\u2019 personal data.\" \r\n\r\n\"... With AT Internet, you always remain the owner of your data. We never use or merge our customers\u2019 analytics data for our own purposes. We do not carry out any profiling activities, and in light of the GDPR, we strongly encourage our customers and prospects to carefully any profiling activities done on their advertising networks, especially when analytics data is being used to establish this profiling.\"\r\n\r\n## Relationships\r\n\"AT Internet has more than 3,800 web analytics customers worldwide from all industries, including more than half of the companies listed on the French stock exchange (CAC 40), as well as many other leading international groups.\" \r\n\r\n\"The power of AT Internet\u2019s Analytics Suite and the quality of its services (consulting, training and support) are recognised worldwide.\" XiTi is \" in all industries\", including \"e-commerce, media, finance/banking, corporate institutions... With more than 200 employees, the group is present in 32 countries via its customers, subsidiaries and partners\" [XiTi, 01](https://www.xiti.com/en). \r\n\r\n\"Our solution is used on more than 20,000 sites and apps around the globe. Discover how our clients have improved their results (ROI, conversion rate, online sales\u2026) thanks to our solutions and services. Learn from their experiences and best practices in web marketing, digital intelligence and digital analytics\" [Ad Internet, 04](https://www.atinternet.com/en/resources/customer-success-stories).\r\n\r\n_AT Internet Clients (from \"Case Studies\"):_ L'Equipe / Groupe La Poste / Younited Credit (Pret D'Union) / Vente-Privee / Lagardere Active / Meinestadt.de / Rambler.ru / Soundcloud / Caradisiac / France Televisions / Reed Expositions / Oxybul Eveil et Jeux / Solocal Group / Nexity / Le Parisien / Priceminister / Ryanair / French Government Information Service (SIG) / Total [Ad Internet, 04](https://www.atinternet.com/en/resources/customer-success-stories)\r\n\r\n## Details\r\n_Financial details:_ AT Internet was founded in 1996, and has raised \u20ac10,250,000 from funders [Crunchbase, 01](https://www.crunchbase.com/organization/at-internet). In 2016, AT Internet obtained 4 million Euros in financing to expand its business [French Chamber Singapore, 01](http://www.fccsingapore.com/publications/internet-obtains-4-million-euros-financing-continue-its-international-growth-and), after having raised approximately 6 million Euros over three years prior [JDN, 01](http://www.journaldunet.com/solutions/analytics/1179294-mathieu-llorens-at-internet-ces-4-millions-d-euros-vont-nous-aider-a-passer-un-nouveau-cap).\r\n\r\n_Devices:_ Desktop / Mobile (Android / iOS)\r\n\r\n_History:_ \"For more than 15 years AT Internet has provided website owners with free access to their web traffic data. Thanks to an easy-to-use solution, you can benefit from key information such as traffic sources, visitor geolocation, and more, in order to manage and improve your site\u2019s impact (whether it\u2019s a blog, a personal website, or otherwise).\r\n\r\nThe XiTi Free project was launched back in 2000 by AT Internet, one of the world\u2019s leading digital analytics companies, and today continues to illustrate the company\u2019s desire to make digital analytics accessible to everyone. The decision to continue supporting a free version to the benefit of a large user community has been the success behind XiTi Free, an essential solution for measuring the traffic of personal websites. [XiTi, 01](https://www.xiti.com/en)\r\n\r\n_Slogans:_ \"The leading free solution for measuring website traffic\" [XiTi, 01](https://www.xiti.com/en)\r\n\r\n## References\r\n\r\n* _AT Internet, 01._ [https://www.atinternet.com/en/products](https://www.atinternet.com/en/products) \r\n* _At Internet, 02, PDF._ [https://www.atinternet.com/uploads/Digital-Analytics-the-GDPR-5-Things-You-Must-Know.pdf](https://www.atinternet.com/uploads/Digital-Analytics-the-GDPR-5-Things-You-Must-Know.pdf)\r\n* _Ad Internet, 03._ [https://blog.atinternet.com/en/interview-finding-the-value-in-your-data-step-by-step](https://blog.atinternet.com/en/interview-finding-the-value-in-your-data-step-by-step) \r\n* _Ad Internet, 04._ [https://www.atinternet.com/en/resources/customer-success-stories](https://www.atinternet.com/en/resources/customer-success-stories) \r\n* _AT Internet, 05._ [https://www.atinternet.com/en/glossary/xiti-free-2](https://www.atinternet.com/en/glossary/xiti-free-2) \r\n* _AT Internet, 06._ [https://developers.atinternet-solutions.com/android-en/getting-started-android-en/tracker-initialisation-android-en](https://developers.atinternet-solutions.com/android-en/getting-started-android-en/tracker-initialisation-android-en)\r\n* _AT Internet, 07._ [https://developers.atinternet-solutions.com/apple-en/getting-started-apple-en/configuration-apple-en](https://developers.atinternet-solutions.com/apple-en/getting-started-apple-en/configuration-apple-en)\r\n* _AT Internet, 08._ [https://developers.atinternet-solutions.com/javascript-en/getting-started-javascript-en/tracker-initialisation-javascript-en](https://developers.atinternet-solutions.com/javascript-en/getting-started-javascript-en/tracker-initialisation-javascript-en) \r\n* _French Chamber Singapore, 01._ [http://www.fccsingapore.com/publications/internet-obtains-4-million-euros-financing-continue-its-international-growth-and](http://www.fccsingapore.com/publications/internet-obtains-4-million-euros-financing-continue-its-international-growth-and)\r\n* _JDN, 01._ [http://www.journaldunet.com/solutions/analytics/1179294-mathieu-llorens-at-internet-ces-4-millions-d-euros-vont-nous-aider-a-passer-un-nouveau-cap](http://www.journaldunet.com/solutions/analytics/1179294-mathieu-llorens-at-internet-ces-4-millions-d-euros-vont-nous-aider-a-passer-un-nouveau-cap) \r\n* _Wikipedia, 01, translated from French._ [https://fr.wikipedia.org/wiki/XiTi](https://fr.wikipedia.org/wiki/XiTi) \r\n* _Xiti, 01._ [https://www.xiti.com/en](https://www.xiti.com/en) \r\n\r\n## External Links\r\n* _Wikipedia (AT Internet):_ [https://en.wikipedia.org/wiki/AT_Internet](https://en.wikipedia.org/wiki/AT_Internet)\r\n* _XiTi (AT Internet):_ [https://www.crunchbase.com/organization/at-internet](https://www.crunchbase.com/organization/at-internet)\r\n* _Ghostery (AT Internet):_ [https://apps.ghostery.com/apps/at_internet](https://apps.ghostery.com/apps/at_internet)", "id": 10, "code_signature": "NC", "website": "http://Xiti.com", "name": "Xiti", "network_signature": "NC", "creation_date": "2017-09-24"}, "11": {"description": "\"Our Mission Help people discover content that they can trust to be interesting, relevant and timely for them. OUTBRAIN BY THE NUMBERS We were first in creating content discovery and we are first in markets across the world. We reach more than a half billion people globally each month. 557 MILLION The global audience Outbrain reaches each month. 200 BILLION The total recommendations we serve consumers monthly. 80% Of the world\u2019s leading brands use Outbrain.\" \r\n\r\n[Privacy Policy](http://www.outbrain.com/legal/privacy)\r\n\r\n## Data Collected\r\n * Anonymous (Ad Views, Analytics, Browser Information, Cookie Data , Date/Time, Demographic Data, Hardware/Software Type, Internet Service Provider, Interaction Data , Page Views , Serving Domains)\r\n * Pseudonymous (IP Address (EU PII), Location Based Data, Clickstream Data, Device ID (EU PII))\r\n * PII (Name , Phone Number, Email Address, Login, EU- IP Address, EU- Unique Device ID )\r\n\r\n## Data Sharing\r\nAggregate data is shared with 3rd parties., Anonymous data is shared with 3rd parties., PII data is shared with 3rd parties.\r\n\r\n## Data Retention\r\nAs long as necessary to fulfill a business need or as required by law.", "id": 11, "code_signature": "com.outbrain.", "website": "http://www.outbrain.com/", "name": "OutBrain", "network_signature": "outbrain\\.com", "creation_date": "2017-09-24"}, "12": {"description": "## Primary Location\r\nIsrael (Herzliya)\r\n\r\n## Website\r\n[https://www.appsflyer.com](https://www.appsflyer.com)\r\n\r\n## About\r\nA mobile & attribution analytics platform that aims to help marketers make better decisions [AppsFlyer, 01](https://www.appsflyer.com)\r\n\r\n## Ownership\r\nAppsFlyer\r\n\r\n## Documentation\r\n[https://support.appsflyer.com/hc/en-us/articles/207032126-AppsFlyer-SDK-Integration-Android](https://support.appsflyer.com/hc/en-us/articles/207032126-AppsFlyer-SDK-Integration-Android)\r\n\r\n## Products and Services\r\nAppsFlyer provides the following services: \r\n\r\n* Fraud prevention, malware protection [AppsFlyer, 04](https://www.appsflyer.com/product/protect360)\r\n* Identity attribution services. AppsFlyer fingerprints devices by their IDs and tracks across datasets (to solve the problem of fragmentation across devices). This works with all Windows 10 devices (including mobile), Android, and iOS [AppsFlyer, 03](https://www.appsflyer.com/product/mobile-attribution-for-user-acquisition).\r\n* Mobile services for targeted advertising [AppsFlyer, 05](https://www.appsflyer.com/product/mobile-ecosystem)\r\n* Marketing across devices and channels [AppsFlyer, 06](https://www.appsflyer.com/product/marketing-analytics)\r\n* Generates reports based on user behavior [AppsFlyer, 06](https://www.appsflyer.com/product/marketing-analytics)\r\n* Tracks which users install apps; tracks successful re-targeting marketing campaigns [AppsFlyer, 07](https://www.appsflyer.com/product/overview)\r\n\r\nAppsFlyer uses artificial intelligence and machine learning for big data analytics [AppsFlyer, 04](https://www.appsflyer.com/product/protect360); [VentureBeat, 01](https://venturebeat.com/2017/05/25/appsflyer-helps-mobile-advertisers-beat-back-ad-fraud-via-machine-learning).\r\n\r\n## Privacy Policy\r\n_Third Parties:_ AppsFlyer states it does not sell data to third parties [AppsFlyer, 02](https://www.appsflyer.com/we-are-appsflyer)\r\n\r\n## Relationships\r\nOver 2,000 network and analytics partners have integrated with AppsFlyer.\r\n\r\n_Investors include:_ Goldman Sachs / Deutsche Telekom / Qumra Capital / Magma Venture Partners / Pitango [AppsFlyer, 02](https://www.appsflyer.com/we-are-appsflyer) \r\n\r\n_Partners:_ Google [Google, 01](https://adwords.googleblog.com/2015/05/new-media-partnerships-and-ad-solutions.html); [TechCrunch, 02](https://techcrunch.com/2015/05/28/google-expands-its-app-promotion-business-with-universal-app-campaigns-and-new-media-partnerships) / Snap / Tencent / HBO / Playtika / Waze / Alibaba / Kayak / Activision [VentureBeat, 01](https://venturebeat.com/2017/05/25/appsflyer-helps-mobile-advertisers-beat-back-ad-fraud-via-machine-learning) / Facebook / Twitter / Accuweather / AdlQuity/Flipkart / Bing Search / Pandora / Opera Software / Ad4Screen / Cooladata / Fiksu / EveryAds / Nanigans / Fyber / HeyZap / Tapjoy / Adroll / Flurry / GameAnalytics / Jampp / Inmobi / Appnexus / Vserv / AppLovin / Vungle / URX / Mobvista / Inneractive / Aarki / Bidalgo / Avazu / Taptica / NativeX / AirPush / Amobee / PlayHaven / Mobilecore / Accesstrade / ADS / ADSNative / Ad County Media / AccordantMedia / Ad2games / Ad2iction / Abakus / APUS / ADyes / Accruo / AID / Aarki / Ad4Game / APPROUND MOBILE / AML / APPSILON / ART DMP / ActionAds / APPAniac / ADvantage / AdBuddiz / ADRW / ADXMI Exchange / ADSAXIS / APPAVE / AVH digital / Actionpay / Ad2Click / ART Ad Platform / ASB / Ad2c / ADPRESSO / Ad@m (kakao) / ADZ JUNCTION MEDIA / ADVERTISE.RU / Ad County / AWIN / Adbird / AdCorsa / Adamas / Adbert / AdReady / Adbrain / Adacts / AdChakra / AdCare / Adattract / AdTiming / AdWyze / AdTen / Adboosters / Adara / AdDeals / Adblender / AdView / AdTiger / AdFit / AdTriba / AdPacker / and many more. For a longer list, see [AppsFlyer, 03](https://www.appsflyer.com/partners)\r\n\r\n## Details\r\n### Financial details & history \r\nAppsFlyer received early seed funding from Microsoft Accelerator and Magma Venture Partners [CrunchBase, 01](https://www.crunchbase.com/funding_round/appsflyer-seed--4b06b119). As of November 2017, AppsFlyer's website lists $84M raised from Top VC's, $6B+ annual mobile ad spend measured, 3k+ mobile tech partners, and 13 global offices (and growing) [AppsFlyer, 02](https://www.appsflyer.com/we-are-appsflyer).\r\n\r\n### Scope\r\nAccording to VentureBeat, AppsFlyer leverages metadata from 98% of the world's mobile devices [VentureBeat, 01](https://venturebeat.com/2017/05/25/appsflyer-helps-mobile-advertisers-beat-back-ad-fraud-via-machine-learning).\r\n\r\n### Devices\r\nThe AppsFlyer SDK is available for Android, iPhone, and Windows Phone\r\n\r\n## References\r\n* _AppsFlyer, 01_. [https://www.appsflyer.com](https://www.appsflyer.com) \r\n* _AppsFlyer, 02_. [https://www.appsflyer.com/we-are-appsflyer](https://www.appsflyer.com/we-are-appsflyer) \r\n* _AppsFlyer, 03_. [https://www.appsflyer.com/partners](https://www.appsflyer.com/partners) \r\n* _AppsFlyer, 04_. [https://www.appsflyer.com/product/protect360](https://www.appsflyer.com/product/protect360) \r\n* _AppsFlyer, 05_. [https://www.appsflyer.com/product/mobile-ecosystem](https://www.appsflyer.com/product/mobile-ecosystem) \r\n* _AppsFlyer, 06_. [https://www.appsflyer.com/product/marketing-analytics](https://www.appsflyer.com/product/marketing-analytics) \r\n* _AppsFlyer, 07_. [https://www.appsflyer.com/product/overview](https://www.appsflyer.com/product/overview)\r\n* _CrunchBase, 01_. [https://www.crunchbase.com/funding_round/appsflyer-seed--4b06b119](https://www.crunchbase.com/funding_round/appsflyer-seed--4b06b119) \r\n* _Google, 01_. [https://adwords.googleblog.com/2015/05/new-media-partnerships-and-ad-solutions.html](https://adwords.googleblog.com/2015/05/new-media-partnerships-and-ad-solutions.html) \r\n* _TechCrunch, 02_. [https://techcrunch.com/2015/05/28/google-expands-its-app-promotion-business-with-universal-app-campaigns-and-new-media-partnerships](https://techcrunch.com/2015/05/28/google-expands-its-app-promotion-business-with-universal-app-campaigns-and-new-media-partnerships)\r\n* _VentureBeat, 01_. [https://venturebeat.com/2017/05/25/appsflyer-helps-mobile-advertisers-beat-back-ad-fraud-via-machine-learning](https://venturebeat.com/2017/05/25/appsflyer-helps-mobile-advertisers-beat-back-ad-fraud-via-machine-learning)\r\n\r\n## External Links\r\n* _Wikipedia (AppsFlyer)_: [https://en.wikipedia.org/wiki/AppsFlyer](https://en.wikipedia.org/wiki/AppsFlyer)\r\n* _AppBrain_: [https://www.appbrain.com/app/appsflyer-sdk-integration-test/com.appsflyer.referrerSender](https://archive.is/ufCAR)", "id": 12, "code_signature": "com.appsflyer.", "website": "http://AppsFlyer.com", "name": "AppsFlyer", "network_signature": "appsflyer\\.com", "creation_date": "2017-09-24"}, "13": {"description": "\"Ligatus is a performance-marketing system permanently integrated into more than 260 premium-partner portals. Using its own optimisation algorithm, Ligatus enables advertising clients and agencies to position their advertising messages intelligently so that they precisely match the respective target group.\"\r\n\r\n## Data Collected\r\n * Anonymous (Browser Information, Cookie Data )\r\n * Pseudonymous (IP Address (EU PII))\r\n * PII (Name , Address, Phone Number, Email Address)\r\n * Undisclosed \r\n\r\n## Data Sharing\r\nUndisclosed\r\n\r\n## Data Retention\r\nUndisclosed\r\n\r\n[source Ghostery](https://apps.ghostery.com/en/apps/ligatus)", "id": 13, "code_signature": ".LigatusManager|.LigatusViewClient", "website": "http://ligatus.com", "name": "Ligatus", "network_signature": "ligatus\\.com", "creation_date": "2017-09-24"}, "14": {"description": "\"Widespace is an international mobile advertising marketplace connecting mobile advertisers with mobile publishers.\"\r\n\r\n## Data Collected\r\n * Anonymous (Analytics, Browser Information, Hardware/Software Type)\r\n\r\n## Data Sharing\r\nAggregate data is shared with 3rd parties.\r\n\r\n## Data Retention\r\nUndisclosed\r\n\r\n[source Ghostery](https://apps.ghostery.com/en/apps/widespace)", "id": 14, "code_signature": "com.widespace.", "website": "http://widespace.com", "name": "Widespace", "network_signature": "widespace\\.com", "creation_date": "2017-09-24"}, "15": {"description": "## Primary Location\r\nUnited States (New York City) [Bloomberg, 01](https://www.bloomberg.com/research/stocks/private/snapshot.asp?privcapId=48973441)\r\n\r\n## Website\r\n[https://www.appnexus.com](https://www.appnexus.com)\r\n\r\n## About\r\nAppNexus offers services for auction-based and directly negotiated media campaigns across the Internet. According to CEO Brian O'Kelley, \"the AppNexus platform\" is \"a single point where all key stakeholders in our ecosystem -- marketers, ad networks, demand side platforms (DSPs), agency networks, exchanges, inventory aggregators, third party data providers, and more -- connect with one another through a powerful technology platform\" [PR Newswire, 01](https://www.prnewswire.com/news-releases/appnexus-officially-launches-ad-platform-fueling-the-real-time-bidding-revolution-in-display-advertising-87460287.html).\r\n\r\n## Ownership\r\nAppNexus\r\n\r\n## Documentation\r\n[https://wiki.appnexus.com/display/sdk/Integrate+the+SDK](https://wiki.appnexus.com/display/sdk/Integrate+the+SDK)\r\n\r\n## Products and Services\r\nFor publishers:\r\n\r\n* Segments audiences\r\n* Uses data analytics to predict delivery risk (ie, delivery of ads)\r\n* Connects ads across devices\r\n* Run bidding ad processes [AppsNexus, 01](https://www.appnexus.com/en/publishers)\r\n\r\nFor advertisers:\r\n\r\n* Harnesses machine learning for \"targeted ads to tens of millions of users, spread out across billions of interconnected devices, all over the world\"\r\n* Real-time data solutions\r\n* Services are used to \"deliver intelligent and customized campaigns to hundreds of millions of consumers each day\"\r\n* Provide over 100 data points at the (consumer) impression level [AppNexus, 02](https://www.appnexus.com/en/buyers)\r\n* 10 billion impressions transactions each day [AppNexus, 03](https://www.appnexus.com/en)\r\n\r\n## Privacy Policy\r\n_Data use and sharing:_ \"The AppNexus Platform allows clients to collect and use Platform data. The Platform ingests information provided by third-party sources to allow clients to use such data to target ads. To do this, clients and data providers may use ID synching to enable the use of this information through the Platform.\" \r\n\r\n\"... The Platform enables AppNexus's clients to collect, buy, and sell data and to use Platform Data to buy and sell online advertising. Sometime AppNexus staff give \"hands-on\" help to clients using the Platform for these purposes, for example by configuring advertising campaigns for clients to best meet their objectives.\"\r\n\r\n\"... The AppNexus Platform allows clients to provide and share Platform Data with each other. Clients also have access to their Platform Data that they collect, acquire, or use on the Platform, and may remove it from the Platform for their own use. AppNexus may provide Platform Data to service providers in order to provide, operate, manage, maintain, and enhance AppNexus' services. AppNexus may provide, or enable others to collect, information for purposes of protecting the safety and security of the online ecosystem, including to detect and prevent malicious activity or fake traffic. AppNexus may also disclose such information in the event we reasonably suspect malicious activity or fake traffic or when we reasonably believe it is required by law, subpoena or other legal process, including to meet national security or law enforcement requirements. AppNexus may also share aggregated data derived from the Platform, including, for example, statistics about Platform activity. Finally, we may transfer Platform Data to a successor entity in connection with a corporate merger, consolidation, sale of assets, bankruptcy, or other corporate change.\"\r\n\r\n_Precise location data collection:_ \"The Platform may ingest Precise Location Information when, for example, an app makes such information available through the Platform.\" \r\n\r\n_PII:_ \"AppNexus does not collect, use, or allow its clients to transfer to or use on the Platform, data that, by itself, directly identifies an individual, such as name, address, phone number, email address, or government identifier. We also prohibit certain categories of sensitive data from being collected, used, or transferred on the Platform.\" \r\n\r\n_Opt-Out:_ In browsers, AppNexus offers an opt-out web browser cookie to opt out of interest-based advertising. On mobile, AppNexus lists an opt-out option through general device settings in Android and iOS. In Android, the setting is \"Opt out of Interest-Based Ads\". To stop location collection, AppNexus tells users to either change the preferences on their device or adjust settings in individual apps. \r\n\r\n_Data Retention:_ AppNexus retains data according to \"industry standards\". \"Platform Data is stored using generally accepted security standards. It is usually aggregated or deleted within 30-60 days, but may be retained in the Platform for up to 18 months from the date of collection before aggregation or deletion. Aggregated data is used for reporting and analysis, and may be stored in the Platform for up to 2 additional years. When clients remove their data from the Platform, their storage and retention of data is governed by their own privacy policies and applicable laws, rules, or regulations.\"\r\n\r\n_Regulation:_ AppNexus supports industry self-regulation, and is \"a member in good standing of the Network Advertising Initiative (NAI), and adheres to the NAI Code of Conduct for Web and Mobile\" [AppNexus, 04](https://www.appnexus.com/en/company/platform-privacy-policy#choices). \r\n\r\n## Relationships\r\n_Clients:_ Affiperf / Air France / Hearst / MEDIA.figaro / The Guardian / Wayfair [AppNexus, 03](https://www.appnexus.com/en) / Underdog Media / Liftoff / Advance Digital / USA Today / Xaxis / Accuen / Bloomberg / Defy Media / Dow Jones / Spectrum Platform Company / District M / BannerConnect / Hitch Digital / ESPN / Fox News / Saavn [AppNexus, 05](https://www.appnexus.com/en/customer-stories)\r\n\r\n## Details\r\n_History:_ AppNexus is \"Founded and managed by the pioneers of the Web's original and most successful ad exchanges at Yahoo!'s Right Media and Google's DoubleClick\" [PR Newswire, 01](https://www.prnewswire.com/news-releases/appnexus-officially-launches-ad-platform-fueling-the-real-time-bidding-revolution-in-display-advertising-87460287.html). AppNexus claims to be \"The world's largest independent digital marketplace\" [AppsNexus, 01](https://www.appnexus.com/en/publishers). \r\n\r\n_Collection Methods:_ \"The Platform uses cookies, beacons, tags, mobile SDKs, and in some cases non-cookie technologies, to collect Platform Data associated with particular web browsers or devices\" [AppNexus, 04](https://www.appnexus.com/en/company/platform-privacy-policy#choices).\r\n\r\n_AppNexus Platform Data Uses:_\r\n\r\n* Interest-based advertising (To opt out of interest-based advertising on the Platform, go to the \"What are your choices?\" section below.)\r\n* Limiting the number of times a user sees a particular ad\r\n* Showing ads in a particular sequence\r\n* Customizing ads to a particular location\r\n* Showing ads related to the content of the web page on which they are shown\r\n* Determining how users respond to ads\r\n* Reporting aggregated statistics regarding, for example, the effectiveness of online advertising campaigns\r\n* The Platform may use Platform Data for cross-device mapping in order to serve or measure advertising on related devices on behalf of our clients\r\n* Typically, companies using technology like the AppNexus Platform own the data that they provide to and get from the Platform. While the AppNexus Platform is designed to use only certain types of data, and Platform clients are prohibited from bringing data onto the Platform that directly identifies an individual, when clients remove their data from the Platform, their use of that data is governed by their own privacy policies and applicable laws, rules, or regulations [AppNexus, 04](https://www.appnexus.com/en/company/platform-privacy-policy#choices).\r\n\r\n## References\r\n* _AppNexus, 01_. [https://www.appnexus.com/en/publishers](https://www.appnexus.com/en/publishers) \r\n* _AppNexus, 02_. [https://www.appnexus.com/en/buyers](https://www.appnexus.com/en/buyers) \r\n* _AppNexus, 03_. [https://www.appnexus.com/en](https://www.appnexus.com/en) \r\n* _AppNexus, 04_. [https://www.appnexus.com/en/company/platform-privacy-policy#choices](https://www.appnexus.com/en/company/platform-privacy-policy#choices) \r\n* _AppNexus, 05_. [https://www.appnexus.com/en/customer-stories](https://www.appnexus.com/en/customer-stories) \r\n* _Bloomberg, 01_. [https://www.bloomberg.com/research/stocks/private/snapshot.asp?privcapId=48973441](https://www.bloomberg.com/research/stocks/private/snapshot.asp?privcapId=48973441) \r\n* _PR Newswire, 01_. [https://www.prnewswire.com/news-releases/appnexus-officially-launches-ad-platform-fueling-the-real-time-bidding-revolution-in-display-advertising-87460287.html](https://www.prnewswire.com/news-releases/appnexus-officially-launches-ad-platform-fueling-the-real-time-bidding-revolution-in-display-advertising-87460287.html)\r\n\r\n## External Links\r\n* _Wikipedia (AppNexus)_: [https://en.wikipedia.org/wiki/AppNexus](https://en.wikipedia.org/wiki/AppNexus)\r\n* _AppBrain_: [https://www.appbrain.com/dev/AppNexus/](https://archive.is/rI5Hu)", "id": 15, "code_signature": "com.appnexus.opensdk.", "website": "https://www.appnexus.com/", "name": "AppNexus", "network_signature": "adnxs\\.com|247realmedia\\.com|appnexus\\.com|appnexus\\.net", "creation_date": "2017-09-24"}, "16": {"description": "## Primary Location\r\nUnited States (Boston) [Localytics, 01](https://www.localytics.com/company/about)\r\n\r\n## Website\r\n[https://www.localytics.com](https://www.localytics.com)\r\n\r\n## About\r\nLocalytics offers an analytics and marketing platform for targeted and personalized engagement campaigns on mobile [Localytics, 01](https://www.localytics.com/company/about); [Crunchbase, 01](https://www.crunchbase.com/organization/localytics).\r\n\r\n## Ownership\r\nSelf-owned\r\n\r\n## Documentation\r\n[https://docs.localytics.com/dev/android.html#android](https://docs.localytics.com/dev/android.html#android)\r\n\r\n## Products and Services\r\nLocalytics performs a variety of services for clients: \r\n\r\n* Uniquely identify users and devices via the Localytics tracker: \"The Localytics SDK automatically captures and uploads device IDs which the Localytics backend uses to uniquely identify users. Some apps connect to their own backend systems that use different IDs for uniquely identifying users\" [Localytics, 04](https://docs.localytics.com/dev/android.html#android) \r\n* Store and transmit user personal information, such as end user name [Localytics, 05](http://docs.localytics.com/dev/ios.html#identifying-users-ios) \r\n* Identify users who uninstall an app containing the tracker [Localytics, 06](http://docs.localytics.com/dev/ios.html#uninstall-tracking-ios)\r\n* Track detailed geolocation, even without the use of GPS: \"Most apps don't track user geolocation so Localytics uses an IP-to-location lookup service to determine which country they are located in. If your app does track user geolocation, you can use the following code to set latitude and longitude in Localytics much more precisely\" [http://docs.localytics.com/dev/ios.html#location-ios](http://docs.localytics.com/dev/ios.html#location-ios)\r\n\r\nLocalytics leverages the same tracking platform in iOS and Android.\r\n\r\n## Privacy Policy\r\n\r\n_Personally identifiable information collection (via Services):_ Localytics requests that its Customers not provide to it PII about their End Users. However, Localytics states that End Users should be aware Customers may request PII for their own use for their mobile apps. To the extent that Localytics does receive PII from Customers, it pledges to maintain the confidentiality of the PII. Localytics does obtain information from website log files, and maintains the right to combine automatically collected log data with other information they have about you. \r\n\r\n_Information sharing:_ Localytics \"does not rent, sell or share PII, including your Personal Information, with any third parties\" expect with your express consent, or in the event of \"a merger, acquisition, or sale of all or a portion of its assets\", at which case you will be prominently notified \"of any change in ownership or uses of your Personal Information, as well as any choices you may have regarding your Personal Information\" [Localytics, 07](https://www.localytics.com/privacy-policy)\r\n\r\n## Relationships\r\n_Customers:_ Comcast / A&E / OLA / Runkeeper / Microsoft / CVS Pharmacy / The New York Times / Avis / Salesforce Marketing Cloud / Amazon / Wendy's / Zipcar [Localytics, 02](https://www.localytics.com) / Oracle Marketing Cloud / Adobe Marketing Cloud / Facebook Marketing Partners / Twitter \r\n\r\n_Alliance partners:_ Bitbang / Cainkade / Cube Loco / Epicfy / Exicon / Jackrabbit / Jargon / Kapitec Software / Keystone Solutions / Mobiquity / NorthBay / Northout / Pollfish / Rocket Insights / Scholarly iQ / Scientific Computers Ltd. / Semba Mobile / Social Fulcrum / Somo / SP2 Servi\u00e7os Empresariais Ltda / Stratigent / Vendus Labs Inc.\r\n\r\n_Technology partners:_ Aarki / adjust / Applift / Applovin / AppsFlyer / Apptimize / Apsalar / Branch Metrics / ExactTarget / Facebook / Fiksu / Greystripe / IBM PartnerWorld / Impact Radius / InMobi / Jampp / Kochava / Liftoff / Mag+ / Marketo / Method Mill / Millennial Media / NativeX / Optimizely / Phunware / Pinsight Media+ / Rocket Fule / StrikeAd / Supersonic / Tapstream / Taptica / Textur / TUNE / Twitter / Yozio [Localytics, 03](https://www.localytics.com/company/partners)\r\n\r\n## Details\r\n_Financial details:_ Localytics was founded in 2009 and and has raised over $69 million from funders [Localytics, 01](https://www.localytics.com/company/about); [Crunchbase, 01](https://www.crunchbase.com/organization/localytics).\r\n\r\n## References\r\n* _Localytics, 01._ [https://www.localytics.com/company/about](https://www.localytics.com/company/about) \r\n* _Localytics, 02._ [https://www.localytics.com](https://www.localytics.com) \r\n* _Localytics, 03._ [https://www.localytics.com/company/partners](https://www.localytics.com/company/partners) \r\n* _Localytics, 04._ [https://docs.localytics.com/dev/android.html#android](https://docs.localytics.com/dev/android.html#android) \r\n* _Localytics, 05._ [http://docs.localytics.com/dev/ios.html#identifying-users-ios](http://docs.localytics.com/dev/ios.html#identifying-users-ios) \r\n* _Localytics, 06._ [http://docs.localytics.com/dev/ios.html#uninstall-tracking-ios](http://docs.localytics.com/dev/ios.html#uninstall-tracking-ios) \r\n* _Localytics, 07._ [https://www.localytics.com/privacy-policy](https://www.localytics.com/privacy-policy](https://www.localytics.com/privacy-policy)", "id": 16, "code_signature": "com.localytics.android.", "website": "http://localytics.com", "name": "Localytics", "network_signature": "analytics\\.localytics\\.com|manifest\\.localytics\\.com|profile\\.localytics\\.com|sdk-assets\\.localytics\\.com", "creation_date": "2017-09-24"}, "17": {"description": "## Primary Location\r\nUnited States (New York City) [Crunchbase, 01](https://www.crunchbase.com/organization/braze)\r\n\r\n## Website\r\n[https://www.braze.com](https://www.braze.com)\r\n\r\n## About\r\nBraze is a mobile marketing company that offers CRM solutions and mobile marketing automation software for mobile applications.\r\n\r\n## Ownership\r\nBraze\r\n\r\n## Documentation\r\n[https://www.braze.com/documentation/Android](https://www.braze.com/documentation/Android)\r\n\r\n## Products and Services\r\n_Cross-Channel Personalization:_ Target customers based on personal interests, location, past purchases, and more [Braze, 02](https://www.braze.com/product/cross-channel-personalization)\r\n\r\n_Identification and Analytics:_ Profile users, segment audiences, and utilize analytics for targeted advertisements [Braze, 02](https://www.braze.com/product/cross-channel-personalization); [Braze, 02](https://www.braze.com/product/cross-channel-personalization); [Braze, 01](https://www.braze.com); [Braze, 02](https://www.braze.com/product/cross-channel-personalization); [Braze, 03](https://www.slideshare.net/Appboy/appboy-urban-outfitters-placeiq-case-study)\r\n\r\n### Advertising Networks\r\n* Data sharing (vague) [Braze, 07](https://www.braze.com/product/integrations)\r\n\r\n## Privacy Policy\r\n_Data Collection:_ Braze collects data through the use of Developer apps. This includes:\r\n\r\n* Device information (OS version, IP address, carrier information, country code) and a unique Braze-generated ID\r\n* Application usage\r\n* Personally identifiable information: Braze \"may collect personally identifiable information shared with Developer Applications. We may also collect personally identifiable information from third parties used for authentication, such as when a user logs in to a Developer Application using a Facebook account, and from third party partners such as Facebook, Twitter, and Klout. Personally identifiable information collected may include information like name, email address, location, gender, interests, device, app usage, user ID, and contact information\".\r\n\r\n_Location Information:_ Braze \"may collect device location information if location services are enabled for any Developer Applications on the device. We use location information to provide Developers with information about the use of their Developer Applications\".\r\n\r\n_Information Use:_ Braze can \"use information we collect to provide partner Developers with information about usage of Developer Applications that integrate the Braze Service.\"\r\n\r\n_Data Sharing:_ Data is shared with app Developers \"in the form of aggregated, anonymous data about the way Developer Applications are used so that Developers can improve their respective Developer Applications.\" Braze may disclose information to third parties as required by law; to trusted service providers working on their behalf; to protect their rights, the safety of others, or in response to a government request; and in conjunction with a merger, acquisition, or sale of Braze.\r\n\r\n_Automatic Data Collection:_ Braze will \"automatically collect information about how Developer Applications are used, such as the frequency and duration of usage. This includes details about mobile devices, such as a unique Braze-generated ID for the mobile device. We share anonymous information about use of their respective Developer Applications with Developers, including which Developer Applications users have downloaded and the way those Developer Applications are used, which facilitates improvements to Developer Applications.\"\r\n\r\n_Opt-Out:_ End users may opt out of location collection by turning off location services for Developer apps in their mobile device. They can opt out of personally identifiable information by not providing that information to the Developer apps, and in the case of third parties, not providing that information to the third parties. Braze states, \"You can prevent collection of all information by uninstalling Developer Applications that integrate the Braze Service.\"\r\n\r\n_Data retention:_ Braze \"will retain information collected throughout the life of each user\u2019s use of Developer Applications except where prohibited by law.\" Users can email privacy@braze.com to request data deletion. Braze \"will keep anonymous information and may need to retain some identifying information to ensure that your request continues to be honored. Your information will be deleted from our active database but may remain in our archives. If we are required to maintain certain information about you, we will comply with your deletion request after fulfilling any legal requirements.\"\r\n\r\n_International Law:_ Braze complies with the U.S.-EU Safe Harbor Framework and the U.S.-Swiss Safe Harbor Framework.\r\n\r\n_Consent:_ Braze states, \"By using a Developer Application, you are consenting to our collection and processing of information as set forth in this Privacy Policy now and as amended by us. 'Processing' means using cookies on a computer/hand held device or using or touching information in any way, including, but not limited to, collecting, storing, deleting, using, combining and disclosing information, all of which activities will take place in the United States. If you reside outside the U.S. your information will be transferred to the U.S., and processed and stored there under U.S. privacy standards. By using the Application and providinginformation to us, you consent to such transfer to, and processing in, the U.S.\" [Braze, 11](https://www.braze.com/privacy).\r\n\r\n## Relationships\r\nABC News / Citi / GAP / Axel Springer / Dominos / Delivery Hero / Hearst / KFC / Microsoft / Nascar / iHeartMedia / RTR / Postmates / OKCupid / Urban Outfitters [Braze, 01](https://www.braze.com) / American Cancer Society / Dots / ibotta / 1-800-Flowers.com / Momondo [Braze, 02](https://www.braze.com/customers)\r\n\r\n## Details\r\n_Financial details:_ Braze was founded in 2011 and has raised over $95 million from funders. Braze changed its name from Appboy in 2017 [Crunchbase, 01](https://www.crunchbase.com/organization/braze).\r\n\r\n### Methods\r\n* Targeted advertisments [Braze, 01](https://www.braze.com) \r\n* Location-based targeting [Braze, 07](https://www.braze.com/product/integrations)\r\n* Real-world location targeting (including real-time targeting) [Braze, 02](https://www.braze.com/product/cross-channel-personalization) [Braze, 03](https://www.slideshare.net/Appboy/appboy-urban-outfitters-placeiq-case-study); [Braze, 07](https://www.braze.com/product/integrations); [Braze, 08](https://www.braze.com/academy/User_Targeting); [Braze, 09](https://www.braze.com/blog/appboy-location-targeting-tool); [Braze, 10](http://www.prweb.com/releases/2013/10/prweb11275487.htm)\r\n* Targeted advertising based on consumer actions [Braze, 02](https://www.braze.com/product/cross-channel-personalization)\r\n* Timed advertisements [Braze, 02](https://www.braze.com/product/cross-channel-personalization)\r\n* Targeting across devices and channels [Braze, 02](https://www.braze.com/product/cross-channel-personalization)\r\n* Real-time services [Braze, 04](https://www.braze.com/customers/postmates); [Braze, 05](https://www.braze.com/product/lifecycle-engagement-orchestration)\r\n* Artificial intelligence for analytics [Braze, 06](https://www.braze.com/product/optimization-ai)\r\n* Reports for clients [Braze, 06](https://www.braze.com/product/optimization-ai)\r\n\r\n## References\r\n* _Braze, 01._ [https://www.braze.com](https://www.braze.com)\r\n* _Braze, 02._ [https://www.braze.com/product/cross-channel-personalization](https://www.braze.com/product/cross-channel-personalization)\r\n* _Braze, 03._ [https://www.slideshare.net/Appboy/appboy-urban-outfitters-placeiq-case-study](https://www.slideshare.net/Appboy/appboy-urban-outfitters-placeiq-case-study) \r\n[Braze, 04._ [https://www.braze.com/customers/postmates](https://www.braze.com/customers/postmates)\r\n* _Braze, 05._ [https://www.braze.com/product/lifecycle-engagement-orchestration](https://www.braze.com/product/lifecycle-engagement-orchestration)\r\n* _Braze, 06._ [https://www.braze.com/product/optimization-ai](https://www.braze.com/product/optimization-ai)\r\n* _Braze, 07._ [https://www.braze.com/product/integrations](https://www.braze.com/product/integrations)\r\n* _Braze, 08._ [https://www.braze.com/academy/User_Targeting](https://www.braze.com/academy/User_Targeting)\r\n* _Braze, 09._ [https://www.braze.com/blog/appboy-location-targeting-tool](https://www.braze.com/blog/appboy-location-targeting-tool)\r\n* _Braze, 10._ [http://www.prweb.com/releases/2013/10/prweb11275487.htm](http://www.prweb.com/releases/2013/10/prweb11275487.htm)\r\n* _Braze, 11._ [https://www.braze.com/privacy](https://www.braze.com/privacy)\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/braze](https://www.crunchbase.com/organization/braze)\r\n\r\n## External Links\r\n* _Crunchbase (Braze):_ [https://www.crunchbase.com/organization/braze](https://www.crunchbase.com/organization/braze)", "id": 17, "code_signature": "com.appboy", "website": "https://www.braze.com", "name": "Braze (formerly Appboy)", "network_signature": "appboy\\.com", "creation_date": "2017-09-24"}, "18": {"description": "## Primary location\r\nUnited States (New York) [Crunchbase, 01](https://www.crunchbase.com/organization/mparticle)\r\n\r\n## Website\r\n[https://www.mparticle.com](https://www.mparticle.com)\r\n\r\n## About\r\nmParticle offers \"a customer data platform built for mobile and native apps across all devices\" [mParticle, 04](https://www.mparticle.com/news/mparticle-raises-15-million-series-a-led-by-social-capital)\r\n\r\n## Ownership\r\nmParticle\r\n\r\n## Documentation\r\n[https://docs.mparticle.com/developers/sdk/android/getting-started](https://docs.mparticle.com/developers/sdk/android/getting-started)\r\n\r\n## Products and Services\r\nmParticle's core features include:\r\n\r\n* _Simplicity and organization:_ Clients \"collect and control all\" their \"customer data through a single API\"\r\n* _Cross-device identification:_ \"Recognize customers at every step of the buying process\"\r\n* _Market orchestration:_ \"Personalize experiences across channels, partners, and screens\"\r\n\r\nProducts and services include:\r\n\r\n* _Customer Data Platform (CDP):_\r\n* * _Understand the entire buying process:_ Merge online and offline data through collection of digital and offline customer journey data; stream it to platforms and systems\r\n* * _Understand and predict customers:_ \"Link customer identities and profile information across internal and external systems for...customer insights\"\r\n* * _Integration:_ \"Integrate with 175+ of the leading marketing, analytics and data warehousing solutions\"\r\n* * _Control your data:_ \"Set rules to transform and filter data without having to make changes to client-side code, and monitor all integrations in real-time\"\r\n* * * _IDSync:_ \"Create fine-grained identity mappings and logic to meet nuanced business requirements and share them across providers\"\r\n* * * _AudienceSync:_ \"Transform raw data into actionable audience segments and sync them across paid media, CRM, and other platforms\"\r\n* * * _Enrichment:_ \"Manage integrations with third-party profile enrichment providers and supplement existing data with additional customer insights\"\r\n* * * _Warehouses:_ \"Instantly load data into Amazon Redshift, BigQuery and other data warehouses, BI tools, and machine learning extensions\" [mParticle, 05](https://www.mparticle.com/product)\r\n* _Enhance analytics:_ \"Unify data around a single customer profile to fuel better insights and attribution reporting\" \r\n* _Segmentation:_ Build and sync audience segments across platforms [mParticle, 06](https://www.mparticle.com/marketer)\r\n* _Data integration:_ \"Unite disparate data sources to better understand the customer and key business metrics\" [mParticle, 07](https://www.mparticle.com/productmanager)\r\n* _Cross-device identification:_ \"Improve media measurement, customer journey analytics, lifetime value modeling, and more by resolving customer identity data across disparate sources\" [mParticle, 08](https://www.mparticle.com/analytics)\r\n\r\n* _Location tracking with SafeGraph integration:_ By integrating with SafeGraph, clients have the tools to track user physical locations, and harness machine learning to analyze the data: \"mParticle customers can now create, monitor, and control server-to-server integrations with SafeGraph via the mParticle platform. With the integration enabled, brands can stream real-time mobile location data directly from their apps to SafeGraph, which will then translate long/lat coordinates into known locations and use machine learning to help brands understand their customers offline movement patterns\" [mParticle, 10](https://www.mparticle.com/integrations/integration-safegraph)\r\n\r\n## Privacy Policy\r\n\r\n_Data Collection:_ Clients \"collect information based on User interaction with their mobile application(s), mobile website(s) or other digital properties where Clients have integrated with the\" mParticle Platform. mParticle calls this \"Client Digital Properties\". Data collected through \"via Client Digital Properties for the Platform includes: the date/time for a visit to a Client Digital Property, referrer information such as what search engine and search keywords Users may have used to get to a Client Digital Property, information about the browser or device your User is on such as their Operating System, as well as the city/country location of Users, and any pseudonymous tokens and mobile advertising IDs (e.g., IDFA in iOS). In addition, our Clients can choose what other User data they want to collect and store on the platform such as an IP address, location information, a User\u2019s age, user names, real names, email addresses and other custom data points as determined by each Client.\" \r\n\r\nmParticle places restrictions on data practices. They state, \"We contractually prohibit Clients from placing sensitive information (e.g., passwords, authentication credentials, credit cards, social security or driver\u2019s license numbers) or information that is deemed sensitive by applicable law or self-regulatory codes such as the Digital Advertising Alliance. mParticle functions strictly as the data processing agent of our Clients. Accordingly, other than those aforementioned restrictions, the data stored on the Platform is subject to the privacy policies of each Client\".\r\n\r\n_Information sharing:_ Third party sharing may proceed as follows:\r\n\r\n* Third-party agents working as subprocessors (who must adhere to mParticle's privacy policy)\r\n* \"To protect the rights and property of mParticle, our agents, Clients and others \"\r\n* \"In an emergency, including protection of the personal safety of any person\"\r\n* \"For the purposes of a business deal (or negotiation of a business deal) involving sale or transfer of all or a part of our business or assets\"\r\n* In response to a lawful request by public authorities\r\n* mParticle \"may also share aggregate or anonymous information without restriction\"\r\n\r\n_Security:_ mParticle asserts that they take reasonable steps to protect information. They state, \"We encrypt transmission of data on pages where you provide payment information or otherwise provide sensitive information. However, no security or encryption method can be guaranteed to protect information from hackers or human error. Information we collect may be stored or processed on computers located in any country where we do business\".\r\n\r\n_Data retention:_ mParticle \"retains Client data for so long as you remain are a Client and will delete Client\u2019s information within 12 months of either party\u2019s termination of applicable Client agreement upon written request. We retain User level data on the Platform as directed by our Clients and for a reasonable time thereafter for audit purposes and as otherwise required by law\".\r\n\r\n_Opt-out:_ mParticle has an email-based opt-out procedure for Clients, but does not list opt-out procedures for End Users on its Privacy Policy web page. The opt-out procedure for Clients is as follows: \"You may opt out of receiving promotional emails from mParticle by following the instructions in those emails. If you opt out, we may still send you non-promotional emails, such as emails about your mParticle projects or our ongoing business relationship. An individual wishing to limit the use or sharing of their data should contact email support@mparticle.com. mParticle will respond within ninety (90) days to any request to delete your information. Individuals who have provided information directly to one of mParticle\u2019s Clients must send follow-up requests to change or delete such information to that particular mParticle Client\"\r\n\r\n_International law:_ mParticle complies with the EU-US Privacy Shield Framework and the Swiss-US Privacy Shield Framework [mParticle, 12](https://www.mparticle.com/privacypolicy).\r\n\r\n## Relationships\r\n_Customers:_ Airbnb / King / Spotify / Jet / EA / SeatGeek / Ticketmaster / Gilt / Bleacher Report / Chick-fil-A / Postmates / Lilly Pulitzer [mParticle, 01](https://www.mparticle.com) / Venmo / Via / Stash / Starwood Preferred Guest / Draft / StockTwits / OKCupid / NBCUniversal / Turner / theSkimm / Lakes Fifth Avenue / Lululemon Athletica / Goat / Live Nation [mParticle, 02](https://www.mparticle.com/customers) / Walmart [mParticle, 03](https://www.mparticle.com/news/mparticle-gartner-magic-quadrant-digital-marketing-hubs) / iHeartRadio / Starwood / SoulCycle [mParticle, 04](https://www.mparticle.com/news/mparticle-raises-15-million-series-a-led-by-social-capital) \r\n\r\n_Integrations:_ mParticle offers \"Full-featured integrations with the top marketing, advertising, analytics, and data warehousing platforms\". Integrations include: Amazon Redshift / Amplitude / Appboy / Kahuna / Kochava / SendGrid [mParticle, 04](https://www.mparticle.com/news/mparticle-raises-15-million-series-a-led-by-social-capital) / Facebook / Snap / Twitter / TUNE / Adobe Marketing Cloud / Oracle Marketing Cloud / Salesforce Marketing Cloud / Zendesk / MailChimp / Google Analytics / Looker / Mixpanel / comScore [mParticle, 01](https://www.mparticle.com). For a detailed database of integrations, see [mParticle, 09](https://www.mparticle.com/integrations).\r\n\r\n_Key partnerships:_ Some key partnerships include integration with SafeGraph [mParticle, 10](https://www.mparticle.com/integrations/integration-safegraph) and Salesforce Marketing Cloud [mParticle, 11](https://www.mparticle.com/blog/salesforce-partnership).\r\n\r\n## Details\r\n_Financial details:_ mParticle was founded in 2013 and has raised over $76 million from funders [Crunchbase, 01](https://www.crunchbase.com/organization/mparticle). \r\n\r\n_Location-based tracking:_ Via, an \"on-demand ride-sharing app based in NYC\", integrates with mParticle for geofencing services [mParticle, 13](https://www.mparticle.com/blog/via-predictive-analytics-radar).\r\n\r\n## References\r\n* _mParticle, 01._ [https://www.mparticle.com](https://www.mparticle.com) \r\n* _mParticle, 02._ [https://www.mparticle.com/customers](https://www.mparticle.com/customers) \r\n* _mParticle, 03._ [https://www.mparticle.com/news/mparticle-gartner-magic-quadrant-digital-marketing-hubs](https://www.mparticle.com/news/mparticle-gartner-magic-quadrant-digital-marketing-hubs) \r\n* _mParticle, 04._ [https://www.mparticle.com/news/mparticle-raises-15-million-series-a-led-by-social-capital](https://www.mparticle.com/news/mparticle-raises-15-million-series-a-led-by-social-capital) \r\n* _mParticle, 05._ [https://www.mparticle.com/product](https://www.mparticle.com/product) \r\n* _mParticle, 06._ [https://www.mparticle.com/marketer](https://www.mparticle.com/marketer) \r\n* _mParticle, 07._ [https://www.mparticle.com/productmanager](https://www.mparticle.com/productmanager) \r\n* _mParticle, 08._ [https://www.mparticle.com/analytics](https://www.mparticle.com/analytics) \r\n* _mParticle, 09._ [https://www.mparticle.com/integrations](https://www.mparticle.com/integrations) \r\n* _mParticle, 10._ [https://www.mparticle.com/integrations/integration-safegraph](https://www.mparticle.com/integrations/integration-safegraph) \r\n* _mParticle, 11._ [https://www.mparticle.com/blog/salesforce-partnership](https://www.mparticle.com/blog/salesforce-partnership)\r\n\r\n## External Links\r\n* _Crunchbase (mParticle):_ [https://www.crunchbase.com/organization/mparticle](https://www.crunchbase.com/organization/mparticle)", "id": 18, "code_signature": "com.mparticle", "website": "http://MParticle.com", "name": "MParticle", "network_signature": "mparticle\\.com", "creation_date": "2017-09-24"}, "20": {"description": "## Websites\r\n * http://www.s4m.io/", "id": 20, "code_signature": "com.sam4mobile.", "website": "http://www.s4m.io/", "name": "S4M", "network_signature": "sam4m\\.com|s4m.io", "creation_date": "2017-09-24"}, "22": {"description": "\"Sizmek (NASDAQ: SZMK) fuels digital advertising campaigns for advertisers and agencies around the world with the most cutting-edge technology to engage audiences across any screen. ...Sizmek has proudly pioneered industry firsts in digital, including rich media, video and online targeted advertising across channels. Sizmek's open ad management stack delivers the most creative and impactful multiscreen digital campaigns, across mobile, display, rich media, video and social, all powered by an unrivaled data engine.\"\r\n\r\n[Privacy Policy](http://www.sizmek.com/privacy-policy/)\r\n\r\n## Data Collected\r\n * Anonymous (Browser Information, Date/Time, Demographic Data, Hardware/Software Type, Page Views )\r\n * Pseudonymous (IP Address (EU PII), Location Based Data)\r\n\r\n## Data Sharing\r\nAnonymous data is shared with 3rd parties., PII data is shared with 3rd parties.\r\n\r\n## Data Retention\r\n0-3 Months\r\n\r\n[source Ghostery](https://apps.ghostery.com/en/apps/sizmek)", "id": 22, "code_signature": ".sizmek.", "website": "https://www.sizmek.com", "name": "Sizmek", "network_signature": "serving-sys\\.com", "creation_date": "2017-09-24"}, "23": {"description": "## Websites\r\n * https://batch.com", "id": 23, "code_signature": "com.batch.android.", "website": "https://batch.com", "name": "Batch", "network_signature": "batch\\.com", "creation_date": "2017-09-24"}, "24": {"description": "## Websites\r\n * https://www.sync2ad.com/\r\n\r\n## Infos\r\n * https://www.crunchbase.com/organization/sync2television#/entity", "id": 24, "code_signature": "com.visiware.sync2ad.dmp.", "website": "https://www.sync2ad.com/", "name": "Sync2Ad", "network_signature": "sync2ad\\.com", "creation_date": "2017-09-24"}, "25": {"description": "## Primary Location\r\nUnited States\r\n\r\n## Website\r\n[https://developer.yahoo.com](https://developer.yahoo.com)\r\n\r\n## About\r\nFlurry is part of the Yahoo Developer network suite. Flurry's product, Flurry Analytics, offers mobile analytics, monetization, and advertising services [Yahoo, 01](https://developer.yahoo.com/analytics); [Yahoo, 14](https://developer.yahoo.com/flurry/docs); [Wikipedia, 01](https://en.wikipedia.org/wiki/Flurry_(company)).\r\n\r\n## Ownership\r\nOath Inc. (subsidiary of Verizon Communications; Oath includes Yahoo and AOL) [Wikipedia, 01](https://en.wikipedia.org/wiki/Oath_Inc.); [Ars Technica, 01](https://arstechnica.com/information-technology/2017/06/oath-verizon-completes-4-5-billion-buy-of-yahoo-and-merges-it-with-aol)\r\n\r\n## Products and Services\r\nFlurry Analytics:\r\n\r\n* Utilizes tracking to analyze user interaction, correlating with other users\r\n* Groups and correlates user data\r\n* Tracks in-app actions of users\r\n* Segments users\r\n* Funnels users into specific in-app paths\r\n* Monitors user churn and retention\r\n* Determines user \"personas\"\r\n* Predicts user demographics\r\n* Monitors user acquisition efforts\r\n* Measures the impact of advertising campaigns or channels [Yahoo, 02](https://developer.yahoo.com/analytics/features.html).\r\n\r\nAnalytics services cover in-app behaviors like \"making a purchase, playing a song, or sharing on Facebook\" [Yahoo, 03](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/events/android). \r\n\r\nFlurry Pulse provides \"the ability to share your app data with integrated partners\" [Yahoo, 13](https://developer.yahoo.com/flurry-pulse). \r\n\r\n## Privacy Policy\r\n_Data sharing:_ As of September 18, 2017, Yahoo stated that Yahoo and Oath \"plan to share some user information within the Verizon family of companies which will enable us to integrate our business, allowing us to coordinate more and improve your experiences\". Yahoo further explained, \"We will share the same information that our companies have previously collected and used for the development and operation of our products and services. This may include your account registration information (such as your user ID, gender, name, email address, postcode & age), your content and advertising interests, content associated with your account, the types of services you use and how you engage with them, cookie and device IDs, IP addresses, geolocation information and activity information from across our websites, apps, software and other services. All of the information that we collect about you may be shared across the various Oath brands and within our Verizon family of companies\" [Yahoo, 02](https://policies.yahoo.com/ie/en/yahoo/privacy/euoathnoticefaq). \r\n\r\nYahoo shares data with third parties, and allows third parties to place tracking technologies like cookies, web beacons, applicaitons (or \"widgets), SDKs, and similar technologies on Yahoo sites and apps. Yahoo adds that \"We do not share your personally identifiable information from your Yahoo account with our advertisers or our partners as part of our analytics programs. We may, however, share pseudonymous information - including demographic information - with our advertisers or partners\" [Yahoo, 04](https://policies.yahoo.com/ie/en/yahoo/privacy/topics/thirdparties/index.htm). \r\n\r\n_Opt-out:_ Yahoo offers an option to opt out of \"interest-based advertising, analysis of communications content for advertising purposes, and the sharing of your information with partners for data matching and appends using the tools\" on their Ad Interest Manager website. This includes \"Your advertising choices\" both \"across the web\" and \"On Yahoo\" [Yahoo, 05](https://aim.yahoo.com/aim/ie/en/optout). Their Privacy Controls page offers settings for Marketing Preferences, Ad Interest Manager, Content preferences, Search history, and Location management [Yahoo, 06](https://policies.yahoo.com/ie/en/yahoo/privacy/tools/index.htm). \r\n\r\n\"You must allow cookies from Yahoo in order to opt out. To make your opt-out apply to every computer that you use, you must be signed in to your Yahoo account\". Yahoo's opt out page also includes \"Your interest categories\" [Yahoo, 05](https://aim.yahoo.com/aim/ie/en/optout).\r\n\r\nYahoo offers opt-out options for third parties, including the recommendation to visit their websites individually [Yahoo, 04](https://policies.yahoo.com/ie/en/yahoo/privacy/topics/thirdparties/index.htm).\r\n\r\n## Relationships\r\n_Yahoo partners:_ Adxpose (comScore product) / Audience Science / comScore/ScorecardResearch / DoubleVerify / Integral Ads / KN Dimestore / Nielsen / Facebook / Google+ / LinkedIn / Pinterest / Twitter / 30 Boxes / Amazon / Basil (Backstage Technologies) / Bunchball Games / ChitChat (Monusoft) / CoverGirl Beauty Consultant Live Chat / Dropbox / eBay / enDICEr / Love Match/Fun Center (B4U.com) / NDCSA / NewsGator / OtherInBox / Pandaf Games / StumbleUpon / WackyB Twitter Sync / WebEx Co-Browse / YouSendIt / ABC / Astrology.com/iVillage / Cars.com / Healthline / Match.com / Monster Inc. / Nokia Maps / Orbitz / PriceGrabber / Shopzilla / Spotify / Team Fan Shop (Pro Football Weekly) / Tenor / TripAdvisor / TrueCar / Turner / Vast (Autos) / Zillow / ABC News / Blastro.com / Blip.tv / CNBC / CNN / CollegeHumor.com / Dailymotion / Ebaumsworld.com / Ehow.com / Fox News / Gametrailers.com / Good Morning America / Guardian News / Hulu / Metacafe / Metatube.com / Myspace.com / NBC / NFL / PBS / Ustream / Vevo / Videobash.com / Vimeo / Washington Post / Worldstarhiphop.com / YouTube / Chitika / Google / Media.net / Microsoft / NetSeer / Yandex / Abaca Technology Corporation / AOL / Authentication Metrics / Aviary / Bankrate / Bloomreach (Commerce SEO) / Branch.io / Detroit Trading Company / Dropbox / Google / HelloWorld, Inc. / HortonWorks / Lashback / Luminate / Manilla / Outbrain / Paypal / Project Slice / SigFig / Symantec / Trend Micro / Truedomain / Urban Airship / Vantage (Yahoo Real Estate) [Yahoo, 04](https://policies.yahoo.com/ie/en/yahoo/privacy/topics/thirdparties/index.htm)\r\n\r\n## Details\r\n_Financial Details:_ Flurry was founded in 2005. By December 2013, it had raised $62.5 million [TechCrunch, 01](https://techcrunch.com/2013/12/06/flurry-funding). On July 21, 2014 Yahoo bought Flurry for a reported $200-300 million [TechCrunch, 02](https://techcrunch.com/2014/07/21/yahoo-is-buying-mobile-analytics-firm-flurry-for-north-of-200m). Flurry partnered with Research Now, a digital data collecting firm, in 2014, for the purpose of \"to track mobile app users, offline\" [AdAge, 01](http://adage.com/article/digital/flurry-research-build-mobile-app-advertising-database/292287). \r\n\r\n_Scope:_ By December 6, 2013, Flurry told TechCrunch \"400,000 apps are using its analytics product, with 20,000 additions each month, and that it's tracking activity from 1.2 billion smartphones and tablets. It also said that it's working with 125,000 developers\" [TechCrunch, 01](https://techcrunch.com/2013/12/06/flurry-funding). \r\n\r\n_Additional services:_ Additional Flurry Analytics features for Android include:\r\n\r\n* Revenue Analytics [Yahoo, 07](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/revenue/android)\r\n* Crash Analytics [Yahoo, 08](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/trackcrashes/android)\r\n* Track Geographic Location (at the city level where the app is being used; or, without that level of detail, the country level as based on IP address)\r\n* Track user ID and demographics\r\n* Track page views [Yahoo, 09](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/technicalquickstart/android)\r\n* Object-based API for Native, Interstatial and Banner ads [Yahoo, 10](https://developer.yahoo.com/flurry/docs/publisher/code/android-ad-publishing)\r\n* User paths reporting [Yahoo, 11](https://developer.yahoo.com/flurry/docs/analytics/lexicon/analyticsusage)\r\n* Utilizes mobile SDK in apps to inject advertising, including video: \"Monetize your app with native and video ads from Yahoo, Flurry, and BrightRoll advertisers\" [Yahoo, 12](https://developer.yahoo.com/monetize)\r\n\r\n## References\r\n* _AdAge, 01_. [http://adage.com/article/digital/flurry-research-build-mobile-app-advertising-database/292287](http://adage.com/article/digital/flurry-research-build-mobile-app-advertising-database/292287) \r\n* _Ars Technica, 01_. [https://arstechnica.com/information-technology/2017/06/oath-verizon-completes-4-5-billion-buy-of-yahoo-and-merges-it-with-aol](https://arstechnica.com/information-technology/2017/06/oath-verizon-completes-4-5-billion-buy-of-yahoo-and-merges-it-with-aol) \r\n* _TechCrunch, 01_. [https://techcrunch.com/2013/12/06/flurry-funding](https://techcrunch.com/2013/12/06/flurry-funding) \r\n* _TechCrunch, 02_. [https://techcrunch.com/2014/07/21/yahoo-is-buying-mobile-analytics-firm-flurry-for-north-of-200m](https://techcrunch.com/2014/07/21/yahoo-is-buying-mobile-analytics-firm-flurry-for-north-of-200m) \r\n* _Yahoo, 01_. [https://developer.yahoo.com/analytics](https://developer.yahoo.com/analytics) \r\n* _Yahoo, 02_. [https://policies.yahoo.com/ie/en/yahoo/privacy/euoathnoticefaq](https://policies.yahoo.com/ie/en/yahoo/privacy/euoathnoticefaq) \r\n* _Yahoo, 03_. [https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/events/android](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/events/android) \r\n* _Yahoo, 04_. [https://policies.yahoo.com/ie/en/yahoo/privacy/topics/thirdparties/index.htm](https://policies.yahoo.com/ie/en/yahoo/privacy/topics/thirdparties/index.htm) \r\n* _Yahoo, 05_. [https://aim.yahoo.com/aim/ie/en/optout](https://aim.yahoo.com/aim/ie/en/optout) \r\n* _Yahoo, 06_. [https://policies.yahoo.com/ie/en/yahoo/privacy/tools/index.htm](https://policies.yahoo.com/ie/en/yahoo/privacy/tools/index.htm) \r\n* _Yahoo, 07_. [https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/revenue/android](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/revenue/android) \r\n* _Yahoo, 08_. [https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/trackcrashes/android](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/trackcrashes/android) \r\n* _Yahoo, 09_. [https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/technicalquickstart/android](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/technicalquickstart/android) \r\n* _Yahoo, 10_. [https://developer.yahoo.com/flurry/docs/publisher/code/android-ad-publishing](https://developer.yahoo.com/flurry/docs/publisher/code/android-ad-publishing) \r\n* _Yahoo, 11_. [https://developer.yahoo.com/flurry/docs/analytics/lexicon/analyticsusage](https://developer.yahoo.com/flurry/docs/analytics/lexicon/analyticsusage) \r\n* _Yahoo, 12_. [https://developer.yahoo.com/monetize](https://developer.yahoo.com/monetize) \r\n* _Yahoo, 13_. [https://developer.yahoo.com/flurry-pulse](https://developer.yahoo.com/flurry-pulse) \r\n* _Yahoo, 14_. [https://developer.yahoo.com/flurry/docs](https://developer.yahoo.com/flurry/docs)\r\n\r\n## External links\r\n* _Ghostery_: [https://apps.ghostery.com/apps/flurry](https://apps.ghostery.com/apps/flurry) \r\n* _Wikipedia_: [https://en.wikipedia.org/wiki/Flurry_(company)](https://en.wikipedia.org/wiki/Flurry_(company)) \r\n* _Flurry FAQ_: [https://developer.yahoo.com/flurry/docs/faq](https://developer.yahoo.com/flurry/docs/faq)\r\n* _AppBrain_: [https://www.appbrain.com/dev/Yahoo/](https://archive.is/7BNpX)", "id": 25, "code_signature": "com.flurry.", "website": "https://developer.yahoo.com/flurry/", "name": "Flurry", "network_signature": "flurry\\.com", "creation_date": "2017-09-24"}, "26": {"description": "## Primary Location\r\nMicrosoft: United States (Seattle) / Bit Stadium: Germany (Stuttgart) [Crunchbase, 01](https://www.crunchbase.com/organization/bit-stadium-gmbh)\r\n\r\n## Website\r\n[https://www.hockeyapp.net](https://www.hockeyapp.net)\r\n\r\n## About\r\nHockeyApp is utilized for crash reporting, app distribution, user feedback, and the collection of user metrics. \"HockeyApp is a service for app developers to support them in various aspects of their development process, including the management and recruitment of testers, the distribution of apps and the collection of crash reports.\" [HockeyApp 01](https://support.hockeyapp.net/kb/general-account-management-2/general-questions)\r\n\r\n## Ownership\r\nBit Stadium is a subsidiary of Microsoft [Bloomberg, 01](https://www.bloomberg.com/research/stocks/private/snapshot.asp?privcapId=279701634)\r\n\r\n## Documentation\r\n[https://support.hockeyapp.net/kb/client-integration-android/hockeyapp-for-android-sdk](https://support.hockeyapp.net/kb/client-integration-android/hockeyapp-for-android-sdk)\r\n\r\n## What it does\r\nAnalyzes user behavior and app usage. \"Understand user behavior to improve your\r\napp. Track app adoption through daily active users, monthly active users, and net\r\nnew users. Measure customer engagement through session count and verify your apps\r\nreliability day by day with Crash Free Users.\" [HockeyApp, 02](https://www.hockeyapp.net/features/user-metrics/)\r\n\r\n\"When enabled, the SDK anonymously tracks the users of your app by creating a UUID that is then securely stored. The UUID is securely stored in the preferences of the client app.\" [HockeyApp, 03](https://support.hockeyapp.net/kb/app-management-2/what-data-is-collected-with-the-hockeysdks-2#data-collected-for-the-user-metrics-features)\r\n\r\n## Privacy Policy\r\n\r\nMicrosoft Privacy Statement [https://privacy.microsoft.com/en-us/PrivacyStatement](https://privacy.microsoft.com/en-us/PrivacyStatement)\r\n\r\nDevelopers can opt out of statistical analysis of their app's users. \"Just in case you want to opt-out of the automatic collection of anonymous users and sessions statistics, there is a way to turn this functionality off at any time.\" [HockeyApp, 04](https://support.hockeyapp.net/kb/general-account-management-2/getting-started-with-user-metrics)\r\n\r\n## Details\r\n\r\nHockeyApp was launched in 2012. It was acquired by Microsoft in 2014 [Crunchbase, 01](https://www.crunchbase.com/organization/bit-stadium-gmbh). The company existed in some form in 2011, with Microsoft as a customer [HockeyApp, 05](https://www.hockeyapp.net/blog/2014/12/11/hockeyapp-joins-microsoft.html).\r\n\r\n\"HockeyApp does not collect any PII (Personable Identifiable Information) and the user tracking is done anonymously... Keep in mind that whenever the HockeySDK sends metric data to our backend, a corresponding app version gets automatically added to the app.\" [HockeyApp, 04](https://support.hockeyapp.net/kb/general-account-management-2/getting-started-with-user-metrics)\r\n\r\n\"You can get more insights into user behavior for the testers of your app. You can see basic user metrics, gauge customer engagements and even check your app\u2019s reliability throughout the day. More than that, you can drill down on the users that have experienced a particular crash type or a crash that happened during a specific time period. This will help you know if the crash has affected a lot of people over a cross section of your users or if there are specific groups of people who experience the same type of crashes repeatedly.\" [Stackify, 01](https://stackify.com/what-is-hockeyapp/)\r\n\r\n## References\r\n* _HockeyApp, 01._ [https://support.hockeyapp.net/kb/general-account-management-2/general-questions](https://support.hockeyapp.net/kb/general-account-management-2/general-questions)\r\n* _HockeyApp, 02._ [https://www.hockeyapp.net/features/user-metrics/](https://www.hockeyapp.net/features/user-metrics/)\r\n* _HockeyApp, 03._ [https://support.hockeyapp.net/kb/app-management-2/what-data-is-collected-with-the-hockeysdks-2#data-collected-for-the-user-metrics-features](https://support.hockeyapp.net/kb/app-management-2/what-data-is-collected-with-the-hockeysdks-2#data-collected-for-the-user-metrics-features)\r\n* _HockeyApp, 04._ [https://support.hockeyapp.net/kb/general-account-management-2/getting-started-with-user-metrics](https://support.hockeyapp.net/kb/general-account-management-2/getting-started-with-user-metrics)\r\n* _HockeyApp, 05._ [https://www.hockeyapp.net/blog/2014/12/11/hockeyapp-joins-microsoft.html](https://www.hockeyapp.net/blog/2014/12/11/hockeyapp-joins-microsoft.html)\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/bit-stadium-gmbh](https://www.crunchbase.com/organization/bit-stadium-gmbh)\r\n* _Bloomberg, 01._ [https://www.bloomberg.com/research/stocks/private/snapshot.asp?privcapId=279701634](https://www.bloomberg.com/research/stocks/private/snapshot.asp?privcapId=279701634)\r\n* _Stackify, 01._ [https://stackify.com/what-is-hockeyapp/](https://stackify.com/what-is-hockeyapp/)\r\n\r\n## External Links\r\n* _Crunchbase (HockeyApp):_ [https://www.crunchbase.com/organization/bit-stadium-gmbh](https://www.crunchbase.com/organization/bit-stadium-gmbh)\r\n* _Wikipedia (List of mergers and acquisitions by Microsoft):_ [https://en.wikipedia.org/wiki/List_of_mergers_and_acquisitions_by_Microsoft#cite_note-195](https://en.wikipedia.org/wiki/List_of_mergers_and_acquisitions_by_Microsoft#cite_note-195)\r\n* _Owler company profile:_ [https://www.owler.com/iaApp/1149223/hockeyapp-company-profile](https://www.owler.com/iaApp/1149223/hockeyapp-company-profile)", "id": 26, "code_signature": "net.hockeyapp.", "website": "http://hockeyapp.net", "name": "HockeyApp", "network_signature": "hockeyapp\\.net", "creation_date": "2017-09-24"}, "27": {"description": "## Primary Location\r\nUnited States (Boston) [Crunchbase, 01](https://www.crunchbase.com/organization/crashlytics)\r\n\r\n## Website\r\n[http://try.crashlytics.com](http://try.crashlytics.com)\r\n\r\n## About\r\nCrashlytics offers a crash reporting solution for app developers.\r\n\r\n## Ownership\r\nGoogle [Recode, 01](https://www.recode.net/2017/1/18/14313164/google-twitter-acquisition-fabric-crashlytics)\r\n\r\n## Documentation\r\n[https://fabric.io/kits/android/crashlytics](https://fabric.io/kits/android/crashlytics)\r\n\r\n## Products and Services\r\nCrashlytics offers a variety of services for app developers. Crashlytics:\r\n\r\n* Receives and analyzes app crash reports which may contain user and device-specific data.\r\n\r\n* Performs analytics on app logs \"even the exact line of code your app crashed on\" [Crashlytics, 03](https://fabric.io/kits/ios/crashlytics)\r\n\r\n* Performs analytics on app users and utilizes social media advertising. \"Get insight into your users, what they\u2019re doing, and inject live social content to delight them\" [Fabric, 01](https://get.fabric.io)\r\n\r\n* Performs cross-device user identity and authentication via \"Fabric\" [Wired, 01](https://www.wired.com/2014/10/twitter-fabric-sdk)\r\n\r\n## Privacy Policy\r\nCrashlytics Privacy Policy can be viewed at [Crashlytics, 04](https://try.crashlytics.com/terms/privacy-policy.pdf).\r\n\r\n## Relationships\r\n_Customers:_ Square / Walmart / Paypal / Yelp / Paperless Post / Blackboard / Path / Groupon / Domino's / Expedia / Orbitz / Kayak / 5 Infinity / Waze / OpenTable [Crashlytics, 01](https://try.crashlytics.com)\r\n\r\n_Integrations:_ Redmine / Pivotal Tracker / Jira / PagerDuty / Asana / OpsGenie / GitHub / Campfire / Sprintly / Hall / YouTrack / Bitbucket / Trello / FogBugz / Zoho / Slack / GitLab / Asana / YouTrack / Sprint.ly / Bitbucket / HipChat [Crashlytics, 02](http://try.crashlytics.com/integrations)\r\n\r\n## Details\r\n_Financial details:_ Crashlytics was founded in 2011 and had raised $6 million from funders. Twitter acquired Crashlytics in in 2013 for a reported $38 million [Crunchbase, 01](https://www.crunchbase.com/organization/crashlytics); [Boston Business Journal, 01](https://www.bizjournals.com/boston/blog/techflash/2013/10/twitter-crashlytics-bluefin-labs.html). In 2017, Google acquired Twitter's developer suite Fabric, which included Crashlytics, for integration into Google Firebase. The details of the deal were not publicly disclosed [Recode, 01](https://www.recode.net/2017/1/18/14313164/google-twitter-acquisition-fabric-crashlytics). Crashlytics is a business division of Google, Inc. [Crashlytics, 04](https://try.crashlytics.com/terms/privacy-policy.pdf).\r\n\r\n## References\r\n* _Boston Business Journal, 01._ [https://www.bizjournals.com/boston/blog/techflash/2013/10/twitter-crashlytics-bluefin-labs.html](https://www.bizjournals.com/boston/blog/techflash/2013/10/twitter-crashlytics-bluefin-labs.html) \r\n* _Crashlytics, 01._ [https://try.crashlytics.com](https://try.crashlytics.com) \r\n* _Crashlytics, 02._ [http://try.crashlytics.com/integrations](http://try.crashlytics.com/integrations) \r\n* _Crashlytics, 03._ [https://fabric.io/kits/ios/crashlytics](https://fabric.io/kits/ios/crashlytics) \r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/crashlytics](https://www.crunchbase.com/organization/crashlytics) \r\n* _Fabric, 01._ [https://get.fabric.io](https://get.fabric.io) \r\n* _Recode, 01._ [https://www.recode.net/2017/1/18/14313164/google-twitter-acquisition-fabric-crashlytics](https://www.recode.net/2017/1/18/14313164/google-twitter-acquisition-fabric-crashlytics) \r\n* _Wired, 01._ [https://www.wired.com/2014/10/twitter-fabric-sdk](https://www.wired.com/2014/10/twitter-fabric-sdk) \r\n\r\n## External Links\r\n* _Crunchbase (Crashlytics):_ [https://www.crunchbase.com/organization/crashlytics](https://www.crunchbase.com/organization/crashlytics) \r\n* _Wikipedia (Crashlytics):_ [https://en.wikipedia.org/wiki/Crashlytics](https://en.wikipedia.org/wiki/Crashlytics) \r\n* _TechCrunch, 01:_ [https://techcrunch.com/2013/01/28/twitter-acquires-crash-reporting-tool-crashalytics-development-of-the-product-will-continue-unabated](https://techcrunch.com/2013/01/28/twitter-acquires-crash-reporting-tool-crashalytics-development-of-the-product-will-continue-unabated) \r\n* _Fabric, 02:_ [https://blog.twitter.com/developer/en_us/a/2015/fabric-leading-the-sdk-market-in-performance-and-mobile-analytics.html](https://blog.twitter.com/developer/en_us/a/2015/fabric-leading-the-sdk-market-in-performance-and-mobile-analytics.html) \r\n* _The Register, 01:_ [https://www.theregister.co.uk/2017/01/19/google_buys_twitters_mobile_app_development_team_fabric](https://www.theregister.co.uk/2017/01/19/google_buys_twitters_mobile_app_development_team_fabric)", "id": 27, "code_signature": "io.fabric.|com.crashlytics.", "website": "http://crashlytics.com", "name": "Google CrashLytics", "network_signature": "crashlytics\\.com", "creation_date": "2017-09-24"}, "28": {"description": "## Primary Location\r\nUnited States (San Francisco)\r\n\r\n## Website\r\n[https://www.leanplum.com](https://www.leanplum.com)\r\n\r\n## About\r\nLeanplum offers a mobile marketing platform with solutions for mobile messaging, in-app experiences, and detailed analytics.\r\n\r\n## Ownership\r\nLeanplum\r\n\r\n## Documentation\r\n[https://www.leanplum.com/docs/android](https://www.leanplum.com/docs/android)\r\n\r\n## Products and Services\r\nLeanplum has a number of services. They include:\r\n\r\n* _Messaging:_ Send push notifications, in-app messages, email, and more, using wide broadcasts or personalized content. Deliver messages with \"triggers or drip campaigns across the customer lifecycle\". Other targeting strategies include \"onboarding, engagement, conversion, reactivation, and loyalty\" [Leanplum, 05](https://www.leanplum.com/platform/push-notifications-messaging).\r\n* _Mobile Marketing Automation:_ Create \"context-rich campaigns that understand and respond to user actions\". Target users based on \"what users do and who they are\", and engage along the full customer journey. Tailor interactions based on behavior, location, timing, and channel. Automate self-activating messages in response to \"personalized behaviors\" [Leanplum, 06](https://www.leanplum.com/platform/mobile-marketing-automation).\r\n* _App Experience Command Center:_ A mobile content management system [Leanplum, 07](https://www.leanplum.com/platform/app-editor).\r\n* _App Personalization:_ Leanplum \"provides context and personalization enabled by individual user profiles that get richer over time. Demographic, behavior, location, time, and external data provide the deep insights that power relevance. The key to meaningful engagement is understanding who users are and what they do inside your app.\" They \"capture limitless user events and behaviors to fuel highly contextual messaging campaigns\" [Leanplum, 08](https://www.leanplum.com/platform/personalization).\r\n* _A/B Testing:_ Leanplum claims to have \"the most extensive mobile A/B testing solution in the industry\". Their product \"comes equipped with the ability to run A/B and multivariate tests\" to maximize return on investment [Leanplum, 09](https://www.leanplum.com/platform/mobile-ab-testing-optimization).\r\n* _Analytics:_ Leanplum's approach is to \"capture all events and behaviors associated with a user, without limits or data point costs\" in order to \"inspire real-time action\". Clients can \"customize parameters, reports, and metrics\". Insights examine \"engagement, retention, revenue, uninstalls, and more\" [Leanplum, 10](https://www.leanplum.com/platform/mobile-app-analytics).\r\n\r\nLeanplum gathers detailed user profile information and correlates with behavioral data [Leanplum, 11](https://leanplum-wordpress.storage.googleapis.com/Pers_new@1x-min.png). Their platoform is \"built on a foundation of A/B Testing and Analytics\" to deliver \"deep customer understanding\" [Leanplum, 12](https://www.leanplum.com/platform).\r\n\r\n## Privacy Policy\r\nIt is not clear if Leanplum's Privacy Policy listed on its website also applies to its mobile tracker. The Privacy Policy posted on their website covers a number of topics:\r\n\r\n_PII collection:_ Leanplum collects both PII (\"personal information\") and non-PII data. They collect information that is voluntarily provided (eg, through email newsletters, accounts, or profiles users sign up for), passively provided (eg, IP address, mobile device ID, server logs, cookies, web beacons, user actions like clicks, and so on).\r\n\r\n_Third party collection:_ Leanplum \"may receive information about you, including Personal Information, from third parties (e.g., opt-in lists where you have requested information about Leanplum or the Service while visiting a Third-Party Site). We may combine this information with other Personal Information we maintain about you. If we do so, this Policy governs any combined information that we maintain in personally identifiable format\".\r\n\r\n_Data sharing:_ Leanplum states, \"Except as described in this Policy, we will not disclose your Personal Information that we collect on the Service to third parties without your consent. We may disclose your Personal Information to third parties if you consent to us doing so, as well as in...circumstances\" involving service providers, business transfers, the protection of Leanplum's interests, and public authorities.\r\n\r\n_Opt-out:_ Leanplum offers an ability to opt out from the disclosure of information to third parties, as well as for use cases that are \"incompatible with the purpose(s) for which it was originally collected or subsequently authorized\". Individuals must contact Leanplum by email to exercise their choice.\r\n\r\n_Access and retention:_ Individuals with user accounts or profiles on the Leanplum Service can email Leanplum requesting access to their Personal Information; they can also request to amend or update the data. Users can also request Leanplum delete their data. However, Leanplum states they \"may need to retain some of your Personal Information in order to satisfy our legal obligations, or where we reasonably believe that we have a legitimate reason to do so\".\r\n\r\n_International law:_ Leanplum states it is in compliance with the EU-U.S. Privacy Shield and the Swiss-U.S. Privacy Shield.\r\n\r\n_Security:_ Leanplum states it takes reasonable security measures, but also states that \"no data security measures can be guaranteed to be completely effective. Consequently, we cannot ensure or warrant the security of any information that you provide to us. You transmit information to us at your own risk\" [Leanplum, 13](https://www.leanplum.com/privacy).\r\n\r\n## Relationships\r\n_Customers:_ Grab / NBC / QVC / TED / Tinder / Zynga [Leanplum, 01](https://www.leanplum.com) / Bleacher Report / Hotwire / Macy's / Red Bull [Leanplum, 02](https://www.leanplum.com/customers) / Tesco / App Annie / Last Minute Travel / Pixowl / Mixbook / Wanelo / Pixelberry Studios / Big Fish / TextNow / MobilityWare / Fetch Rewards / Via [Leanplum, 03](https://www.leanplum.com/customers/case-studies)\r\n\r\n## Details\r\n_Financial details:_ Leanplum was founded in 2012. It has raised over $93 million [Crunchbase, 01](https://www.crunchbase.com/organization/leanplum). In November 2017, it raised $47 million from investors. The company was founded by former Google engineers [Business Insider, 01](http://www.businessinsider.com/why-i-quit-google-to-become-a-startup-founder-2015-11). \r\n\r\n_Scope:_ Leanplum says it handles 14 billion events per day. \r\n\r\n_Infrastructure:_ Leanplum built their service on the Google Cloud Platform \"to optimize for fault-tolerance and availability\" [Leanplum, 04](https://www.leanplum.com/plans).\r\n\r\n## References\r\n* _Business Insider, 01_. [http://www.businessinsider.com/why-i-quit-google-to-become-a-startup-founder-2015-11](http://www.businessinsider.com/why-i-quit-google-to-become-a-startup-founder-2015-11) \r\n* _Crunchbase, 01_. [https://www.crunchbase.com/organization/leanplum](https://www.crunchbase.com/organization/leanplum) \r\n* _Leanplum, 01_. [https://www.leanplum.com](https://www.leanplum.com) \r\n* _Leanplum, 02_. [https://www.leanplum.com/customers](https://www.leanplum.com/customers) \r\n* _Leanplum, 03_. [https://www.leanplum.com/customers/case-studies](https://www.leanplum.com/customers/case-studies) \r\n* _Leanplum, 04_. [https://www.leanplum.com/plans](https://www.leanplum.com/plans) \r\n* _Leanplum, 05_. [https://www.leanplum.com/platform/push-notifications-messaging](https://www.leanplum.com/platform/push-notifications-messaging) \r\n* _Leanplum, 06_. [https://www.leanplum.com/platform/mobile-marketing-automation](https://www.leanplum.com/platform/mobile-marketing-automation)\r\n* _Leanplum, 07_. [https://www.leanplum.com/platform/app-editor](https://www.leanplum.com/platform/app-editor) \r\n* _Leanplum, 08_. [https://www.leanplum.com/platform/personalization](https://www.leanplum.com/platform/personalization) \r\n* _Leanplum, 09_. [https://www.leanplum.com/platform/mobile-ab-testing-optimization](https://www.leanplum.com/platform/mobile-ab-testing-optimization) \r\n* _Leanplum, 10_. [https://www.leanplum.com/platform/mobile-app-analytics](https://www.leanplum.com/platform/mobile-app-analytics) \r\n* _Leanplum, 11_. [https://leanplum-wordpress.storage.googleapis.com/Pers_new@1x-min.png](https://leanplum-wordpress.storage.googleapis.com/Pers_new@1x-min.png) \r\n* _Leanplum, 12_. [https://www.leanplum.com/platform](https://www.leanplum.com/platform)\r\n\r\n## External Links\r\n* _Crunchbase (Leanplum)_: [https://www.crunchbase.com/organization/leanplum](https://www.crunchbase.com/organization/leanplum)", "id": 28, "code_signature": "com.leanplum.", "website": "https://www.leanplum.com/", "name": "LeanPlum", "network_signature": "leanplum\\.com", "creation_date": "2017-09-24"}, "29": {"description": "## Primary Location\r\nUnited States\r\n\r\n## Website\r\n[https://www.tinder.com](https://www.tinder.com)\r\n\r\n## About\r\nTinder is a location-based social search mobile app geared towards dating and hook-up culture.\r\n\r\n## Ownership\r\nMatch Group (a division of IAC/InterActiveCorp) [BusinessInsider, 01](http://www.businessinsider.com/match-the-company-that-owns-tinder-just-filed-to-go-public-2015-10); [CrunchBase, 01](https://www.crunchbase.com/organization/match-group)\r\n\r\n## Documentation\r\nNot public\r\n\r\n## Products and Services\r\nIt is note entirely clear what the Tinder Analytics SDK does. Some news outlets have published details about Tinder analytical practices, often in conjunction with third parties. Minor press about Tinder and \"swiping right\" offers clues:\r\n\r\n\"Earlier this year, to combat this collection of overzealous swipers, the company set a limit on the number of right swipes users could make daily. Then it rounded up profiles of the most prolific right-swipers and watched what happened. Would they get upset and leave? Would they stop using for a while and lick their wounds? Or would they realize the error in their ways and be a little more discriminating in suggesting possible hookups?\" [Fortune, 01](http://fortune.com/2015/09/29/tinder-interana-analytics/)\r\n\r\n## Privacy Policy\r\nThe privacy policy for the Tinder Analytics SDK tracker is not public. In September 2017, French journalist Judith Duportail published details about her data request from Tinder which revealed that Tinder had 800 pages of information about her. The profile was created over four years of use, and included information about her Facebook \"likes\", links to (now-deleted) Instagram photos, her education, the age-rank of men she was interested in, number of Facebook friends, the when and where of every one of her Tinder match conversations, and more [The Guardian, 01](https://www.theguardian.com/technology/2017/sep/26/tinder-personal-data-dating-app-messages-hacked-sold).\r\n\r\n### General Tinder Privacy Policy\r\n_PII:_ Tinder collects Personal Information (Personally Identifiable Information), including Sensitive Data, and other information. Sensitive Data includes \"information, comments or content (e.g. photographs, video, profile, lifestyle) that you optionally provide that may reveal your ethnic origin, nationality, religion and/or sexual orientation\". Users consent to the \"collection, use, and disclosure of Sensitive Data\" in accordance with the law. \r\n\r\n_Geolocation:_ Tinder states \"We may also collect your geolocation information with your consent. We may collect this information through a website, mobile application, or other online services... the information may be sent to servers located in the United States and countries around the world\". \r\n\r\n_Collection of data through Facebook:_ By registering with Tinder, you authorize Tinder to access certain Facebokk information, such as \"your public Facebook profile (consistent with your privacy settings in Facebook), your email address, interests, likes, gender, birthday, education history, relationship interests, current city, photos, personal description, friend list, and information about and photos of your Facebook friends who might be common Facebook friends with other Tinder users\". \r\n\r\n_Collection of conversations:_ \"If you chat with other Tinder users, you provide us the content of your chats\".\r\n\r\n_Third Party data collection:_ \"Tinder is part of The Match Group family of businesses, which as of the date of this policy includes websites and apps such as OurTime.com, BlackPeopleMeet.com, OkCupid, Twoo, POF, Meetic, LoveScout24, Match and ParPerfeito. We may obtain both personal and non-personal information about you from other Match businesses, business partners and other third parties.\" \r\n\r\n_Technologies used to collect data:_ \r\n\r\n* When visiting Tinder's Service, you automatically provide Tinder with your \"IP address, device ID and type, your browser type and language, the operating system used by your device, access times, your mobile device\u2019s geographic location while our application is actively running, and the referring website address.\"\r\n* _Cookies_ are used track users. They state, \"If we advertise, we (or third parties) may use certain data collected on our Service to show you Tinder advertisements on other sites or applications\".\r\n* _Pixel tags_ (aka, web beacons or clear GIFs) are used in web pages, ads, and emails. These are used to access cookies and track user activities.\r\n* _Mobile device IDs_ are used to store your preferences and track your use of the Tinder app. \r\n * \"Ad companies also use device IDs or Advertising IDs to track your use of the app, track the number of ads displayed, measure ad performance and display ads that are more relevant to you. Analytics companies use device IDs to track information about app usage.\"\r\n\r\n_Third Party data collecting:_ \"We may allow service providers, advertising companies and ad networks, and other third parties to display advertisements on our Service and elsewhere. These companies may use tracking technologies, such as cookies or web beacons, to collect information about users who view or interact with their advertisements. We do not provide any non-masked or non-obscured personal information to third parties.\" \r\n\r\n_Data Sharing with Third Parties:_ Tinder may share information with: \r\n\r\n* _Service providers:_ Third parties that perform services on behalf of Tinder may include \"fulfilling orders, providing customer service and marketing assistance, performing business and sales analysis, ad tracking and analytics, member screenings, supporting our Service functionality, and supporting contests, sweepstakes, surveys and other features offered through our Service. These service providers may have access to personal information needed to perform their functions but are not permitted to share or use such information for any other purposes.\"\r\n* _Other Match Group businesses:_ Including \"Match.com, OkCupid, OurTime.com, BlackPeopleMeet.com, Twoo, Meetic, POF, LoveScout24, ParPerfeito and others... subject to your consent where required under applicable law.\"\r\n* _Other situations:_ Some other situations include actions in response to a subpeona or similar investigative demand; when Tinder believes it is appropriate in connection with illegal activity; and \"In connection with a substantial corporate transaction, such as the sale of our business, a divestiture, merger, consolidation, or asset sale, or in the unlikely event of bankruptcy\". \r\n\r\n_Aggregated and non-personal Information:_ Tinder states, \"We may use and share non-personal information we collect under any of the above circumstances. We may also share it with other Match Group companies and third parties to develop and deliver targeted advertising on our Service and on websites or applications of third parties, and to analyze and report on advertising you see. We may combine non-personal information we collect with additional non-personal information collected from other sources. We also may share aggregated, non-personal information, or personal information in hashed, non-human readable form, with third parties, including advisors, advertisers and investors, for the purpose of conducting general business analysis, advertising, marketing, or other business purposes. For example, we may engage a data provider who may collect web log data from you (including IP address and information about your browser or operating system), or place or recognize a unique cookie on your browser to enable you to receive customized ads or content. The cookies may re\ufb02ect de-identified demographic or other data linked to data you voluntarily have submitted to us (such as your email address), that we may share with a data provider solely in hashed, non-human readable form. We may also share your geolocation information in de-identified form with Match Group companies and third parties for the above purposes.\" \r\n\r\n_Opt-Out (geolocation:_ \"To opt out of the sharing of your geolocation information, please discontinue use of the Tinder application\".\r\n\r\n_Opt-Out (third party):_ Some \"third-party advertising companies may be advertising networks that are members of the Network Advertising Initiative, which offers a single location to opt out of ad targeting from member companies (www.networkadvertising.org). Opting out will not decrease the number of advertisements you see. To opt-out of cookies that may be set by third party data or advertising partners, please go to http://www.aboutads.info/choices\". \r\n\r\n_Security:_ Tinder states that \"although we take steps to secure your information, we do not promise, and you should not expect, that your personal information, chats, or other communications will always remain secure\" \r\n\r\n_Data Retention:_ Tinder states, \"We keep your information only as long as we need it for legitimate business purposes and as permitted by applicable legal requirements. If you close your account, we will retain certain data for analytical purposes and recordkeeping integrity, as well as to prevent fraud, enforce our Terms of Use, take actions we deem necessary to protect the integrity of our Service or our users, or take other actions otherwise permitted by law. In addition, if certain information has already been provided to third parties as described in this Privacy Policy, retention of that information will be subject to those third parties\u2019 policies.\" \r\n\r\n_Jurisdictional issues:_ Tinder states, \"we cannot always know where personal information may be accessed or processed. While our primary data centers are in the United States, we may transfer personal information or other information to our offices outside of the United States. In addition, we may employ other companies and individuals to perform functions on our behalf. If we disclose personal information to a third party or to our employees outside of the United States, we will seek assurances that any information we may provide to them is safeguarded adequately and in accordance with this Privacy Policy and the requirements of applicable privacy laws.\r\n\r\nIf you are visiting from the European Union or other regions with laws governing data collection and use, please note that you are agreeing to the transfer of your personal data, including sensitive data, by Tinder from your region to countries which do not have data protection laws that provide the same level of protection that exists in countries in the European Economic Area, including the United States. By providing your personal information, you consent to any transfer and processing in accordance with this Policy\" [Tinder, 01](https://www.gotinder.com/privacy).\r\n\r\n## Relationships\r\n_Match Group businesses:_ Match.com / OkCupid / OurTime.com / BlackPeopleMeet.com / Twoo / Meetic / POF / LoveScout24 / ParPerfeito [Tinder, 01](https://www.gotinder.com/privacy)\r\n\r\n## Details\r\n_Usage requirements:_ Tinder users are required to have a Facebook account and turn on loction-based tracking in order to use the app. [Tinder, 01](https://www.gotinder.com/privacy) \r\n\r\n_Analytics:_ Tinder uses Spotify and Facebook data to match users [Tech Times, 01](http://www.techtimes.com/articles/199964/20170302/tinder-users-finding-more-matches-thanks-spotify-popular-anthems-include.htm)\r\n\r\n## References\r\n* _BusinessInsider, 01._ [http://www.businessinsider.com/match-the-company-that-owns-tinder-just-filed-to-go-public-2015-10](http://www.businessinsider.com/match-the-company-that-owns-tinder-just-filed-to-go-public-2015-10) \r\n* _CrunchBase, 01._ [https://www.crunchbase.com/organization/match-group](https://www.crunchbase.com/organization/match-group) \r\n* _Fortune, 01._ [http://fortune.com/2015/09/29/tinder-interana-analytics/](http://fortune.com/2015/09/29/tinder-interana-analytics/])\r\n* _Tech Times, 01._ [http://www.techtimes.com/articles/199964/20170302/tinder-users-finding-more-matches-thanks-spotify-popular-anthems-include.htm](http://www.techtimes.com/articles/199964/20170302/tinder-users-finding-more-matches-thanks-spotify-popular-anthems-include.htm) \r\n* _The Guardian, 01._ [https://www.theguardian.com/technology/2017/sep/26/tinder-personal-data-dating-app-messages-hacked-sold](https://www.theguardian.com/technology/2017/sep/26/tinder-personal-data-dating-app-messages-hacked-sold) \r\n* _Tinder, 01._ [https://www.gotinder.com/privacy](https://www.gotinder.com/privacy)\r\n\r\n## External Links\r\n* _Wikipedia (Tinder app):_ [https://en.wikipedia.org/wiki/Tinder_(app)](https://en.wikipedia.org/wiki/Tinder_(app))", "id": 29, "code_signature": "com.tinder.analytics|com.tinder.ads", "website": "http://tinder.com", "name": "Tinder Analytics", "network_signature": "etl\\.tindersparks\\.com", "creation_date": "2017-09-24"}, "30": {"description": "## Websites\r\n * http://www.schibsted.com/en/ir/", "id": 30, "code_signature": ".schibsted.", "website": "http://www.schibsted.com/en/ir/", "name": "Schibsted", "network_signature": "schibsted\\.com|schibsted\\.io", "creation_date": "2017-09-25"}, "31": {"description": "## Websites\r\n * https://www.atinternet.com/en/", "id": 31, "code_signature": "com.atinternet.", "website": "https://www.atinternet.com/en/", "name": "ATInternet", "network_signature": "ati-host\\.net", "creation_date": "2017-09-25"}, "32": {"description": "## Primary location\r\nUnited States (San Diego) [Crunchbase, 01](https://www.crunchbase.com/organization/tealium)\r\n\r\n## Website\r\n[https://www.tealium.com](https://www.tealium.com)\r\n\r\n## About\r\nTealium offers a universal data hub that unites its clients' tools and teams with \"universally acceptable, real-time customer data\" [Tealium, 01](https://www.tealium.com).\r\n\r\n## Ownership\r\nTealium\r\n\r\n## Documentation\r\nhttps://community.tealiumiq.com/t5/Tealium-for-Android/Adding-Tealium-to-Your-Android-App/ta-p/16846\r\n\r\n## Products and Services\r\nTealium integrates technologies and services. Products and services include:\r\n\r\n* Build & Stitch Profiles\r\n* Define Audiences\r\n* Trigger Actions\r\n* Analytics\r\n* Big Data\r\n* Customer Relations Management\r\n* Display Ad\r\n* Email\r\n* Personalization\r\n* Search\r\n* Social [Tealium, 01](https://www.tealium.com)\r\n\r\nProducts include:\r\n\r\n* _Tealium iQ Tag Management:_ Integrate with other vendors through tags [Telium, 02](https://tealium.com/products/tealium-iq-tag-management-system).\r\n* _Tealium Event Stream:_ Data collection from any source (web, mobile, OTT), monitor data stream in real time, and leverage data in real time, especially for use on mobile devices [Tealium, 03](https://tealium.com/products/tealium-eventstream).\r\n* _Tealium AudienceStream Customer Data Platform:_ A CDP that offers \"robust audience management and data enrichment capabilities resulting in unified customer profiles and the ability to take immediate, relevant action... Tealium AudienceStream allows users to connect all of their customer data, creating a single view of customers and the ability to automate actions across every channel, touchpoint and vendor in your entire digital ecosystem\". Tealium's Audience Sizing \"allows users to connect all of their customer data, creating a single view of customers and the ability to automate actions across every channel, touchpoint and vendor in your entire digital ecosystem\" [Tealium, 04](https://tealium.com/products/audiencestream).\r\n* _Tealium DataAccess:_ DataAccess \"offers the richest source of clean and correlated omnichannel, event and audience data collected across web and mobile touch points, and makes that data available for real-time action\". It focuses on unifying data and offers the capacity to \"Correlate and stitch online and offline data assets to provide a rich \u201cready to query\u201d visitor dataset\" [Tealium, 05](https://tealium.com/products/tealium-dataaccess).\r\n\r\nTealium's \"Visitor Stitching\" tracks user behavior on and offline, across devices. With this technology, Tealium states, \"Previously anonymous visitor behavior will fulfill critical gaps in customer knowledge when cross device activity is merged with known customer profiles\". Tealium has a patent on their visitor stitching approach that combines the details from two or more profiles into one. Their \"proprietary technology \u2018replays\u2019 the data from each of the stitched profiles back in order, so that the profile can be built taking into account the sequence of the customer\u2019s journey\". \r\n\r\nTealium \"tracks visitor IDs from a variety of sources including Facebook, Amazon, Twitter, LinkedIn, Google Plus and more. When any known ID is matched, visitors, their behaviors, and devices are automatically stitched together. AudienceStream then enables you to take actions using these profile-based attributes and create unique audiences, facilitating compelling omnichannel campaigns that may begin on a mobile device and follow the user to his or her desktop\" [Tealium, 06](https://tealium.com/resources/visitor-stitching).\r\n\r\n## Privacy Policy\r\nTealium lists a Privacy Policy on its website; it is unclear if there are any differences in policy as it applies to their mobile tracker. \r\n\r\n_Data collection:_ Tealium collects both PII and non-PII from individuals visiting its website or using its services. PII may be collected when signing up for Tealium services. Non-PII may be collected when visiting the Tealium website from a web browser or mobile device. Tealium collects information from web browser through the use of cookies and web beacons. They also collect data on IP addresses to \" administer the Tealium Website, analyze trends, track visitor movements, and gather broad demographic information that assists us in identifying visitor preferences\". They \"may collect aggregated data regarding use of the Services and the Tealium Website, including, without limitation, number of Site Visitors, frequency and patterns of use, tag usage, feedback request trends, etc. (\u201cAggregated Data\u201d)\". They state they use \"Aggregated Data as a statistical measure and not in a manner that would identify you personally\" and that they \"may make use of, or make such Aggregated Data available to, third parties, in any manner in our sole discretion\". Details on what constitutes \"aggregated data\" or not available. \r\n\r\n_Data sharing:_ Tealium shares data with service providers, affiliates, partners and affiliated businesses not controlled by Tealium, billing, and when compelled by authorities.\r\n\r\n_International law:_ Tealium \"participates in and has certified its compliance with the EU-U.S. Privacy Shield Framework (Privacy Shield) and Swiss Safe Harbor\".\r\n\r\n_Opt-out:_ Tealium states, \"You may correct, update and delete your Customer Information, change your choices for alerts and other messages, choose whether to receive offers and promotions from us or you may request access to the Personal Information we hold about you and ask us to amend or delete such Personal Information. You can send your request to support@tealium.com.\" They also honor Do Not Track headers and \"allows its users to opt\u2010out of having their personal information collected by Tealium\". It is not clear how individuals could opt-out of data collection from the Telium mobile device tracker.\r\n\r\n_Data retention:_ Tealium \" retains the information we receive as described in this Privacy Statement for as long as needed to provide our Services, comply with our legal obligations, resolve disputes, establish legal defenses, conduct audits, pursue legitimate business purposes, and enforce our agreements\".\r\n\r\n_Security:_ Tealium states that it \"takes precautions, including administrative, technical, and physical measures \u2013 to help safeguard Customer Information against loss, theft, and misuse as well as unauthorized access, disclosure, alteration, and destruction. While we follow generally accepted standards to protect information submitted to us, no method of storage or transmission is 100% secure. Users are solely responsible for protecting their passwords, limiting access to their computers, and signing out of the Services after their sessions\" [Tealium, 07](https://tealium.com/privacy).\r\n\r\n## Relationships\r\n_Integrations (technological):_ Amazon Web Services / Bronto / Campaign Monitor / Twitter Campaigns / Facebook / CheetahMail / Criteo / Demandware [Tealium, 01](https://www.tealium.com).\r\n\r\n## Details\r\n_Financial details:_ Tealium was founded in 2008 and has raised over $112 million from funders [Crunchbase, 01](https://www.crunchbase.com/organization/tealium).\r\n\r\n## References\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/tealium](https://www.crunchbase.com/organization/tealium) \r\n* _Tealium, 01._ [https://www.tealium.com](https://www.tealium.com) \r\n* _Tealium, 02._ [https://tealium.com/products/tealium-iq-tag-management-system](https://tealium.com/products/tealium-iq-tag-management-system) \r\n* _Tealium, 03._ [https://tealium.com/products/tealium-eventstream](https://tealium.com/products/tealium-eventstream) \r\n* _Tealium, 04._ [https://tealium.com/products/audiencestream](https://tealium.com/products/audiencestream) \r\n* _Tealium, 05._ [https://tealium.com/products/tealium-dataaccess](https://tealium.com/products/tealium-dataaccess) \r\n* _Tealium, 06._ [https://tealium.com/resources/visitor-stitching](https://tealium.com/resources/visitor-stitching) \r\n* _Tealium, 07._ [https://tealium.com/privacy](https://tealium.com/privacy)\r\n\r\n## External Links\r\n* _Wikipedia (Tealium):_ [https://en.wikipedia.org/wiki/Tealium](https://en.wikipedia.org/wiki/Tealium) \r\n* _Ghostery (Tealium):_ [https://apps.ghostery.com/apps/tealium](https://apps.ghostery.com/apps/tealium)\r\n* _Crunchbase (Tealium):_ [https://www.crunchbase.com/organization/tealium](https://www.crunchbase.com/organization/tealium)", "id": 32, "code_signature": ".tealium.", "website": "https://tealium.com/", "name": "Tealium", "network_signature": "tiqcdn.com|tealiumiq.com", "creation_date": "2017-09-25"}, "33": {"description": "## Primary Location\r\nUnited States (Boston) [Crunchbase, 01](https://www.crunchbase.com/organization/nexage)\r\n\r\n## Website\r\n[http://www.nexage.com](http://www.nexage.com)\r\n\r\n## About\r\nNexage \"offers a mobile advertising platform that provides private and public exchanges, data enrichment, and real-time targeting solutions\" [Crunchbase, 01](https://www.crunchbase.com/organization/nexage).\r\n\r\n## Ownership\r\nMillenial Media, which became part of ONE by AOL; the AOL company name has changed to Oath, which is a subsidiary of Verizon Communications [AOL, 01](http://privacy.aol.com)\r\n\r\n## Documentation\r\n[http://docs.onemobilesdk.aol.com/android-ad-sdk/integration-guide.html](http://docs.onemobilesdk.aol.com/android-ad-sdk/integration-guide.html)\r\n\r\n## Products and Services\r\nServices (ostensibly now under Millenial Media):\r\n\r\n* Real-time bidding to help automate the buying and selling of mobile advertising [MillenialMedia, 01](http://www.millennialmedia.com/press/millennial-media-to-acquire-nexage-a-leading-mobile-ssp-and-advertising-exchange).\r\n* Millenial Media has a \"mobile-first\" data management platform (DMP) which can \"ingest publisher and advertiser data to enable re-targeting, audience extensions, and cross-device attribution\" [MillenialMedia, 01](http://www.millennialmedia.com/press/millennial-media-to-acquire-nexage-a-leading-mobile-ssp-and-advertising-exchange).\r\n* Targeted advertising through channel and demographic segments: \"Leveraging Millennial Media's audience and channel targeting, the campaign reached women ages 25-55 with an emphasis on the following conditions: pregnancy, stress, and bleaching/coloring. The consumer interaction garnered from the precise targeting far exceeded expectations.\" [MillenialMedia, 02](http://www.millennialmedia.com/mobile-insights/client-stories/fall-for-unilever-singapore-dove-hair-rescue)\r\n\r\n## Privacy Policy\r\nNexage's current privacy policy links to a URL at AOL.com, which displays privacy policy for \"Oath: A Verizon company\" [AOL, 01](http://privacy.aol.com). \r\n\r\n_Location tracking:_ According to Oath, \"Depending on how you access and use our Services, we may receive... _Location Information._ This information can include your device's GPS signal and information about Bluetooth connections, nearby WiFi networks, cell towers, and other types of precise location. We get this information, for example, when you use location-enabled services\" [AOL, 04](http://privacy.aol.com/privacy-policy). \r\n\r\nThey further state, \"With your consent, we may use available services on your device to determine or derive your precise location, including cellular, Wi-Fi, Bluetooth, and GPS information. In addition and with your consent, we may share your precise location information or personal information with third parties for their independent use. You may opt-out of providing precise location information to Oath, and having that information shared with third parties, at any time by adjusting the settings on your device. Please note that you may need to adjust multiple settings, and not just your location preference, to opt out of providing precise location information to Oath. If you subsequently opt in to sharing location information for an individual service, your location information will be shared with that service. Note that if you consent to share your location information within a particular app, your location information collected from within that app may continue to be shared even after you have opted-out on your device. If you opt-out of providing precise location information to Oath, we may continue to derive your approximate location from your IP address and other information we may collect. For more information, please review your app and device settings.\" \r\n\r\n_Location tracking and third parties:_ Oath states, \"We may use third-party providers to help operate our Services, including to deliver ads and understand how people use our Services on various devices. These providers may collect information about other apps on your various devices, the websites you visit, location information, inaudible audio waves, and other information in order to help analyze usage and target advertising on the site or app and elsewhere across your devices. These providers may use cookies, web beacons, and other technologies (including audio beacons) to collect this information\" [AOL, 07](http://legal.aol.com/mobileTOS).\r\n\r\n_Other information collected:_ \r\n\r\n* Log information (interactions with web sites, search queries, information about your operating system, IP address, etc)\r\n* Device information (the type of device, such as iPhone; device identifiers which may be unique to your device; your Internet Service Provider)\r\n* \"Other information\" (such as information from AOL Mail or Instant Messenger, but not the private communications without your consent)\r\n* Third Party data: Oath states, \"We may receive additional information about you that is publicly or commercially available and combine it along with the information we have collected or received about you in other ways. Also, we receive information about you when you choose to connect with social networking services while using our Services\" [AOL, 04](http://privacy.aol.com/privacy-policy).\r\n\r\n_Mobile device information:_ Oath states, \"When you use our Services on a mobile device, Oath, our partners, and service providers may collect certain information automatically, such as the type of device you use, unique device ID, wireless mobile subscriber ISDN numbers, Verizon Wireless UIDH, IP address, operating system, browser type, and information about your use of our Services. We may use this information as described in the Oath Privacy Policy, which explains, among other things, that we may combine information about your use of our various Services in all the ways you may connect to Oath.\r\n\r\nCertain Services may require the collection of the phone number of your device. We may associate that phone number with other information; however, we will not use that number for telemarketing to you without your consent\" [AOL, 07](http://legal.aol.com/mobileTOS).\r\n\r\n_Oath Standard Categories (segments) for targeted advertising:_ See Oath website for their list of Standard Categories [AOL, 05](https://advertising.aol.com/advisibility/standard-categories).\r\n\r\n_Opt-out on mobile:_ Oath states users can opt out of interest-based (targeted) advertising through general device settings in iOS and Android. However, to stop data collection of an Oath app, users must uninstall the app. \r\n\r\n_PII vs non-PII:_ Oath defines PII as \"name, address, telephone number, email address, payment card number, and government-issued identification number\", and non-PII to include \"without limitation cookie IDs, device identifiers, hashed values (such as email addresses and other types of information that are transformed into a sequence of random-looking characters that are no longer recognizable as an email address), and IP addresses\" [AOL, 02](http://privacy.aol.com/definitions). \r\n\r\nOath states it abides by \"standards restricting the use of sensitive financial account number data and other types of sensitive data as defined by these programs. For example, we do not use or allow others to use sensitive data to determine eligibility for health insurance, life insurance, or employment. We also do not target ads to users based on sensitive health data, including cancer, mental health-related conditions, and sexually-related areas\". They add, \"If a user appears interested in non-sensitive, health-related topics, (such as, by visiting pages related to a topic) an ad relevant to those interests may be displayed. We may also display non-sensitive, health-related ads to users who we or our advertisers believe may be an appropriate audience for such topics\" [AOL, 06](http://privacy.aol.com/advertising-and-privacy).\r\n\r\n_Information sharing:_ Oath states it \"may share your information in limited circumstances, including when we have your consent to do so or when sharing is necessary to protect Oath or comply with the law. Our agents and contractors may have access to your information, but only to perform services for Oath. We do not sell or rent your personal information to third parties. We may, however, share non-personally identifiable information with select business partners\" [AOL, 01](http://privacy.aol.com). Oath also states it does not \"rent or sell personal information to third parties for their marketing purposes. But we may share certain information we collect or receive with our affiliates and others to respond to your requests, provide our Services, when we have your consent, or as described in\" their Privacy Policy.\r\n\r\nParties Oath may share data with include:\r\n\r\n* Affiliates (any company that is controlled by or under common control with Oath Inc. Oath is part of the Verizon family of companies, which includes Yahoo Inc. For a list of Oath's major content brands\") [AOL, 02](http://privacy.aol.com/definitions)\r\n* Business partners (non-personally identifiable information)\r\n* Other parties in response to legal process or when necessary to protect our Services\r\n* Companies that provide services to Oath\r\n\r\nThird Parties that Provide Content, Advertising Services, or Functionality on Our Services:\r\n\r\n* Advertising providers (for targeted advertising or analytics)\r\n* Audience-measurement companies (to measure and compare usage on Oath Services, in comparison to other online services)\r\n* Social networking services \" (like Facebook, Twitter, LinkedIn, and Google) that enable you to login to certain of our Services and to share things you find on our Services with your social network. If you choose to connect with a social networking service, we may share information with that service, and that service may share information about you with us. We may use the information for the reasons explained in this Privacy Policy, including to make your experience on our Services more personal and social. For example, we might show you what content is popular among your connections on the social networking service or give you a glimpse of what your friends are saying about that content.\"\r\n\r\nAccording to Oath, \"These and other third parties may collect or receive information about your use of our Services, including through the use of cookies, web beacons and other technologies, and this information may be collected over time and combined with information collected on different websites and online services across your devices\" [AOL, 04](http://privacy.aol.com/privacy-policy). \r\n\r\nKey third parties Oath works with include, but are not limited to: \r\n\r\nAnalytics Providers:\r\n\r\n* Google Analytics\r\n* Nielsen Digital Measurement\r\n* Scorecard Research\r\n\r\nOther companies:\r\n\r\n* Acxiom\r\n* Session M\r\n* Taboola\r\n* Tapad \r\n\r\nOath states that, \"like Oath, these companies and other third parties not listed above may use cookies, web beacons, and similar technologies on or in connection with our Services\" [AOL, 06](http://privacy.aol.com/advertising-and-privacy).\r\n\r\n_Regulation:_ Oath is committed to self-regulatory requiremets for online advertising, including the Digital Advertising Alliance's Self-Regulatory Program for Online Behavioral Advertising and the Network Advertising Initiative's Self-Regulatory Code of Conduct.\r\n\r\n_Retention:_ Oath states, \"Data used to create segments for ad targeting is retained for no longer than 2 years. Other data (for example, data used to determine long-term or seasonal trends) may be retained for as long as Oath has a legitimate business reason for retaining it\" [AOL, 06](http://privacy.aol.com/advertising-and-privacy).\r\n\r\n_Tracking technologies:_ Oath Services use cookies, web beacons, and other technologies, as well as device fingerprinting and a \"device graph\" to link multiple devices to the same user [AOL, 03](http://privacy.aol.com/cookies-web-beacons).\r\n\r\n## Relationships\r\n_Media relationships:_ Oath offers free Services such as Oath.com, HuffPost, Moviefone, and TechCrunch with support from ads displayed on those Services. \r\n\r\nOath brands include: #BuiltByGirls / Yahoo! Finance / Yahoo! / AOL / Yahoo! Sports / Yahoo! Mail / TechCrunch / Yahoo! News / HuffPost / Yahoo! Fantasy / Flurry / Yahoo! Gemini / Verizon / BrightRoll by Yahoo! / ONE by AOL / kanvas / flickr / tumblr / Yahoo! Weather / Alto / Yahoo! Messenger / engadet / Style Me Pretty / autoblog / Polyvore / Makers / Moviefone / Build / Ryot / Convertro / BBG Ventures / Cambio / rivals / alephd by AOL [Oath, 01](https://www.oath.com/our-brands)\r\n\r\n## Details\r\n_Financial details:_ Nexage was founded in 2006 and had raised $19.5 million by 2012. It was acquired by Millenial Media for approximately $108 million in 2014 [Crunchbase, 01](https://www.crunchbase.com/organization/nexage); [AdExchanger.com, 01](https://adexchanger.com/mobile/millennial-media-to-buy-nexage-mobile-ssp-and-exchange-for-108m). \r\n\r\n## References\r\n* _AdExchanger.com, 01._ [https://adexchanger.com/mobile/millennial-media-to-buy-nexage-mobile-ssp-and-exchange-for-108m](https://adexchanger.com/mobile/millennial-media-to-buy-nexage-mobile-ssp-and-exchange-for-108m)\r\n* _AOL, 01._ [http://privacy.aol.com](http://privacy.aol.com)\r\n* _AOL, 02._ [http://privacy.aol.com/definitions](http://privacy.aol.com/definitions)\r\n* _AOL, 03._ [http://privacy.aol.com/cookies-web-beacons](http://privacy.aol.com/cookies-web-beacons)\r\n* _AOL, 04._ [http://privacy.aol.com/privacy-policy](http://privacy.aol.com/privacy-policy)\r\n* _AOL, 05._ [https://advertising.aol.com/advisibility/standard-categories](https://advertising.aol.com/advisibility/standard-categories)\r\n* _AOL, 06._ [http://privacy.aol.com/advertising-and-privacy](http://privacy.aol.com/advertising-and-privacy) \r\n* _AOL, 07._ [http://legal.aol.com/mobileTOS](http://legal.aol.com/mobileTOS)\r\n* _Millenial Media, 01._ [http://www.millennialmedia.com/press/millennial-media-to-acquire-nexage-a-leading-mobile-ssp-and-advertising-exchange](http://www.millennialmedia.com/press/millennial-media-to-acquire-nexage-a-leading-mobile-ssp-and-advertising-exchange)\r\n* _Millenial Media, 02._ [http://www.millennialmedia.com/mobile-insights/client-stories/fall-for-unilever-singapore-dove-hair-rescue](http://www.millennialmedia.com/mobile-insights/client-stories/fall-for-unilever-singapore-dove-hair-rescue)\r\n* _Oath, 01._ [https://www.oath.com/our-brands](https://www.oath.com/our-brands)\r\n\r\n## External Links\r\n* _Ghostery (Nexage)_: [https://apps.ghostery.com/apps/nexage](https://apps.ghostery.com/apps/nexage)", "id": 33, "code_signature": "com.nexage.android.|org.nexage.", "website": "http://nexage.com/", "name": "Nexage", "network_signature": "nexage\\.com", "creation_date": "2017-09-27"}, "34": {"description": "*\"Ogury is activating proprietary true mobile data from more than 300 million global users.\r\nNo other player in the market has such an ultra-granular knowledge of the complete mobile user journey.\r\nOgury\u2019s omniscient mobile data platform gives businesses the tools to harness the power of mobile data.\r\nBetter Insights = Better Targeting = Better App Monetisation = Better Mobile Experience.\"* - from Ogury website", "id": 34, "code_signature": "io.presage.", "website": "http://www.presage.io/", "name": "Ogury Presage", "network_signature": "presage\\.io", "creation_date": "2017-09-27"}, "35": {"description": "## Primary location\r\nUnited States\r\n\r\n## Website\r\n[https://www.mopub.com](https://www.mopub.com)\r\n\r\n## About\r\nMoPub offers services aimed th help publishers acquire and serve advertisements and advertisers to reach audiences that may be interested in their products and services [MoPub, 03](https://www.mopub.com/legal/privacy).\r\n\r\n## Ownership\r\nTwitter\r\n\r\n## Documentation\r\n[https://www.mopub.com/resources/docs/android-sdk-integration](https://www.mopub.com/resources/docs/android-sdk-integration)\r\n\r\n## Products and Services\r\nMopub describes itself as \"The leading monetization platform for mobile app publishers and developers\" [MoPub, 01](https://www.mopub.com). \r\n\r\n* They connect publishers with advertisers in a way aimed to \"drive the highest price for every ad impression\" [MoPub, 01](https://www.mopub.com).\r\n* They \"flexible mediation system allows publishers to target the right inventory with the right network partner, based on each publisher\u2019s unique business goals\" [MoPub, 01](https://www.mopub.com).\r\n* They offer \"ad serving tools, interface, and analytics.\"\r\n\r\nFor publishers: [Mopub, 02](https://www.mopub.com/publishers/overview)\r\n* Offer a \"dependable back-end systems powered by Twitter\u2019s world-class data center strength.\"\r\n* Offer consultative services.\r\n* Offer a creative dashboard for ad serving tools, interface, and ad formats.\r\n* Offer publishers access to over 180 demand-side platforms.\r\n* Help publishers reach an audience across 49,000 apps and 1.5 billion devices [MoPub, 03](https://www.mopub.com/dsp/overview).\r\n\r\n## Privacy Policy\r\n\r\n### Section 1: End User Policies\r\n_Information Collection on End Users:_ MoPub states, \"we may collect information about your device and the ads you view or click. The MoPub Services are designed to avoid collecting information that identifies you personally, such as your name, address, or email address, but the information we collect does enable us to recognize your device over time\". Data collected includes, but is not limited to:\r\n\r\n* \"Information about your device, such as the type and model, manufacturer, operating system (e.g. iOS or Android), carrier name, IP address, mobile browser (e.g. Chrome, Safari), applications using the MoPub Services and the version of such applications, and identifiers assigned to your device, such as its iOS Identifier for Advertising (IDFA), Android Advertising ID, or unique device identifier (a number uniquely allocated to your device by your device manufacturer).\r\n* Log information, including the app or website visited, session start/stop time, time zone, and network connection type (e.g., WiFi, cellular), and cookie information.\r\n* The geo-location of your device (using GPS or other geo-location data), when location services have been enabled for the mobile app or website that uses the MoPub Services.\r\n* Information about ads served, viewed, or clicked on, such as the type of ad, where the ad was served, whether you clicked on it, and whether you visited the advertiser\u2019s website or purchased the product or service advertised.\r\n* Information that MoPub Customers and other third parties have collected and share with MoPub, such as information about activity in their services. This may include the content you view or searches you made, the language you prefer, or other non-personally identifying demographic or interest information, to help make the ads served to you more relevant.\" \r\n\r\n_Information Use on End Users:_ This includes for the following purposes:\r\n\r\n* Serving Ads\r\n* Ad Reporting and Conversations\r\n* Frequency Capping\r\n* Fraud Detection and Prevention\r\n* Interest-Based Advertising\r\n* Geo-Targeting\r\n* Providing and Improving MoPub Services\r\n\r\n_PII:_ \"MoPub will not combine the non-personally identifiable information collected to provide the MoPub Services with your personally-identifying information without your express consent.\" \r\n\r\n_Information sharing:_ \r\n\r\n* With advertiser customers: for the purposes of the ad bidding process.\r\n* Aggregated and non-PII data: \"We share aggregate or non-personally identifiable information about the use of our Services with MoPub Customers. For example, we provide advertisers reports showing how many users viewed or clicked on their ads. We also provide publishers reports about the types of ads served to their apps.\"\r\n* With partners: who help with anti-fraud, quality, and security efforts.\r\n* With partners: who help MoPub improve mobile advertising exchange services.\r\n* Within \"our corporate family to provide, understand, or improve their or our services.\"\r\n\r\nMoPub also shares data as described in Section 3 of the Privacy Policy (see below). \r\n\r\n_Opt-Out:_ \"Your iOS mobile device may provide a 'Limit Ad Tracking' setting. On Android devices, your settings may allow you to 'Opt out of Interest-Based Ads.' When you have opted out using this setting on a device, MoPub will not use in-app information collected from that device to infer your interests or serve ads to that device that are targeted based on your inferred interests.\" MoPub also observes \"Do Not Track\" requests in web browsers. MoPub \"requires its advertising customers to honor opt-out preferences expressed using these controls.\" \r\n\r\n_Requirements of MoPub Customers:_ \"MoPub requires MoPub Customers to comply with all applicable laws and regulations and to provide end users with notice of the collection of data for advertising purposes as outlined in this Privacy Policy. We encourage all users to review the privacy policies of sites and apps they visit for information about those sites\u2019 and apps\u2019 data collection and use practices.\" \r\n\r\n### Section 3: General Information\r\n_Other sharing policies:_ MoPub \"may preserve or disclose information if we believe that it is reasonably necessary to comply with a law, regulation, legal process, or governmental request; to protect the safety of any person; to address fraud, security or technical issues; or to protect the rights or property of MoPub, MoPub Customers, users of our website, or end users.\"\r\n\r\n_Information from Third Parties:_ MoPub \"may receive information about you from third parties, including MoPub Customers, data partners, and our corporate family. This information may include, for example, browser cookie IDs, mobile device IDs, demographic or interest data, and content viewed or actions taken on a website or app.\" \r\n\r\n_Other sites:_ MoPub \"is not responsible for the privacy practices or content of these other sites.\" \r\n\r\n_Confidentiality and Security:_ MoPub \"has implemented reasonable security measures in order to protect both personal and non-personal information from loss, misuse and unauthorized access, disclosure, alteration or destruction.\"\r\n\r\n## Relationships\r\n_Clients:_ Apalon / ASKfm / FEO Media / First Touch Games / glu / Gram Games / Jorudan / LA Place Media / Lotum / Lovoo / MeetMe / Miniclip / MobilityWare / Outfit7 / theScore / Simeji / Spinrilla / timehop / truecaller / tunein / Ubisoft / Paper.io / The Weather Channel / Zynga [MoPub, 04](https://www.mopub.com/publishers/clients)\r\n\r\n## Details\r\n_Financial history:_ MoPub was founded in 2010 [CrunchBase, 01](https://www.crunchbase.com/organization/mopub). It was acquired by Twitter in 2013; the details of the deal were not disclosed. Media outlets estimated the deal at around $300 million [CCN Tech, 01](http://money.cnn.com/2013/09/10/technology/social/twitter-acquisition/index.html)\r\n\r\n## References\r\n* _CNN Tech, 01_. [http://money.cnn.com/2013/09/10/technology/social/twitter-acquisition/index.html](http://money.cnn.com/2013/09/10/technology/social/twitter-acquisition/index.html) \r\n* _CrunchBase, 01_. [https://www.crunchbase.com/organization/mopub](https://www.crunchbase.com/organization/mopub)\r\n* _MoPub, 01_. [https://www.mopub.com](https://www.mopub.com) \r\n* _MoPub, 02_. [https://www.mopub.com/publishers/overview](https://www.mopub.com/publishers/overview) \r\n* _MoPub, 03_. [https://www.mopub.com/legal/privacy](https://www.mopub.com/legal/privacy) \r\n* _MoPub, 04_. [https://www.mopub.com/publishers/clients](https://www.mopub.com/publishers/clients)\r\n\r\n## External Links\r\n* _Ghostery (MoPub)_: [https://apps.ghostery.com/ko/apps/mopub](https://apps.ghostery.com/ko/apps/mopub)", "id": 35, "code_signature": "com.mopub.mobileads.", "website": "https://www.mopub.com/", "name": "Twitter MoPub", "network_signature": "mopub\\.com", "creation_date": "2017-09-27"}, "36": {"description": "", "id": 36, "code_signature": "com.intentsoftware.addapptr.", "website": "https://www.addapptr.com", "name": "Add Apt Tr", "network_signature": "aatkit\\.com", "creation_date": "2017-09-27"}, "37": {"description": "", "id": 37, "code_signature": "io.vectaury.", "website": "http://vectaury.io/", "name": "Vectaury", "network_signature": "vectaury\\.io", "creation_date": "2017-09-28"}, "38": {"description": "## Primary Location\r\nUnited States (Seattle) [Crunchbase, 01](https://www.crunchbase.com/organization/tune)\r\n\r\n## Website\r\n[https://www.tune.com](https://www.tune.com)\r\n\r\n## About\r\nTUNE offers products and services for the digital marketing and advertising industry, including the TUNE Marketing Console, a mobile marketing technology stack [TUNE, 08](https://www.tune.com/who-we-are).\r\n\r\n## Ownership\r\nTUNE\r\n\r\n## Documentation\r\n[https://developers.tune.com/sdk/android-quick-start](https://developers.tune.com/sdk/android-quick-start)\r\n\r\n## Products and Services\r\nMany of TUNE's services are provided through the TUNE Marketing Console (TMC). The TMC \"is designed to collect and use data such as Unique Advertising Identifiers, Statistical Identifiers, Geographic Location Data, Email Addresses, and other data provided by the Advertiser for attribution, app store optimization, and in-app marketing. Advertisers are able to view and measure data provided by TUNE, as well as third-party Partners that the Advertiser selects, in the TMC. For instance, an Advertiser can compare the results of advertising campaigns conducted with different Partners in the TMC. Advertisers and Partners may also send information to the TMC via Postback\" [TUNE, 10](https://www.tune.com/resources/data-and-privacy/privacy-policies/tmc-privacy-policy).\r\n\r\nTUNE products and services offered include:\r\n\r\n* _In-App Marketing:_ Leverage customer segmentation tools and contextual insight to send personalized messages, guide users through from onboarding to conversion, and take action with real-time reporting, A/B testing, and optimization. Features include location-based triggers, deep links, automatic actions, automated triggers, and scheduled campaigns [TUNE, 02](https://www.tune.com/solutions/tune-marketing-console/in-app-marketing).\r\n* _TUNE Marketing Console:_ \r\n* * Track user behavior on and offline, across devices, via TUNE's understanding of the \"customer journey\".\r\n* * Uniques identify users and target their \"proximity\" via location tracking.\r\n* * Help clients to \"Streamline your mobile marketing and measurement\" with services that are \"people-centric\". \r\n* * Unify data into one place, and give ownership of the data to the client. \r\n* * TUNE's APIs allows clients to sync with thousands of integrated partners [TUNE, 03](https://www.tune.com/solutions/tune-marketing-console/our-difference).\r\n* _Attribution Analytics:_ TUNE offers mobile analytics based on detailed performance reports and people-centric segmentation to maximize return on investment; analytics for re-engagement; analytics for return on ad spend; as well as analytics for fraud prevention [TUNE, 04](https://www.tune.com/solutions/tune-marketing-console/attribution-analytics).\r\n* _App Store Analytics:_ TUNE provides tools to optimize success in app stores [ TUNE, 05](https://www.tune.com/solutions/tune-marketing-console/app-store-analytics).\r\n* _Fraud prevention:_ TUNE Fraud services identify install and click fraud, allows businesses to set custom fraud rules, and provides analytics to detect and classify potential fraud [TUNE, 06](https://www.tune.com/solutions/tune-marketing-console/mobile-ad-fraud-detection-prevention) \r\n\r\nTUNE is \"a 'data processor' that collects and analyzes End User data at the specific request of our client Advertisers, the 'data controllers'\" [TUNE, 10](https://www.tune.com/resources/data-and-privacy/privacy-policies/tmc-privacy-policy).\r\n\r\nTUNE also tracks in-app user behavior and correlates it with a unique identifier [TUNE, 07](https://developers.tune.com/sdk/measuring-in-app-events).\r\n\r\nA simple version of TUNE's targeted advertising is provided on their opt-out website. It is explained as follows: \r\n\r\n\"Within the TMC, two features allow advertisers to use data to target advertising to an end user:\r\n\r\n1. AUDIENCES allows Advertisers to build segments based on previously acquired attribution data (from the TMC's Attribution Analytics feature)...\r\n2. IN APP MARKETING allows advertisers to send end users push notifications outside of the app environment, as well as in-app messages - for promotional and other activities...\" [TUNE, 09](http://www.optoutmobile.com).\r\n\r\nIn this context, TMC covers \"Attribution Analytics, App Store Analytics, Audiences, and In-App Marketing\" [TUNE, 10](https://www.tune.com/resources/data-and-privacy/privacy-policies/tmc-privacy-policy).\r\n\r\n## Privacy Policy\r\nTUNE \"defines privacy as the end user\u2019s rights to receive notice, give consent, and opt-out of the collection, use, and sharing of data that is about or can identify that end user\".\r\n\r\n_Opt-out:_ TUNE has an opt-out website, www.optoutmobile.com, which details how end users can opt out of features in the TUNE Marketing Console (TMC) that target users online. Users can opt out of the \"audiences\" segment-based targeted advertising if they \"enable Limit Ad Tracking or \u201cLAT\u201d or re-set their ad identifier on their device OR opt out within the app itself\". They can opt out of \"in app marketing\" if they \"use the appropriate settings on their mobile platform (Android, iPhone, or Windows)\". Additional details of how to opt out of mobile on the outoutmobile.com website. TUNE will pass on LAT requests to Advertisers, and will honor opt-outs provided to them by Advertisers. They also honor push notification opt outs set by the End User on their device. \r\n\r\nOpting out of the TMC \"will not stop those users from receiving interest-based advertisements from Advertisers or other publishers or ad networks. End Users who want to opt out of a particular ad network, publisher, or Advertiser\u2019s ads must contact those companies directly to opt out.\"\r\n\r\n_Data ownership (TMC):_ \"Unless otherwise specified, and pursuant to the TUNE Data Pledge, Advertisers own the data that they provide to and collect through the TMC. When Advertisers remove or export their data from the TMC, their use of End User data is governed by their own privacy policies and applicable laws, rules, or regulations.\" \r\n\r\n_Data collected (TMC):_ The TMC \"is designed to collect and use data such as Unique Advertising Identifiers, Statistical Identifiers, Geographic Location Data, Email Addresses, and other data provided by the Advertiser for attribution, app store optimization, and in-app marketing.\" \r\n\r\n_Data sharing (TMC):_ Advertisers \"are able to view and measure data provided by TUNE, as well as third-party Partners that the Advertiser selects, in the TMC. For instance, an Advertiser can compare the results of advertising campaigns conducted with different Partners in the TMC. Advertisers and Partners may also send information to the TMC via Postback\"... Advertisers can share all data collected through the TMC with Partners via Postback, data exports, and/or API calls\". TUNE itself may provide or disclose, or enable others to provide, End User Data for the purposes of detecting and preventing malicious activity of invalid traffic, or believe that we are legally required to do so.\" \r\n\r\n_Personally identifiable information:_ \"The TMC does not primarily rely on data that is considered \u201cpersonal\u201d in other jurisdictions for Attribution and App Store Optimization. The TMC does support automatic hashing in cases where the Advertiser chooses to upload \u201cpersonal\u201d data into the TMC to ensure that the TMC does not process such data in raw form\". A detailed list of what TUNE considers PII and non-PII can be found at their data & security web page [TUNE, 13](https://help.tune.com/marketing-console/the-importance-of-securing-data-in-the-tmc). \r\n\r\n_Advertiser data use permissions (TMC):_ Advertisers can use information collected through by the TMC for:\r\n\r\n* Attribution (eg, ad campaign analytics, cross-device attribution)\r\n* App Store Analytics (eg, A/B testing, analytics)\r\n* Audiences (eg, segments, behavioral and demographic profiling)\r\n* In-App Marketing (eg, push notifications, A/B testing of push notifications)\r\n\r\n_Regulation:_ TUNE complies with the Digital Advertising Alliance self-regulatory requirements.\r\n\r\n_International Law:_ TUNE adheres to the Privacy Shield Principles. \r\n\r\n_Security:_ TUNE \" uses commercially reasonable efforts including a variety of security technologies and procedures to secure client and End User Data from unauthorized access, use or disclosure\" [TUNE, 10](https://www.tune.com/resources/data-and-privacy/privacy-policies/tmc-privacy-policy).\r\n\r\n## Relationships\r\n_Customers:_ ebay / Sony / Expedia / LINE / Supercell / Flipkart / Staples / Zillow / Sephora / Kabam / Starz / Draft Kings [TUNE, 01](https://www.tune.com) / MovieStarPlanet / Zoosk / Cheerz / SaferVPN / Schoold / Appromoters [TUNE, 12](https://www.tune.com/resources/resource-library/#customer-stories)\r\n\r\n## Details\r\n_Financial details:_ TUNE was founded in 2009 and has raised over $36 million from funders [Crunchbase, 01](https://www.crunchbase.com/organization/tune). \r\n\r\n_Innovation:_ TUNE claims to be at the forefront of many innovations in the advertising industry. They state they are \"the first self-service performance marketing platform, the original mobile app measurement product, and the first multi-touch attribution for app advertising. We were also the first to combine app and web measurement, and the first to measure performance on nearly every mobile advertising platform like Google, Twitter, Snapchat and others\" [TUNE, 08](https://www.tune.com/who-we-are).\r\n\r\n## References\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/tune](https://www.crunchbase.com/organization/tune) \r\n* _TUNE, 01._ [https://www.tune.com](https://www.tune.com) \r\n* _TUNE, 02._ [https://www.tune.com/solutions/tune-marketing-console/in-app-marketing](https://www.tune.com/solutions/tune-marketing-console/in-app-marketing) \r\n* _TUNE, 03._ [https://www.tune.com/solutions/tune-marketing-console/our-difference](https://www.tune.com/solutions/tune-marketing-console/our-difference) \r\n* _TUNE, 04._ [https://www.tune.com/solutions/tune-marketing-console/attribution-analytics](https://www.tune.com/solutions/tune-marketing-console/attribution-analytics) \r\n* _TUNE, 05._ [https://www.tune.com/solutions/tune-marketing-console/app-store-analytics](https://www.tune.com/solutions/tune-marketing-console/app-store-analytics) \r\n* _TUNE, 06._ [https://www.tune.com/solutions/tune-marketing-console/mobile-ad-fraud-detection-prevention](https://www.tune.com/solutions/tune-marketing-console/mobile-ad-fraud-detection-prevention) \r\n* _TUNE, 07._ [https://developers.tune.com/sdk/measuring-in-app-events](https://developers.tune.com/sdk/measuring-in-app-events) \r\n* _TUNE, 08._ [https://www.tune.com/who-we-are](https://www.tune.com/who-we-are) \r\n* _TUNE, 09._ [http://www.optoutmobile.com](http://www.optoutmobile.com) \r\n* _TUNE, 10._ [https://www.tune.com/resources/data-and-privacy/privacy-policies/tmc-privacy-policy](https://www.tune.com/resources/data-and-privacy/privacy-policies/tmc-privacy-policy) \r\n* _TUNE, 11._ [https://www.tune.com/resources/data-and-privacy](https://www.tune.com/resources/data-and-privacy) \r\n* _TUNE, 12._ [https://www.tune.com/resources/resource-library/#customer-stories](https://www.tune.com/resources/resource-library/#customer-stories) \r\n* _TUNE, 13._ [https://help.tune.com/marketing-console/the-importance-of-securing-data-in-the-tmc](https://help.tune.com/marketing-console/the-importance-of-securing-data-in-the-tmc)\r\n\r\n## External Links\r\n* _Crunchbase (TUNE):_ [https://www.crunchbase.com/organization/tune](https://www.crunchbase.com/organization/tune)", "id": 38, "code_signature": "com.tune|com.mobileapptracker", "website": "https://www.tune.com", "name": "Tune", "network_signature": "mobileapptracking\\.com", "creation_date": "2017-11-02"}, "39": {"description": "## Primary Location\r\nUnited States (Washington, DC) [CrunchBase, 01](https://www.crunchbase.com/organization/pushwoosh)\r\n\r\n## Website\r\n[https://www.pushwoosh.com](https://www.pushwoosh.com)\r\n\r\n## About\r\nPushwoosh pushes in-app messaging across platforms [Pushwoosh, 01](https://www.pushwoosh.com)\r\n\r\n## Ownership\r\nPushwoosh\r\n\r\n## Documentation\r\n[http://docs.pushwoosh.com/docs/fcm-integration](http://docs.pushwoosh.com/docs/fcm-integration)\r\n\r\n## Products and services\r\nFeatures include:\r\n\r\n* _Data collection (via tags):_ \"Collect additional data from your users as Tags - gender, city and DOB, or the amount of money spent on in-app purchases. Then use this data for precise segmentation, personal communication, push automation and analytics.\"\r\n* _Real world location targeting:_ \"Try real-time location-based feature to send automated push notifications to users entering a specific area. Send your sale offers, discount alerts and welcoming messages automatically\" [Pushwoosh, 02](https://www.pushwoosh.com/features). \r\n * _Targeting in geozones:_ \"pins on the map that allow sending automatically triggered push notifications right at the moment a user enters the specified area on the map. Its range can be set from 50 to 1000 meters, and it has an adjustable cooldown period\" [Pushwoosh, 03](http://docs.pushwoosh.com/docs/geozones).\r\n * _iBeacon micro-targeting_ [Pushwoosh, 10](https://www.pushwoosh.com/blog/features-guides/ibeacons)\r\n* _Segmentation of audiences for marketing campaigns_ [Pushwoosh, 02](https://www.pushwoosh.com/features). Segments could include \"username, ID, city, favorite football team, preferred news categories, or any other piece of information about your users\" [Pushwoosh, 04](http://docs.pushwoosh.com/docs/segmentation-tags-and-filters).\r\n* _In-apps tracking:_ In-app purchases (\"The total amount of money spent on in-app purchases for the device\"); Last In-App Purchase Date (\"The date of the last in-app purchase made on the device\"); and In-App Product (\"Names of in-app products that were purchased on the device\") [Pushwoosh, 05](https://docs.pushwoosh.com/v1.0/docs/in-apps-tracking).\r\n* 250+ million pushes per day.\r\n* _Personalized messages:_ \"Address your users by name, and use any of their preferences in the message to make it relevant for every single user\"\r\n* _Statistics:_ \"Measure app installs and opens, push subscription, sent & open rates, all tag data statistics, and much more.\"\r\n* _In-app messaging:_ \"deeply customizable rich content in-app banners and full-screen interstitials.\"\r\n* _A/B Tests:_ \"Perform A/B tests on your audience to figure out which push configuration works better for you.\"\r\n* _Multiple languages_ [Pushwoosh, 02](https://www.pushwoosh.com/features)\r\n* _Conversion Tracking:_ Track \"the number of users who perform specific actions in your application or on your website after opening the push\" [Pushwoosh, 06](https://www.pushwoosh.com/conversion-tracking)\r\n* _Push Recovery Campaigns:_ Target abandon carts by returning customers to finish the transaction [Pushwoosh, 07](https://www.pushwoosh.com/abandoned-cart).\r\n* _Loyalty:_ Boost audience loyalty with personalized messages.\r\n* _Targeted messaging:_ Send targeted messages to segments [Pushwoosh, 09](https://www.pushwoosh.com/business-cases).\r\n\r\n## Privacy Policy\r\nPrivacy policy is listed at [Pushwoosh, 08](https://www.pushwoosh.com/privacy-policy). The Privacy Policy web page does not address opt-out; it appears to be directed at prospective business clients.\r\n\r\n## Relationships\r\nNissan / Mercedes / Leica / Bosch / Sabre / runtastic / Abbyy / Silicon Beach Media / Reaktor / redBit games / Saatchi & Saatchi / RTL Group / Skyjey / STC / SurfStitch / rtve / Ubisoft / Unaversidad APEC / Tripcase / Suzuki / VANSO / Veikkaus / Urban Rivals / XiMad / Sony Entertainment Television / MSC Cruises / Rayman Jungle Run / World Wide Fund for Nature (WWF) / Red Cross / Diner Dash / Plymouth University / Playscape / MLB.com / Marmalade / Mastercard / Hewlett-Packard / MTN / 3rd Sense / ixigo.com / JDG / Elektromarked / LOT Polish Airlines / FX Guru / G5 Games / Haaretz / Frima Studio / FunPlus / Concentra / Fanfair / Deloitte Digital / Exhibit Force / Firezoo / AppPresser / Autoliv / Bag It! / Carrefour / Chicago Tribune Trivia [Pushwoosh, 01](https://www.pushwoosh.com)\r\n\r\n## Details\r\n_Financial details:_ Pushwoosh was founded in 2011 [Crunchbase, 01](https://www.crunchbase.com/organization/pushwoosh).\r\n\r\n## References\r\n* _CrunchBase, 01._ [https://www.crunchbase.com/organization/pushwoosh](https://www.crunchbase.com/organization/pushwoosh) \r\n* _Pushwoosh, 01._ [https://www.pushwoosh.com](https://www.pushwoosh.com) \r\n* _Pushwoosh, 02._ [https://www.pushwoosh.com/features](https://www.pushwoosh.com/features)\r\n* _Pushwoosh, 03._ [http://docs.pushwoosh.com/docs/geozones](http://docs.pushwoosh.com/docs/geozones) \r\n* _Pushwoosh, 04._ [http://docs.pushwoosh.com/docs/segmentation-tags-and-filters](http://docs.pushwoosh.com/docs/segmentation-tags-and-filters) \r\n* _Pushwoosh, 05._ [https://docs.pushwoosh.com/v1.0/docs/in-apps-tracking](https://docs.pushwoosh.com/v1.0/docs/in-apps-tracking) \r\n* _Pushwoosh, 06._ [https://www.pushwoosh.com/conversion-tracking](https://www.pushwoosh.com/conversion-tracking) \r\n* _Pushwoosh, 07._ [https://www.pushwoosh.com/abandoned-cart](https://www.pushwoosh.com/abandoned-cart) \r\n* _Pushwoosh, 08._ [https://www.pushwoosh.com/privacy-policy](https://www.pushwoosh.com/privacy-policy) \r\n* _Pushwoosh, 09._ [https://www.pushwoosh.com/business-cases](https://www.pushwoosh.com/business-cases)\r\n\r\n## External Links\r\n* Owler company profile: [https://www.owler.com/iaApp/4589235/pushwoosh-company-profile](https://www.owler.com/iaApp/4589235/pushwoosh-company-profile)\r\n* Pushwoosh on Github: [https://github.com/Pushwoosh](https://github.com/Pushwoosh)", "id": 39, "code_signature": "com.pushwoosh", "website": "https://www.pushwoosh.com/", "name": "Pushwoosh", "network_signature": "pushwoosh\\.com", "creation_date": "2017-11-12"}, "40": {"description": "## Primary Location\r\nUnited States\r\n\r\n## Website\r\n[https://www.adobe.com/data-analytics-cloud/audience-manager.html](https://www.adobe.com/data-analytics-cloud/audience-manager.html)\r\n\r\n## About\r\nDemdex offers audience management solutions for parts of Adobe's advertising ecosystem.\r\n\r\n## Ownership\r\nAdobe Systems Incorporated\r\n\r\n## Documentation\r\n[https://marketing.adobe.com/developer/get-started/mobile/c-measuring-mobile-applications](https://marketing.adobe.com/developer/get-started/mobile/c-measuring-mobile-applications)\r\n\r\n## Products and Services\r\nAdobe's Audience Manager service was build on top of the Demdex data bank product they acquired in 2011 [Analytics Demystified, 01](http://analyticsdemystified.com/adobe-analytics/adobes-new-marketing-cloud-visitor-id-how-does-it-work). Some services include:\r\n\r\n* _Segmenting:_ \"Build, test, and activate...audiences...based on a set of traits\". \"Divide millions of records into trait-specific categories\" like \"moms of grade school kids\". Find new prospects with \"look-alike modeling\"; \"pinpoint your most frequent users, as well as how recently they've interacted with your marketing.\" \r\n* _Cross-device identification:_ Use the \"profiling feature\" in Audience Manager \"to tie one profile to multiple devices\" and \"discover if users are sharing a device, for instance, within a household\". Target customers \"after they may logged off your site or app.\"\r\n* _Reports:_ Generate reports like Optimal Frequency reports, Advertiser Performance Reports to gain insight about user interactions like impressions, clicks, and conversions \r\n* _Predictive analytics:_ Performs predictive analytics\r\n* Organize your own first party data and augment it with second or third party data with the Audience Marketplace feature\r\n* Price your data for sale and partners [Adobe, 19](https://www.adobe.com/data-analytics-cloud/audience-manager.html)\r\n* _Geotargeting and location-based targeting:_ Adobe Mobile Marketing offers \"support for many location services, including GPS, geofencing, beacons, and more\". Geolocation services allow marketers to \"measure and respond to user engagement in mobile apps connected to beacons in sports stadiums, retail stores, and other points of interest. Marketers can also easily deliver \u201clocal\u201d notifications and promotions based on proximity to a beacon. In addition, companies can tie app interactions to all other app engagement data in Adobe Analytics\" [Adobe, 23](https://blogs.adobe.com/digitalmarketing/mobile/10-things-you-need-to-know-about-adobes-mobile-marketing). Adobe states that \"app targeting based on GPS location and proximity to a particular area in a store or event venue\", built into Analytics and Target products [MarketWatch, 01](https://www.marketwatch.com/story/adobe-launches-mobile-services-for-adobe-marketing-cloud-2013-11-07); [Forbes, 01](https://www.forbes.com/sites/roberthof/2013/11/07/adobe-takes-its-marketing-cloud-services-mobile); [PCWorld, 01](https://www.pcworld.com/article/2061880/adobe-adds-geolocation-targeting-to-marketing-cloud.html).\r\n* Real-time geo- and location-based targeting: Adobe's in-app messaging feature \" allows marketers to promote real-time content (e.g., new video, breaking news) or cross-promote apps, products, or services to people who are actively using their app. Messages, such as full-screen communications, alerts, and local notifications, can be triggered by analytics data, including user behavior, lifecycle metrics, or location (GPS or iBeacons), that is collected with the Mobile Services SDK. In-app messaging can be deployed without the need for app development or a new app update in the app store\" [Adobe, 23](https://blogs.adobe.com/digitalmarketing/mobile/10-things-you-need-to-know-about-adobes-mobile-marketing)\r\n* A/B testing [Forbes, 01](https://www.forbes.com/sites/roberthof/2013/11/07/adobe-takes-its-marketing-cloud-services-mobile) \r\n\r\nA variety of other services extend across the Adobe Marketing & Analytics ecosystem. The Demdex SDK may collect information for those services, including Adobe Campaign and Adobe Experience Manager [MarketWatch, 01](https://www.marketwatch.com/story/adobe-launches-mobile-services-for-adobe-marketing-cloud-2013-11-07). See \"Details\" below.\r\n\r\n## Privacy Policy\r\nAdobe business customers \"use Adobe Marketing Cloud services to collect and analyze information, such as clicks made by visitors on their websites\" [Adobe, 21](https://www.adobe.com/privacy/opt-out.html).\r\n\r\n_Data Privacy:_ \"App publishers can easily manage opt-in or opt-out functionality to enable compliance with data collection and privacy laws for specific countries including the Children's Online Privacy Protection Act (COPPA). In addition, Adobe Mobile services customers own their data - not Adobe\" [Forbes, 01](https://www.forbes.com/sites/roberthof/2013/11/07/adobe-takes-its-marketing-cloud-services-mobile). \r\n\r\nIn 2013, Adobe's Ray Pun stated that users must opt-in for geotargeting services, and that companies must write their terms in conditions \"in a language that a normal person can understand, not an attorney\" [PCWorld, 01](https://www.pcworld.com/article/2061880/adobe-adds-geolocation-targeting-to-marketing-cloud.html). \r\n\r\n_Mobile privacy policy:_ Adobe Marketing Cloud states that a \"company may also use Adobe Marketing Cloud technologies within its mobile apps. These technologies allow the company to send information to its Adobe Marketing Cloud account -- for example, how you use the company\u2019s mobile apps as well as other information your mobile device may make available to apps, such as location information.\"\r\n\r\n_Mobile opt-out:_ For opting out of mobile data collection and use in connection with Adobe Marketing Cloud, Adobe states that \"Most mobile devices allow you to the limit use of mobile advertising identifiers for interest-based advertising. For more information, please review the instructions provided by your mobile device manufacturer. The Digital Advertising Alliance\u2019s AppChoices app may also provide you with more options to opt out of receiving interest-based advertising within mobile apps. Please see Your Privacy Choices to learn more about your choices for opting out of companies\u2019 use of Adobe Marketing Cloud solutions.\"\r\n\r\nAdobe has an opt-out web page [Adobe, 21](https://www.adobe.com/privacy/opt-out.html) and a page for Audience Manager privacy policy [Adobe, 22](https://marketing.adobe.com/resources/help/en_US/aam/faq_privacy.html).\r\n\r\nAdobe suggests users \"review the privacy policy\" of the mobile app company \"as well as privacy information provided by your mobile device manufacturer\" [Adobe, 20](http://www.adobe.com/privacy/marketing-cloud.html). They also recommend \"self-regulatory sites\" like the Digital Advertising Alliance to opt out of advertising solutions by companies who are members of those groups [Adobe, 21](https://www.adobe.com/privacy/opt-out.html).\r\n\r\n## Relationships\r\n_Clients:_ Princess / Conde Nast / Lenovo [Adobe, 17](http://www.adobe.com/data-analytics-cloud/audience-manager.html) \r\n\r\n_Partners:_ Accenture Interactive / Cognizant / Deloitte Digital / dentsu aegis network / Epsilon / Havas / IBM / iCrossing / Infosys / IPG / OmnicomGroup / Publicis Groupe / pwc / Tata Consultancy Services / wipro / WPP [Adobe, 24](http://www.adobe.com/experience-cloud/service-support/partners.html)\r\n\r\n## Details\r\n### Financial details & history\r\nIn 2011, Adobe acquired Demdex for $109 million [Crunchbase, 01](https://www.crunchbase.com/organization/demdex). Demdex offered a \"behavioral data bank\" for advertising purposes. The data bank was used for audience segmenting, and could be plugged into ad servers or services, giving websites and advertisers control over the data. DemDex was added to Adobe's \"Online Marketing Suite\" (powered by Adobe-acquired Omniture) [TechCrunch, 01](https://techcrunch.com/2011/01/18/adobe-buys-behavioral-data-management-platform-demdex). \r\n\r\n### Adobe Audience Manager\r\nAdobe Audience Manager is Adobe's data management platform, built on top of the Demdex product they acquired in 2011 [Analytics Demystified, 01](http://analyticsdemystified.com/adobe-analytics/adobes-new-marketing-cloud-visitor-id-how-does-it-work). Audience Manager:\r\n\r\n* Gives a \"complete view\" of an audience by combining clients' data sources into one place [Adobe, 17](http://www.adobe.com/data-analytics-cloud/audience-manager.html)\r\n* Segments audiences for \"smart targeting\" and \"personalization\" for targeted advertisements [Adobe, 02](https://www.adobe.com/data-analytics-cloud/audience-manager/audience-segmentation.html)\r\n* Targets \"specific segments on any platform\" [Adobe, 19](https://www.adobe.com/data-analytics-cloud/audience-manager.html)\r\n\r\nIt aims to provide \"a seamless experience and a seamless profile for all the different marketing cloud solutions to use. It's also a gateway for the broader ecosystem\" such that clients with their own proprietary platforms or working with other technologies outside of Adobe, \"audience manager helps with the syndication and consistency of that audience regardless of the actual technology that is serving and delivering that audience experience. Ultimately Audience Manager allows marketers to take this vast amount of information, transform it into meaningful audience segments, to deliver the most effective message at the right time\" [Adobe, 18](https://www.adobe.com/data-analytics-cloud/audience-manager.html#m226a251c23c15530b6f70ef20da2003c)\r\n\r\nProducts it integrates with include Adobe Target and Adobe Media Optimizer, as well as solutions beyond the Marketing Cloud [Adobe, 19](https://www.adobe.com/data-analytics-cloud/audience-manager.html#x).\r\n\r\n### Adobe Marketing & Analytics ecosystem: The Adobe Experience Cloud\r\nThe Adobe Experience Cloud provides \"access to an integrated set of solutions to build campaigns, manage your advertising, and gain deep intelligence about your business. And it\u2019s all unified through powerful core services that give you access to your customer profiles, centralized assets, powerful tagging, and an ecosystem of partners and developers to extend the value of all the solutions\". Adobe's Experience Cloud website features the Adobe Advertising Cloud, Adobe Analytics Cloud, and Adobe Marketing Cloud [Adobe, 07](www.adobe.com/experience-cloud/overview.html).\r\n\r\n#### Adobe Marketing Cloud\r\nProvides a \"set of integrated digital marketing solutions...to organize, access, and personalize your marketing content\". Adobe Marketing Cloud solutions fall into four categories:\r\n\r\n* _Measurement solutions_, \"which help companies measure and understand how you use their websites, apps, social networking pages, as well as how you interact with their online marketing campaigns\"\r\n* _Personalization solutions_, \"which help companies test new content and make their websites, apps, social networking pages, and emails more relevant to you\"\r\n* _Content management solutions_, \"which help companies store, update, and deliver images and other content on their websites, within their apps, and in online marketing materials\"\r\n* _Advertising solutions_, which help companies improve their online advertising on websites, search engines, and social media platforms. These solutions also help companies send emails, text messages, and other online and offline marketing campaigns\" [Adobe, 20](http://www.adobe.com/privacy/marketing-cloud.html)\r\n\r\nProducts include:\r\n\r\n* _Adobe Experience Manager:_ \"helps you manage all your assets, build websites and mobile apps, and integrate content from online communities\" [Adobe, 03](http://www.adobe.com/marketing-cloud.html); [Adobe, 10](http://www.adobe.com/marketing-cloud/experience-manager.html)\r\n* _Adobe Campaign:_ \"helps you personalize and deliver your campaigns across all your channels, from web and mobile to email and display\" [Adobe, 03](http://www.adobe.com/marketing-cloud.html); [Adobe, 11](http://www.adobe.com/marketing-cloud/campaign.html)\r\n* _Adobe Target:_ \"helps you turn data into results by testing and personalizing your content so you can deliver the best content to the right audience\" [Adobe, 03](http://www.adobe.com/marketing-cloud.html); [Adobe, 12](http://www.adobe.com/marketing-cloud/target.html)\r\n* _Adobe Primetime:_ \"helps you create, deliver, and monetize personal video experiences\" [Adobe, 03](http://www.adobe.com/marketing-cloud.html); [Adobe, 13](http://www.adobe.com/marketing-cloud/primetime.html)\r\n* _Adobe Social:_ \"helps you create relevant social content and quantify your social marketing results\" [Adobe, 03](http://www.adobe.com/marketing-cloud.html)\r\n\r\n#### Adobe Advertising Cloud\r\nAdobe states this is \"the industry\u2019s first end-to-end platform for managing advertising across traditional TV and digital formats\". It is a cross-channel platform that delivers \"video, display, and search advertising across any screen in any format\"; \"media planning and buying are integrated into one programmatic solution\" [Adobe, 04](http://www.adobe.com/advertising-cloud.html). Produce include:\r\n\r\n* _Demand Side Platform:_ A \"unified cross-channel, software-based solution\" to \"streamline global advertising from a single platform\" [Adobe, 05](https://www.adobe.com/advertising-cloud/media-optimizer/demand-side-platform.html)\r\n* _Adobe Media Optimizer:_ This \"uses unified campaign tracking and reporting, real-time bidding, impression-level decisioning abilities, attribution reporting and simulations, and integration with the top ad exchanges to help you meet display objectives\" [Adobe, 06](https://www.adobe.com/advertising-cloud/media-optimizer/display-advertising-management.html)\r\n* _Brand Safety:_ Prevent advertising campaigns from \"mixing with content and properties that don't align with your brand's image\" [Adobe, 08](https://www.adobe.com/advertising-cloud/protecting-brand-equity.html)\r\n* _Dynamic creative optimization:_ Reach \"specific audiences with flexible ad creative that\u2019s personalized in real time to drive user engagement, conversions, and integrated experiences\". Use dynamic creatives to \"target customers with flexible ad creative that\u2019s personalized in real time based on site actions, customer and partner data, and third-party demographic data\" [Adobe, 09](https://www.adobe.com/advertising-cloud/media-optimizer/dynamic-creative-optimization.html)\r\n\r\n#### Adobe Analytics Cloud\r\nAdobe Analytics Cloud aims to provide a business' \"core intelligence engine\". It strives to bring \"context to online and offline data\" and build \"loyalty with customers\". It offers \"intelligence\" and \"precise audience creation\" to help put \"real-time insights into action\". \r\n\r\nServices include:\r\n\r\n* _Accessible analytics:_ \"Make enterprise-level marketing analytics understandable and accessible to everyone in your organization\"\r\n* _Precise segmentation:_ \"Continuously refine the view of your customers. As you do, you\u2019ll discover and create high-value audiences and understand the best way to reach them\"\r\n* _Real-time tageting:_ \"Connect your analytics with real-time activation so the transition from insight to action is as fast as it can be\"\r\n* _Next-generation attribution:_ \"To understand your ROI, you need an objective view of the customer journey across every device and channel \u2014 paid, earned, and owned\" [Adobe, 15](http://www.adobe.com/data-analytics-cloud.html)\r\n\r\nProducts include:\r\n\r\n* _Adobe Analytics:_ \"Discover your most valuable customer segments and use these insights to steer your entire business with customer intelligence\" [Adobe, 16](http://www.adobe.com/data-analytics-cloud/analytics.html)\r\n* _Adobe Audience Manager:_ A \"data management platform (DMP) that helps you build unique audience profiles so you can identify your most valuable segments and use them across any digital channel\" [Adobe, 17](http://www.adobe.com/data-analytics-cloud/audience-manager.html)\r\n\r\n### Device support\r\nAdobe's platform support \"includes Apple App Store, Google Play, Amazon Appstore, Windows Store, and Windows Phone Store, as well as analytics support for Roku, Xbox, AppleTV, PlayStation, and other connected devices\" [Adobe, 23](https://blogs.adobe.com/digitalmarketing/mobile/10-things-you-need-to-know-about-adobes-mobile-marketing)\r\n\r\n## References\r\n* _Adobe, 01_. [http://www.adobe.com/marketing-cloud.html](http://www.adobe.com/marketing-cloud.html) \r\n* _Adobe, 02_. [https://www.adobe.com/data-analytics-cloud/audience-manager/audience-segmentation.html](https://www.adobe.com/data-analytics-cloud/audience-manager/audience-segmentation.html) \r\n* _Adobe, 03_. [http://www.adobe.com/marketing-cloud.html](http://www.adobe.com/marketing-cloud.html) \r\n* _Adobe, 04_. [http://www.adobe.com/advertising-cloud.html](http://www.adobe.com/advertising-cloud.html) \r\n* _Adobe, 05_. [https://www.adobe.com/advertising-cloud/media-optimizer/demand-side-platform.html](https://www.adobe.com/advertising-cloud/media-optimizer/demand-side-platform.html) \r\n* _Adobe, 06_. [https://www.adobe.com/advertising-cloud/media-optimizer/display-advertising-management.html](https://www.adobe.com/advertising-cloud/media-optimizer/display-advertising-management.html) \r\n* _Adobe, 07_. [https://www.adobe.com/experience-cloud/overview.html](https://www.adobe.com/experience-cloud/overview.html) \r\n* _Adobe, 08_. [https://www.adobe.com/advertising-cloud/protecting-brand-equity.html](https://www.adobe.com/advertising-cloud/protecting-brand-equity.html) \r\n* _Adobe, 09_. [https://www.adobe.com/advertising-cloud/media-optimizer/dynamic-creative-optimization.html](https://www.adobe.com/advertising-cloud/media-optimizer/dynamic-creative-optimization.html) \r\n* _Adobe, 10_. [http://www.adobe.com/marketing-cloud/experience-manager.html](http://www.adobe.com/marketing-cloud/experience-manager.html) \r\n* _Adobe, 11_. [http://www.adobe.com/marketing-cloud/campaign.html](http://www.adobe.com/marketing-cloud/campaign.html) \r\n* _Adobe, 12_. [http://www.adobe.com/marketing-cloud/target.html](http://www.adobe.com/marketing-cloud/target.html) \r\n* _Adobe, 13_. [http://www.adobe.com/marketing-cloud/primetime.html](http://www.adobe.com/marketing-cloud/primetime.html) \r\n* _Adobe, 14_. [http://www.adobe.com/marketing-cloud/social.html](http://www.adobe.com/marketing-cloud/social.html) \r\n* _Adobe, 15_. [http://www.adobe.com/data-analytics-cloud.html](http://www.adobe.com/data-analytics-cloud.html) \r\n* _Adobe, 16_. [http://www.adobe.com/data-analytics-cloud/analytics.html](http://www.adobe.com/data-analytics-cloud/analytics.html) \r\n* _Adobe, 17_. [http://www.adobe.com/data-analytics-cloud/audience-manager.html](http://www.adobe.com/data-analytics-cloud/audience-manager.html) \r\n* _Adobe, 18_. [https://www.adobe.com/data-analytics-cloud/audience-manager.html#m226a251c23c15530b6f70ef20da2003c](https://www.adobe.com/data-analytics-cloud/audience-manager.html#m226a251c23c15530b6f70ef20da2003c) \r\n* _Adobe, 19_. [https://www.adobe.com/data-analytics-cloud/audience-manager.html#x](https://www.adobe.com/data-analytics-cloud/audience-manager.html#x) \r\n* _Adobe, 20_. [http://www.adobe.com/privacy/marketing-cloud.html](http://www.adobe.com/privacy/marketing-cloud.html) \r\n* _Adobe, 21_. [https://www.adobe.com/privacy/opt-out.html](https://www.adobe.com/privacy/opt-out.html) \r\n* _Adobe, 22_. [https://marketing.adobe.com/resources/help/en_US/aam/faq_privacy.html](https://marketing.adobe.com/resources/help/en_US/aam/faq_privacy.html) \r\n* _Adobe, 23_. [https://blogs.adobe.com/digitalmarketing/mobile/10-things-you-need-to-know-about-adobes-mobile-marketing](https://blogs.adobe.com/digitalmarketing/mobile/10-things-you-need-to-know-about-adobes-mobile-marketing) \r\n* _Adobe, 24_. [http://www.adobe.com/experience-cloud/service-support/partners.html](http://www.adobe.com/experience-cloud/service-support/partners.html) \r\n* _Analytics Demystified, 01_. [http://analyticsdemystified.com/adobe-analytics/adobes-new-marketing-cloud-visitor-id-how-does-it-work](http://analyticsdemystified.com/adobe-analytics/adobes-new-marketing-cloud-visitor-id-how-does-it-work) \r\n* _Crunchbase, 01_. [https://www.crunchbase.com/organization/demdex](https://www.crunchbase.com/organization/demdex) \r\n* _Forbes, 01_. [https://www.forbes.com/sites/roberthof/2013/11/07/adobe-takes-its-marketing-cloud-services-mobile](https://www.forbes.com/sites/roberthof/2013/11/07/adobe-takes-its-marketing-cloud-services-mobile) \r\n* _MarketWatch, 01_. [https://www.marketwatch.com/story/adobe-launches-mobile-services-for-adobe-marketing-cloud-2013-11-07](https://www.marketwatch.com/story/adobe-launches-mobile-services-for-adobe-marketing-cloud-2013-11-07) \r\n* _PCWorld, 01_. [https://www.pcworld.com/article/2061880/adobe-adds-geolocation-targeting-to-marketing-cloud.html](https://www.pcworld.com/article/2061880/adobe-adds-geolocation-targeting-to-marketing-cloud.html) \r\n* _TechCrunch, 01_. [https://techcrunch.com/2011/01/18/adobe-buys-behavioral-data-management-platform-demdex](https://techcrunch.com/2011/01/18/adobe-buys-behavioral-data-management-platform-demdex)\r\n\r\n## External links\r\n* _Wikipedia (Adobe Marketing Cloud_: [https://en.wikipedia.org/wiki/Adobe_Marketing_Cloud](https://en.wikipedia.org/wiki/Adobe_Marketing_Cloud) \r\n* _Adobe Audience Manager_: [https://www.adobe.com/data-analytics-cloud/audience-manager.html](https://www.adobe.com/data-analytics-cloud/audience-manager.html) \r\n* _Adobe Marketing Cloud_: [http://www.adobe.com/marketing-cloud.html](http://www.adobe.com/marketing-cloud.html)", "id": 40, "code_signature": "com.adobe.mobile.Analytics", "website": "https://www.adobe.com/data-analytics-cloud/audience-manager.html", "name": "Demdex", "network_signature": "demdex\\.net", "creation_date": "2017-11-15"}, "41": {"description": "", "id": 41, "code_signature": ".adswizz.", "website": "http://www.adswizz.com/", "name": "AdsWizz", "network_signature": "adswizz\\.com|cdn\\.adswizz.com\\.edgesuite\\.net", "creation_date": "2017-11-15"}, "42": {"description": "Belongs to SalesForce", "id": 42, "code_signature": "com.exacttarget.", "website": "http://help.exacttarget.com/en/technical_library/API_Overview/", "name": "ExactTarget", "network_signature": "\\.exacttarget\\.", "creation_date": "2017-11-16"}, "43": {"description": "## About\r\n\r\nOmniture, originally a online marketing and web analytics company, was acquired by Adobe in 2009 and it was run as a separate business unit until 2012 when it was integrated into the Adobe Marketing Cloud. Several of Omniture's LLC filings remain active. [Source: OpenCorporates](https://opencorporates.com/companies/us_de/3077923)\r\n\r\n## Ownership\r\n\r\nAdobe (NASDAQ: ADBE) is a publicly-traded multinational software company. \r\n\r\n## What it does\r\n\r\n* Behavioral Analytics\r\n* Online Marketing\r\n* Machine-learning Analysis\r\n\r\n## Privacy Policy\r\n\r\n[Onminture's Privacy Policy is the same as Adobe's. Policy dated 3/5/18 and reviewed 17/11/2018:](https://www.adobe.com/privacy/policy.html)\r\n\r\n* Adobe's Privacy Policy is broad and covers the span of its wide-ranging services. It is unclear what is specifially covered by the Omniture business line. \r\n\r\n* Users must opt-out of each segment of data collection individually: Desktop Identifiable Data Collection, Device Identifiable Data Collection, Mobile Data Collection, Experience Cloud service usage data, \r\nMachine learning analysis of user content, Interest-based ads, and Adobe websites. [Link to opt-out](https://www.adobe.com/privacy/opt-out.html)\r\n\r\n* Data may be shared with fraud prevention services, law enforcement services in the context of an investigation, social media marketers and platforms, sales and advertising partners, retailers, research organizations, advertisers, ad agencies, advertising networks and platforms, information service providers, publishers, and non-profit organizations.", "id": 43, "code_signature": "com.omniture.|com.adobe.adms.measurement.", "website": "http://www.omniture.com", "name": "Omniture", "network_signature": "omtrdc\\.net|omniture\\.com", "creation_date": "2017-11-16"}, "44": {"description": "* Website: https://www.safegraph.com, https://github.com/OpenLocate\r\n* Comment: SafeGraph specializes in the collection of physical location data for data mining and analytics. OpenLocate is the SDK announced in 2017.\r\n* Category: [Location]\r\n* Code signature: `com.safegraph.|com.openlocate`\r\n* Network signature: `api\\.safegraph\\.com`\r\n* Maven repository: `https://s3-us-west-2.amazonaws.com/openlocate-android/`\r\n* Artifact ID: `openlocate-android`\r\n* Group ID: `com.openlocate` \r\n* Gradle: `com.openlocate:openlocate:1.+`\r\n* Additional links: [OpenLocate SDK repo](https://github.com/OpenLocate/openlocate-android/), [Crunchbase](https://www.crunchbase.com/organization/safegraph), [Stanford economics paper](https://web.archive.org/web/20171116110210if_/https://economics.stanford.edu/sites/default/files/sharable_fulldraft.pdf), [Washington Post](https://www.washingtonpost.com/news/wonk/wp/2017/11/15/politics-really-is-ruining-thanksgiving-according-to-data-from-10-million-cellphones), [The Outline](https://theoutline.com/post/2490/why-is-this-company-tracking-where-you-are-on-thanksgiving)\r\n* Notes: SafeGraph collected 17 trillion location markers for 10 million smartphones in November 2016. OpenLocate SDK for Android is MIT/Expat licensed.\r\n\r\n## Primary Location\r\nUnited States (San Francisco) [Crunchbase, 01](https://www.crunchbase.com/organization/safegraph)\r\n\r\n## Website\r\n[https://www.safegraph.com](https://www.safegraph.com)\r\n\r\n## About\r\nSafeGraph specializes in the collection of physical location data for data mining and analytics.\r\n\r\n## Ownership\r\nSafeGraph\r\n\r\n## Documentation\r\n[https://github.com/OpenLocate/openlocate-android](https://github.com/OpenLocate/openlocate-android)\r\n\r\n## Products and Services\r\nSafeGraph is a data company which aims to build a robust and detailed location-based tracking service for advertisers, industry, government and researchers. Products and services include:\r\n\r\n* _SafeGraph Movement Panel:_ SafeGraph's \"database of ultra-accurate GPS-location data that comes from anonymized mobile devices.\" The Movement panel offers:\r\n * _Sink detection:_ Detection of inaccurate location data based on \" specific coordinates occurring at impossibly high rates\".\r\n * _Teleporting detection:_ Detection of inaccurate location data when \"devices appear to move at impossibly fast speeds, ostensibly traveling large distances between data points that occur next to each other\" in data streams like bid streams.\r\n * _Jumpiness detection:_ Detection of innacurate location data when \"we see two consecutive points in time that are fairly close but still implausibly spaced\" (eg, \"the GPS receiver in your phone lags or if a nearby skyscraper interferes with the location signal\") [SafeGraph, 01](https://blog.safegraph.com/less-than-10-of-bid-stream-location-data-is-high-quality-and-we-know-how-to-find-it-3a2c0df35475)\r\n* _SafeGraph Places API:_ This \"to easily find the places of interest that are near a given lat/long, ordered by distance or relevance\" [SafeGraph, 03](https://developers.safegraph.com/docs/places.html).\r\n* _OpenLocate:_ The OpenLocate SDK will \"collect location data (like GPS) from phones\" [SafeGraph, 04](https://github.com/OpenLocate). This includes an Android and iOS SDK. The service is built to provide developers complete control over their location data. Developers can build location-enabled features into their apps and \"maintain complete control over how end-user data is collected, where it is stored, and which APIs it will be sent to\". This includes sending to storage services (like Amazon S3) or APIs (such as Google Places API or SafeGraph's Places API) [SafeGraph, 05](https://blog.safegraph.com/introducing-openlocate-the-open-source-location-sdk-f5c5d2739a48).\r\n\r\nOther services include:\r\n* \"Detailed polygon maps on 50+ million U.S. places of interest\r\n* Understanding of each business's popularity, taxonomy, hours, etc.\r\n* Core investments in benchmarking via truth sets\"\r\n * This includes Explicit Truth Sets (Check-ins, Daily diaries, Web surveys) and Implicit Truth Sets (Credit card data, Receipt data, First-party transactions) \r\n\r\nData from visits may include:\r\n\r\n* _Core truth set for matching:_\r\n * High-res GPS data\r\n * Deterministic data\r\n * Explicit and implicit truth\r\n * Data collected in background from large population\r\n* _Deep places map:_\r\n * Best polygons\r\n * Footprint geometries\r\n * Metadata\r\n * Categories\r\n * Hours of operation\r\n* Machine learning technology\r\n * Cross-validated against multiple independent 3rd party truth sets about where people go\r\n* _Truth and accuracy_\r\n * High Precision // Low false positive rate; High recall // Low false negative rate\" [SafeGraph, 06](https://www.safegraph.com/truth)\r\n\r\n## Privacy Policy\r\n_Data collection (method and use):_ SafeGraph collects data from \"trusted third-party data partners such as mobile application developers, through APIs and other delivery methods\". The data collection and use is \"governed by the privacy policy and legal terms of the data collector and the website using the data; it is not governed by SafeGraph.\" SafeGraph \"aggregates data collected from our data partners, and allows third party customers to access the Data for a variety of purposes such as ad targeting, traffic analysis, and market research.\" SafeGraph may also use data for their own \"internal and operational purposes\", and share data in response to requests from law enforcement or a governmental agency, \"to protect or enforce our rights or those of others, or to investigate potential wrongdoing.\" Data can also be transferred to a successor entity in the event of a merger or acquisition.\r\n\r\n_Information collected:_ Information collected includes \"data regarding a device\u2019s precise geographic location, as well as other mobile identifiers such as Apple IDFAs and Google Android IDs, and other information about users and their devices.\" \r\n\r\n_Jurisdictions:_ \"SafeGraph stores and processes information on servers in many countries around the world. We therefore may process your information on a server located outside the country where you live... Our customers (or companies that help us process the Data) may be located in other countries, so the Data we provide may be processed or used in a variety of countries, other than those our users reside in.\" Customers of SafeGraph may create cross-device capabilities \"to enable marketers to target users across various channels and devices.\"\r\n\r\n_Opt-out:_ SafeGraph informs users of opt-out procedures for interest-based advertising and location tracking. To opt out of interest-based advertising, they state, users can adjust settings in their Android or iOS devices. This procedure, which they note may change, is mentioned in the SafeGraph privacy policy \"purely for informational purposes.\" SafeGraph further notes that \"You also can remove your consent to having your location data collected by changing the settings on your device. (Certain services may lose functionality as a result.)\" SafeGraph's Privacy Policy provides links to the Network Advertising Initiative and the Digital Advertising Alliance, as well as www.youronlinechoices.com. It informs users that these websites may provide additional opt-out options.\r\n\r\n_Retention:_ Information SafeGraph collects is \"retained indefinitely unless there has been a direct opt-out with us as directed above.\"\r\n\r\n_Security:_ SafeGraph has security policies and procedures to \" ensure compliance with industry best practices.\" They state, \"no physical or technological safeguards are 100 percent secure, we do not guarantee the security of any particular elements of Data that we hold\" [SafeGraph, 07](https://www.safegraph.com/privacy-policy).\r\n\r\n## Relationships\r\n_Clients and partners:_ Statiq / AirSage / Stanford University / GroundTruth (formerly xAd) / UCLA / Baylor University / Weborama / Tufts University / The University of Chicago / Alphonzo / Freckle IoT / Georgia Tech / Esri / Appnext / 4Info / Research Now / Tapfwd / Arrivalist / Placecast / ThinkNear by Telenav / Pitney Bowes / Columbia University / Purdue University / UC San Diego / Sidewalk Labs / Temple University / Citilabs / PlaceIQ / Moovit / Skyhook / Postie / PicsArt / Oklahoma State University / Santa Clara University / OpenLocate\r\n\r\n## Details\r\n_Financial details:_ SafeGraph was founded in 2016, and has raised $16 million from funders [Crunchbase, 01](https://www.crunchbase.com/organization/safegraph); [SafeGraph, 02](https://blog.safegraph.com/safegraph-raises-16-million-series-a-e8e88eeb7beb) \r\n\r\n_Scope:_ SafeGraph \"has access to super-accurate, anonymized location data on over 5% of all mobile phones in the U.S. (as of August 2017)\" and is \"increasing that percentage every day\" [SafeGraph, 01](https://blog.safegraph.com/less-than-10-of-bid-stream-location-data-is-high-quality-and-we-know-how-to-find-it-3a2c0df35475).\r\n\r\n_Slogans:_\r\n\r\n* \"SafeGraph maintains the ground truth dataset for human movement across the globe\"\r\n* \"We provide high-quality location data products to help organizations make better decisions and improve lives\"\r\n\r\n## References\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/safegraph](https://www.crunchbase.com/organization/safegraph) \r\n* _SafeGraph, 01._ [https://blog.safegraph.com/less-than-10-of-bid-stream-location-data-is-high-quality-and-we-know-how-to-find-it-3a2c0df35475](https://blog.safegraph.com/less-than-10-of-bid-stream-location-data-is-high-quality-and-we-know-how-to-find-it-3a2c0df35475) \r\n* _SafeGraph, 02._ [https://blog.safegraph.com/safegraph-raises-16-million-series-a-e8e88eeb7beb](https://blog.safegraph.com/safegraph-raises-16-million-series-a-e8e88eeb7beb) \r\n* _SafeGraph, 03._ [https://developers.safegraph.com/docs/places.html](https://developers.safegraph.com/docs/places.html) \r\n* _SafeGraph, 04._ [https://github.com/OpenLocate](https://github.com/OpenLocate) \r\n* _SafeGraph, 05._ [https://blog.safegraph.com/introducing-openlocate-the-open-source-location-sdk-f5c5d2739a48](https://blog.safegraph.com/introducing-openlocate-the-open-source-location-sdk-f5c5d2739a48) \r\n* _SafeGraph, 06._ [https://www.safegraph.com/truth](https://www.safegraph.com/truth) \r\n* _SafeGraph, 07._ [https://www.safegraph.com/privacy-policy](https://www.safegraph.com/privacy-policy)\r\n\r\n## External Links\r\n* _Crunchbase (SafeGraph):_ [https://www.crunchbase.com/organization/safegraph](https://www.crunchbase.com/organization/safegraph) \r\n* _Gigya:_ [https://www.gigya.com/blog/exploring-future-identity](https://www.gigya.com/blog/exploring-future-identity) \r\n* _Even:_ [https://evenfinancial.com/press/mit-brings-together-fintech-financial-services-first-ever-hackathon](https://evenfinancial.com/press/mit-brings-together-fintech-financial-services-first-ever-hackathon) \r\n* _SafeGraph:_ [https://blog.safegraph.com/less-than-10-of-bid-stream-location-data-is-high-quality-and-we-know-how-to-find-it-3a2c0df35475](https://blog.safegraph.com/less-than-10-of-bid-stream-location-data-is-high-quality-and-we-know-how-to-find-it-3a2c0df35475) \r\n* _Stanford Economics:_ [https://web.archive.org/web/20171116110210if_/https://economics.stanford.edu/sites/default/files/sharable_fulldraft.pdf](https://web.archive.org/web/20171116110210if_/https://economics.stanford.edu/sites/default/files/sharable_fulldraft.pdf) \r\n* _Washington Post:_ [https://www.washingtonpost.com/news/wonk/wp/2017/11/15/politics-really-is-ruining-thanksgiving-according-to-data-from-10-million-cellphones](https://www.washingtonpost.com/news/wonk/wp/2017/11/15/politics-really-is-ruining-thanksgiving-according-to-data-from-10-million-cellphones) \r\n* _The Outline:_ [https://theoutline.com/post/2490/why-is-this-company-tracking-where-you-are-on-thanksgiving](https://theoutline.com/post/2490/why-is-this-company-tracking-where-you-are-on-thanksgiving)", "id": 44, "code_signature": "com.safegraph.|com.openlocate", "website": "https://www.safegraph.com/", "name": "Safe Graph", "network_signature": "api\\.safegraph\\.com", "creation_date": "2017-11-16"}, "45": {"description": "", "id": 45, "code_signature": "com.tagcommander.", "website": "https://www.commandersact.com/en/", "name": "Tag Commander", "network_signature": "\\.commander1\\.com", "creation_date": "2017-11-28"}, "46": {"description": "We can only detect network activity of this tracker.\r\n\r\n * [API doc](https://github.com/CrowdTangle/API/wiki)\r\n * [Mediapart article](https://www.mediapart.fr/journal/france/011217/comment-facebook-achete-la-presse-francaise)", "id": 46, "code_signature": ".", "website": "https://www.crowdtangle.com/", "name": "CrowdTangle", "network_signature": "api\\.crowdtangle\\.com", "creation_date": "2017-12-03"}, "47": {"description": "", "id": 47, "code_signature": "com.facebook.audiencenetwork", "website": "https://developers.facebook.com/docs/android/", "name": "Facebook Audience", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-03"}, "48": {"description": "", "id": 48, "code_signature": "com.google.android.apps.analytics.|com.google.android.gms.analytics.", "website": "http://www.google.com/analytics/", "name": "Google Analytics", "network_signature": "google-analytics\\.com", "creation_date": "2017-12-03"}, "49": {"description": "[API documentation](https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/package-summary)", "id": 49, "code_signature": "com.google.firebase.analytics.|com.google.android.gms.measurement.", "website": "https://firebase.google.com/", "name": "Google Firebase Analytics", "network_signature": "firebase\\.com", "creation_date": "2017-12-03"}, "51": {"description": "## About\r\n\r\nEulerian Technologies is a privately-held e-marketing and web analytics company based in France. [Source: OpenCorporates](https://opencorporates.com/companies/gb/04437532) It has offices in Paris, Madrid, Lille, and staff in Canada. [Source: Linkedin](https://www.linkedin.com/company/eulerian-technologies/])\r\n\r\n## Ownership\r\n\r\nGuillaume Fougnies and Mathieu Jondet founded Eulerian Technologies in 2002. [Source: Eulerian.com](https://www.eulerian.com/en/about-us/)\r\n\r\n## What it does\r\n\r\n* Behavioral Analytics \r\n* Data Collection\r\n* Attribution Modeling\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 5/9/2018](https://www.eulerian.com/en/privacy/):\r\n\r\n* Eulerian's policy acknowledges that it may receive (\"including personal data\") data from from its clients' partners for statistical and analytical reporting. It states that it acts as a \"data processor\" on behalf of its clients' instructions.\r\n\r\n* Collected data is the \"property of our clients, [who] are data controllers, at all times.\" It is \"not used on behalf of Eulerian Technologies.\"\r\n\r\n* Users looking to request deletion of their data are referred to contact their clients directly using the contact details on their respective websites. The policy then provides a list of websites that use their software.", "id": 51, "code_signature": "com.eulerian.android.sdk", "website": "https://www.eulerian.com/en/", "name": "Eulerian", "network_signature": "eulerian\\.com", "creation_date": "2017-12-03"}, "52": {"description": "", "id": 52, "code_signature": "com.adjust.sdk.", "website": "https://www.adjust.com/", "name": "Adjust", "network_signature": "adjust\\.com|adj\\.st", "creation_date": "2017-12-03"}, "53": {"description": "", "id": 53, "code_signature": "com.chartboost.sdk.", "website": "https://answers.chartboost.com/en-us/", "name": "ChartBoost", "network_signature": "\\.chartboost\\.com", "creation_date": "2017-12-03"}, "54": {"description": "By *CapGemini*", "id": 54, "code_signature": "com.backelite.android.|com.backelite.bkdroid.", "website": "https://www.backelite.com/", "name": "Backelite", "network_signature": "backelite\\.com", "creation_date": "2017-12-03"}, "55": {"description": "[SDK documentation](https://areametrics-android-sdk.readme.io/)\r\nMaven repository: `https://dl.bintray.com/areametrics/AreaMetricsSDK`\r\nArtifact: `com.areametrics:sdk:2.2.2`", "id": 55, "code_signature": "com.areametrics.areametricssdk|com.areametrics.nosdkandroid", "website": "https://areametrics.com/", "name": "Areametrics", "network_signature": "areametrics\\.com", "creation_date": "2017-12-03"}, "56": {"description": "", "id": 56, "code_signature": "com.comscore.", "website": "https://comscore.com/", "name": "ComScore", "network_signature": "comscore\\.com", "creation_date": "2017-12-03"}, "57": {"description": "", "id": 57, "code_signature": "com.cuebiq.cuebiqsdk.model.Collector|com.cuebiq.cuebiqsdk.receiver.CoverageReceiver", "website": "http://www.cuebiq.com/", "name": "Cuebiq", "network_signature": "cuebiq\\.com", "creation_date": "2017-12-03"}, "58": {"description": "", "id": 58, "code_signature": "com.helpshift", "website": "https://www.helpshift.com", "name": "HelpShift", "network_signature": "helpshift.com", "creation_date": "2017-12-03"}, "59": {"description": "Bluetooth Beacons & Location Solutions", "id": 59, "code_signature": "com.kontakt.sdk.android.", "website": "https://kontakt.io/", "name": "Kontakt", "network_signature": "kontakt.io", "creation_date": "2017-12-03"}, "60": {"description": "Indoor location", "id": 60, "code_signature": "com.locuslabs.sdk", "website": "http://locuslabs.com", "name": "Locuslabs", "network_signature": "locuslabs\\.com", "creation_date": "2017-12-03"}, "61": {"description": "Track what ads users are viewing", "id": 61, "code_signature": "com.moat.analytics.mobile.", "website": "https://moat.com/analytics", "name": "Moat", "network_signature": "moat\\.com", "creation_date": "2017-12-03"}, "62": {"description": "Collect behavioral data", "id": 62, "code_signature": "com.segment.analytics.", "website": "https://segment.com/", "name": "Segment", "network_signature": "segment.com|api.segment.io", "creation_date": "2017-12-03"}, "63": {"description": "Microsoft", "id": 63, "code_signature": "com.ubikod.capptain.|com.microsoft.azure.engagement.", "website": "https://docs.microsoft.com/en-us/azure/mobile-engagement/mobile-engagement-android-sdk-overview", "name": "Mobile Engagement", "network_signature": "login\\.microsoftonline\\.com|management\\.azure\\.com", "creation_date": "2017-12-04"}, "64": {"description": "", "id": 64, "code_signature": "net.crowdconnected.androidcolocator", "website": "https://developers.colocator.net", "name": "Colocator", "network_signature": "colocator\\.net", "creation_date": "2017-12-04"}, "65": {"description": "", "id": 65, "code_signature": "com.facebook.ads", "website": "https://developers.facebook.com/docs/android", "name": "Facebook Ads", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-05"}, "66": {"description": "", "id": 66, "code_signature": "com.facebook.appevents", "website": "https://developers.facebook.com/docs/android", "name": "Facebook Analytics", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-05"}, "67": {"description": "", "id": 67, "code_signature": "com.facebook.login", "website": "https://developers.facebook.com/docs/android", "name": "Facebook Login", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-05"}, "68": {"description": "", "id": 68, "code_signature": "com.facebook.notifications", "website": "https://developers.facebook.com/docs/android", "name": "Facebook Notifications", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-05"}, "69": {"description": "", "id": 69, "code_signature": "com.facebook.places", "website": "https://developers.facebook.com/docs/android", "name": "Facebook Places", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-05"}, "70": {"description": "", "id": 70, "code_signature": "com.facebook.share", "website": "https://developers.facebook.com/docs/android", "name": "Facebook Share", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-05"}, "71": {"description": "https://developers.google.com/admob/android/mediation", "id": 71, "code_signature": "com.google.android.gms.ads.mediation.", "website": "https://developers.google.com/admob/android", "name": "Google Ads", "network_signature": "\\.google\\.com", "creation_date": "2017-12-05"}, "72": {"description": "* Website: https://www.applovin.com/\r\n* Comment: AppLovin is a mobile advertising technology company that enables brands to create mobile marketing campaigns that are fueled by data. \r\n* Category: Advertising\r\n* Code signature: `com.applovin.`\r\n* Network signature: `applovin\\.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `applovin-sdk`\r\n* Group ID: `com.applovin` \r\n* Gradle: `com.applovin:applovin-sdk:7.6.0`\r\n* Additional links: [Crunchbase](https://www.crunchbase.com/organization/applovin)\r\n* Notes: AppLovin SDK requires Google Ads Identifier `com.google.android.gms.ads.identifier.*`", "id": 72, "code_signature": "com.applovin", "website": "https://www.applovin.com/", "name": "AppLovin", "network_signature": "applovin\\.com|applvn\\.com", "creation_date": "2018-01-05"}, "73": {"description": "* Website: https://www.avocarrot.com/\r\n* Comment: Avocarrot is a native mobile advertising platform which provides real rewards on mobile apps. \r\n* Category: Advertising\r\n* Code signature: `com.avocarrot.sdk`\r\n* Network signature: `\\.avocarrot\\.com`\r\n* Maven repository: `https://s3.amazonaws.com/avocarrot-android-builds/dist/`\r\n* Artifact ID: `mediation-sdk-nativead`\r\n* Group ID: `com.avocarrot.sdk` \r\n* Gradle: `com.avocarrot.sdk:mediation-sdk-nativead:4.7.1`\r\n* Additional links: [Crunchbase](https://www.crunchbase.com/organization/avocarrot) [Dev doc](https://docs.avocarrot.com/android/native-list-feed)\r\n* Notes: Uses Google Ads", "id": 73, "code_signature": "com.avocarrot.sdk", "website": "https://www.glispa.com", "name": "Glispa Connect (Formerly Avocarrot)", "network_signature": "\\.avocarrot\\.com|ads\\.glispa\\.com|exp\\.glispa\\.com|rtb\\.platform\\.glispa\\.com|trk\\.glispa\\.com|templates\\.glispaconnect\\.com", "creation_date": "2018-01-05"}, "74": {"description": "* Website: http://www.nativex.com/\r\n* Comment: NativeX is the leading ad technology for mobile games. \r\n* Category: Advertising\r\n* Code signature: `com.nativex.`\r\n* Network signature: `mobvista\\.com|nativex\\.com`\r\n* Maven repository: `NC`\r\n* Artifact ID: `NC`\r\n* Group ID: `NC` \r\n* Gradle: `NC`\r\n* Additional links: [Crunchbase](https://www.crunchbase.com/organization/nativex) [NativeX Android SDK](https://github.com/nativex/NativeX-Android-SDK/archive/master.zip) [Dev doc](http://www.help.nativex.com/monetize/android-monetization/android-sdk-integration-guide/)\r\n* Notes: Acquired by MobVista", "id": 74, "code_signature": "com.nativex", "website": "http://www.nativex.com/", "name": "NativeX", "network_signature": "nativex\\.com", "creation_date": "2018-01-05"}, "75": {"description": "* Website: https://map.baidu.com\r\n* Comment: Baidu is the Web giant in China, the homegrown counterpart to Google.\r\n* Category: Maps, Location\r\n* Code signature: `com.baidu.BaiduMap`\r\n* Network signature: `map.baidu\\.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.baidu` \r\n* Gradle: `NC`\r\n* Additional links: [Android SDK documentation](http://lbsyun.baidu.com/index.php?title=android-locsdk), [iOS SDK](https://github.com/iosmvn/BaiduMap-iOS-SDK)\r\n* Notes: [\"Baidu uses millions of users\u2019 location data to make predictions\", New Scientist](https://www.newscientist.com/article/2098206-baidu-uses-millions-of-users-location-data-to-make-predictions/)", "id": 75, "code_signature": "com.baidu.BaiduMap", "website": "https://map.baidu.com", "name": "Baidu Maps", "network_signature": "map\\.baidu\\.com", "creation_date": "2018-01-05"}, "76": {"description": "* Website: https://wechat.com, https://weixin.qq.com\r\n* Comment: WeChat is the most popular chat client in China and may become the official app for state identification.\r\n* Category: Maps, Location\r\n* Code signature: `com.tencent.map.geolocation|com.tencent.mm.plugin.location.|com.tencent.mm.plugin.location_soso.|com.tencent.mm.plugin.location_google.`\r\n* Network signature: `map.qq\\.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.tencent` \r\n* Gradle: `NC`\r\n* Additional links: [Reverse-engineered WeChat code](https://github.com/reverseengineeringer/com.tencent.mm)\r\n* Notes: [\"WeChat poised to become China\u2019s official electronic ID system\", South China Morning Post](http://www.scmp.com/tech/social-gadgets/article/2125736/wechat-poised-become-chinas-official-electronic-id-system)", "id": 76, "code_signature": "com.tencent.map.geolocation|com.tencent.mm.plugin.location.|com.tencent.mm.plugin.location_soso.|com.tencent.mm.plugin.location_google", "website": "https://wechat.com", "name": "WeChat Location", "network_signature": "map\\.qq\\.com", "creation_date": "2018-01-05"}, "77": {"description": "* Website: http://hypertrack.com, https://github.com/hypertrack\r\n* Comment: HyperTrack implements live location sharing and activity tracking.\r\n* Category: [Maps, Location]\r\n* Code signature: `com.hypertrack.|com.hypertracklive.|io.hypertrack.`\r\n* Network signature: `trck.at|hypertrack\\.amazonaws.com|api\\.hypertrack\\.com`\r\n* Maven repository: `http://hypertrack-android-sdk.s3-website-us-west-2.amazonaws.com/`\r\n* Artifact ID: `hypertrack-live-android`\r\n* Group ID: `com.hypertrack` \r\n* Gradle: `com.hypertrack:android:0.4.22:release@aar`\r\n* Additional links: [HyperTrack SDK repo](https://github.com/hypertrack/hypertrack-live-android), [Documentation](https://docs.hypertrack.com/)\r\n* Notes: HyperTrack SDK for Android is MIT/Expat licensed.", "id": 77, "code_signature": "com.hypertrack|com.hypertracklive.|io.hypertrack", "website": "http://hypertrack.com", "name": "HyperTrack", "network_signature": "trck\\.at|hypertrack\\.amazonaws\\.com|api\\.hypertrack\\.com", "creation_date": "2018-01-05"}, "78": {"description": "* Website: https://uber.com\r\n* Comment: Uber Analytics tracks location and behavior as part of its suite of apps such as Uber, UberEATS, and Uber Driver.\r\n* Category: Location, Analytics\r\n* Code signature: `com.ubercab.analytics.|com.ubercab.library.metrics.analytics.|com.ubercab.client.core.analytics.`\r\n* Network signature: `events.uber.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.ubercab` \r\n* Gradle: `NC`\r\n* Additional links: [Dissassembled Uber code](https://github.com/IRMobydick/AndroidDissambleApps/tree/master/com.ubercab), [Reverse-engineered Uber code](https://github.com/reverseengineeringer/com.ubercab)\r\n* Notes: Uber acquired map and location startup deCarta, which included data and maps from TomTom.", "id": 78, "code_signature": "com.ubercab.analytics.|com.ubercab.library.metrics.analytics.|com.ubercab.client.core.analytics.", "website": "https://uber.com", "name": "Uber Analytics", "network_signature": "events\\.uber\\.com", "creation_date": "2018-01-05"}, "79": {"description": "* Website: http://lisnr.com\r\n* Comment: LISNR tracks users via audio beacons in retail outlets, as well as collecting behavioral data on a mobile device. Retailers broadcast a \"Smart Tone\" on speaker systems and LISNR reacts to the sound.\r\n* Category: [Audio Beacon, Analytics]\r\n* Code signature: `com.lisnr.|com.lisnr.sdk.`\r\n* Network signature: `lisnr\\.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.lisnr.sdk` \r\n* Gradle: `com.lisnr.sdk:sdk:5.0.0.+`\r\n* Additional links: [LISNR demo app repo](https://github.com/LISNR/LISNR-Auth-Demo-Android), [\"Privacy Threats through Ultrasonic Side Channels on Mobile Devices\", Technische Universit at Braunschweig](http://christian.wressnegger.info/content/projects/sidechannels/2017-eurosp.pdf)\r\n* Notes:", "id": 79, "code_signature": "com.lisnr.", "website": "http://lisnr.com", "name": "Lisnr", "network_signature": "lisnr\\.com", "creation_date": "2018-01-05"}, "80": {"description": "* Website: http://silverpush.co, http://silverpush.com\r\n* Comment: SilverPush tracks users via audio beacons in retail outlets, as well as collecting behavioral and location data on a mobile device. Retailers broadcast a ultrasonic tone on speaker systems and SilverPush reacts to the sound.\r\n* Category: [Audio Beacon, Analytics]\r\n* Code signature: `com.silverpush.|com.silverpush.location|com.silverpush.sdk.android.SPService`\r\n* Network signature: `silverpush\\.co|silverpush\\.com|54.243.73.253:8080/SilverPush/`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.silverpush` \r\n* Gradle: `NC`\r\n* Additional links: [\"SilverPush Unmasked\" repo](https://github.com/MAVProxyUser/SilverPushUnmasked), [\"Privacy Threats through Ultrasonic Side Channels on Mobile Devices\", Technische Universit at Braunschweig](http://christian.wressnegger.info/content/projects/sidechannels/2017-eurosp.pdf)\r\n* Notes:", "id": 80, "code_signature": "com.silverpush.|com.silverpush.location|com.silverpush.sdk.android.SPService", "website": "http://silverpush.co", "name": "SilverPush", "network_signature": "silverpush\\.co|silverpush\\.com|54\\.243\\.73\\.253:8080/SilverPush/", "creation_date": "2018-01-05"}, "81": {"description": "* Website: https://shopkick.com\r\n* Comment: Shopkick tracks users via \"shopBeacon\" beacons (Apple iBeacons) in retail outlets, as well as collecting behavioral and location data on a mobile device.\r\n* Category: [Audio Beacon, Bluetooth Beacon, Analytics]\r\n* Code signature: `com.shopkick.sdk.api.|com.shopkick.fetchers.`\r\n* Network signature: `shopkick\\.com|shopkick\\.de|sdk.shopkick.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.shopkick` \r\n* Gradle: `NC`\r\n* Additional links: [Shopkick on Github](https://github.com/shopkick), [Shopkick on Anaconda Cloud](https://anaconda.org/shopkick), [Shopkick on Docker Hub](https://hub.docker.com/r/shopkick/), [\"Privacy Threats through Ultrasonic Side Channels on Mobile Devices\", Technische Universit at Braunschweig](http://christian.wressnegger.info/content/projects/sidechannels/2017-eurosp.pdf)\r\n* Notes: Shopkick is a very popular shopping app \"companion\" used by millions. Shopkick has a close relationship with Scandit barcode scanner SDK.", "id": 81, "code_signature": "com.shopkick.sdk.api.|com.shopkick.fetchers.", "website": "https://shopkick.com", "name": "Shopkick", "network_signature": "shopkick\\.com|shopkick\\.de|sdk.shopkick.com", "creation_date": "2018-01-05"}, "82": {"description": "* Website: http://alphonso.tv\r\n* Comment: Alphonso listens to audio signals in TV advertisements and is included in games and other apps for children.\r\n* Category: [Audio Beacon, Analytics]\r\n* Code signature: `tv.alphonso.service`\r\n* Network signature: `prov.alphonso.tv|api.alphonso.tv`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `tv.alphonso` \r\n* Gradle: `NC`\r\n* Additional links: [Presentation about TV ads data from Alphonso](https://github.com/kupagulova/alphonso-analysis-demo), [\"That Game on Your Phone May Be Tracking What You\u2019re Watching on TV\", New York Times](https://www.nytimes.com/2017/12/28/business/media/alphonso-app-tracking.html)\r\n* Notes: Alphonso SDK makes heavy use of the Google Admob mediation service.", "id": 82, "code_signature": "tv.alphonso.service", "website": "http://alphonso.tv", "name": "Alphonso", "network_signature": "prov.alphonso.tv|api.alphonso.tv", "creation_date": "2018-01-05"}, "83": {"description": "* Website: https://smaato.com\r\n* Comment: Smaato is a mobile ad platform that includes video ads.\r\n* Category: [Advertising, Analytics]\r\n* Code signature: `com.smaato.soma.`\r\n* Network signature: `soma.smaato.net|smaato.net`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.smaato.soma` \r\n* Gradle: `NC`\r\n* Additional links: [Smaato SDK Documentation](https://wiki.smaato.com/display/IN/Android)\r\n* Notes:", "id": 83, "code_signature": "com.smaato.soma.", "website": "https://smaato.com", "name": "Smaato", "network_signature": "soma.smaato.net|smaato.net", "creation_date": "2018-01-05"}, "84": {"description": "* Website: https://scandit.com\r\n* Comment: Scandit is a barcode scanner SDK that offers real-time analytics (\"scanalytics\") to track what barcodes users have scanned and profile users for targeted advertising.\r\n* Category: [Barcode Scanner, Analytics]\r\n* Code signature: `com.scandit.`\r\n* Network signature: `scandit\\.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `scanditsdk-android`\r\n* Group ID: `com.scandit` \r\n* Gradle: `ScanditBarcodeScanner`\r\n* Additional links: [Scandit SDK Documentation](https://docs.scandit.com/stable/android/), [\"Scandit launches first-of-its-kind barcode scanning analytics\", Analytics Magazine](http://analytics-magazine.org/scandit-launches-first-of-its-kind-barcode-scanning-analytics/), [\"Shopkick Partners with Scandit to Boost Consumer Engagement with Products in Store\", PRWeb](http://www.prweb.com/releases/2012/10/prweb9954971.htm), [Shopkick Case Study](https://www.scandit.com/resources/case-studies/shopkick/)\r\n* Notes: Shopkick is a close partner with Scandit.", "id": 84, "code_signature": "com.scandit.", "website": "https://scandit.com", "name": "Scandit", "network_signature": "scandit\\.com", "creation_date": "2018-01-05"}, "85": {"description": "* Website: http://inrix.com/\r\n* Comment: INRIX offers real-time traffic information solutions that help develop traffic data and traffic speed for freeways, highways and arterials. \r\n* Category: Location\r\n* Code signature: `com.inrix.sdk`\r\n* Network signature: `inrix\\.com|inrix\\.io`\r\n* Maven repository: `NC`\r\n* Artifact ID: `NC`\r\n* Group ID: `NC` \r\n* Gradle: `NC`\r\n* Additional links: [Inrix on Crunchbase](https://www.crunchbase.com/organization/inrix), [Inrix population analytics](http://inrix.com/resources/inrix-population-analytics-video/)\r\n* Notes:", "id": 85, "code_signature": "com.inrix.sdk", "website": "http://inrix.com/", "name": "Inrix", "network_signature": "inrix\\.com|inrix\\.io", "creation_date": "2018-01-06"}, "86": {"description": "* Website: http://www.signal360.com\r\n* Comment: Signal360 (formerly Sonic Notify) is a leader in proximity marketing via audio beacons and bluetooth beacons in sports stadiums, retail outlets, and vending machines.\r\n* Category: [Audio Beacon, Bluetooth Beacon]\r\n* Code signature: `com.signal360.sdk.core.|com.sonicnotify.sdk.core.|com.rnsignal360|`\r\n* Network signature: `signal360\\.com|sonicnotify\\.com`\r\n* Maven repository: `NA`\r\n* Gradle: `NA`\r\n* Group ID: `com.signal360.sdk` \r\n* Gradle: `NA`\r\n* Additional links: [React Native Bridge for Signal 360 SDK on Github](https://github.com/EwyynTomato/react-native-signal360), [\"Scandit launches first-of-its-kind barcode scanning analytics\", Sport Techie](https://www.sporttechie.com/signal360-is-bringing-sponsor-messaging-to-nba-teams-and-heres-how-to-get-creative-with-it/)\r\n* Notes: Signal360 has partnerships with PlayNetwork, YinzCam, and Coca-Cola Amatil.", "id": 86, "code_signature": "com.signal360.sdk.core.|com.sonicnotify.sdk.core.|com.rnsignal360", "website": "http://www.signal360.com", "name": "Signal360", "network_signature": "signal360\\.com|sonicnotify\\.com", "creation_date": "2018-01-13"}, "87": {"description": "* Website: http://www.telequid.com/\r\n* Comment: Ads synced to the TV\r\n* Category: Advertising\r\n* Code signature: `com.telequid.`\r\n* Network signature: `mars\\.telequid\\.com`\r\n* Maven repository: `xxx.com`\r\n* Artifact ID: `xxx`\r\n* Group ID: `xxx` \r\n* Gradle: `xxx`\r\n* Additional links: xxx xxx\r\n* Notes: \r\n> TAAS (Telequid Augmented Advertising Server) can be embedded in an existing app to detect images in any printed document or TV spots and display related multimedia content on mobile screen.", "id": 87, "code_signature": "com.telequid.", "website": "http://www.telequid.com/", "name": "TeleQuid", "network_signature": "mars\\.telequid\\.com", "creation_date": "2018-03-04"}, "88": {"description": "* Website: http://retency.com\r\n* Comment: xxxx\r\n* Category: Analytics\r\n* Code signature: `com.retency.sdk.android`\r\n* Network signature: `NC`\r\n* Maven repository: `NC`\r\n* Artifact ID: `NC`\r\n* Group ID: `NC` \r\n* Gradle: `NC`\r\n* Additional links: \r\n* Notes:", "id": 88, "code_signature": "com.retency.sdk.android", "website": "http://retency.com", "name": "Retency", "network_signature": "NC", "creation_date": "2018-03-04"}, "89": {"description": "* Website: http://madvertise.com\r\n* Comment: xxxx\r\n* Category: Advertising\r\n* Code signature: `com.mngads.sdk|com.mngads.views|com.mngads.`\r\n* Network signature: `NC`\r\n* Maven repository: `NC`\r\n* Artifact ID: `NC`\r\n* Group ID: `NC` \r\n* Gradle: `NC`\r\n* Additional links: \r\n* Notes:", "id": 89, "code_signature": "com.mngads.sdk|com.mngads.views|com.mngads.", "website": "http://madvertise.com", "name": "MAdvertise", "network_signature": "dispatcher\\.mng\\-ads\\.com|mobile\\.mng\\-ads\\.com", "creation_date": "2018-03-04"}, "90": {"description": "_AdColony delivers zero-buffering, full-screen Instant-Play\u2122 HD video, interactive Aurora\u2122 Video, and Aurora\u2122 Playable ads that can be displayed anywhere within your application. Our advertising SDK is trusted by the world\u2019s top gaming and non-gaming publishers, delivering them the highest monetization opportunities from brand and performance advertisers. AdColony\u2019s SDK can monetize a wide range of ad formats including in-stream/pre-roll, out-stream/interstitial and V4VC\u2122, a secure system for rewarding users of your app with virtual currency upon the completion of video and playable ads._ from [AdColony on Github](https://github.com/AdColony/).", "id": 90, "code_signature": "com.adcolony", "website": "http://adcolony.com/", "name": "AdColony", "network_signature": "adc3-launch.adcolony.com|ads30.adcolony.com|androidads20.adcolony.com|androidads21.adcolony.com|androidads23.adcolony.com|events3alt.adcolony.com|wd.adcolony.com|adcolony.com", "creation_date": "2018-03-04"}, "91": {"description": "## About\r\n\r\nAccountKit is a product of Facebook lets users quickly register/login to apps by using just their phone number or email address. No password is needed. [Link to weblink](https://www.accountkit.com/faq/)\r\n\r\n## Ownership\r\n\r\nAccountKit is owned by Facebook (NASDAQ: FB). \r\n\r\nNote: there is an unaffiliated Australian Accounting firm of the same name. \r\n\r\n## What it does\r\n\r\n* User Verification\r\n* Phone number collection\r\n* Permits direct app logins without SMS code\r\n\r\n## Data Policy\r\n\r\n[Policy as of 8/9/2018:](https://www.facebook.com/privacy/explanation/)\r\n\r\n* Identical to Facebook's Policy. This provides controls for users to opt out but no actual commitment to reduce the collection and use of personal data. \r\n\r\n* Data will be used to \"reasearch and innovate for social good\", \"promote satety, integrity and security\", personalize advertising, communicate with users, and measure analytics for business services. \r\n\r\n* Third-party apps and websites integrated with Facebook and its products receive information on what users post and share. This \"information collected by these third-party services is subject to their own terms and policies, not this one.\" \r\n\r\n* Facebook's policy states that it doesn't \"sell any of your information to anyone and we never will.\" It imposes \"strict restrictions\" on how partners use and disclose the data it provides. \r\n\r\n* Information may be accessed, preserved, and shared with regulators, law enforcement, and others in response to legal requests (including those in outside jurisdictions if there is a \"good faith belief\" they're required to respond), prevention of fraud, unauthorized use of products or services, breaches of Terms or Policies, to prevent harm to Facebook or its property, and harmful or illegal activity.", "id": 91, "code_signature": "com.facebook.accountkit", "website": "https://www.accountkit.com/", "name": "AccountKit", "network_signature": "graph.accountkit.com", "creation_date": "2018-03-04"}, "92": {"description": "", "id": 92, "code_signature": "com.amazon.device.ads", "website": "https://developer.amazon.com/public/apis/earn/mobile-ads/docs/quick-start", "name": "Amazon Advertisement", "network_signature": "NC", "creation_date": "2018-03-04"}, "93": {"description": "Advertisement", "id": 93, "code_signature": "com.amazon.device.associates", "website": "https://developer.amazon.com/mobile-associates", "name": "Amazon Mobile Associates", "network_signature": "NC", "creation_date": "2018-03-04"}, "94": {"description": "* Website: https://www.radiusnetworks.com/\r\n* Comment: Radius Networks offers a wide range of hardware, software and proximity services designed to enable hyper-proximity, micro-location engagement capabilities and analytics in today's leading mobile apps, products and technologies\r\n* Category: Analytics, Tracking, Beacons, Location\r\n* Code signature: `com.radiusnetworks`\r\n* Network signature: `proximitykit.radiusnetworks.com`\r\n* Maven repository: `xxx.com`\r\n* Artifact ID: `xxx`\r\n* Group ID: `xxx` \r\n* Gradle: `org.altbeacon:android-beacon-library:2+`\r\n* Additional links: http://developer.radiusnetworks.com/ , http://altbeacon.github.io/android-beacon-library/\r\n* Notes: xxx", "id": 94, "code_signature": "com.radiusnetworks", "website": "https://www.radiusnetworks.com/", "name": "Radius Networks", "network_signature": "proximitykit.radiusnetworks.com", "creation_date": "2018-03-04"}, "95": {"description": "Analytics", "id": 95, "code_signature": "com.amazon.insights|com.amazonaws.mobileconnectors.pinpoint.analytics.", "website": "https://developer.amazon.com/public/apis/manage/analytics/docs/analytics-for-android-fire-os", "name": "Amazon Analytics", "network_signature": "mobileanalytics.us-east-1.amazonaws.com", "creation_date": "2018-03-04"}, "96": {"description": "Advertisement", "id": 96, "code_signature": "com.baidu.appx", "website": "https://app.baidu.com/", "name": "Baidu APPX", "network_signature": "NC", "creation_date": "2018-03-04"}, "97": {"description": "Map/LBS", "id": 97, "code_signature": "com.baidu.location", "website": "https://developer.baidu.com/", "name": "Baidu Location", "network_signature": "NC", "creation_date": "2018-03-04"}, "99": {"description": "Map/LBS", "id": 99, "code_signature": "com.baidu.mapapi", "website": "http://lbsyun.baidu.com/", "name": "Baidu Map", "network_signature": "NC", "creation_date": "2018-03-04"}, "100": {"description": "Advertisement", "id": 100, "code_signature": "com.baidu.mobads", "website": "https://developer.baidu.com/", "name": "Baidu Mobile Ads", "network_signature": "NC", "creation_date": "2018-03-04"}, "101": {"description": "Analytics", "id": 101, "code_signature": "com.baidu.mobstat", "website": "https://developer.baidu.com/", "name": "Baidu Mobile Stat", "network_signature": "NC", "creation_date": "2018-03-04"}, "102": {"description": "## About\r\n\r\nEstimote is private company that creates and sells sensor-based proximity tracking devices. These \"physical world\" beacons allow retailers to track users by compelling their cell phone microphones to emit high-frequency tones that are inaudible to humans. \r\n\r\nEstimote is registered in Delaware [Source:OpenCorporates](https://opencorporates.com/companies/us_de/5201683) and has offices in San Francisco, New York, and Krakow, Poland. In 2017, the company registered in the Dominican Republic. [Source:OpenCorporates](https://opencorporates.com/companies/do/491544)\r\n\r\n## Ownership\r\n\r\nEstimote's founders are Jakub Krzych and Lukasz Kostka. [Source: website](https://estimote.com/about/)\r\n\r\n## What it does\r\n\r\n* Ultrasonic proximity tracking\r\n* Indoor location beacons for use in retail stores, museums, and stadiums. Also deployed with in conjunction with robotic technology.\r\n* Integrates wireless APIs that take control over nearby displays\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 15/9/2018, last modified 13/5/15](https://estimote.com/legal/privacy-policy.html)\r\n\r\n* Estimote's policy mainly concerns its relationship with business affiliates and account holders. It does, however, refer to \"Customer Data\" collected from its services.\r\n\r\n* Personal data collected is treated by Estimote as \"strictly confidential\" and subject to internal controls and protections. This may include \"latitude/longitude coordinates\", the time of day, and user locations when their device is near a beacon. \r\n\r\n* If users do not want Estimote's beacon to identify their device, it directs them to \"(a) delete the Customer app or adjust the in-app settings of the Customer app if the app makes that option available, or (b) turn \u201coff\u201d Bluetooth through [their] device\u2019s Settings feature.\"\r\n\r\n* In the event of a data breach, Estimote will \"take reasonable steps to investigate the situation and to notify our Customers if the security, integrity or confidentiality of personal information has been compromised, in accordance with any applicable laws and regulations.\"", "id": 102, "code_signature": "com.estimote.", "website": "https://estimote.com/", "name": "Estimote", "network_signature": "NC", "creation_date": "2018-03-04"}, "103": {"description": "Map/LBS", "id": 103, "code_signature": "com.baidu.navi", "website": "http://lbsyun.baidu.com/index.php?title=android-navsdk", "name": "Baidu Navigation", "network_signature": "NC", "creation_date": "2018-03-04"}, "104": {"description": "Advertisement", "id": 104, "code_signature": "com.fyber.", "website": "https://www.fyber.com/", "name": "Fyber", "network_signature": "adproxy.fyber.com|appengage-video.fyber.com|banner.fyber.com|engine.fyber.com|interstitial.fyber.com|mbe-cdn.fyber.com|offer.fyber.com|service.fyber.com|tracker.fyber.com|video.fyber.com|video-interstitial-assets-cdn.fyber.com", "creation_date": "2018-03-04"}, "105": {"description": "Analytics", "id": 105, "code_signature": "com.google.tagmanager", "website": "https://www.google.com/analytics/tag-manager/", "name": "Google Tag Manager", "network_signature": "www.googletagmanager.com|www.googletagservices.com", "creation_date": "2018-03-04"}, "106": {"description": "## About\r\n\r\n[InMobi](https://www.inmobi.com/) is a private, Indian-based advertising behemoth. It has relationships with over 30,000 companies and app developers. It has approximately 1,500 employees in offices in 12 different countries. [See also: OpenCorporates](https://opencorporates.com/companies/us_ca/C3422070)\r\n\r\nInMobi's founder, in a recent [Forbes article,](http://www.forbesindia.com/article/leaderboard/inmobi-wants-to-glue-your-attention-to-your-lock-screen/53095/1) stated that \"Consumers will move from seeking content to consuming what is shown to them.\" \r\n\r\n## Ownership\r\n\r\nInMobi was founded in Mumbai, India, as mKhoj, in 2007 by Naveen Tewari, Abhay Singhal, Amit Gupta and Mohit Saxena. Its investors include Softbank and its debt financier is Tennenbaum Capital Partners. \r\n\r\n## What it does\r\n\r\n* Native/Targeted Advertising\r\n* E-Commerce\r\n* In-app Mobile Advertising\r\n* Market Research Platform\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 17/2/2017, reviewed 21/4/2019:](https://www.inmobi.com/privacy-policy/)\r\n\r\n* InMobi's opt-out is [located here.](https://www.inmobi.com/page/opt-out/) Users will need their iOS or Android ID. \r\n\r\n* InMobi's privacy policy states that it collects information about the \"device type (e.g. smartphone, tablet, etc.),operating system (e.g. iOS, Android, Windows, Blackberry), network provider, mobile browser used (e.g. Safari, Internet Explorer etc.),platform, SDK version, timestamp, API key (identifier for application), application version, iOS Identifier for Advertising, iOS Identifier for Vendors, model, manufacture of device, OS version of device, session start/stop time, locale (specific location where a given language is spoken), time zone, network status such as WiFi, the geo-location of your device (using GPS or other geo-location data) and the Identifier for Advertising (IDFA) or the Google Advertising ID (AAID) etc\" which it may infer from WiFi identifiers in the area. \r\n\r\n* It also collects information regarding \"(i) the content type of the ad (what the ad is about, e.g. games, finance, entertainment, news); (ii) the ad type (e.g. whether the ad is a text, image, or video based ad); (iii) where the ad is being served (e.g. the address of the site on which the ad appears); and (iv) certain information about post-click activity in relation to the ad including user interaction with such ad.\" It may also collect email addresses in a hashed format. \r\n\r\n* This information is shared with \"Publishers, Developers, Advertisers, Data Partners, Measurement Companies, InMobi Affiliates, and third parties such as advisors and law enforcement authorities.\" \r\n\r\n* Data is kept for a 13-month period, after which InMobi \"may retain and use such data in an aggregated format, as necessary for internal analytical purposes, to comply with its legal obligations, resolve disputes and enforce agreements.\"\r\n\r\n## Lawsuits and Settlements\r\n\r\n* In 2016, InMobi settled with the FTC (US Federal Trade Commission) for $950,000 over the Children's Online Privacy Protection Act violations (\"COPPA\"). [See more information](https://www.ftc.gov/news-events/press-releases/2016/06/mobile-advertising-network-inmobi-settles-ftc-charges-it-tracked)", "id": 106, "code_signature": "com.inmobi", "website": "http://inmobi.com", "name": "Inmobi", "network_signature": "config-ltvp.inmobi.com|sdkm.w.inmobi.com|inmobi.com|inmobi.info|inmobi.us", "creation_date": "2018-03-04"}, "107": {"description": "## About\r\n\r\nMillennial Media was founded in 2006 and publicly acquired by AOL in 2015. Oath Inc., a Verizon subsidiary, acquired AOL in 2017. \r\n\r\n## Ownership\r\n\r\nOath, Inc., owns Millennial Media as a legacy product. Oath is a subsidiary of Verizon Communications. [See: OpenCorporates](https://opencorporates.com/companies/us_de/4107146)\r\n\r\n## What it does\r\n\r\n* Behavorial Analytics\r\n* Personalized Advertising\r\n* Data Collection\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 27/12/2018:](https://policies.oath.com/us/en/oath/privacy/index.html)\r\n\r\n* Oath's policy states that it collects device and location information; \"the kind of content or ads served, viewed or clicked on; the frequency and duration of your activities; the sites or apps you used before accessing our Services and where you went next; whether you engaged with specific content or ads; and whether you went on to visit an advertiser's website, downloaded an advertiser\u2019s app, purchased a product or service advertised, or took other actions.\"\r\n\r\n* Information may be collected from third-parties and affilates, publicly-available sources, and appended and matched data from [other companies.](https://policies.oath.com/us/en/oath/privacy/topics/appenddata/index.html)\r\n\r\n* Oath states that it has \"technical, administrative and physical safeguards in place to help protect against unauthorized access, use or disclosure of customer information we collect or store.\" It also states that while it may share aggregated or pseudonymous information with other companies, this is not personally identifiable information (example given: \"name or email address\").\r\n\r\n* Oath's privacy controls and opt-out can be found [here.](https://policies.oath.com/us/en/oath/privacy/controls/index.html)", "id": 107, "code_signature": "com.millennialmedia.", "website": "https://www.millennialmedia.com/", "name": "Millennial Media", "network_signature": "contextual.media.net|media.net|millennialmedia.com|adtech\\.de", "creation_date": "2018-03-04"}, "108": {"description": "* Website: https://snowplowanalytics.com/\r\n* Comment: Cloud-native web, mobile and event analytics, running on AWS and on-premise with Kafka\r\n* Category: Analytics, Trackers\r\n* Code signature: `com.snowplowanalytics`\r\n* Network signature: `xxx.com`\r\n* Maven repository: `xxx`\r\n* Artifact ID: `xxx`\r\n* Group ID: `xxx` \r\n* Gradle: ``\r\n* Additional links: https://github.com/snowplow/snowplow\r\n* Notes: Mobile, Web, Game, IoT trackers", "id": 108, "code_signature": "com.snowplowanalytics.", "website": "https://snowplowanalytics.com/", "name": "Snowplow", "network_signature": "NC", "creation_date": "2018-03-04"}, "109": {"description": "Advertisement", "id": 109, "code_signature": "com.sponsorpay", "website": "http://www.sponsorpay.com", "name": "Fyber SponsorPay", "network_signature": "appengage-video.sponsorpay.com|cdn1.sponsorpay.com|cdn2.sponsorpay.com|cdn3.sponsorpay.com|cdn4.sponsorpay.com|engine.sponsorpay.com", "creation_date": "2018-03-04"}, "110": {"description": "Advertisement", "id": 110, "code_signature": "com.supersonic.adapters.supersonicads|com.supersonicads.sdk", "website": "https://www.supersonic.com/", "name": "Supersonic Ads", "network_signature": "tag-mediation.supersonic.com|click-haproxy.supersonicads.com|init.supersonicads.com|outcome.supersonicads.com|ow-gateway.supersonicads.com|rv-gateway.supersonicads.com|pixel-tracking.sonic-us.supersonicads.com|ua.supersonicads.com|www.supersonicads.com|supersonic.com", "creation_date": "2018-03-04"}, "111": {"description": "* Website: http://carnival.io/\r\n* Comment: Carnival mobile marketing automation drives app engagement and customer conversions.\r\n* Category: Analytics, Advertising\r\n* Code signature: `com.carnival.sdk, com.carnivalmobile`\r\n* Network signature: `xxx.com`\r\n* Maven repository: `xxx.com`\r\n* Artifact ID: `xxx`\r\n* Group ID: `xxx` \r\n* Gradle: `xxx`\r\n* Additional links: https://devices.carnivalmobile.com\r\n* Notes: FakePhoneCallActivity, \"fake_call_message\"", "id": 111, "code_signature": "com.carnival.sdk|com.carnivalmobile", "website": "http://carnival.io/", "name": "Carnival", "network_signature": "devices.carnivalmobile.com", "creation_date": "2018-03-04"}, "112": {"description": "Map/LBS", "id": 112, "code_signature": "com.tencent.lbs", "website": "https://lbs.qq.com/", "name": "Tencent Map LBS", "network_signature": "NC", "creation_date": "2018-03-04"}, "113": {"description": "Advertisement", "id": 113, "code_signature": "com.tencent.mobwin", "website": "https://www.tencent.com/en-us/", "name": "Tencent MobWin", "network_signature": "NC", "creation_date": "2018-03-04"}, "114": {"description": "Analytics", "id": 114, "code_signature": "com.tencent.mta", "website": "https://mta.qq.com/", "name": "Tencent MTA", "network_signature": "NC", "creation_date": "2018-03-04"}, "115": {"description": "* Website: https://www.apptentive.com/\r\n* Comment: Build brands customers love by understanding their behavior and expectations\r\n* Category: [Analytics, Engagment]\r\n* Code signature: `com.apptentive`\r\n* Network signature: `?`\r\n* Maven repository: `?`\r\n* Artifact ID: `?`\r\n* Group ID: `?` \r\n* Gradle: `com.apptentive:apptentive-android:5.0.2`\r\n* Additional links: https://github.com/apptentive/apptentive-android\r\n* Notes: Founded 2011, Seattle, USA. Total Funding 11.9M$", "id": 115, "code_signature": "com.apptentive.", "website": "https://www.apptentive.com/", "name": "Apptentive", "network_signature": "api.apptentive.com", "creation_date": "2018-03-04"}, "116": {"description": "Analytics", "id": 116, "code_signature": "com.tencent.stat", "website": "http://stat.qq.com/", "name": "Tencent Stats", "network_signature": "NC", "creation_date": "2018-03-04"}, "117": {"description": "Analytics", "id": 117, "code_signature": "com.tencent.weiyun", "website": "https://www.weiyun.com", "name": "Tencent Weiyun", "network_signature": "NC", "creation_date": "2018-03-04"}, "118": {"description": "## About\r\n\r\nMixPanel, Inc. is a privately-held marketing technology company with 250+ employees and offices in San Francisco, New York, Seattle, Salt Lake City, and London, UK. [Source: OpenCorporates](https://opencorporates.com/companies/us_de/4689044); [Source: Linkedin](https://www.linkedin.com/company/mixpanel-inc-)\r\n\r\n## Ownership\r\n\r\nMixPanel was founded in 2009 by Suhail Doshi and Tim Trefren. [Source: website](https://mixpanel.com/about/)\r\n\r\n## What it does\r\n\r\n* Behavioral Analytics\r\n* Data Collection\r\n* Media Trend analysis [See: Forbes article on 2018 report](https://www.forbes.com/sites/curtissilver/2018/05/08/mixpanel-2018-media-benchmarks-report-reveals-the-truth-of-our-media/#19fc268d2349)\r\n* Anonymous Profiling \"Firmographics\"\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of May 2018, reviewed 25/10/18:](https://mixpanel.com/legal/privacy-policy/)\r\n\r\n* MixPanel's privacy policy does not apply to end-users. Its policy refers to \"Customers\", who are MixPanel's clients. MixPanel tracks its clients by default but they have the right to delete their personal information at any time. Personal information includes location, name, email, pixel tag, and online tracking data. \r\n\r\n* End-users who are tracked by MixPanel's \"Customers\" have no right to delete their personal information and are refered to their individual client privacy policies. MixPanel's clients are not identifed anywhere in the policy. The client is referred to as the \"data controller.\"\r\n\r\n* Interestingly, MixPanel's policy notes that it \"does not respond\" to its clients' Do Not Track signals, by default, since there is \"no standard that governs what, if anything, websites should do if they receive these signals.\"\r\n\r\n* Per the [Terms of Use](https://mixpanel.com/legal/terms-of-use/) end-users can opt-out of MixPanel website tracking through this [link.](https://mixpanel.com/optout) NOTE: this is strictly limited to the use of Mixpanel's website and does not apply to tracking done by their clients or through MixPanel's services.", "id": 118, "code_signature": "com.mixpanel.", "website": "https://mixpanel.com/", "name": "MixPanel", "network_signature": "api\\.mixpanel\\.com|decide\\.mixpanel\\.com|switchboard\\.mixpanel\\.com|mixpanel\\.com", "creation_date": "2018-03-04"}, "119": {"description": "## About\r\n\r\nUmeng is a Private company founded by Fan Jiang in April 2010 and acquired by Alibaba Group in 2013. [(Source)](https://techcrunch.com/2013/11/20/umeng-alibaba/) It is based in Beijing, China and has approxmately 50-100 employees. \r\n\r\nTwo company filings were found in Hong Kong: [here](https://opencorporates.com/companies/hk/1579937) and [here.](https://opencorporates.com/companies/hk/2756553) \r\n\r\n## Ownership\r\n\r\nUmeng is owned by the Alibaba Group. Alibaba is listed on the NYSE under the ticker BABA. \r\n\r\n## What it does\r\n\r\n* Behavioral analytics\r\n* Data Collection and usage statistics\r\n* Advertising platforms\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 12/27/2018:](http://mobile.umeng.com/privacypolicy/)\r\n\r\n* An english-version of Umeng's privacy policy could not be located. As such, it was not reviewed. \r\n\r\n* An opt-out page in Mandarin language was located [here.](https://outdip.umeng.com/opt_out.html?spm=a211g2.181323.0.0.3cb23604DDAijH)", "id": 119, "code_signature": "com.umeng.analytics", "website": "https://www.umeng.com/analytics", "name": "Umeng Analytics", "network_signature": "alog.umeng.com|alogs.umeng.com|ar.umeng.com|oc.umeng.com|uop.umeng.com|umeng.com", "creation_date": "2018-03-04"}, "120": {"description": "## About\r\n\r\nUmeng is a Private company founded by Fan Jiang in April 2010 and acquired by Alibaba Group in 2013. [(Source)](https://techcrunch.com/2013/11/20/umeng-alibaba/) It is based in Beijing, China and has approxmately 50-100 employees. \r\n\r\nTwo company filings were found in Hong Kong: [here](https://opencorporates.com/companies/hk/1579937) and [here.](https://opencorporates.com/companies/hk/2756553) \r\n\r\n## Ownership\r\n\r\nUmeng is owned by the Alibaba Group. Alibaba is listed on the NYSE under the ticker BABA. \r\n\r\n## What it does\r\n\r\n* Behavioral analytics\r\n* Data Collection and usage statistics\r\n* Advertising platforms\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 12/27/2018:](http://mobile.umeng.com/privacypolicy/)\r\n\r\n* An english-version of Umeng's privacy policy could not be located. As such, it was not reviewed. \r\n\r\n* An opt-out page in Mandarin language was located [here.](https://outdip.umeng.com/opt_out.html?spm=a211g2.181323.0.0.3cb23604DDAijH)", "id": 120, "code_signature": "com.umeng.fb", "website": "http://dev.umeng.com/feedback", "name": "Umeng Feedback", "network_signature": "alog.umeng.com|alogs.umeng.com|ar.umeng.com|oc.umeng.com|uop.umeng.com|umeng.com", "creation_date": "2018-03-04"}, "121": {"description": "Advertisement", "id": 121, "code_signature": "com.unity3d.services|com.unity3d.ads", "website": "https://unity3d.com/", "name": "Unity3d Ads", "network_signature": "analytics.social.unity.com|api.uca.cloud.unity3d.com|config.uca.cloud.unity3d.com|stats.unity3d.com|adserver.unityads.unity3d.com|auction.unityads.unity3d.com|cdn.unityads.unity3d.com|cdn-highwinds.unityads.unity3d.com|config.unityads.unity3d.com|webview.unityads.unity3d.com", "creation_date": "2018-03-04"}, "122": {"description": "* Website: https://count.ly/\r\n* Comment: Countly is the best analytics platform for tracking customer journeys in web, desktop and mobile applications. We process billions of data points every day and help businesses across the globe understand their product usage and act on highly detailed data.\r\n* Category: [Analytics]\r\n* Code signature: `ly.count.android`\r\n* Network signature: `xxx.com`\r\n* Maven repository: `http://dl.bintray.com/countly/maven`\r\n* Artifact ID: `xxx`\r\n* Group ID: `ly.count.android` \r\n* Gradle: `xxx`\r\n* Additional links: https://github.com/Countly/countly-sdk-android\r\n* Notes: Open Source. Founded 2013, London, England", "id": 122, "code_signature": "ly.count.android.", "website": "https://count.ly/", "name": "Countly", "network_signature": "NC", "creation_date": "2018-03-04"}, "123": {"description": "Analytics", "id": 123, "code_signature": "com.urbanairship", "website": "https://www.urbanairship.com/", "name": "Urbanairship", "network_signature": "device-api.urbanairship.com|urbanairship.com", "creation_date": "2018-03-04"}, "124": {"description": "## About\r\n\r\nYandex (NASDAQ: YNDX) is a multinational corporation dealing in Internet-related products and services. It is the largest technology company in Russia. Its parent company, Yandex N.V., is based in the Netherlands. [Source: OpenCorporates](https://opencorporates.com/companies/nl/27265167) \r\n\r\n## Ownership\r\n\r\nYandex's current CEO and founder is Arkady Volozh. In 2018, Volozh was added the US Treasury Department's list of Russian \"oligarchs\" linked to Russian President Vladmir Putin. [Source: Boston Globe](https://www.bostonglobe.com/news/world/2018/01/30/releases-putin-list-russian-politicians-oligarchs/PUw8A93TCiXGMMOMNSKTUI/story.html) \r\n\r\n## What it does\r\n\r\n* Behavioral Analytics\r\n* Mobile Advertising\r\n* Enables tracking by unspecified third parties\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 29/8/2018](https://yandex.ru/legal/confidential/):\r\n\r\n* Yandex's policy does not define personal information but refers the reader to \"applicable laws and regulations.\" \r\n\r\n* Personal information can be obtained by advertising partners. \r\n\r\n* Yandex \"does not actively collect any sensitive personal data (such as racial origins, political opinions, health or biometric data).\" They \"do not engage in any form of profiling that has the potential to significantly impact your rights and freedoms.\" Employees must follow internal rules and protocols to ensure confidentiality when processing personal information. \r\n\r\n* Yandex may transfer personal information to business partners, advertisers, any third party with whom they contract, and to any governmental body, regulatory or enforcement agency at their request or as required by law. \r\n\r\n* If provided by law within the user's jurisdiction, users may: request erasure of their personal information and restriction of its processing. Users may also request a copy of the Standard Contractual Clauses enabling the transfer of their personal information to Russia. \r\n\r\n* Users may possess other rights not mentioned within this policy to the extent provided by applicable law.", "id": 124, "code_signature": "com.yandex.mobile.ads", "website": "https://www.yandex.com/", "name": "Yandex Ad", "network_signature": "appmetrica.yandex.com|report.appmetrica.yandex.net|analytics.mobile.yandex.net|banners.mobile.yandex.net|banners-slb.mobile.yandex.net|startup.mobile.yandex.net|mc.yandex.ru", "creation_date": "2018-03-04"}, "125": {"description": "Analytics", "id": 125, "code_signature": "com.amplitude.", "website": "http://www.amplitude.com", "name": "Amplitude", "network_signature": "api.amplitude.com|amplitude.com", "creation_date": "2018-03-04"}, "126": {"description": "* Website: https://www.appsee.com\r\n* Comment: Via user session recordings, touch heatmaps, and single-user journey data, mobile professionals get a complete picture of what\u2019s going on in their app, without having to guess the \u201cwhys\u201d behind certain KPIs. Instead of focusing on tracking everything, these tools support an actionable, lean approach to being \u201cdata-driven\u201d. \r\n* Category: [Analytics]\r\n* Code signature: `com.appsee`\r\n* Network signature: `?`\r\n* Maven repository: `NA`\r\n* Artifact ID: `?`\r\n* Group ID: `?` \r\n* Gradle: `com.appsee:appsee-android:+`\r\n* Additional links: https://www.appsee.com/docs/android/native\r\n* Notes: Founded 2012, Israel Total Funding Amount 3M$", "id": 126, "code_signature": "com.appsee.", "website": "https://www.appsee.com/", "name": "AppSee", "network_signature": "api.appsee.com", "creation_date": "2018-03-04"}, "127": {"description": "Analytics", "id": 127, "code_signature": "com.kochava.base.Tracker|com.kochava.android.tracker.", "website": "https://www.kochava.com/", "name": "Kochava", "network_signature": "control\\.kochava\\.com|kvinit\\-prod\\.api\\.kochava\\.com", "creation_date": "2018-03-04"}, "129": {"description": "Analytics", "id": 129, "code_signature": "com.webtrends.mobile.analytics.|com.webtrends.mobile.android", "website": "https://www.webtrends.com/", "name": "Webtrends", "network_signature": "dc.webtrends.com|webtrends.com", "creation_date": "2018-03-04"}, "130": {"description": "* Website: https://www.newrelic.com\r\n* Comment: App usage stats\r\n* Category: Analytics\r\n* Code signature: `com.newrelic.agent`\r\n* Network signature: `nr-data.net|newrelic.com`\r\n* Maven repository: \r\n* Artifact ID: `android-agent`\r\n* Group ID: `com.newrelic.agent.android` \r\n* Gradle: `com.newrelic.agent.android:android-agent` `com.newrelic.agent.android:agent-gradle-plugin`\r\n* Additional links: \r\n* Notes: Requires `android.permission.INTERNET` and `android.permission.ACCESS_NETWORK_STATE`", "id": 130, "code_signature": "com.newrelic.agent.", "website": "http://www.newrelic.com", "name": "New Relic", "network_signature": "js-agent.newrelic.com|mobile-collector.newrelic.com|newrelic.com|nr-data.net", "creation_date": "2018-03-04"}, "131": {"description": "* Website: http://appanalytics.io\r\n* Comment: Real-time mobile app analytics for the entire customer lifecycle with event-based analytics, crash analytics, heat map analytics and gesture recognition!\r\n* Category: [Analytics]\r\n* Code signature: `io.appanalytics.sdk`\r\n* Network signature: `?`\r\n* Maven repository: `?`\r\n* Artifact ID: `?`\r\n* Group ID: `?` \r\n* Gradle: `NA`\r\n* Additional links: http://appanalytics.io/Support#IntegratingSDK\r\n* Notes: Founded 2015, USA (San Jose) Seed round 300k$ \r\nApp Analytics records all touch events of your users and shows as a heat map. App Analytics allows you to see all specific touches (first touch, second touch, etc.) as a heat map analytics", "id": 131, "code_signature": "io.appanalytics.sdk", "website": "http://appanalytics.io/", "name": "AppAnalytics", "network_signature": "NC", "creation_date": "2018-03-04"}, "132": {"description": "Analytics", "id": 132, "code_signature": "com.applause.android.", "website": "http://www.applause.com", "name": "Applause", "network_signature": "NC", "creation_date": "2018-03-04"}, "133": {"description": "Analytics", "id": 133, "code_signature": "com.quantcast.measurement.service.", "website": "http://www.quantcast.com", "name": "Quantcast", "network_signature": "quantcast.com|quantcast.net", "creation_date": "2018-03-04"}, "135": {"description": "Analytics", "id": 135, "code_signature": "com.apptimize.", "website": "http://www.apptimize.com", "name": "Apptimize", "network_signature": "brahe.apptimize.com|md-a-c.apptimize.com|md-a-s.apptimize.com", "creation_date": "2018-03-04"}, "136": {"description": "* Website: https://www.appbrain.com/info/help/sdk/index.html\r\n* Comment: The AppBrain SDK is present in over 50,000 apps and is downloaded onto millions of phones every day. 2 main services: Promotion: pay-per-install based app promotion to drive installs of your Android app. Monetization: earn money with your app using the interstitials and banners of the AppBrain SDK. \r\n* Category: [Analytics, Advertising]\r\n* Code signature: `com.appbrain`\r\n* Network signature: `?`\r\n* Maven repository: `?`\r\n* Artifact ID: `NA`\r\n* Group ID: `NA`\r\n* Gradle: `com.appbrain:appbrain-sdk:+@aar`\r\n* Additional links: https://github.com/swisscodemonkeys/appbrain-sdk http://www.appbrain.com/ \r\n* Notes: Launched in 2009 by two former Googlers. Suisse (Zurich)\r\nAppBrain is saying to dev that integrate the SDK: *It is your sole responsibility to communicate the privacy implications of your use of the AppBrain SDK to your users.* http://www.appbrain.com/info/help/sdk/policy.html\r\nThe potentially privacy sensitive data that\u2019s collected includes the phone model information, phone identifier (Google Advertiser ID), IP address of the phone, country and carrier of the connected mobile network and of the SIM card, and the AppBrain AppMetric\u2122, a token that conveys information about which categories of apps a user is interested in in a privacy-conserving way. Demographic data (gender, age) is only collected when the developer receives this information and forwards it to the AppBrain SDK. When the app has permission to acquire geographic location, this is collected and deleted at most seven days after collection. IP address and phone identifier for COPPA-enabled apps are also deleted at most 7 days after collection.", "id": 136, "code_signature": "com.appbrain.", "website": "https://www.appbrain.com/info/help/sdk/index.html", "name": "AppBrain", "network_signature": "sdk.appbrain.com", "creation_date": "2018-03-04"}, "137": {"description": "Analytics", "id": 137, "code_signature": "com.dynatrace.android.app.", "website": "http://www.dynatrace.com", "name": "Dynatrace", "network_signature": "NC", "creation_date": "2018-03-04"}, "138": {"description": "* Website: https://matomo.org/mobile\r\n* Comment: Matomo (formerly Piwik) is the leading open-source analytics platform.\r\n* Category: Analytics\r\n* Code signature: `org.piwik|org.piwik.mobile|org.matomo`\r\n* Network signature: `matomo\\.org`\r\n* Maven repository: `NA`\r\n* Gradle: `NA`\r\n* Group ID: `org.piwik` \r\n* Gradle: `NA`\r\n* Additional links: [Piwik SDK on Github](https://github.com/matomo-org/piwik-sdk-android), [Matomo Analytics on Github](https://github.com/matomo-org), [Matomo Documentation](https://developer.matomo.org/integration), [Matomo API Reference](https://developer.matomo.org/api-reference), [Matomo on English Wikipedia](https://en.wikipedia.org/wiki/Matomo_(software)), [Piwik PRO on English Wikipedia](https://en.wikipedia.org/wiki/Piwik_PRO)\r\n* Notes: [Piwik PRO](https://piwik.pro) is an enterprise fork of Piwik with proprietary components.", "id": 138, "code_signature": "org.piwik|org.piwik.mobile|org.matomo", "website": "https://matomo.org/mobile", "name": "Matomo (Piwik)", "network_signature": "matomo\\.org", "creation_date": "2018-03-04"}, "140": {"description": "Analytics", "id": 140, "code_signature": "com.yandex.metrica.", "website": "https://tech.yandex.com/metrica-mobile-sdk/", "name": "AppMetrica", "network_signature": "appmetrica.yandex.com|report.appmetrica.yandex.net|analytics.mobile.yandex.net|banners.mobile.yandex.net|banners-slb.mobile.yandex.net|startup.mobile.yandex.net|mc.yandex.ru", "creation_date": "2018-03-04"}, "142": {"description": "Capabilities:\r\n* Targets users via geotargeting\r\n* Tracks users using GPS\r\n* Tracks users using WiFi\r\n* Tracks users using location data\r\n\r\nAdvertising:\r\n* Location-based ad pushing\r\n* Real-world location targeting\r\n* Targeted advertising based on consumer actions\r\n\r\nAnalytic:\r\n* Identifies users via Google ID (AAID)\r\n* Identifies users via iOS ID (IDFA)", "id": 142, "code_signature": "com.sptproximitykit.", "website": "https://www.singlespot.com/", "name": "Singlespot", "network_signature": "singlespot\\.com", "creation_date": "2018-08-16"}, "143": {"description": "*SENSORO is committed to the convergence of the physical and digital world through the application of sensing technologies. SENSORO\u2019s Alpha Product Suite delivers a comprehensive solution for implementing an easily managed and monitored IoT sensor network.*\r\n\r\nCapability:\r\n* Tracks users using bluetooth\r\n* Tracks users using location data", "id": 143, "code_signature": "com.sensoro.beacon.kit.|com.sensoro.cloud", "website": "https://www.sensoro.com/", "name": "Sensoro", "network_signature": "NC", "creation_date": "2018-08-16"}, "144": {"description": "*At the core of our research is our sensor-technology which uses the mobile sensors built into smartphones to understand a user\u2019s location and activity. We have trained our algorithms with hundreds of thousands of labeled data points and incorporate data from GPS, accelerometer, gyroscope, barometer, wifi, ambient light, and many other sensors. This provides us with an anonymous, but highly accurate understanding of where, how, and when people interact with physical locations and businesses.\r\nSense360\u2019s sensor-technology is on dozens of apps and more than 2 million devices in the US. Our panel generates more than a terabyte of sensor data every single day and provides a detailed view of more than 150 million anonymous user visits a month.*\r\n\r\nCapability:\r\n* Tracks users using bluetooth", "id": 144, "code_signature": "com.sense360.android.quinoa.lib.Sense360", "website": "https://sense360.com/", "name": "Sense360", "network_signature": "quinoa-personal-identify-prod.sense360eng.com|android-quinoa-config-prod.sense360eng.com|incoming-data-sense360.s3.amazonaws.com", "creation_date": "2018-08-16"}, "145": {"description": "Capability:\r\n* Tracks users using GPS", "id": 145, "code_signature": "com.rfm.sdk", "website": "https://rubiconproject.com", "name": "Rubicon Project", "network_signature": "ads.rubiconproject.com|stats.aws.rubiconproject.com|fastlane.rubiconproject.com|optimized-by.rubiconproject.com|pixel.rubiconproject.com|tap2-cdn.rubiconproject.com|video-ads.rubiconproject.com", "creation_date": "2018-08-16"}, "146": {"description": "*ironSource builds monetization, engagement, analytics and discovery tools for app developers, device manufacturers, mobile carriers and advertisers. We empower content creators across platforms to turn their digital content into viable businesses without having to charge for them. Our technologies make free-to-play and free-to-use possible for the internet community.*", "id": 146, "code_signature": "com.ironsource.", "website": "https://www.ironsrc.com", "name": "ironSource", "network_signature": "NC", "creation_date": "2018-08-16"}, "147": {"description": "", "id": 147, "code_signature": "com.heyzap.sdk.ads.", "website": "https://www.heyzap.com", "name": "Heyzap (bought by Fyber)", "network_signature": "ads.heyzap.com|fyc.heyzap.com|med.heyzap.com|x.heyzap.com|img-cloudflare.haizap.com|img-cloudflare-2.haizap.com", "creation_date": "2018-08-16"}, "148": {"description": "", "id": 148, "code_signature": "com.gigya.", "website": "https://www.gigya.com", "name": "Gigya", "network_signature": "cdn.gigya.com|cdn1.gigya.com|cdn2.gigya.com|cdn3.gigya.com|cdns.us1.gigya.com", "creation_date": "2018-08-16"}, "149": {"description": "", "id": 149, "code_signature": "com.foresee.sdk.ForeSee", "website": "https://www.foresee.com", "name": "Foresee", "network_signature": "4seeresults.com|analytics.foresee.com|i.4see.mobi|rec.replay.answerscloud.com|foreseeresults.com|foresee.com", "creation_date": "2018-08-16"}, "150": {"description": "Analytic:\r\n* Audience segmenting", "id": 150, "code_signature": "com.fiksu.asotracking", "website": "https://fiksu.com", "name": "Fiksu", "network_signature": "a.fiksu.com|sdk.fiksu.com", "creation_date": "2018-08-16"}, "151": {"description": "Analytic:\r\n* Offers analytics activity to app developers\r\n* Offers reports to app developers", "id": 151, "code_signature": "com.ensighten.", "website": "https://www.ensighten.com", "name": "Ensighten", "network_signature": "nexus.ensighten.com", "creation_date": "2018-08-16"}, "152": {"description": "Capability:\r\n* Targets user location and proximity via geofencing\r\n* Targets users via geotargeting\r\n* Tracks users using GPS\r\n* Tracks users using WiFi\r\n* Tracks users using location data\r\n\r\nAdvertising:\r\n* Alters app functionality based upon user profiles\r\n* Loads advertisements\r\n* Loads targeted advertisements\r\n* Location-based ad pushing\r\n* Real-world location targeting\r\n* Targeted advertising based on consumer actions\r\n* Targets across devices, channels and/or platforms (omni-channel marketing, customer journey)\r\n* Timed advertisements\r\n\r\nAnalytic:\r\n* Analytics AI and machine learning\r\n* Audience segmenting\r\n* Collects Personally Identifiable Information (PII)\r\n* Collects Sensitive Personal Information (SPI)\r\n* Identifies users via Google ID (AAID)\r\n* Identifies users via iOS ID (IDFA)\r\n* Offers analytics activity to app developers\r\n* Offers reports to app developers\r\n* Performs cross-device identification\r\n* Profiles users via Personally Identifiable Information (PII)\r\n* Profiles users via Sensitive Personal Information (SPI)\r\n* Stores personal profile data (name, address, phone)", "id": 152, "code_signature": "com.dynamicyield.", "website": "https://www.dynamicyield.com", "name": "Dynamic Yield", "network_signature": "cdn.dynamicyield.com|adm.dynamicyield.com|api.dynamicyield.com|px.dynamicyield.com|st.dynamicyield.com", "creation_date": "2018-08-16"}, "153": {"description": "", "id": 153, "code_signature": "com.bluekai.sdk.", "website": "http://bluekai.com/registry/", "name": "BlueKai (acquired by Oracle)", "network_signature": "stags.bluekai.com|tags.bluekai.com", "creation_date": "2018-08-16"}, "154": {"description": "## About\r\n\r\nBlueConic, Inc. is a privately-held e-marketing company that sells targeted advertising through marketing management systems, or CDPs (Customer Data Platforms). The company has 50-100 employees and is headquartered in Boston, MA with a European office in Nijmegen, The Netherlands. [For more information, see OpenCorporates.](https://opencorporates.com/companies/us_ma/001126438)\r\n\r\nBlueConic's customers include the Boston Globe, Hearst Newspapers, Moen, T-Mobile, ING, America's Test Kitchen, and the American Kennel Club. [Source: website](https://www.blueconic.com/about/)\r\n\r\n## Ownership\r\n\r\nBlueConic was founded by Bart Heilbron and Martjin van Berkum in 2010. [Source: website](https://www.blueconic.com/about/)\r\n\r\n## What it does\r\n\r\n* Behavioral Analytics\r\n* Customer Data Platform (CDP) Marketing Management Systems\r\n* Targeted Advertising/Personalization\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 1/11/2018, last updated 1/11/2017:](https://www.blueconic.com/privacy-policy/)\r\n\r\n* BlueConic's privacy policy applies to both its website and its services platform. It is not clear to what extent end users have rights under the policy separate from clients.\r\n\r\n* Personal data is not defined in the policy. It may be used by third party affiliates in the ordinary course of business, however, \"the use of information collected through BlueConic Services Platform shall be limited to the purpose of providing the service for which the Client has engaged BlueConic.\"\r\n\r\n* Infomation gathered may include \"Internet Protocol (IP) addresses, browser type and language, Internet service provider (ISP), referring and exit pages, operating system, date/time stamp, and other data\", including \"social networking pages.\" \r\n\r\n* BlueConic may \"share or publish aggregate information that doesn\u2019t specifically identify you, such as statistical information about visitors to our Websites or statistical information about how customers use our applications.\"\r\n\r\n* The policy states that BlueConic will \"follow generally accepted standards to protect the personal information submitted to us, both during transmission and once it is received, including requiring our suppliers to meet such standards to protect your personal data from unauthorized access, use, and disclosure. If you have questions about the security of your personal data, you can contact us at info@blueconic.com. \"\r\n\r\n* BlueConic has certified its compliance with the EU-U.S. Privacy Shield Framework and the Swiss-U.S. Privacy Shield Framework.", "id": 154, "code_signature": "com.blueconic", "website": "https://www.blueconic.com", "name": "BlueConic", "network_signature": "NC", "creation_date": "2018-08-16"}, "155": {"description": "Formerly **Crittercism**", "id": 155, "code_signature": "com.crittercism.app.Crittercism", "website": "http://www.apteligent.com", "name": "Apteligent by VMWare (formerly Crittercism)", "network_signature": "api.crittercism.com|appload.ingest.crittercism.com|txn.ingest.crittercism.com", "creation_date": "2018-08-16"}, "156": {"description": "", "id": 156, "code_signature": "com.kakao.adfit.ads.", "website": "https://www.daum.net", "name": "AdFit (Daum)", "network_signature": "analytics.ad.daum.net|statistics.videofarm.daum.net", "creation_date": "2018-08-16"}, "157": {"description": "", "id": 157, "code_signature": "com.adform.sdk.", "website": "https://site.adform.com", "name": "Adform", "network_signature": "track.adform.net|adformdsp.net|adform.com|adx.adform.net|files.adform.net", "creation_date": "2018-08-16"}, "158": {"description": "", "id": 158, "code_signature": "jp.tjkapp.adfurikunsdk.", "website": "https://adfurikun.jp/adfurikun/", "name": "Adfurikun", "network_signature": "ginf.adfurikun.jp|adfurikun.jp", "creation_date": "2018-08-16"}, "159": {"description": "Mobvista is a leading technology platform providing mobile advertising and mobile analytics services to the app developers globally.\r\nAdvanced real-time data analysis and predictive technology let you target the right users for your products.\r\nLeverage our robust big data and AI capabilities to deliver better engagement.\r\nPowerful audience profiling, optimization and retargeting are combined to amplify your campaigns\u2019 impact and achieve a higher ROI\r\nPowering leading companies in driving more growth through massive coverage of media, innovation ad formats and predictive analytics, all fueled by advanced AI intelligence.", "id": 159, "code_signature": "com.mobvista.", "website": "https://www.mobvista.com/", "name": "Mobvista", "network_signature": "mobvista\\.com", "creation_date": "2019-03-10"}, "160": {"description": "Placed - The Leader in Offline Attribution\r\nPlaced is trusted by 350+ publishers, networks, and platforms, and 500+ advertisers and agencies to measure advertising's impact on store visits\r\nConsumer Path from TV Screen to Store\r\nPartnering with Inscape and Kantar, Placed closes the loop to store visitation across mobile devices used by 1 in 3 U.S. adults.\r\nPlaced Insights - Analytics for the Real World\r\nOpen-source location analytics platform mapping the real-world relationship between people and places\r\n\r\nBy leveraging one of the world's largest location platforms, billions of directly measured locations, and patent-pending statistical models, Placed is able to turn complex location data into actionable insights for our clients.\r\nPlaced is the leading provider of directly-measured location insights, analyzing billions of locations from its opt-in audience. Accurately measuring location is more than just data volume; it requires models, real-world context, and the ability to observe the complete path of consumer activity.\r\n\r\nBy measuring location continuously, Placed observes when data signals shift from a single point to a cluster of points; identifying a visit has occurred.\r\n\r\nOnce a visit is identified, Placed searches its database of hundreds of millions of business features to determine the likely place of the visit.\r\n\r\nPlaced understands that location accuracy is more than a latitude and longitude. Leveraging the intelligence from Data Clustering and Place Search, the Placed Inference Model applies a statistical probability to each and every visit, bringing the highest level of accuracy to consumer location insights. The Placed Inference Model is continuously trained against millions of first-hand validation points confirmed by panelists in the field.", "id": 160, "code_signature": "com.placed.client", "website": "http://placed.com/", "name": "Placed", "network_signature": "NC", "creation_date": "2019-03-10"}, "161": {"description": "Adot (formerly Adotmob) is a technology company founded in 2014 in Paris that provides agencies and advertisers with powerful insights on their audiences for a more accurate media activation.\r\n\r\nAdot (formerly Adotmob) uses both online and offline data sources.\r\n\r\nThanks to its exclusive partnership with vente-privee, Adot (formerly Adotmob) has access to a pool of exclusive e-commerce data: declared socio-demographic data and e-commerce intent data. Our last online data source arises from our earned bid requests, that allows the company to identify navigation media patterns, in particular through the analysis of keywords based on the visited pages and media interest by topic. Lastly, Adot (formerly Adotmob) owns geolocation data generated through proprietary technology integrated in partners\u2019 mobile apps.", "id": 161, "code_signature": "com.adotmob", "website": "https://we-are-adot.com/", "name": "Adot", "network_signature": "sdk\\.adotmob\\.com|sync\\.adotmob\\.com|tracker\\.adotmob\\.com", "creation_date": "2019-03-10"}, "162": {"description": "## About\r\nA Full Stack Ad Monetization Platform. Take full control of your monetization strategy with Appodeal\u2019s complete suite of tools.\r\n\r\n## Category\r\nAnalyitics, Location, Advertising, Identity\r\n\r\n## Additional links\r\nhttps://s3.amazonaws.com/appodeal-unity/\r\n\r\n## Notes\r\nAppodeal supports iOS, Android, and Amazon devices. Unity3D and Corona Labs.", "id": 162, "code_signature": "com.appodeal.ads.", "website": "https://www.appodeal.com", "name": "Appodeal", "network_signature": "appodeal.com|appodealx.com", "creation_date": "2019-03-10"}, "163": {"description": "AppMonet is a Container technology that enables publishers to have fewer SDKs while maximizing and diversifying their Brand Advertising demand sources. Simply put, almost all of the top 100 brand advertising demand sources work with AppMonet. All of those Video and Display demand sources simply plug into our Container \u2013 No SDKs required", "id": 163, "code_signature": "com.monet.", "website": "http://appmonet.com", "name": "AppMonet", "network_signature": "NC", "creation_date": "2019-03-10"}, "164": {"description": "\"Our mission is to help publishers make data-driven decisions for their monetization efforts.\r\n\r\nAt SOOMLA we aim to give mobile app publishers insights into the revenue they are making from advertising. We specifically help track revenue per user, per segment, per cohort and per traffic source. With the help of this data, we want to help facilitate better monetization and marketing decisions for our clients. More often than not, publishers are leaving money on the table. It's time to take control.\"", "id": 164, "code_signature": "com.soomla.", "website": "https://soomla.com/", "name": "Soomla", "network_signature": "\\soom.la", "creation_date": "2019-03-10"}, "165": {"description": "AdinCube has been acquired by Ogury.\r\nhttps://www.ogury.com/ogury_resources/ogury-acquires-adincube-faq/\r\n\r\nWhat does Adincube do?\r\n\r\nDespite the abundance of mediation solution options available, mobile publishers still struggle to optimize ad revenue and fill 100% of their inventory. Maximum yield is not being realized, and valuable revenue is being left on the table. Adincube Intelligent Mediation solves this problem.\r\n\r\nThrough one simple integration, Adincube Intelligent Mediation uses artificial intelligence to boost publishers' ad revenue by an average of 218%. The SDK optimizes revenue between all demand sources and buying metrics on the market, ensuring maximum yield from every single impression. Additionally, it gathers publishers\u2019 earnings and pays out immediately.\r\n\r\nHow does Adincube Intelligent Mediation work?\r\n\r\nOne SDK plugs publishers into all demand sources on the market eliminating the need for adapters or manual set up of individual accounts. Adincube Intelligent Mediation technology then analyses every available campaign, ad network, ad exchange, buying metric, and creative format in real-time, at ad request level.", "id": 165, "code_signature": "com.adincube.sdk.", "website": "https://www.adincube.com/", "name": "Adincube", "network_signature": "sdk.adincube.com", "creation_date": "2019-03-10"}, "166": {"description": "Persona.ly is a global mobile ad-tech company. We create mobile monetization solutions and acquire engaged users for top grossing app developers. Our team is full of vibrant, proactive and passionate developers and marketers with diverse backgrounds and vast experience in the mobile monetization field, allowing us to overcome almost any challenge and create solutions that exceed our partners' expectations, developers and advertisers alike.\r\n\r\nhttp://knowledge.persona.ly/", "id": 166, "code_signature": "ly.persona.sdk", "website": "http://persona.ly/", "name": "Persona.ly", "network_signature": "dev\\.persona\\.ly|dev-api\\.persona\\.ly|dev\\.dsp\\.persona\\.ly|dsp\\.persona\\.ly|rtb\\.persona\\.ly|sdk\\.persona\\.ly|persona\\.ly", "creation_date": "2019-03-10"}, "167": {"description": "View https://branch.io/\r\n\r\n(branch has acquired TUNE)\r\n\r\nSend Local IP, device_fingerprint_id, identity_id, hardware_id, brand, model, screen_dpi, screen_height and other\r\n\r\nIncrease mobile revenue with enterprise-grade links built to acquire, engage, and measure across all devices, channels, and platforms.", "id": 167, "code_signature": "io.branch.", "website": "https://branch.io/", "name": "Branch", "network_signature": "api.branch.io", "creation_date": "2019-03-10"}, "168": {"description": "Cheetah Ads is Cheetah Mobile's self-operated ad platform offering a wide range of ad formats, from high-performing display and native ads, to beautiful, full-screen vertical video. Cheetah Ads offers diverse, global reach with over 600 million users from 200+ countries and regions across Cheetah Mobile's owned and operated inventory, including Clean Master, CM Security, Cheetah Keyboard and LiveMe. Enhanced by Cheetah Mobile's artificial intelligence and big data capabilities, Cheetah Ads helps brands reach the right audience, at the right time, in the right format throughout the entire purchase cycle.", "id": 168, "code_signature": "com.cmcm.", "website": "https://www.cmcm.com/", "name": "Cheetah Ads", "network_signature": "cmcm.com", "creation_date": "2019-03-10"}, "169": {"description": "Target high-value consumers with our proprietary LTV optimization technology.\r\nGet transparent user acquisition reporting with our third-party UA data integrations.\r\nReach unique consumers globally with our first-party supply in the world's top apps.\r\n\r\nAdditional links:\r\nhttps://support.vungle.com/hc/en-us\r\nhttps://github.com/Vungle/Android-SDK\r\nhttps://bintray.com/vungle/com.vungle/publisher-sdk-android\r\nhttps://vungle.bintray.com/com.vungle", "id": 169, "code_signature": "com.vungle.publisher.", "website": "https://vungle.com", "name": "Vungle", "network_signature": "ads\\.api\\.vungle\\.com|akamai\\.vungle\\-cdn\\.vungle\\.com|api\\.vungle\\.akadns\\.net|api\\.vungle\\.com|bd\\.vungle\\.com|billboard\\.vungle\\.com|cdn\\-lb\\.vungle\\.com|ci\\.vungle\\.com|data\\.vungle\\.com|ingest\\.vungle\\.com|jaeger\\.vungle\\.com|ltv\\-data\\-api\\.kube\\-prod\\.vungle\\.com|monitoring\\.vungle\\.com|ssl\\.vungle\\.com|v\\.vungle\\.com", "creation_date": "2019-03-10"}, "170": {"description": "https://en.wikipedia.org/wiki/Criteo\r\n\r\nCriteo is a personalized retargeting company that works with Internet retailers to serve personalized online display advertisements to consumers who have previously visited the advertiser's website. The company currently operates in a total of 30 markets around the world and is headquartered in Paris, FranceCriteo enables online businesses to follow up visitors who have left their website without making a purchase using personalized banners which aim to drive potential customers back to the business website.", "id": 170, "code_signature": "com.criteo.", "website": "https://www.criteo.com/", "name": "Criteo", "network_signature": "criteo.com", "creation_date": "2019-03-10"}, "171": {"description": "Our tools let developers build a new world powered by location data. Real-time updates. Total customization. Developers first.\r\n\r\nhttps://docs.mapbox.com/android/maps/overview/\r\nhttps://github.com/mapbox/mapbox-gl-native", "id": 171, "code_signature": "com.mapbox.mapboxsdk.", "website": "https://www.mapbox.com/", "name": "Mapbox", "network_signature": "a.tiles.mapbox.com|api.tiles.mapbox.com", "creation_date": "2019-03-10"}, "172": {"description": "Optimizely is the world\u2019s leading experimentation platform, enabling businesses to deliver continuous experimentation and personalization across websites, mobile apps and connected devices. Optimizely enables businesses to experiment deeply into their technology stack and broadly across the entire customer experience.\r\n\r\nhttps://optimizely.bintray.com/optimizely\r\nhttps://www.optimizely.com/products/mobile/\r\nhttps://docs.developers.optimizely.com/full-stack/docs", "id": 172, "code_signature": "com.optimizely.", "website": "https://www.optimizely.com/", "name": "Optimizely", "network_signature": "optimizely.com", "creation_date": "2019-03-10"}, "173": {"description": "Thousands of leading publishers, marketers, and agencies utilize Taboola\u2019s predictive technology to increase user engagement, monetize their traffic, and distribute their content to engaged audiences across the web. Together, our teams have pioneered a major new marketing channel alongside \u201csearch\u201d and \u201csocial,\u201d proving that \u201cdiscovery\u201d can power successful campaigns for companies of all sizes, throughout the customer journey.\r\n\r\nhttps://sdk.taboola.com/taboolasdk/docs", "id": 173, "code_signature": "com.taboola.", "website": "https://www.taboola.com/", "name": "Taboola", "network_signature": "\\taboola.com", "creation_date": "2019-03-10"}, "174": {"description": "CleverTap brings together real-time user insights, an advanced segmentation engine, and easy-to-use marketing tools in one mobile marketing platform \u2014 giving your team the power to create amazing experiences that deepen customer relationships. \r\nCleverTap enables growth and retention teams to manage and improve the impact of mobile marketing across the entire customer lifecycle. Leverage user data, automation, AI/ML, and personalization techniques in one enterprise platform.", "id": 174, "code_signature": "com.clevertap.", "website": "https://clevertap.com/", "name": "CleverTap", "network_signature": "wzrkt.com", "creation_date": "2019-03-10"}, "175": {"description": "Mobile app marketing platform with predictive analytics.", "id": 175, "code_signature": "com.my.tracker.", "website": "https://tracker.my.com/", "name": "myTracker", "network_signature": "tracker-api.my.com", "creation_date": "2019-03-10"}, "176": {"description": "Cloudmobi provides CloudTech SDK, integrated with Facebook Audience Network and Admob ads resource.\r\n\r\nhttps://github.com/cloudmobi/AndroidSDK/blob/master/AndroidSDK_Integration_Guide.md\r\n\r\nConnections:\r\nhttps://api.cloudmobi.net\r\nhttp://logger.cloudmobi.net", "id": 176, "code_signature": "com.cloudtech.", "website": "http://www.cloudmobi.net/", "name": "Cloudmobi", "network_signature": "api\\.cloudmobi\\.net|logger\\.cloudmobi\\.net|vast\\.cloudmobi\\.net|cloudmobi\\.net", "creation_date": "2019-03-10"}, "177": {"description": "https://developer.adlibr.com/guide/Android", "id": 177, "code_signature": "com.mocoplex.adlib.", "website": "https://adlibr.com", "name": "ADLIB", "network_signature": "adlibr\\.com", "creation_date": "2019-03-10"}, "178": {"description": "## About\r\nIdentify your best content and uncover actionable audience behaviors with comprehensive analytics and reporting. Dive into your viewer\u2019s engagement data at an individual level with Brightcove\u2019s advanced profile analytics.\r\n\r\n## Category\r\nAnalytics, Identity, Location\r\n\r\n## Additional links\r\nhttps://www.brightcove.com/en/online-video-platform/analytics https://www.brightcove.com/en/partners?pages=2 https://support.brightcove.com/ https://github.com/BrightcoveOS/android-player-samples\r\n\r\n## Notes\r\nVideo delivery, DRM, Video Streaming, Monetization, partner integration", "id": 178, "code_signature": "com.brightcove", "website": "https://www.brightcove.com", "name": "Brightcove", "network_signature": "metrics.brightcove.com/v2/tracker", "creation_date": "2019-03-19"}, "179": {"description": "## About\r\nDOV-E\u2019s patented technology utilizes these speakers and provides secure, quick, easy to use mobile payment and interactive mobile engagement on any platform.\r\n\r\n## Category\r\nBeacon, Advertising\r\n\r\n## Notes\r\nMobile payment methods, advertising cross-device triggers, reference hardware for vendors, browser, iOS", "id": 179, "code_signature": "com.dv.", "website": "https://www.dov-e.com/", "name": "DOV-E", "network_signature": ".dov-e.com", "creation_date": "2019-03-19"}, "180": {"description": "## About\r\nInspire shoppers when it matters most - as they enter the store, ready to make purchase decisions. Just as restaurants know to advertise before the lunch rush instead of after, Preceptivity personalizes receptivity for your customer based on unique shopping patterns and how they relate to the product category.\r\n\r\n## Category\r\nLocation, Beacon, Advertising\r\n\r\n## Additional links\r\nhttp://data.altbeacon.org/android-distance.json \r\n\r\n## Notes\r\nintegration with Moat", "id": 180, "code_signature": "com.inmarket", "website": "https://inmarket.com/", "name": "Inmarket", "network_signature": "m2m-api.inmarket.com", "creation_date": "2019-03-19"}, "181": {"description": "## About\r\nEmbed the most comprehensive location awareness engine into your app to engage users with contextually-relevant and geo-aware content.\r\n\r\n## Category\r\nAdvertising, Location, Identity, Tracking, Beacon\r\n\r\n## Additional links\r\nhttps://github.com/foursquare/pilgrim-unity-sdk https://developer.foursquare.com/docs/pilgrim-sdk/android\r\n\r\n## Notes\r\nFoursquare's location tracker for iOS, Android and Unity3D", "id": 181, "code_signature": "com.foursquare.pilgrim|com.foursquare.pilgrimsdk.android", "website": "https://enterprise.foursquare.com/products/pilgrim", "name": "Pilgrim", "network_signature": "sdk.foursquare.com", "creation_date": "2019-03-19"}, "182": {"description": "## About\r\nOtherLevels provides the platform and the knowledge to help you increase conversion and deliver the right content, to the right user, at the right time, on the right channel. Engage and retain your customers better, with relevant, omni-channel campaigns across mobile app, mobile web and desktop.\r\n\r\n## Category\r\nTracking, Location, Messaging, Advertising.\r\n\r\n## Additional links\r\nhttps://www.otherlevels.com/partners/ https://beacons.otherlevels.com/ https://github.com/OtherLevels\r\n\r\n## Notes\r\nrecent promotions of In-Play Messaging Solution for gambling and betting companies.", "id": 182, "code_signature": "com.otherlevels.", "website": "https://www.otherlevels.com/", "name": "OtherLevels", "network_signature": "api.otherlevels.com|rich.otherlevels.com|geodata.otherlevels.com|tags.otherlevels.com|ws.otherlevels.com|mdn.otherlevels.com", "creation_date": "2019-03-19"}, "183": {"description": "Mobile monetization", "id": 183, "code_signature": "net.pubnative", "website": "https://pubnative.net/", "name": "PubNative", "network_signature": "pubnative.net", "creation_date": "2019-03-19"}, "184": {"description": "App marketing and mobile monetization", "id": 184, "code_signature": "com.appnext.", "website": "https://www.appnext.com/", "name": "Appnext", "network_signature": "\\appnext.com", "creation_date": "2019-03-19"}, "185": {"description": "Advertising platform", "id": 185, "code_signature": "com.mobfox.", "website": "https://www.mobfox.com/", "name": "MobFox", "network_signature": "NC", "creation_date": "2019-03-19"}, "186": {"description": "Mobile Advertising Platform\r\n\r\nMain Features\r\n- Mobile Ad Server\r\n- In-Application Banner(CPC, CPI, CPA, CPM)\r\n- Mobile App PR(Direct Download)\r\n- iOS & Android(Google Play, T-Store) Promotion", "id": 186, "code_signature": "com.jm.co.shallwead.sdk.|com.co.shallwead.sdk.", "website": "http://www.shallwead.com", "name": "ShallWeAD", "network_signature": "NC", "creation_date": "2019-03-19"}, "187": {"description": "Game Analytics and Marketing", "id": 187, "code_signature": "com.deltadna", "website": "https://deltadna.com/", "name": "deltaDNA", "network_signature": "deltadna.net", "creation_date": "2019-03-19"}, "188": {"description": "Mobile marketing", "id": 188, "code_signature": "io.display.", "website": "https://www.display.io/en/", "name": "Display", "network_signature": "\\display.io", "creation_date": "2019-03-19"}, "189": {"description": "HyprMX brings brand advertising to mobile apps. Part of Jun Group, an Advantage Solutions company. Founded in 2012, we're headquartered on Fifth Avenue in New York City, with offices in Seattle and San Francisco.\r\n\r\nhttps://documentation.hyprmx.com/", "id": 189, "code_signature": "com.hyprmx.android.sdk.", "website": "https://www.hyprmx.com", "name": "HyprMX", "network_signature": "hyprmx.com", "creation_date": "2019-04-15"}, "190": {"description": "Bugly is a software manufacturing company specializing in detecting and tracking bug issues\r\nhttps://www.crunchbase.com/organization/bugly", "id": 190, "code_signature": "com.tencent.bugly.", "website": "https://bugly.qq.com/v2/", "name": "Bugly", "network_signature": "bugly.qq.com", "creation_date": "2019-04-15"}, "191": {"description": "Analysis\r\nApp Monetization", "id": 191, "code_signature": "com.duapps.", "website": "http://ad.duapps.com/", "name": "Duapps", "network_signature": "duapps.com", "creation_date": "2019-04-15"}, "192": {"description": "Swrve real-time marketing automation increases customer engagement through dynamic campaigns that deliver relevant, personalized messages in micromoments that matter across mobile, email, web, TV and emerging digital channels.", "id": 192, "code_signature": "com.swrve.sdk", "website": "https://www.swrve.com/", "name": "Swrve", "network_signature": "content.swrve.com|api.swrve.com", "creation_date": "2019-04-15"}, "193": {"description": "Mobile Push Notifications, Web Push, and In-App Messaging", "id": 193, "code_signature": "com.onesignal.", "website": "https://onesignal.com/", "name": "OneSignal", "network_signature": "onesignal.com", "creation_date": "2019-04-15"}, "194": {"description": "AppDynamics is a application performance management (APM) company based in San Francisco.\r\nAppDynamics is now a part of Cisco.", "id": 194, "code_signature": "com.appdynamics.", "website": "https://www.appdynamics.com/", "name": "Appdynamics", "network_signature": "NC", "creation_date": "2019-04-15"}, "195": {"description": "Data driven mobile media, marketing and monetization.", "id": 195, "code_signature": "com.startapp.android.publish", "website": "https://www.startapp.com", "name": "Startapp", "network_signature": "c2i.startappnetwork.com|c2s.startappnetwork.com|click.startappservice.com|dts.startappservice.com|events.startappservice.com|images.startappservice.com|imp.startappservice.com|init.startappservice.com|va.origin.startappservice.com|req.startappservice.com|soda.startappservice.com|info.static.startappservice.com|startappservice.com", "creation_date": "2019-04-15"}, "196": {"description": "Advertisement.\r\nAcquired by InMobi.", "id": 196, "code_signature": "com.aerserv.sdk.", "website": "https://www.aerserv.com/", "name": "AerServ", "network_signature": "ads.aerserv.com|debug.aerserv.com", "creation_date": "2019-04-15"}, "197": {"description": "INFOnline is the specialist provider of Digital Audience Measurement Services in Germany.", "id": 197, "code_signature": "de.infonline.", "website": "https://www.infonline.de", "name": "INFOnline", "network_signature": "de.ioam.de", "creation_date": "2019-04-15"}, "198": {"description": "myTarget is an advertising platform provided by Mail.Ru Group. It includes all the major social networks on the Runet (Russian-speaking Internet) and services that reach more than 140 million people.", "id": 198, "code_signature": "com.my.target.", "website": "https://target.my.com/", "name": "myTarget", "network_signature": "NC", "creation_date": "2019-04-15"}, "199": {"description": "Engagement and monetization for advertisers and app developers.", "id": 199, "code_signature": "com.tapjoy.", "website": "https://www.tapjoy.com/", "name": "Tapjoy", "network_signature": "tapjoy.com|tapjoyads.com|www.5rocks.io", "creation_date": "2019-04-15"}, "200": {"description": "Mintegral is a programmatic advertising platform in the mobile marketing world.", "id": 200, "code_signature": "com.mintegral.", "website": "https://www.mintegral.com/en/", "name": "Mintegral", "network_signature": "analytics.rayjump.com|cdn-adn.rayjump.com|de.rayjump.com|de01.rayjump.com|detect.rayjump.com|fk-mtrack.rayjump.com|hybird.rayjump.com|jssdk.rayjump.com|net.rayjump.com|online.rayjump.com|setting.rayjump.com|sg.rayjump.com|sg-mtrack.rayjump.com|sg01.rayjump.com|tknet.rayjump.com|us01.rayjump.com|rayjump.com", "creation_date": "2019-04-15"}, "201": {"description": "Advertisement.", "id": 201, "code_signature": "com.gimbal.android", "website": "https://gimbal.com/", "name": "Gimbal", "network_signature": "analytics-server.gimbal.com|api.gimbal.com|registration.gimbal.com|sdk-info.gimbal.com", "creation_date": "2019-04-15"}, "202": {"description": "The real-time measurement and intelligence platform for the streaming TV industry.", "id": 202, "code_signature": "com.conviva.", "website": "https://www.conviva.com/", "name": "Conviva", "network_signature": "cws.conviva.com", "creation_date": "2019-04-15"}, "203": {"description": "## About\r\nThe Adobe\u00ae Auditude\u00ae platform is used by companies that want to provide relevant content and advertisements in videos you watch on the web.\r\n\r\nLegacy, superceded by Adobe Primetime\r\n\r\n## Category\r\nAdvertising, Location, Identity, Tracking", "id": 203, "code_signature": "com.auditude.ads", "website": "https://www.adobe.com/privacy/policies/auditude.html", "name": "Auditude", "network_signature": "auditude.com", "creation_date": "2019-05-02"}, "204": {"description": "## About\r\nVoice-enabled audio technology is the biggest breakthrough in audio advertising in the last 70 years. Voice-enabled audio ads allow users to interact with ads, literally speaking with the brand\r\n\r\n## Category\r\nAdvertising, Tracking", "id": 204, "code_signature": "com.instreamatic", "website": "http://instreamatic.com/", "name": "Instreamatic", "network_signature": "instreamatic.com", "creation_date": "2019-05-02"}}} \ No newline at end of file +{"trackers": {"1": {"name": "Teemo", "description": "## Primary Location\r\nFrance (Paris) [Crunchbase, 01](https://www.crunchbase.com/organization/databerries)\r\n\r\n## Website\r\n[https://www.teemo.co](https://www.teemo.co)\r\n\r\n## About\r\nTeemo claims to run the \"World's first and biggest persistent geolocation targeting database\". They provide \"solutions\" for \"retail advertisers\" and \"app publishers\". [Teemo, 01](http://teemo.co). \r\n\r\n## Ownership\r\nTeemo\r\n\r\n## Documentation\r\nhttps://teemo.co/sdkguidelines/\r\n\r\n## Products and Services\r\n\r\n_Retail Advertisers - Real Life Targeting:_ \"We target your prospects based on the places they attend in real life with the geolocation of millions smartphones continuously.\" \r\n\r\n * Exclusive Teemo Data \r\n * SDK accurate collection \r\n * 10 to 15 meters accuracy \r\n * 100k+ points of Interest redefined \r\n * 1,170 billion + geolocation data points \r\n * World's Biggest Real Life Targeting DMP \r\n\r\nOffline measurement & insight: \r\n\r\nTeemo measures the exact number of people who visit your point of sale and give you insights on their habits. \r\n\r\n * 7-day attribution \r\n * Exhaustive data \r\n * Provenance of your customers \r\n * Customer loyalty index \r\n\r\n_App Publishers - We Monetize Your Geolocation Data:_ \"Our SDK: \r\n\r\n * Anonymous collection of IDFA and GAID \r\n * Data collection only \r\n * Only 25 KB \r\n\r\n### Methods\r\n\r\nTeemo utilizes geolocation collection through the Databerries (Teemo) SDK.\r\n\r\n## Privacy Policy\r\n\r\nTeemo states that even without a device identifier, such as Apple's IDFA, they can still identify users: \"without the IDFA, and only with the address and the place of work of a person, to find any French would take 5 seconds to a team of 20 people\", is it added in the article\" (French-English translation; see [L'Expansion, 01](https://lexpansion.lexpress.fr/high-tech/teemo-la-start-up-qui-traque-10-millions-de-francais-en-continu_1937638.html)). \r\n\r\n\"The Databerries / Teemo SDK collects location information, for example precise location using GPS, wireless networks, cell towers, and Wi-Fi access points. You must ensure that all applications that use the Databerries / Teemo SDK comply with all of the Google Play's developer requirements and Apple's App Store requirements (collectively, the **'Requirements'**) including obtaining appropriate consent to the collection of location information... Each application that uses the Databerries / Teemo SDK must (a) notify users of the application's use of location data for third-party advertising purposes via a custom notification window, and (b) provide user of the application the ability to consent or withhold consent through an 'Allow' / 'Don't Allow' option, 'Accept' / 'Don't Accept' option, or similarly-worded option... Each application that uses the Databerries / Teemo SDK must inform users of relevant data collection practices and choices available to them. Users of such applications must consent to the collection of location and device information and the sharing of such information with third parties such as Databerries / Teemo. Applications that use the Databerries / Teemo SDK must be provided with an accurate, current and complete privacy policy that:\r\n\r\na. is available prior to download (i.e. from all applicable app storefronts) and from within the settings of the app; \r\nb. is in compliance with all applicable laws and self-regulatory principles; \r\nc. clearly and truthfully describes what data is collected from the app, how such data is used, and the circumstances under which it is disclosed; \r\nd. discloses that location information and other user information will be shared with third parties for advertising purposes; and \r\ne. explains to users how to opt out of the collection of information about their precise location and how to opt out of the use of information about their app usage for interest-based advertising purposes through the settings available on their Android or iOS device.\" \r\n\r\nThe Databerries / Teemo SDK may not be used in apps designed for use by children below the age of 13 (or the age of consent where offered, if higher than 13) \"or be used to collect information from any user known to be under the age of 13 or under the age of consent where they reside\". [Teemo, 03](https://teemo.co/sdkguidelines) \r\n\r\n_Information Collected Automatically Through the Services:_\r\n\"In order to help advertisers reach their audiences and understand the effect of their advertising, we automatically collect certain information when you access mobile applications that incorporate the Services. This information does not identify you personally, but it does reflect information about the mobile applications you use, your location, and how you interact with our Services. This information includes:\r\n\r\n * Location Information: When you use mobile apps that integrate the Services, we may collect information about your precise location using various technologies, including GPS, wireless networks, cell towers, Wi-Fi access points, and other sensors, such as gyroscopes, accelerometers, compasses, and barometers. For information about how to opt out of the collection of certain location information, please see 'Your Choices' below. \r\n\r\n * Device Information: We collect information about your mobile device, including the advertising identifiers assigned to your device, IP address, device type, operating system, and mobile carrier. \r\n\r\n * Usage Data: We collect information about the mobile apps you use that integrate our Services, including the date and time your device accesses such apps.\" \r\n\r\n_Information Teemo Collects from Other Sources:_\r\n\r\nTeemo \"may also obtain information from other sources and combine that with information we collect through our Services. For example, we may collect information about you from third parties, including our business partners, other advertising companies, and publicly available sources.\"\r\n\r\n_Sharing of Information:_\r\n\r\nTeemo \"may share the information we collect as follows or as otherwise described in this Privacy Policy: \r\n\r\n * With vendors, consultants and other service providers who need access to such information to carry out work or perform services on our behalf; \r\n * In response to a request for information if we believe disclosure is in accordance with, or required by, any applicable law, rule, regulation or legal process; \r\n * If we believe your actions are inconsistent with our user agreements or policies, or to protect the rights, property or safety of Databerries or others; \r\n * In connection with, or during negotiations of, any merger, sale of company assets, financing or acquisition of all or a portion of our business by another company; \r\n * Between and among Databerries and any current or future parent, subsidiary and/or affiliated company; and \r\n * With your consent or at your direction.\" \r\n\r\nTeemo \"may also share aggregated or de-identified information, which cannot reasonably be used to identify you. For example, we may share de-identified information with the partners that use our technology about the users of their apps.\" \r\n\r\n_Your Choices:_ \r\n\r\n\"Location Tracking: You can stop the collection of precise location information by individual apps or by your device as a whole changing the preferences in the settings of your mobile device. \r\n\r\nOpting Out of Teemo Services: You can stop the collection of information from Teemo by opting out of our service. You can opt-out from our service either from our ads or by asking us by contacting us at privacy@teemo.co \r\n\r\nOpting Out of Personalized Ads: You may opt out of the use of information about your mobile app activities to serve ads that are targeted to your interests using the settings available on your mobile device. For information about how to opt out on your Android device, click here. For information about how to opt out on your iOS device, click [here](https://support.apple.com/en-us/HT202074). If you wish to opt out on multiple devices, you must repeat the process on each device where you wish to opt out\" [Teemo, 04](https://teemo.co/privacy)\"\r\n\r\n## Relationships\r\n_Customers:_ Volkswagon / MyMedia / Intersport / Havas / dentsu / OMD / WPP / Publics Groupe / Carrefour / Toys\"R\"Us / McDonald's / Ford / Decathlon / FNAC / Leclerc [Teemo, 01](http://teemo.co)\r\n\r\n## Details\r\n_Financial details:_ Teemo (then Databerries) \"raised $16m (?15m) in a Series A funding round led by new investor Index Ventures with support from existing investors ISAI and Mosaic Ventures and new individual investors Greg Coleman and Pascal Gauthier. The company will use the funds to launch its product in the US and double its workforce.\" [Go4Venture, 01](http://go4venture.com/hti/usd-16m-a-mar-2017-databerries) \r\n\r\n_Background and history:_ Formerly known as Databerries, Teemo \"reinvents offline marketing. Its mobile marketing solution combines user offline behavior understanding and algorithms to drive in-store sales. Its performance-based marketing solution delivers relevant, personalized ads that generate in-store sales it can measure. Co-founded in 2014 by Guillaume Charhon, Fran\u00e7ois Wyss and Benoit Grouchko, Teemo has 50 employees in Paris and New-York.\" [Teemo, 02](https://teemo.co/about) \r\n\r\n\"Founded in 2014, Databerries offers brick and mortar retailers a mobile marketing solution, refferred to as Real Life Targeting, that targets mobile users based on locations they have visited in the past and measures the impact of marketing campaigns on store visits. The solution allows retailers to target users who have visited their stores and those of their competitors. The company\u2019s technology collects geolocation and navigation data from mobile users and targets them with relevant and personalised ads. This allows retailers to generate store visits with a significantly lower cost per physical visit (CPV). Databerries enables retailers to count the cost per visit and therefore measure the impact of a campaign on point-of-sale traffic, offering retailers a solution that works for offline marketing while combining online advertising standards such as accurate targeting, personalisation, performance measurement and return on investment optimisation.\r\n\r\nHeadquartered in Paris, Databerries employs 40 people and plans to double its workforce by the end of 2017. Since its launch, the solution has generated more than one million in-store visits and supports more than 20 prestigious advertisers on a daily basis. It serves more than 100 brick and mortar retailers including Carrefour, Decathlon, FNAC, Leclerc, McDonald's (NYSE: MCD) and Volkswagen (ETR: VOW3).\r\n\r\nAccording to the company, offline retailers spend more than $100bn (\u20ac93.9bn) on advertising every year, relying largely on outdoor and other offline channels to increase store visits with limited ability to track the performance of their advertising campaigns. According to a report by MarketsandMarkets, the cross-platform and mobile advertising market is estimated to grow from $25.2bn (\u20ac23.7bn) in 2015 to $80.5bn (\u20ac75.6bn) by 2020, at a CAGR of 26.1%.\" [Go4Venture, 01](http://go4venture.com/hti/usd-16m-a-mar-2017-databerries)\r\n\r\n_Slogans:_ \r\n* \"Real-life Targeting, Offline Measurement\" \r\n* \"Reinventing offline marketing\"\r\n\r\n_Devices:_ Android (Google Android ID) and Apple (IDFA)\r\n\r\n## References\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/databerries](https://www.crunchbase.com/organization/databerries)\r\n* _Teemo, 01._ [http://teemo.co](http://teemo.co) \r\n* _Teemo, 02._ [https://teemo.co/about](https://teemo.co/about) \r\n* _Teemo, 03._ [https://teemo.co/sdkguidelines](https://teemo.co/sdkguidelines) \r\n* _Teemo, 04._ [https://teemo.co/privacy](https://teemo.co/privacy)\r\n\r\n## External Links\r\n* _Go4Venture, 01:_ [http://go4venture.com/hti/usd-16m-a-mar-2017-databerries](http://go4venture.com/hti/usd-16m-a-mar-2017-databerries) \r\n* _L'Expansion, 01:_ [https://lexpansion.lexpress.fr/high-tech/teemo-la-start-up-qui-traque-10-millions-de-francais-en-continu_1937638.html](https://lexpansion.lexpress.fr/high-tech/teemo-la-start-up-qui-traque-10-millions-de-francais-en-continu_1937638.html)", "network_signature": "databerries\\.com", "creation_date": "2017-09-24", "id": 1, "website": "https://www.teemo.co", "code_signature": "com.databerries.|com.geolocstation."}, "2": {"name": "FidZup", "description": "## Primary Location\r\nFrance (Paris) [Crunchbase, 01](https://www.crunchbase.com/organization/fidzup)\r\n\r\n## Website\r\n[https://www.fidzup.com/en](https://www.fidzup.com/en)\r\n\r\n## About\r\nFidzup merges online and offline mobile marketing for retailers. Their services include fine-grained location tracking through mobile devices for advertising purposes [Fidzup, 02](https://www.fidzup.com/en/team).\r\n\r\n## Ownership\r\nFidzup\r\n\r\n## Documentation\r\nFidzup SDK not listed, other code available at https://github.com/Fidzup\r\n\r\n## Products and Services\r\nFidzup has two primary services:\r\n\r\n1. Drive to store campaign \r\n2. Retargeting campaign \r\n\r\nTheir service is designed to protect retailers for \"showcasing\" whereby consumers view products in retail stores and look for prices and promotions found elsewhere, especially online. \"Thus,\" Fidzup states, \"those consumers who move to a point of sale but do not buy represent a real 'blind spot' for the brand.\"\r\n\r\nGeofencing technologies make it possible to know precisely the location of the consumer and offer new possibilities to harness data for retailers in stores and leverage the same techniques available to retailers in the online space. This helps retailers:\r\n\r\n* Know when the consumer goes to the store, whether they shop or not\r\n* Target their communication with contextualized promotions, or additional services to better inform the consumer during its purchase process\" [Marketing-Professionnel.fr, 01](http://www.marketing-professionnel.fr/parole-expert/distribution-retail-geofencing-geolocalisation-indooor-201411.html) \r\n\r\nFidzup's technology also helps retailers generate in-store traffic through targeting \"specific mobile audiences in your catchment area having an affinity with your brand.\" \r\n\r\nFidzup's in-store tracking helps retailers retarget customers who physically visited their store, according to their in-store behavior. According to Fidzup, their \"Fidzup Retargeting currently manages to detect 40% of point-of-sale traffic, more than 80% of smartphones... Thanks to point-of-sale technologies, Fidzup Retargeting is able to measure the ROI of all the campaigns sent (store visit, download of the application, etc.) and to report to the company. This marketing tool is therefore much more effective than a classic advertising campaign, because it occurs at the psychological moment when the user considers the purchase and allows to finalize the sale it is done in store or on its m-commerce site\" [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip).\r\n\r\nFidzup's technology helps retailers target competitor prospects to \"Serve ads to customers and prospects of retail/brand competitors\" [Fidzup, 01](https://www.fidzup.com/en).\r\n\r\n_Advertised services for clients:_ \r\n\r\nStores: \r\n1. Encourage impulsive purchasing \r\n2. Direct customers to shelves where discontinued products are placed \r\n3. Boost the use of its mobile application \r\n\r\nShopping malls: \r\n1. Create an attraction in the mall. \r\n2. Promote the release of the mobile application. \r\n3. Attract users of the application to the various shops in the shopping mall (eg, with list of promotions). \r\n\r\nTrade fairs: \r\n1. Provide its exhibitors with a special tool to attract more visitors to their stands. \r\n2. Inform visitors effectively of exhibition conferences and other upcoming events. \r\n\r\nConcerts and museums: \r\nFidzup could allow each visitor to a museum to \"automatically receive information of a work or piece just by being close to it\". At a concert, \"it is possible to send the corresponding clip for the song played, or even send a survey to the crowd to let it choose the next title to be played\" [Fidzup v2, 03](https://web.archive.org/web/20171015030737/http://v2.fidzup.com/en//cas-dusage). \r\n\r\n_Scope:_ \r\nAccording to Viuz, Fidzup has \"more than 250 Fidboxes already installed, more than 5 million unique database clients and more than 150 million covered 'foot traffic'\" [Viuz, 01](https://viuz.com/2015/03/19/fidzup-trophee-espoir-lndr-2015-les-outils-du-web-pour-re-inventer-le-commerce-physique).\r\n\r\n## Privacy Policy\r\n_Data collection and identifiable information:_ Fidzup states it \"collects data from wifi-enabled smartphones. No personal information is ever collected by us. We don't know who you are, we don't have access to your contacts, your messages, etc.\"\r\n\r\n_Retention:_ Collected data \"are stored anonymously on our servers for 12 months.\"\r\n\r\n_Data Use:_ \"Collected data allows: \r\n\r\n1. To enhance your experience while you visit point of sales equipped with our technologies.\r\n2. To provide visitors\u2019 in\u00adstore behavior reports to our customers. Those reports contain point of sales visit trends, made of aggregated data. No personal or individual information is included.\r\n3. To personalize visitors mobile ads on smartphone applications they use.\r\nWe use anonymous visit data to provide a personalized experience on our partners smartphone applications. For example: after visiting a shop you could see a personalized banner for this particular shop instead of a generic one.\"\r\n\r\n_Opt-out:_ Fidzup states, \"The simplest way to prevent data collection from your Wifi is to disable your Wifi connection near places that use it. \r\n\r\nWe also provide a way to delete all data regarding your smartphone with our opt-out form\" [Fidzup, 04](https://www.fidzup.com/en/privacy).\r\n\r\nTheir opt-out form can be located at [https://www.fidzup.com/en/opt-out-en](https://www.fidzup.com/en/opt-out-en).\r\n\r\n## Relationships\r\n_Brands and retailers:_ Gemo / Timberland / Buffalo Grill / Grand Optical / Opel / Renault / Kl\u00e9pierre / Etam / Mercedes / Nissan [Fidzup, 01](https://www.fidzup.com/en) / Hammerson & Les Terrasses du Port shopping center / Vache Noire shopping center (in Arcueil) [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip) / KFC / BMW [BusinessWire, 01](http://www.businesswire.com/news/home/20161130005981/en/Fidzup-Performance-Marketing-Startup-Retailers-Raises-3.7) / Galeries Lafayette / Darty / ITF / La Halle / Peugeot / FDJ Cultura [Tech.eu, 01](http://tech.eu/brief/fidzup-raises-investment) / Kiabi / SNCF [L'Usine Digitale, 01](https://www.usine-digitale.fr/editorial/les-100-du-digital-retail-fidzup-pour-geolocaliser-ses-clients-grace-a-leur-smartphone-et-des-ultrasons.N348982) Paris Region Lab / Petit Poucet / scientipole / oseo / R\u00e9seau Entreprendre [Fidzup, 02](https://www.fidzup.com/en/team)\r\n\r\n_Supporters:_ Mobile Marketing Association France / Electronic Business Group / IAB France / Picom / La Nuit Des Rois [Fidzup, 01](https://www.fidzup.com/en) \r\n\r\n## Details\r\n_Financial details: \"Fidzup was founded in 2011 by two entrepreneurs sharing the same idea: to give a lift to traditional business through technological innovation\" [Fidzup, 02](https://www.fidzup.com/en/team). They raised $3,7 million with venture capitalists CapHorn Invest and Turenne Capital as well as existing investors CapDecisif Management via the FRCI (Fonds R\u00e9gional Co-investissement de la R\u00e9gion Ile de France) and Petit Poucet Participation, the press reported in November 2016 [BusinessWire, 01](http://www.businesswire.com/news/home/20161130005981/en/Fidzup-Performance-Marketing-Startup-Retailers-Raises-3.7); [Tech.eu, 01](http://tech.eu/brief/fidzup-raises-investment). \r\n\r\nFor Product pricing (from old website), see [Fidzup v2, 04](https://web.archive.org/web/20171015030915/http://v2.fidzup.com/en//nos-offres).\r\n\r\n_Awards:_ Fidzup won the 2015 \"Kings of Hope Prize\" [Viuz, 01](https://viuz.com/2015/03/19/fidzup-trophee-espoir-lndr-2015-les-outils-du-web-pour-re-inventer-le-commerce-physique).\r\n\r\n_Fidzup history and ideology:_ Fidzup is \"Aware of the opportunities coming from the use of smartphones in your stores, our teams develop microlocation technologies to help you to reach your goals. Continuous innovation and improvement help us to develop more and more relevant and quicker and quicker solutions to install for our customers\" [Fidzup, 02](https://www.fidzup.com/en/team). Their ambition is to \"Provide physical commerce with the tools that pure players now enjoy\". Where on the web professionals are able to identify a highly qualified target to better send them promotions, no solution existed for retailers to recover these prospects.\r\n\r\nSince its creation in 2011, Fidzup was working on an indoor presence detection technology. The idea was to offer retailers and shopping centers a light technology to deploy and without constraint of use for consumers. This is how Fidzup Microtargeting was created, a platform for sending interactive and location-based content on the mobile of visitors to points of sale. It is the explosion of Criteo, the French giant of online advertising retargeting, which pushed the Fidzup teams to pivot towards a similar solution, but to the brick & mortar business. Since the startup was already able to understand the behavior of consumers in points of sale.\r\n\r\nSpecifically, where Criteo is interested in the behavior of Internet users on e-commerce sites to retarget advertising on partner media pages, Fidzup is interested in the consumer shopper journey in physical stores to address contextualized advertising. on its mobile apps\" [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip). \r\n\r\n_Devices:_ Mobile (Android, Apple) / Fidbox\r\n\r\n_Slogans:_ \r\n\r\n* \"Online Offline: Performance mobile marketing for retailers\" [Fidzup, 01](https://www.fidzup.com/en)\r\n* \"An innovative technology for interior presence detection\" \r\n* \"A mailing platform for geolocalized interactive content\" [Fidzup v2, 01](http://archive.is/kUZGK) \r\n\r\n### Methods\r\nFidzup \"has developed 3 solutions to detect the presence of a consumer in stores: Fidzup Microtargeting, Fidzup Retargeting and Fidzup Analytics. These technologies, easily deployable, are based on the principle of indoor geolocation (operating by wifi, ultrasound or BLE) and broadcast interactive content on smartphone. Thus, Fidzup captures and reactivates the consumer or simple visitor, either directly at the point of sale, or when he leaves the sign\" [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip).\r\n\r\nBig Data / Predictive analytics / Programmatic / RTB \r\n\r\n_Consumer targeting:_ Geographical/store / Digital navigation (on devices) / Habits / Purchase intention \r\n\r\n\"The most accurate in-store tracking technology on the market. Measure your online campaigns ROI with adapted offline KPIs\" \r\n_Fidbox:_ \r\n * Works without any mobile app \r\n * 3 meters accuracy; 4 years of R&D, 2 patents registered \r\n * Autonomous in-store sensor [Fidzup, 01](https://www.fidzup.com/en)\r\n\r\nFidbox is \"compatible with 99.9% of smartphones\". Fidboxes \"capture an encrypted identification key, unique to mobile, that Fidzup Retargeting then found on the ad servers. These captured data will be processed to segment the audience of the target brand to address on AdExchanges. This process will thus make it possible to resort to an advertising retargeting by displaying a personalized banner, according to the offline consumption habits of the mobile user, when he / she consults a third-party application (games, news, sports, etc.).\" Fidzup's \"point-of-sale deployment is lightweight and does not require any particular mobile application.\" \r\n\r\n_Fidzup Retargeting:_ Fidzup's \"Totally innovative process allows the Terrasses du Port not to lose its consumers, increase its customer knowledge and optimize its media buying campaigns by addressing a qualified target. Fidzup Retargeting can also measure the visits of the consumer and know the generated downloads in a logic of measurement of the ROI of the carried out campaigns.\" \r\n\r\n_Fidzup Microtargeting:_ Fidzup's microtargeting is \"based on the principle of indoor geofencing and allows shopping centers & retailers to interact instantly with their customers via their smartphone at their points of sale.\" It \"relies on the use of a sound source to send data to a smartphone that will decode and process the received signal. More concretely, Fidzup broadcasts via point of sale via any audio source (speaker system broadcasting music, sound boxes, televisions, etc.) a signal inaudible to the human ear. This signal has the particularity of having a unique identifier corresponding to a specific location. The detection is done when the smartphone receives the signal and decodes it to know where the consumer is.\r\n\r\nFidzup Microtargeting then automatically triggers the sending of interactive and contextualized content on the mobile of the consumer according to his position. Discount coupons, targeted promotion on a product upon entry into the corresponding department, exceptional opening information, contests triggered as soon as they enter the store ... For example, a brand wishes to launch a promotion on its polos: \"1 polo bought, the 2nd to -50% \u00bbFor this, she will have the choice between sending the promotion on the mobile of the consumer as soon as it enters the store or the entrance of the department concerned by the promotion.\r\n\r\nThe consumer then receives relevant content, at the right place and at the best time on his smartphone. With Fidzup technology, the sales area is 'squared': either at the entrance of the store itself or within a specific radius, it is possible for each manager to choose the right place, where the visitor will receive interactive content. \r\n\r\n...Unlike other solutions that require the deployment of a heavy hardware device, and therefore expensive to install and maintain, the technology developed by Fidzup can be deployed without any hardware installation on site if the audio system used is remotely controllable. Indeed, some companies have specialized in the implementation of audio systems, the distribution of music in point of sale can be controlled online. These players cover a majority of the retail and retail market. If, however, the customer is not equipped, Fidzup has developed a battery of inexpensive hardware solutions that are easy to install.\r\n\r\n- Mobile Compatibility: The software brick developed by Fidzup (the SDK) integrates with applications running on iOS mobile OS (iPhone) and Android. Thus, thanks to Fidzup technology it is possible to reach more than 90% of the global mobile market.\r\n\r\n- Use: In the face of the few players capable of detecting presence at the point of sale, Fidzup chose to specialize in consumer care once it is present. Thus, the startup has developed the lightest solution to send promotional content at the best time to maximize efficiency. The end customer has no action to do (except to download the application of the sign or the mall), it is the content that comes to him automatically and at a time when he will be attentive. Since the media is mobile, it is essential to offer end users a limited number of actions to perform for a simple and fluid use.\" \r\n\r\nThis can result in real-time data mining: \"Since the operations implemented are mainly digital, La Vache Noire has the possibility to follow in real time the impact of its operation (participation rate, winning prizes, etc.).\" This can bring businesses that did not previously data mine into the data mining fold: \"Finally, the marketing department of the center has retained a certain interest from brands that have never participated so much in a digital transaction. Thus, prestigious brands such as Celio, Jules, Yves Rocher or Darjeeling participate each week in the operation 'List of promotions'\" [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip).\r\n\r\n\"Fidzup has developed a means of communication between a sonic emitter and a mobile phone. Thus, by diffusing a tone, inaubible to the human ear, inside a building we can detect the presence of mobile phones and therefore their owners. How does the detection work? Your visitors must have the mobile application already installed on their smartphone. This contains a software layer (a SDK supplied by Fidzup) capable of detecting the signals and decoding them. What kind of sonic emitter can be used? It is possible to use any audio source to diffuse the signals. In fact, Fidzup has come up with a variety of hardware solutions depending on the user\u2019s requirements. \r\n\r\n... We supply you with one or several bespoke sonic signals to diffuse in your establishment. Depending on the type of building and the type of usage you require, Fidzup offers a choice of several hardware and software solutions to simplify and optimize the diffusion of its sonic technology. Depending on the method of emission chosen, a sonic signal can be used to cover a precise zone of a store, the corridors of a shopping mall or even detect a visitor admiring a work of art in an art exhibition.\" \r\n\r\n... \"Installing the SDK into your mobile application: We supply you with a software layer (SDK) to add to your mobile application. this layer detects and decodes the audio signal. The SDK is supplied with full documentation to help you install it swiftly and easily into your mobile application.The SDK is compatible with both iOS (iPhone) and Android operating systems. Minimum requirement for the iOS operating system: iOS version 5; Minimum requirement for the Android operating system: Android 2.3.5 (HTC One X not supported)\" [Fidzup v2, 02](https://web.archive.org/web/20171015025307/http://v2.fidzup.com/en//notre-solution).\r\n\r\n_Fidzup Analytics:_ \"Fidzup Analytics is a technology based on wifi that analyzes the traffic in points of sale, especially for shopping centers and supermarkets. Coupled with the Fidzup Retargeting solution, this technology makes it possible to capture on average 40% of the real traffic, whether the consumers / visitors are carriers of the application of the center or not.\r\n\r\nTo facilitate the handling of its solution, Fidzup gives direct access to the Analytics interface to the shopping center teams. The management can then see the route taken by its visitors from one store to another and analyze the data retrieved by day, week or month. Thus, Fidzup Analytics is able to display the traffic generated in the point of sale, the average duration of a visit, its frequency and to couple all these data to highlight trends or peaks of affluence. For the management of the center, the interest of these crossings of data is of size: to be able to identify the typical course of a customer and thus to define the zones \"cold\" or \"hot\" of the shopping mall (that is to say to say the locations more or less visited). Thanks to Fidzup Analytics, retail professionals can have a perfect knowledge of their customers, their habits in the center, but also know if their rental spaces are properly valued according to the passage of visitors. Finally, with the Analytics solution, shopping centers now have the opportunity to measure the audience generated by their communication devices already in place (promotional video screen, POS, display, totem ...). Indeed, depending on the information provided on these media, Fidzup is able to know the impact on the shopping journey of the customer and sales\" [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip).\r\n\r\n\"Fidzup\u2019s Programmatic & Analytics Platform is made up of DSP, DMP and Tag management solutions, developed in-house for bricks-and-mortar stores. These technologies enable store managers to direct their campaigns while accurately measuring their return on investment\" [BusinessWire, 01](http://www.businesswire.com/news/home/20161130005981/en/Fidzup-Performance-Marketing-Startup-Retailers-Raises-3.7).\r\n\r\nSonice emission solutions: \r\n\r\n- Web player: The web player allows you to emit the Fidzup sonic signal via your computer. This solution is ideal for small spaces with no audio system in place. \r\n- Standalone emitter unit: This mains connected unit allows you to broadcast your sound signal continuously in the manner of a portable and independent speaker enclosure. This solution is ideal for creating an interactive zone in a specific area of your establishment. \r\n- Mixer emitter unit: The mixer unit, also mains connected, can automatically mix your signal sound with the music played through your audio system. This solution is ideal for users wishing to cover all areas of their establishment through their own public address system. \r\n- Custom installation: Your audio system is managed by an external provider? No problem, Fidzup can work with them to simplify the deployment, as it could then be managed remotely, without any hardware installation in situ\" [Fidzup, 03](http://www.fidzup.com/fidzup-2015.zip). \r\n\r\n_Web interface:_ \"We give you secure access to an administrative interface that allows you to devise promotional content that will be displayed on visitors\u2019 smartphones as soon as they are detected in your establishment. Adjust the parameters and pre-visualize your content: expiry dates, target zones, message type, image uploads, content descriptions, etc., The interface is intuitive and extensive. From a discount coupon to a simple information bulletin, take advantage of the numerous pre- configured items in the interface to send the right content at the right time to your visitors. \r\n\r\n... Following promotional campaigns: Our administrator\u2019s inferface includes a comprehensive dashboard and accurate statistics that allow you to monitor the performance of your promotional campaigns.The number of detections in your location, number of messages sent and received, CTR (click- through rate)... View the impact of your advertising campaigns at a glance and optimize them swiftly\" [Fidzup v2, 02](https://web.archive.org/web/20171015025307/http://v2.fidzup.com/en//notre-solution). \r\n\r\n_Some of the data collected:_ \r\n\r\n* unique visitors\r\n* duration of visits\r\n* frequency of visits\r\n* hot / cold zone of the store\r\n* customer journey\r\n* fast outputs\r\n* volume of smartphones\r\n* brands and OS terminals [Viuz, 01](https://viuz.com/2015/03/19/fidzup-trophee-espoir-lndr-2015-les-outils-du-web-pour-re-inventer-le-commerce-physique)\r\n\r\n## References\r\n* _Ad-exchange.fr, 01._ http://ad-exchange.fr/fidzup-retargeting-unit-le-ciblage-publicitaire-sur-smartphone-et-le-monde-physique-14297._ http://ad-exchange.fr/fidzup-retargeting-unit-le-ciblage-publicitaire-sur-smartphone-et-le-monde-physique-14297\r\n* _Ad-exchange.fr, 02._ http://ad-exchange.fr/fidzup-veut-booster-ladoption-de-boitiers-du-type-beacon-dans-les-magasins-francais-27156._ http://ad-exchange.fr/fidzup-veut-booster-ladoption-de-boitiers-du-type-beacon-dans-les-magasins-francais-27156 \r\n* _BusinessWire, 01._ http://www.businesswire.com/news/home/20161130005981/en/Fidzup-Performance-Marketing-Startup-Retailers-Raises-3.7\r\n* _Crunchbase, 01._ https://www.crunchbase.com/organization/fidzup\r\n[Fidzup, 01._ https://web.archive.org/web/20171124095315/https://www.fidzup.com/en\r\n* _Fidzup, 02._ https://web.archive.org/web/20171124095424/https://www.fidzup.com/en/team \r\n* _Fidzup, 03, .zip file._ https://web.archive.org/web/20171124095525/http://www.fidzup.com/fidzup-2015.zip\r\n* _Fidzup, 04._ https://web.archive.org/web/20171124095616/https://www.fidzup.com/en/privacy\r\n* _Fidzup v2, 01._ http://archive.is/kUZGK\r\n* _Fidzup v2, 02._ https://web.archive.org/web/20171015025307/http://v2.fidzup.com/en//notre-solution \r\n[Fidzup v2, 03._ https://web.archive.org/web/20171015030737/http://v2.fidzup.com/en//cas-dusage\r\n* _Fidzup v2, 04._ https://web.archive.org/web/20171015030915/http://v2.fidzup.com/en//nos-offres\r\n[L'Usine Digitale, 01._ https://www.usine-digitale.fr/editorial/les-100-du-digital-retail-fidzup-pour-geolocaliser-ses-clients-grace-a-leur-smartphone-et-des-ultrasons.N348982\r\n* _Marketing-Professionnel.fr, 01._ http://www.marketing-professionnel.fr/parole-expert/distribution-retail-geofencing-geolocalisation-indooor-201411.html\r\n* _Tech.eu, 01._ http://tech.eu/brief/fidzup-raises-investment\r\n* _Viuz, 01._ https://viuz.com/2015/03/19/fidzup-trophee-espoir-lndr-2015-les-outils-du-web-pour-re-inventer-le-commerce-physique\r\n\r\n## External Links\r\n* _Crunchbase (Fidzup):_ https://www.crunchbase.com/organization/fidzup._ https://www.crunchbase.com/organization/fidzup\r\n* _Fidzup, 05:_ https://web.archive.o]rg/web/20171123081837/https://fidzup.com/en/live._ https://web.archive.org/web/20171123081837/https://fidzup.com/en/live\r\n* _Fidzup, 06:_ https://web.archive.org/web/20171124000206/https://fidzup.com/en/product._ https://web.archive.org/web/20171124000206/https://fidzup.com/en/product\r\n* _Fidzup, 07 https://web.archive.org/web/20171124094502/https://itunes.apple.com/us/app/fidzup-live/id735938167?mt=8._ https://web.archive.org/web/20171124094502/https://itunes.apple.com/us/app/fidzup-live/id735938167?mt=8\r\n* _Fidzup, 08:_ https://web.archive.org/web/20171124094519/https://play.google.com/store/apps/details?id=com.fidzup.fidzuplive._ https://web.archive.org/web/20171124094519/https://play.google.com/store/apps/details?id=com.fidzup.fidzuplive\r\n* _Fidzup, 09:_ https://web.archive.org/web/20171124094739/https://play.google.com/store/apps/details?id=com.fidzup.spotinstore.diagnostic._ https://web.archive.org/web/20171124094739/https://play.google.com/store/apps/details?id=com.fidzup.spotinstore.diagnostic\r\n* _Fidzup, 10:_ https://web.archive.org/web/20171124094810/https://play.google.com/store/apps/details?id=com.fidzup.petitpoucet._ https://web.archive.org/web/20171124094810/https://play.google.com/store/apps/details?id=com.fidzup.petitpoucet\r\n* _Fidzup, 11:_ https://web.archive.org/web/20171124094853/https://www.fidzup.com/en/use-case/._ https://web.archive.org/web/20171124094853/https://www.fidzup.com/en/use-case/\r\n* _Fidzup, 12:_ https://web.archive.org/web/20171124094955/https://vimeo.com/59666867._ https://web.archive.org/web/20171124094955/https://vimeo.com/59666867\r\n* _Fidzup, 13:_ https://web.archive.org/web/20171124095009/https://vimeo.com/80601084._ https://web.archive.org/web/20171124095009/https://vimeo.com/80601084", "network_signature": "fidzup", "creation_date": "2017-09-24", "id": 2, "website": "https://www.fidzup.com", "code_signature": "com.fidzup."}, "3": {"name": "Krux", "description": "## Primary Location\r\nUnited States (San Francisco) [Crunchbase, 01](https://www.crunchbase.com/organization/krux-digital)\r\n\r\n## Website\r\n[https://www.salesforce.com/products/marketing-cloud/data-management](https://www.salesforce.com/products/marketing-cloud/data-management)\r\n\r\n## About\r\nSalesforce DMP is a data management platform that manages data, identifies end users, and cetnralizes user-level data for advertising and content personalization [Salesforce, 24](https://konsole.zendesk.com/hc/en-us/articles/115012398067-What-if-I-just-want-to-import-data-instead-of-using-the-Control-Tag-SDK-or-other-DMP-tracking-)\r\n\r\n## Ownership\r\nSalesforce\r\n\r\n## Documentation\r\n[https://konsole.zendesk.com/hc/en-us/articles/226031268-Android-SDK-Implementation-Guide](https://konsole.zendesk.com/hc/en-us/articles/226031268-Android-SDK-Implementation-Guide)\r\n\r\n## Products and Services\r\n\r\nSalesforce DMP offers a vast array of technologies in its data management platform. These are detailed in the Techology section under Details, below.\r\n\r\nServices provided by Salesforce DMP include: \r\n\r\n* Accerlated Mobile Pages (facilitate mobile-optimized content)\r\n* Cross Device Identity Mangement (identify individuals across devices)\r\n* Salesforce DMP Einstein Segmentation (segment multiple personas in an audience)\r\n* Tracking (re-identify and track users using various methods)\r\n* Hashed device management (tracking used in reaction to Safari 3rd party blocking)\r\n* User matching (match users with various techniques to identify individuals)\r\n* Ad Server analytics (understand and analyze audience segment delivery and yield across all ad impressions)\r\n* Content engagement reports (loyalty report cards, site visits, and more)\r\n* Frequency engagement reports (how many times a user has seen an ad)\r\n* Funnels report (track customer behaviors across their customer journey)\r\n* Look-alike modeling (\r\n* Audience Profile Report (such as age, gender, and household income)\r\n\r\n## Privacy Policy\r\n**Opting out** \r\n_DMP Opt-Out_ \"DMP Opt-Out\r\nhttps://apiservices.krxd.net/consumer/optout is the standard DMP opt-out URL. When called directly, this URL will execute the Opt-out action for a user and it will return the following JSON response:\r\n\r\n{\"code\":\"success\"}\r\n\r\nA user must allow cookies from Salesforce DMP in order to opt-out. Calling the DMP opt-out code (by clicking on an opt-out button placed on the client's page) will result in a persistent 'cookie' placed in the user\u2019s web browser by Salesforce, identifying that user as being on the Salesforce DMP 'do not target' list. Taking this opt-out step won't prevent all tracking and targeting online, but it will ensure the user\u2019s wishes are honored by all Salesforce DMP clients.\r\n\r\nNote: If the user uses more than one computer, the process must be repeated for each one as this information is associated with a cookie unique to each machine.\" [Salesforce, 7](https://konsole.zendesk.com/hc/en-us/articles/217039187-Privacy-Policy-and-Opt-Out-Guide)\r\n\r\n_On Mobile:_ \"Users can reset their IDFA or AdID to receive a new one. This is comparable to deleting cookies.\r\n\r\nThey can also block these completely by opting-out of Ad Track or Ads Personalization. In that case, Salesforce DMP cannot track or target these users.\" [Salesforce, 3](https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ)\r\n\r\n_In Safari FAQ:_ \"Is there any difference in the how 1st-party cookies and Hashed Device IDs treat opt-outs?\r\nYes, if the client is utilizing a first-party cookie and has multiple domains, a dedicated opt-out will need to be configured and maintained for each site. Alternatively, if hashed device management is employed a single opt-out link will be applicable for a given client.\r\n\r\nCan users opt-out of Hashed ID tracking?\r\nAbsolutely \u2013 unlike other providers of so-called Fingerprinting techniques, the Salesforce DMP actually can manage fingerprinting users through an opt-out. \r\n\r\nDoes Fingerprinting adhere to PII rules?\r\nYes, our hashed device management solution is fully compliant with PII protocols.\r\n\r\nDo both approaches lose uses when they clear their cookies?\r\nNo, first-party cookies can be cleared, while the hashed ID will persist even if cookies are emptied. [Salesforce, 4](https://konsole.zendesk.com/hc/en-us/articles/115000428307-Safari-FAQ)\r\n\r\n\"Can users opt-out of tracking in Mobile Apps?\r\nUsers can reset their IDFA or AdID to receive a new one. This is comparable to deleting cookies.\r\n\r\nThey can also block these completely by opting-out of Ad Track or Ads Personalization. In that case, Salesforce DMP cannot track or target these users.\" [Salesforce, 58](https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ)\r\n\r\n**Personally Identifiable Information** \r\n\"Personally Identifiable Information (PII) includes any data that could potentially identify a specific individual and can be used for de-anonymizing data. Salesforce does not collect or store PII.\"\r\n\r\nSome examples of PII include: Full name; Email address; Phone numbers; Credit card numbers; Date of birth; Login/screen name; IP address is considered PII in some countries outside of the US; Home address; etc\" [Salesforce, 8](https://konsole.zendesk.com/hc/en-us/articles/115007222048-PII)\r\n\r\n**Data Privacy and Security Considerations**\r\n\r\nSalesforce DMP does not accept PII data and it is a breach of the MSA to send to us. Onboarding might be a better option if you have data connected to email addresses and are concerned with offline data import user matching. Usage and set up fees apply.\" [Salesforce, 32](https://konsole.zendesk.com/hc/en-us/articles/214918988-First-Party-Data-Import) \r\n\r\n**Data Retention** \r\n\"Data Expiry\r\n\r\nSalesforce DMP stores any data collected through online mechanisms (including user matching data) for a variable period as defined in the contractual agreement between Salesforce and the client. First-party imports remove any data not included in subsequent imports (full refresh). For best user match results, files should be uploaded frequently, or daily, even if the data output has no change.\" [Salesforce, 32](https://konsole.zendesk.com/hc/en-us/articles/214918988-First-Party-Data-Import) \r\n\r\n## Relationships\r\n_Data Onboarding:_\r\ncomScore / LiveRamp / Neustar [Salesforce, 9](https://konsole.zendesk.com/hc/en-us/articles/115010458727-Data-Onboarding-Partners)\r\n\r\n_Data Collection Partners:_\r\n\r\n* Off-Site Ad Servers:_ Conversant / DoubleClick Campaign Manager (DCM) / Flashtalking / Innovid / Medialets / Sizmek\r\n* On-Site Ad Servers:_ DoubleClick for Pulishers - DFP (Data Transfer Files)\r\n* Email Service Providers:_ SalesforceExactTarget\r\n* Data Management Platforms:_ Adobe Audience Manager / Oracle BlueKai DMP\r\n* Analytics & Measurement:_ Adobe Analytics (fkaOminture SiteCatalyst) / Brightcove / comScore Validated Campaign Essentials (vCE) / Google Analytics Standard / Kochava / MOAT / Tune [Salesforce, 10](https://konsole.zendesk.com/hc/en-us/articles/227144948-Data-Collection-Partners)\r\n\r\n**Data Activation Partners** \r\n\r\n_On-Site Ad Servers:_ Adition / Adswizz / AdTech / DoubleClick for Publishers - DFPAudience / DoubleClick for Publishers - DFP Key/Value Pairs / Freewheel / IPONWeb / LKQD / Nativo / OAS / OpenX / SAS/AIMatch / Smart Ad Server\r\n\r\n_On-Site SSP's:_ DoubleClick AdExchange - AdX (via DFP) / Index Exchange (Casale) / OpenX / Pubmatic / Rubicon / Sonobi / Sticky Ads / Tremor\r\n\r\n_Off-Site Ad Servers:_ Flashtalking / Flite / Innovid / Sizmek\r\n\r\n_Off-Site Data Activation:_ ActiveAgent AG / Adara / AdColony / AdForm / AdRoll / AdSquare / A.ki / Amazon Advertising / AOL ONE / AppNexus / Beeswax / Comscore / Criteo / DataXu / DoubleClick Bid Manager - DBM / Dstillery / Exponential / Facebook Custom Audiences / Google AdWords / Google RLSA / IgnitionOne / Infectious Media / InMobi / Instagram (via Facebook Custom Audiences) / Jivox / Lotame / Maxpoint / MediaMath / [m]Platform | GroupM / Netmining / Next Performance / OwnerIQ / Platform161 / Quantcast / RadiumOne / RocketFuel / Run / Simpli.fi / Specific Media (Viant) / SpotXchange / Teads / The Trade Desk / TimeOne / Tradelab / Termore Video / TubeMogul / Turn / Twitter - Tailored Audience / Undertone / VideoAmp / Videology / Yahoo! DataX (replaced RMX pipeline) / Yieldlab / Zebestof\r\n\r\n_Experience Management Systems & A/B Testing Platforms:_ AB Tasty / Acquia / Adobe Target / Maxymiser / Optimizely / Oracle Real-Time Decisions / Teradata Real - Time Interactions Manager / VWO\r\n\r\n_Assorted Data Outputs:_ Adobe Audience Manager / Moat / Oracle BlueKai DMP / Survata / YieldEx [Salesforce, 11](https://konsole.zendesk.com/hc/en-us/articles/226620988-Data-Activation-Partners)\r\n\r\n_Third-Party Data Marketplace:_ Acxiom / AffinityAnswers / ALC / Alliant / AnalyticsIQ / ASL / Audience Partners / AuDIGENT / B2B Targets / Bombora / Cardlytics / comScore / Connexity / Crossix / Cuebiq, Inc / Dataium / Dataline / Datamyx / DataLogix / Datonics / Digital Elements / Dun & Bradstreet / Epsilon / Ethnic Technologies / eXelate / Experian / Eyeota / Factual / Forbes / i360 / InfoGroup / IRI Worldwide / IXI Services/Equifax / Kantar Shopcom / L2 / LiveRamp Data Store / Mastercard Advisors / Maxpoint / MeritDirect / Mobiquity / GfK MRI / Gravy Analytics / #HOME by Vendigi / Navegg / NetWise Data / Neustar AdAdvisor / Nielsen / Nielsen Catalina Solutions (NCS) / NinthDecimal / PlaceIQ / PushSpring / Quantcast / SambaTV / ShareThis / Skydeo - Mobile AppAudiences / Skyhook / Specialists Marketing Services / Stirista / Tivo / TruSignal / Twine / Vertical Mass / Visual DNA / V12 / Webbula / Windfall [Salesforce, 12](https://konsole.zendesk.com/hc/en-us/articles/217592967-Third-Party-Data-Marketplace)\r\n\r\n## Details\r\n\r\n_Origins:_ Krux began as \"a platform for brands to collect all data from digital interactions across devices and use it to better understand their customers\" for better marketing. However, they \"knew that first-party data (customers\u2019 email addresses and purchase histories) was where the puck was headed, so we doubled down on it.\" They are driven by the concept \"people data\" because people, not browsers and mobile devices, are what buy things. [Salesforce, 1](https://www.salesforce.com/blog/2017/05/krux-is-now-salesforce-dmp.html)\r\n\r\n_Philosophy and approach:_ \"...when I am asked, what is the future of DMPs, I say that DMPs will become completely integrated into larger technology stacks offering a layer of data management (for both known and unknown data) for the \u201cright person.\u201d This orchestration layer consists of connected execution systems that seek to answer the \u201cright message, right time\u201d quandary. It also includes an artificial intelligence (AI) layer, which is the \u201cbrains\u201d of the operation trying determine how to stitch billions of individual data points together in real time.\" \"...marketing is much more than ad campaigns. It is every experience a customer has with the brand, and we empower marketers to use data to impact every touchpoint along that journey, all powered by AI.\" [Salesforce, 1](https://www.salesforce.com/blog/2017/05/krux-is-now-salesforce-dmp.html)\r\n\r\n\"Some of the core reasons to use a DMP are to manage Identity and centralize user-level data for advertising and content personalization. Additionally, the DMP includes insights that help inform targeting and personalization use cases as well as campaign and personalization optimization.\" [Salesforce, 24](https://konsole.zendesk.com/hc/en-us/articles/115012398067-What-if-I-just-want-to-import-data-instead-of-using-the-Control-Tag-SDK-or-other-DMP-tracking-)\r\n\r\n_Scope:_ \"Every month, Salesforce DMP interacts with more than 3 billion browsers and devices, supports more than 200 billion data collection events, processes more than 5 billion CRM records, and orchestrates more than 200 billion personalized consumer experiences.\" [Salesforce, 1](https://www.salesforce.com/blog/2017/05/krux-is-now-salesforce-dmp.html)\r\n\r\n\"The Salesforce Data Management Platform (DMP) allows publishers and marketers to collect and organize all of their consumer web data in one central \"big-data\" warehouse. Using Salesforce DMP, organizations can consolidate and reconcile their first-party \"web-behavior\" data that is generated by consumers as they engage with media and/or content with data from various third-party data providers like eXelate, DataLogix, Targus etc. Organizations can also integrate data from their user registration and subscription databases (hereon referred to as \u201cfirst-party data\u201d) into Salesforce DMP and join that data with web behavior and third-party data. \r\n\r\nUser data stored in Salesforce DMP is keyed off a global Krux User ID. The Krux User ID is a third-party cookie and as such is specific to a browser (and corresponding device too). All data that is collected by Salesforce DMP from online environments is automatically keyed off the Krux User ID.\r\n\r\nSalesforce DMP supports the ingestion of first-party data available in client systems like registration or subscription databases and other CRM systems. This data is keyed off the client\u2019s first-party User ID. A User Matching process that maps the client first-party User ID to the corresponding Krux User ID for every applicable user facilitates the onboarding and ingestion of this data. \r\n\r\nAfter the user matching process has been setup clients can send first-party data corresponding to the matched users. Salesforce DMP has a strict data format for the first-party data outlined below.\" [Salesforce, 32](https://konsole.zendesk.com/hc/en-us/articles/214918988-First-Party-Data-Import)\r\n\r\n_Billing Clients:_ Clients are charged for impressions, and a maximum amount for a single impression is calculate: [Salesforce, 34](https://konsole.zendesk.com/hc/en-us/articles/115011719688-How-Data-Costs-are-Billed)\r\n\r\n### Technology\r\n\r\n**AMP for Mobile Tracking** \r\nAMP stands for \u2018Accelerated Mobile Pages\u2019 and is designed to facilitate mobile-optimized content. A notable aspect of the design is that it keeps 3rd party JavaScript out as much as possible to improve performance, however, there are AMP libraries available to provide additional rich content.\" \r\n\r\nSee AMP FAQ for more: [Salesforce, 56](https://konsole.zendesk.com/hc/en-us/articles/115000428507-AMP-FAQ)\r\n\r\n**Cross Device Identity Mangement (Declarative and Predictive)** \r\nPredictive DCIM costs an extra fee. \"The Predictive CDIM report describes all of the devices associated with people already in a given segment. It allows you to identify and map consumers and behavior patterns consistently across all devices, screens, and platforms.\"\r\n\r\n_Key features include_: \"Connects known and unknown devices (declared and predictive) / Create a CDIM segment directly from the report / Aggregate audiences and their data across devices / A choice of similarity levels allows you to consider the trade off between accuracy and scale\". _Key benefits include_: \"Improves reach, relevance, and inventory monetization / Increases your opportunity to sequence ads, at optimal frequency, for consistent messaging and experience across channels, throughout the journey / Delivers accurate analytics for segment profiles and campaign conversions?\r\n\r\n_Probablistic Matching:_ \r\n\"How does the probabilistic matching algorithm work?\r\n\r\nThe core of the model is designed to uncover the devices that stay together in various places over long periods of time. To do this effectively there are three important considerations - scale, training, and validation.\r\n\r\n* Scale - Because the success of the model is predicated on seeing lots of devices and how they move over time, it is essential to have massive reach into the device world. With one of the largest device footprints on the planet, Salesforce DMP has an advantageous position from which to deliver accurate results.\r\n* Training - Salesforce DMP uses deterministic data coming from authenticated events (logins, purchases, etc) to provide a truth set for training the algorithm.\r\n* Validation - From the deterministic data set, Salesforce DMP reserves some data to validate the efficacy of the model.\r\n\r\nBetween these three items we are able to continuously improve the accuracy of the predictions and deliver a better product.\r\n\r\nTo better understand the view of devices over time, consider a user's work and home movement. During the work day, all of the user's devices are likely to be tied to the same IP from work. However, colleagues are also tied to the same IP and in that single snapshot of time, it may be assumed the user and their colleagues are the same person.\r\n\r\nLooking at that same IP address at night, there is likely no activity, as everyone has left the office. When looking at the user's home IP at night, all of the devices that belong to that user and their family are tied to the same IP. That single snapshot might imply that the usr and their family are one \"person\".\r\n\r\n_Predicting with device composition:_ \"Device Composition: Salesforce DMP uses predictive cookie matching to fill in the gaps where cookies may not be present, such as mobile apps, Safari browser, ad blocking software, etc. However, because Google is looking for active audience cookies, the two systems use different logic around device composition. If your segment includes a high volume of non-stable cookies (mobile/Safari/cookie-less devices), that can impact the match rate.\" [Salesforce, 37](https://konsole.zendesk.com/hc/en-us/articles/115010886887-DFP-FAQ)\r\n\r\n\"Each user creates multiple Krux User IDs (KUIDS) - cookies in browsers as well as IDFAs or AdIDs for mobile apps. Once our cross devices algorithm identifies that two of these KUIDs belong to the same person, we increase the count of \"people\" by one and select one of the KUIDs to be the \"leading\" KUID. We call this the one the \"Uber ID\". \r\n\r\nThere are some rules in place to determine which of the KUIDs is elected the Uber ID. This evaluation can change from day to day. If the Uber ID KUID is not active for a couple of days, it loses it's status as Uber ID. In this special case, the Uber ID is removed from the segment population list and shown accordingly as \"deleted\". \r\n\r\nIt is mainly Safari users to contribute to these Uber ID changes, as on Safari each page impression created a unique new KUID.\" [Salesforce, 54](https://konsole.zendesk.com/hc/en-us/articles/115006652948-Segment-Processing-FAQ)\r\n\r\n**Salesforce DMP Einstein** \r\n\"Salesforce DMP Einstein Segmentation, which allows marketers to use machine learning to discover the multiple distinct personas that exist within their audience.\r\n\r\nUsing Einstein AI, on top of unified consumer data from both first and third-party sources, enables us to algorithmically determine the \u201cpersonas\u201d that best define a brand\u2019s audience. Now, companies can personalize marketing and reach each key persona with a message that is going to resonate, rather than blasting a one-size-fits-all retargeting message to everyone that happened to land on a particular webpage. For example, Conagra Brands has seen dramatic results by customizing the messages to different consumer personas for its Hunt\u2019s brand.\r\n\r\nThis is a great example of how our data management layer consisting of first, second, and third-party data can feed our growing AI layer to create tangible value for marketers\" [Salesforce, 1](https://www.salesforce.com/blog/2017/05/krux-is-now-salesforce-dmp.html)\"\r\n\r\n**Tracking** \r\n_Device strategies & KUIDs:_ \"We differentiate between Mobile Web and Mobile App. Mobile work works just like Desktop Web with KUIDs stored as 3rd Party cookies. This has all the benefits and limitations (e.g. Safari) Desktop Web has.\r\n\r\n_Reidentification:_ \"Can I reidentify users in Apps?\r\nYes, the IDFA or AdID stays constant. Users can be reidentified and targeted in Apps with these device IDs. User can reset this ID and receive a new one though. This is comparable to deleting cookies but not widely used.\" [Salesforce, 3](https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ)\r\n\r\n_Mobile Web & Mobile IDs:_ \"Can I connect Mobile Web and Mobile App users?\r\nNatively this is not possible. If the user logs in on Mobile Web and Mobile App using the same credentials, Salesforce DMP can store this login ID to both the Mobile Web cookie and the Mobile App device ID and such create a connection of the profiles. This is treated just like cross-device identification.\" [Salesforce, 3](https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ)\r\n\r\n_Tracking in Safari and 3rd party cookie subversion:_ Uses Hashed Device Management and 1st Party cookies (set by clients) to target Safari users, as well as a proprietary Hashed Device Identification; fingerprinting. **Salesforce can use Google PPID** if in conjunction with client and client shares Google cloud storage location. \r\n\r\nCan you user-match with 3rd-party data providers when utilizing a first-party cookie?\r\n\r\nClients will issue a 1st-party cookie to the Salesforce DMP, which we then take as our ID. Since it's not a 3rd party cookie \u2013 even though we are acting as an agent of our clients \u2013 it means that we are unable to sync those users with a 3rd party data provider unless the 3rd party fires a match pixel.\r\n [Salesforce, 4](https://konsole.zendesk.com/hc/en-us/articles/115000428307-Safari-FAQ)\r\n\r\n_CDIM & Hashing:_ \"What makes Salesforce's Hashed ID different from competitive offerings?\r\nThere are a few vendors outside of Salesforce who provide Hashed Device IDs, however, they do not couple it with a CDIM solution. This enables Salesforce to associate Safari activity within a larger, holistic set of that individual\u2019s data and utilize Safari activity within a larger conversion path.\r\n\r\nHow can you tell if other providers offering Hashed Device Management solutions are accurate or employing CDIM?\r\nIf or when you hear really high numbers of unique users (UUs) reported against Safari, it often means that they are not resolving the browser down to a single user; each page view counts as a UU in Safari if you don't have a CDIM solution.\" [Salesforce, 4](https://konsole.zendesk.com/hc/en-us/articles/115000428307-Safari-FAQ)\r\n\r\n\"Do users have a KUID in Mobile Devices?\r\nWe differentiate between Mobile Web and Mobile App. Mobile work works just like Desktop Web with KUIDs stored as 3rd Party cookies. This has all the benefits and limitations (e.g. Safari) Desktop Web has.\r\n\r\nMobile Apps cannot access cookies. They provide their device IDs IDFA (iOS) or AdID (Android) which are used by Salesforce DMP as unique identifiers instead of a Salesforce DMP cookie.\r\n\r\nCan I reidentify users in Apps?\r\nYes, the IDFA or AdID stays constant. Users can be reidentified and targeted in Apps with these device IDs. User can reset this ID and receive a new one though. This is comparable to deleting cookies but not widely used.\r\n\r\nCan I connect Mobile Web and Mobile App users?\r\nNatively this is not possible. If the user logs in on Mobile Web and Mobile App using the same credentials, Salesforce DMP can store this login ID to both the Mobile Web cookie and the Mobile App device ID and such create a connection of the profiles. This is treated just like cross-device identification.\" [Salesforce, 58](https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ)\r\n\r\n**Hashed Device Management (targeting Safari 3rd party blocking)** \r\nUsed for Safari because Safari has 3rd party blocking [Salesforce, 16](https://konsole.zendesk.com/hc/en-us/articles/115012183888-Hashed-Device-Management)\r\n\r\n\"The Salesforce DMP Hashed Device Management solution allows for targeting users on Safari browsers that block 3rd party cookies. Please open a ticket in the Help Portal if you would like to request Hashed Device Management.\" Details here: [Salesforce, 35](https://konsole.zendesk.com/hc/en-us/articles/115011230687-How-to-verify-Hashed-Device-Management)\r\n\r\n**User matching** \r\n_For a great guide on user matching, see:_ [Salesforce, 32](https://konsole.zendesk.com/hc/en-us/articles/214918988-First-Party-Data-Import)\r\n\r\nSalesforce and 3rd parties each use their own IDs, and match users by firing the _other_ party's pixel when their own pixel fires on a site. Match rate is the percentage of users of party A known by party B. SF DMP match rates exclude Safari and app IDs. Increased match rates create greater scale, and \"Greater audience scale creates more options for managing and optimizing campaign tactics such as segmentation, personalized messaging, frequency, omni channel journey, etc.\" Because of 3rd party blocking, **Safari users can typicaly not be matched to partners at all.** \r\n\r\n\"By default, we run user match pixels on client\u2019s websites through the Control Tag for all partners a client is working with. We fire it on all pages with a frequency cap of 3 times over a 24-hour period for a given user. This will ensure return users are matched, but will not overwhelm client\u2019s sites with unnecessary tag fires. We set the tag to fire \"immediately\" to make sure users are matched before leaving the page. \r\n\r\nIt will take up to 30 days for the match rate to reach its peak after a new user match pixel has been activated.\r\n\r\nUnlike first party data that is exclusively available to the client who owns it, user match tables are shared across all Salesforce DMP clients. This way, each client can benefit from the user match pixels being fired on other client\u2019s websites.\r\n\r\nSalesforce has one of the largest footprints in the industry, thus providing exceptionally high match rates. Match rates can vary from country to country though, depending on both Salesforce's and the partner\u2019s footprint in that market.\r\n\r\nIt is also possible for partners to fire the Salesforce DMP user match pixel across all their inventory to improve the match rate upon request.\" [Salesforce, 23](https://konsole.zendesk.com/hc/en-us/articles/115006072448-User-Matching-and-Match-Rates-FAQ)\r\n\r\nCritically, \"The Client User ID will have a one-to-many relationship with the Krux User ID in the User Match table. Note that in general, there may be multiple Krux User IDs mapped to a given Client User ID because the Krux User ID is browser specific whereas the Client User ID will be the same across multiple browsers (assuming that it is indeed a persistent user ID as opposed to a first-party cookie).\"\r\n\r\n\"For example, if there are 3 columns called Age Group, Gender, and Interest in the client\u2019s registration database that need to be imported into Salesforce DMP, then the following represents a valid data file that can be ingested by Salesforce DMP:\r\n\r\nUser1234^gender:male;age:18-24;interest:fishing\r\nUser2345^gender:female\r\nUser3456^age:35-44\r\nUser4567^gender:male;interest:fishing,boating\r\n\r\nWhen Salesforce DMP processes this file, we will create 3 attributes called Gender, Age, and Interest in the client\u2019s Salesforce DMP account. We will also automatically create the corresponding attribute values: male and female under gender and 18-24, 35-44 under age, and fishing and boating under interest.\r\n\r\nSalesforce DMP supports full-refresh.\" [Salesforce, 32](https://konsole.zendesk.com/hc/en-us/articles/214918988-First-Party-Data-Import)\r\n\r\nEvaluating matched users:\r\n\r\n\"Segment Population is the device population of this segment from the Manage Segments screen. This is a count of all devices that are part of the segment based on the segment's rules.\r\n\r\nMatchable population is the Segment Population minus those devices that cannot be matched to a partner. This includes Safari cookies, as per default Safari deleted all cookies after each page impression. A DSP Safari cookie will never show up again and thus can't be served ads to. Many DSPs also don't accept mobile identifiers (IDFA and AdID). So in those cases we also deduct them.\r\n\r\nSegment Match Rate is the percentage of users from the matchable population that we have matched the DSPs cookie against within the last 30 days. We only send these users as older users are not accepted by the DSPs.\r\n\r\nMore info on user matching can be found here:\r\nhttps://konsole.zendesk.com/hc/en-us/articles/115006072448-User-Matching-and-Match-Rates-FAQ\r\n\r\nCumulative population is the population we expect to see in DSP after all the previous considerations. In reality this can differ due to circumstances outside our control. E.g. Google only counts users that have been active in Google's universe on at least two different days for its population/forecasting. For full refresh connections the cumulative population is the population we send every day.\" [Salesforce, 48](https://konsole.zendesk.com/hc/en-us/articles/115009920168-Partner-Management-Additional-Account-Details-FAQ)\r\n\r\n**Ad Server analytics** \r\n\"Salesforce DMP's Yield Analytics reports allow you to understand and analyze audience segment delivery and yield across all ad impressions, irrespective of whether an ad was targeted to an audience segment or not. The \"raw\" ad impression delivery information is combined with the user audience segment map managed in the Salesforce DMP platform to produce these audience segment delivery and yield reports... The ad impression log file contains a record of every impression delivered, and each impression delivery record must contain the Krux User ID of the user who saw the ad. Note that it is not required for every delivery record to contain the Krux User ID; Salesforce DMP simply ignores the records that don't contain the Krux User ID, but the accuracy of the reports is directly proportional to the number of records that contain the Krux User ID\" [Salesforce, 30](https://konsole.zendesk.com/hc/en-us/articles/218445237-Ad-Server-Integration-for-Yield-Analytics).\r\n\r\n**Content Engagement Reports** \r\nReports allow site metrics like:\r\n\r\n* pageviews and unique visits for both segments and unique users; \r\n* Loyalty report cards (\" records the number of return visits per unique over a selected time period\"; will \"Monitor website engagement over time\"; and \"Highlights your total users (unique devices) per site, as well as return users to that site and the percentage of your total uniques that those return users represent\"); \r\n\r\n* Social Activity reports (\"describes all social sharing you have enabled through direct integration* with Facebook or Twitter\"; allows you to \"Build social influencer segments. These segments can be used to target users who are likely to share on social media: Capture Facebook Shares, Facebook Likes, Facebook Unlikes and Twitter Tweets\"; with features like \"Flexible date ranges\" and \"See the URLs of the top Facebook Likes and Twitter tweets; click-through to the original content\". (NOTE: \" third-party implementations, such as AddThis or ShareThis are not included.\")\r\n* Search keywords report: \"gives a list and population of referral keywords associated with inbound web traffic from top search engines including Google, Bing, and Yahoo\" so you can \"Build segments around search keywords; Identify valuable words to use for search campaigns to increase traffic to your site. This can help to identify good keywords for paid search campaigns; Capture site search terms and link them to your site as a data source\". This \"Lists the source, keyword, and population of referrals over the last thirty days, and is filterable by site and section\" and \"Site results are processed weekly, and all recorded keywords are available in the Segment Builder [Salesforce, 38](https://konsole.zendesk.com/hc/en-us/articles/115010860288-Content-Engagement-Report-FAQ)\r\n\r\n**Frequency Reports** \r\n\"Frequency Reports describe how many times what percentage of your audience has seen your ad. This allows you to assess how to improve conversion. Very high frequency is typically a sign of waste, and as such, a source of cost-saving. Very low frequency can suggest the audience isn\u2019t seeing the campaign enough to spur conversion, in which case it too is wasteful.\" The goal is to have the right amount of exposure for efficient conversions. [Salesforce, 39](https://konsole.zendesk.com/hc/en-us/articles/115010860128-Frequency-Report-FAQ)\r\n\r\n**Funnels Report** \r\n\"The Funnels report tracks the sequence of events on customers\u2019 paths to conversion and allows you to optimize accordingly. Use Funnels to understand at what stage in the conversion process users drop off, then target those users to encourage them to finish their purchase, registration, etc.\r\n\r\nBenefits:\r\n\r\n* Allows you to track individual user actions in a purchase process (or other conversion)\r\n* Monitor conversion success, perform A/B testing, and learn more about converted users with funnel reports based on events and event attributes\" [Salesforce, 40](https://konsole.zendesk.com/hc/en-us/articles/115010690407-Funnels-FAQ)\r\n\r\n**Lookalike Modeling** \r\n\"Lookalike Modeling applies an algorithm to a base audience segment and finds new people with features and characteristics similar to those in the base audience. Similarity and reach metrics will allow you to find the most useful lookalike with the highest similarity at the reach level required.\r\n\r\nBenefits:\r\n\r\n* Find prospects for acquisition campaigns\r\n* Expand reach by finding lookalikes among known users\"\r\n\r\n\"Uses 1st and 3rd party data for modelling\" [Salesforce, 41](https://konsole.zendesk.com/hc/en-us/articles/115010859928-Lookalike-Modeling-FAQ)\r\n\r\n**Audience Profile Report** \r\n\"The Audience Profile report shows demographic information about a specific campaign or segment and the segments with the greatest number of unique impressions.\"\r\n\r\nBenefits:\r\n\r\n* Learn which demographics your segments or campaigns fall into and export to share with clients or colleagues\r\n* Top overlapping segments will show how similar or unique your segments are\r\n\r\nFeatures:\r\n\r\n* The gender, age, and household income profile of your users is determined using information from third-party data providers\" [Salesforce, 44](https://konsole.zendesk.com/hc/en-us/articles/115010859168-Audience-Profile-Report-FAQ)\r\n\r\n\"Does the Loyalty report use devices or people?\r\n\r\nDevices; People are only displayed in the Segment dashboard.\" Safari users are not included because Safari doesn't allow 3rd party cookies. [Salesforce, 52](https://konsole.zendesk.com/hc/en-us/articles/115007354408-Salesforce-DMP-Reporting-FAQ)\r\n\r\n## References and External Links\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/krux-digital](https://www.crunchbase.com/organization/krux-digital)\r\n* _Salesforce, 01._ https://www.salesforce.com/blog/2017/05/krux-is-now-salesforce-dmp.html\r\n* _Salesforce, 02._ https://konsole.zendesk.com/hc/en-us/articles/115000451248-Salesforce-DMP-SDK-FAQ\r\n* _Salesforce, 03._ https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ\r\n* _Salesforce, 04._ https://konsole.zendesk.com/hc/en-us/articles/115000428307-Safari-FAQ\r\n* _Salesforce, 05._ https://secure.sfdcstatic.com/assets/pdf/misc/BCRPublicFAQ.pdf\r\n* _Salesforce, 06._ https://www.salesforce.com/company/privacy/full_privacy.jsp\r\n* _Salesforce, 07._ https://konsole.zendesk.com/hc/en-us/articles/217039187-Privacy-Policy-and-Opt-Out-Guide\r\n* _Salesforce, 08._ https://konsole.zendesk.com/hc/en-us/articles/115007222048-PII\r\n* _Salesforce, 09._ https://konsole.zendesk.com/hc/en-us/articles/115010458727-Data-Onboarding-Partners\r\n* _Salesforce, 10._ https://konsole.zendesk.com/hc/en-us/articles/227144948-Data-Collection-Partners\r\n* _Salesforce, 11._ https://konsole.zendesk.com/hc/en-us/articles/226620988-Data-Activation-Partners\r\n* _Salesforce, 12._ https://konsole.zendesk.com/hc/en-us/articles/217592967-Third-Party-Data-Marketplace\r\n* _Salesforce, 13._ https://konsole.zendesk.com/hc/en-us/articles/115012227268-Data-Sentry-Iris-Video-Tutorial\r\n* _Salesforce, 14._ https://konsole.zendesk.com/hc/en-us/articles/115010652267-Data-Sentry-IRIS-FAQ\r\n* _Salesforce, 15._ https://konsole.zendesk.com/hc/en-us/articles/115010652267-Data-Sentry-IRIS-FAQ\r\n* _Salesforce, 16._ https://konsole.zendesk.com/hc/en-us/articles/115012183888-Hashed-Device-Management\r\n* _Salesforce, 17._ https://konsole.zendesk.com/hc/en-us/articles/115010825168-Media-Tag-Generator-Video-Overview\r\n* _Salesforce, 18._ https://konsole.zendesk.com/hc/en-us/articles/115008240047-How-to-Create-Bulk-Segments\r\n* _Salesforce, 19._ https://konsole.zendesk.com/hc/en-us/articles/115007996507-Events-Overview\r\n* _Salesforce, 20._ https://konsole.zendesk.com/hc/en-us/articles/115005914227-How-to-Create-Platform-Segments-in-Salesforce-DMP\r\n* _Salesforce, 21._ https://konsole.zendesk.com/hc/en-us/articles/225407808-How-to-set-up-the-Salesforce-DMP-ControlTag-Helper\r\n* _Salesforce, 22._ https://konsole.zendesk.com/hc/en-us/articles/218941948-How-to-validate-a-Video-Ad-Unit-on-Video-Suite-Inspector-using-HTTP-Fox\r\n* _Salesforce, 23._ https://konsole.zendesk.com/hc/en-us/articles/115006072448-User-Matching-and-Match-Rates-FAQ\r\n* _Salesforce, 24._ https://konsole.zendesk.com/hc/en-us/articles/115012398067-What-if-I-just-want-to-import-data-instead-of-using-the-Control-Tag-SDK-or-other-DMP-tracking-\r\n* _Salesforce, 25._ https://konsole.zendesk.com/hc/en-us/articles/115012555408-What-does-the-Control-Tag-do-\r\n* _Salesforce, 26._ https://konsole.zendesk.com/hc/en-us/articles/115012367627-Will-the-DMP-Control-Tag-Impact-Page-Load-Performance-\r\n* _Salesforce, 27._ https://konsole.zendesk.com/hc/en-us/articles/115009397188-Cross-Device-Identity-Management-CDIM-FAQ-\r\n* _Salesforce, 28._ https://konsole.zendesk.com/hc/en-us/articles/226951307-How-to-Build-Segments-with-CDIM\r\n* _Salesforce, 29._ https://konsole.zendesk.com/hc/en-us/articles/226951307-How-to-Build-Segments-with-CDIM\r\n* _Salesforce, 30._ https://konsole.zendesk.com/hc/en-us/articles/218445237-Ad-Server-Integration-for-Yield-Analytics\r\n* _Salesforce, 31._ https://konsole.zendesk.com/hc/en-us/articles/115002783508-Data-Transfer-File-2-0-Import\r\n* _Salesforce, 32._ https://konsole.zendesk.com/hc/en-us/articles/214918988-First-Party-Data-Import\r\n* _Salesforce, 33._ https://konsole.zendesk.com/hc/en-us/articles/115012221127-Browser-Support\r\n* _Salesforce, 34._ https://konsole.zendesk.com/hc/en-us/articles/115011719688-How-Data-Costs-are-Billed\r\n* _Salesforce, 35._ https://konsole.zendesk.com/hc/en-us/articles/115011230687-How-to-verify-Hashed-Device-Management\r\n* _Salesforce, 36._ https://konsole.zendesk.com/hc/en-us/articles/115010886887-DFP-FAQ\r\n* _Salesforce, 37._ https://konsole.zendesk.com/hc/en-us/articles/115010886887-DFP-FAQ\r\n* _Salesforce, 38._ https://konsole.zendesk.com/hc/en-us/articles/115010860288-Content-Engagement-Report-FAQ\r\n* _Salesforce, 39._ https://konsole.zendesk.com/hc/en-us/articles/115010860128-Frequency-Report-FAQ\r\n* _Salesforce, 40._ https://konsole.zendesk.com/hc/en-us/articles/115010690407-Funnels-FAQ\r\n* _Salesforce, 41._ https://konsole.zendesk.com/hc/en-us/articles/115010859928-Lookalike-Modeling-FAQ\r\n* _Salesforce, 42._ https://konsole.zendesk.com/hc/en-us/articles/115010859228-Site-Distribution-Report-FAQ\r\n* _Salesforce, 43._ https://konsole.zendesk.com/hc/en-us/articles/115010859208-Segment-Overlap-Report-FAQ\r\n* _Salesforce, 44._ https://konsole.zendesk.com/hc/en-us/articles/115010859168-Audience-Profile-Report-FAQ\r\n* _Salesforce, 45._ https://konsole.zendesk.com/hc/en-us/articles/115010689407-Segment-Summary-FAQ\r\n* _Salesforce, 46._ https://konsole.zendesk.com/hc/en-us/articles/115010518787--Data-Studio-FAQ\r\n* _Salesforce, 47._ https://konsole.zendesk.com/hc/en-us/articles/115010365788-Why-are-top-segments-different-in-Audience-Profile-Reports-\r\n* _Salesforce, 48._ https://konsole.zendesk.com/hc/en-us/articles/115009920168-Partner-Management-Additional-Account-Details-FAQ\r\n* _Salesforce, 49._ https://konsole.zendesk.com/hc/en-us/articles/115009293927-Over-the-top-OTT-FAQ\r\n* _Salesforce, 50._ https://konsole.zendesk.com/hc/en-us/articles/115009151507-Media-Tagging-FAQ\r\n* _Salesforce, 51._ https://konsole.zendesk.com/hc/en-us/articles/115007393368-Data-Collection-FAQ\r\n* _Salesforce, 52._ https://konsole.zendesk.com/hc/en-us/articles/115007354408-Salesforce-DMP-Reporting-FAQ\r\n* _Salesforce, 53._ https://konsole.zendesk.com/hc/en-us/articles/115006780068-Real-time-Segment-FAQ\r\n* _Salesforce, 54._ https://konsole.zendesk.com/hc/en-us/articles/115006652948-Segment-Processing-FAQ\r\n* _Salesforce, 55._ https://konsole.zendesk.com/hc/en-us/articles/115002018607-UTM-Parameters-FAQ <-- in FP glossary only\r\n* _Salesforce, 56._ https://konsole.zendesk.com/hc/en-us/articles/115000428507-AMP-FAQ\r\n* _Salesforce, 57._ https://konsole.zendesk.com/hc/en-us/articles/115000428427-Data-Layer-FAQ\r\n* _Salesforce, 58._ https://konsole.zendesk.com/hc/en-us/articles/115000428127-Mobile-IDs-FAQ\r\n* _Salesforce, 59._ https://konsole.zendesk.com/hc/en-us/articles/236268468-Reach-Opportunities-Index-Calculation-Chart-Operations\r\n* _Salesforce, 60._ https://konsole.zendesk.com/hc/en-us/articles/227951188-Klever-UI-People-and-Devices\r\n* _Salesforce, 61._ https://konsole.zendesk.com/hc/en-us/articles/228024867-SuperTag-FAQ", "network_signature": "krxd\\.net", "creation_date": "2017-09-24", "id": 3, "website": "https://www.salesforce.com/products/marketing-cloud/data-management", "code_signature": "com.krux.androidsdk"}, "4": {"name": "Ad4Screen", "description": "## Primary Location\r\nFrance (Paris). [Crunchbase, 01](https://www.crunchbase.com/organization/ad4screen)\r\n\r\n## Website\r\n[http://www.ad4screen.com](http://www.ad4screen.com)\r\n\r\n## About\r\nAd4Screen is \"a marketing and advertising pioneer on Mobile Net (Smartphones, Tablets...)\". They help companies \"to set up performant Mobile advertising campaigns and to increase App User engagement, retention and conversion.\" [Ad4Screen, 02](http://www.ad4screen.com/en/presentation)\r\n\r\n## Ownership\r\nAd4Screen\r\n\r\n## Documentation\r\nVia Accengage [https://docs.accengage.com/display/AND/Integration](https://docs.accengage.com/display/AND/Integration)\r\n\r\n## Products and Services\r\n\r\nAd4Screen advises clients on \"the best possible strategy to limit your risks and we manage, for you, the establishment and management of your campaigns from A to Z!\" (translated from French) [Ad4Screen, 03](http://www.ad4screen.com/publicite-mobile).\r\n\r\n### Products and Services for Mobile Advertising\r\nBranding Campaign / Promote Mobile Sites / Promote Mobile Apps / Mobile RTB / Mobile Tracking / App Store Optimization / Event Driven Strategy (Drive In-Store) [Ad4Screen, 01](http://www.ad4screen.com/en), [Ad4Screen, 02](http://www.ad4screen.com/en/presentation) \r\n\r\n_Branding Campaigns:_ \"The best sites & APPS available; Many available targeting criteria\u2019s (socio-demographics\u2026); Geo-target campaigns; Thematic packages (CSP+, Media, Finance, Sports...); Innovative formats (interstial ads, rich media, videos\u2026) \r\n\r\n_Promoting Mobile Sites:_ \"Thanks to Mobile advertising key results, Ad4Screen enables you to harness the power of your brand, generate more traffic, leads (CPL) and sales on your Mobile Sites and Tablets. Often the gap between click and real visits might be significantly important. With the objective to maximize performance, Ad4Screen guarantees an effective Cost Per Visit (CPV).\" \r\n\r\nDisplay / Rich Media / Videos: \"Our Ad Hoc Experts select the best formats, supports, publishers and Ad-Exchanges in the marketplace in order to efficiently enhance the key advantages and offers of your Mobile Sites and Tablets.\" \r\n\r\nFacebook & Twitter campaigns: \"Our teams are Experts in setting up specific mobile campaigns on Facebook and Twitter. Share high visibility and drive a Performance Business Model forward! Many available targeting criteria specific for Mobile and for each specific plateform. Ensure an Ongoing Performance\" \r\n\r\n_Promote Mobile Apps:_ \"Thanks to Mobile advertising, Ad4Screen helps you to enhance your brand reputation, gain in-depth visibility and increase your volume of APP downloads. Ad4Screen\u2019s specific business goal lies on the guarantee to capture a growing share of Cost Per Download (CPD).\" Display / Videos: \"Our Experts select the market\u2019s best set of formats, supports and well known players in the market in order to empower your Mobile APP or Tablet, whether iOS or Android. \r\n \r\n * Traditional formats: banners, interstitials\r\n * Banners, interstitials HTML5 \r\n * Interstitials videos \r\n * Pre-roll videos \r\n * Geolocalisation \r\n * Native Formats (referring to Facebook, Viadeo, Twitter). \r\n\r\nFacebook & Twitter App install campaigns: \"Our teams are Experts on monitoring Facebook and Twitter campaigns on Mobile. (Mobile Ad Formats exclusively designed to install; Share high exposure and drive a Performance Model forward; Many targeting & optimization criteria; Possibility to track APP installs). Search: \"All Queries made on Google from Smartphones and Tablets are explode! It is today\u2019s business imperative to benefit from Search Query Data to obtain high quality users. Our Operations Team is in charge of your Mobile Adwords campaigns from beginning to end. \r\n\r\n * Buy with CPC \r\n * Double Click Download \r\n * Track In-APP conversion with keywords \r\n\r\n_Mobile RTB Insights:_ \"Our Media Buying & Planning team uses the best next generation Mobile technologies (DSP) in order to program Mobile RTB campaigns. We work with the main 100% Mobile Ad-Exchanges in the market (MoPub, Flurry, Smaato, La Place M\u00e9dia\u2026). \r\n\r\n * Gain wide access to apps ad inventory (80% ad impressions & non available on Web AdEx) \r\n * Use conversion tracking to see in-app activity \r\n * Leverage intelligent algorithms in real time based on in-app conversion \r\n * Communicating to the best with digital savvy shoppers \r\n * Identify your look-alike best prospects \r\n * Invite your Mobile Site Visitors to download your APP\") \r\n\r\n_Mobile Tracking:_ \"Our main concern is to accurately follow conversion on mobile acquisition campaigns to overall revenue. Our ad hoc experts group has the know-how for the best acquisitions and tracking plateforms in the right private marketplaces. \r\n\r\n * Track where your users come from (lever, design, adWord...) \r\n * Analyse and compare specific conversion rates per sources, operating systems, countries, segments\u2026 \r\n * Track how your users interact with your app \r\n * Improve overall ROI by our Experts \r\n\r\n_App Store Optimization:_ \"Benefit from our Trends Report to optimize your organic SEO on App Store.\" \r\n\r\n * Optimize your ranking on Google Play and iTunes \r\n * Improve your APP Ranking in your own category \r\n * Create strong viral effects (Earned media) \r\n * Generate an increase on your organic installs from 10% to 40% per day!\" \r\n\r\n_Event Driven Strategy:_ \"For today\u2019s consumer, Mobile has become the ultimate Digital Shopping Tool. Ad4Screen Operations Team helps you generate more Drive In-Store traffic and positively impact on sales conversion.\r\nWe use the most pertinent Marketing Drive In-Store Tools: \r\n\r\n * Mobile Retargeting\r\n * Push Notification\r\n * GeoTargeted Mobile Advertising\r\n * iBeacon, Geofencing, QR Code...\r\n\r\nAd4Screen implements contest specific rules:\r\n\r\n * Instant Win Games\r\n * Sweepstake\r\n * In-APP & Mobile Web animations [Ad4Screen, 05](http://www.ad4screen.com/en/mobile-advertising)\r\n\r\n### Products and Services for Mobile CRM\r\nPush Notifications / Customer Loyalty Programs (Relationship Programs) / Mobile Retargeting / Email Responsive (Responsive Email Templates) / Mobile Couponing (Mobile Email Tag) / Passbook [Ad4Screen, 01](http://www.ad4screen.com/en), [Ad4Screen, 02](http://www.ad4screen.com/en/presentation)\r\n\r\n_Support:_ Sales Team / Advisory Board / Mobile CRM Experts / Media Buying & Planning / IT Team / Data Mining Team / Support Team \r\n\r\n_Sales Team:_ \"We analyze with you all your requirements and needs to create adapted and breakthrough projects maximizing your ROI.\" \r\n\r\n_Advisory Board:_ \"The Advisory Services Team covers App Store SEO, ROI Optimization, International Acquisition Campaigns Management\u2026\" \r\n\r\n_Mobile CRM Experts:_ \"Our team of experts will support you with setting up Customer Loyalty Programs.\" \r\n\r\n_Media Buying & Planning_: \"We will identify the best traffic sources, getting the best price (CPC, CPL, CPV, CPD...).\" \r\n\r\n_IT Team:_ \"We choose next generation Mobile Marketing technologies, at the cutting-edge of innovation.\" \r\n\r\n_Data Mining Team:_ \"We manage the extraction, integration and analysis of large volumes of DATA to optimize your targeting.\" \r\n\r\n_Support Team:_ \"We are here to help you planning, implementing SDK, training, preserving, updating...\" [Ad4Screen, 02](http://www.ad4screen.com/en/presentation) \r\n\r\n* (translated from French:) \"Our Experts select the best formats, supports, boards and Ad-Exchanges of the market to effectively highlight the benefits and offers of your mobile site and / or tablet.\" [Ad4Screen, 03](http://www.ad4screen.com/publicite-mobile)\r\n\r\nAd4Screen also helps clients set up trigger marketing campaigns [Ad4Screen, 01](http://www.ad4screen.com/en).\r\n\r\n## Privacy Policy\r\nAd4Screen does not appear to list a privacy policy for End Users; see [Ad4Screen, 07](http://www.ad4screen.com/en/privacy-police).\r\n\r\n## Relationships\r\nAdd4Screen lists 200 customers and 5,000 mobile campaigns [Ad4Screen, 02](http://www.ad4screen.com/en/presentation)\r\n\r\n_\"They Trust Us\":_ Betclic / Bouyges Telecom / Europcar / SFR / numericable / ebookers / La Tribune / Le Figaro / Universal Music / Axa / Airfrance KLM / Danone / Saxo Banque / Capcom / Cadremploi.fr / nexity / pole emploi / Rocket Internet / Cond\u00e9 Nast / Nestle / vente-privee.com / Pages Jaunes / Groupe Casino / Voyages-sncf.com / The Walt Disney Company / Price Minister (Rakuten Group) / Club Med / Century 21 / TF1 / Monoprix / keljob.com / kobojo / Explorimmo / easyflirt / Le Monde / LA Tribune / La Redoute / Malakoff-M\u00e9d\u00e9ric / Le PointNathan / Radio France / Orange S.A. (ex France T\u00e9l\u00e9com S.A.) / P\u00f4le emploi (government agency for unemployed) [Ad4Screen, 02](http://www.ad4screen.com/en/presentation), [Ad4Screen, 05](http://www.ad4screen.com/en/mobile-advertising) OTC Agregator [Ad4Screen, 01](http://www.ad4screen.com/en), [Ad4Screen, 04](http://www.ad4screen.com/en/nos-references) \r\n\r\n_Mobile First Alliance:_ In 2014, Ad4Screen \"split its activities into two separate and independent companies\", Accengage and Ad4Screen. Accengage offers a Mobile CRM technology while Ad4Screen specializes in \"mobile media buying and mobile relationship marketing consulting\". The Mobile First Alliance was formed thereafter, composed of three companies: Accengage, Ad4Screen, and Relatia. (Quotes are translated from French.) [Marketing web mobile, 01](http://marketing-webmobile.fr/2014/09/ad4screen-separe-ses-activites-dediteur-de-logiciels-de-mobile-crm-et-dagence-de-publicite-mobile).\r\n\r\n## Details\r\n_Financial details:_ Ad4Screen was founded in 2010 and has raised $10 million [Ad4Screen, 02](http://www.ad4screen.com/en/presentation); [Crunchbase, 01](https://www.crunchbase.com/organization/ad4screen). They were crowdfunded by OTC Agregator, a big French Insurance Company (MMA) and Web contractors (Business Interactive Founders as WCube, Betclic, Boncoin or Poweo) [Ad4Screen, 02](http://www.ad4screen.com/en/presentation).\r\n\r\n_Devices:_ Mobile and tablet media; iOS and Android [Ad4Screen, 03](http://www.ad4screen.com/publicite-mobile); works with iBeacons [Ad4Screen, 07](http://www.ad4screen.com/ibeacon).\r\n\r\n### Methods\r\nRetargeting / Push Notifications / GeoTargeted Mobile Advertising / iBeacon, Geofencing, QR Code / Mobile tracking (including across apps) / Conversion tracking (including intelligent algorithms for in-app conversion) \r\n\r\n_Mobile Push Notification & In-app Message:_ \"Do you have a smartphone app? Benefit from push notification, the new and efficient communication channel to interact with your app visitors. Communicate in real time, by sending the right message, to the right person, at the right time toward the right place inside the app. Our CRM Mobile Experts help you build customer loyalty programs in order to create more proximity and engagement with your app users.\" \r\n\r\n_Customer Loyalty Programs:_ \"Ad4Screen enables you to set up a True Value added customer loyalty programs with your savvy shoppers to dialog with them at each touchpoint of their life cycle. \r\n\r\n * Set up trigger marketing scenarios (send fully automated follow-ups according to mobile user behavior)\" \r\n * Display a welcome message at first open \r\n * Send out alerq messages tbox messages in an application\u2019s life-cycle (last update, error messages, news feed\u2026) \r\n * Send out good deals to capture a growing share of revenue \r\n * Reactive abandoned shopping carts \r\n\r\n_Mobile Retargeting:_ \"2 retargeting methods roll into action to retarget your digital device users: \r\n\r\n * From opt-in to push notification, mobile users are identified by Ad4Screen as having abandoned their shopping cart and reminded via customized push notifications \r\n * No opt-in to push are retargeted in a display mode through targeted customized banners and interstitials \r\n\r\n_Responsive Email:_ \"Ad4Screen delivers a Customer Seamless Experience to read your newsletter on Smartphone by displaying the email according to the device used by the user. \r\n\r\nNet benefits with responsive email: \r\n\r\n * Email designed according to the screen size of the device \r\n * Make it easier to read and interact with your current and prospective customers \r\n * Optimize Click-Through-Rates (Click-to-Open Rates, Click Conversation Rates) \r\n * Yield a significant ROI \r\n\r\n_Mobile Email Tag:_ \"Discover belong your subscribers who read your newsletters from a smartphone and display them in real time a bespoke banner offering to download your app. \r\n\r\nNet benefits with Mobile Email Tag: \r\n\r\n * Redefine smartphone users to individual profile \r\n * Complete mobile user\u2019s status \r\n * Enrich profiles according to the device used \r\n * Drive more traffic and generate high quality installs! \r\n\r\n_Passbook:_ \"Thanks to Ad4Screen, discover Passbook and boost your in-store traffic. The application is able to stock reward cards, ad spend coupons and other tickets. With Passbook you can:\r\n\r\n * Dematerialize your loyalty reward cards, ad spend coupons, tickets\u2026 without the need to develop an app dedicate for it \r\n * Generate in-store traffic by sending a relevant message or a push based on user\u2019s location \r\n * Plan specific events and remind them the last discount day \r\n * Recommend to install your iPhone app [Ad4Screen, 06](http://www.ad4screen.com/en/push-notifications)\r\n\r\n## References\r\n* Ad4Screen, 01. [http://www.ad4screen.com/en](http://www.ad4screen.com/en) \r\n* Ad4Screen, 02. [http://www.ad4screen.com/en/presentation](http://www.ad4screen.com/en/presentation) \r\n* Ad4Screen, 03. [http://www.ad4screen.com/publicite-mobile](http://www.ad4screen.com/publicite-mobile) \r\n* Ad4Screen, 04. [http://www.ad4screen.com/en/nos-references](http://www.ad4screen.com/en/nos-references) \r\n* Ad4Screen, 05. [http://www.ad4screen.com/en/mobile-advertising](http://www.ad4screen.com/en/mobile-advertising) \r\n* Ad4Screen, 06. [http://www.ad4screen.com/en/push-notifications](http://www.ad4screen.com/en/push-notifications) \r\n* Ad4Screen, 07. [http://www.ad4screen.com/ibeacon](http://www.ad4screen.com/ibeacon)\r\n* Crunchbase, 01. [https://www.crunchbase.com/organization/ad4screen](https://www.crunchbase.com/organization/ad4screen) \r\n* Marketing Web Mobile, 01. [http://marketing-webmobile.fr/2014/09/ad4screen-separe-ses-activites-dediteur-de-logiciels-de-mobile-crm-et-dagence-de-publicite-mobile](http://marketing-webmobile.fr/2014/09/ad4screen-separe-ses-activites-dediteur-de-logiciels-de-mobile-crm-et-dagence-de-publicite-mobile)\r\n\r\n## External links\r\n* _Crunchbase (Ad4Screen)_: [https://www.crunchbase.com/organization/ad4screen](https://www.crunchbase.com/organization/ad4screen) \r\n* _AppBrain_: [https://www.appbrain.com/dev/AD4Screen/](https://archive.is/SgBjU)", "network_signature": "a4\\.tl|accengage\\.com|ad4screen\\.com|ad4push\\.com", "creation_date": "2017-09-24", "id": 4, "website": "http://www.ad4screen.com", "code_signature": "com.ad4screen.sdk"}, "5": {"name": "Google DoubleClick", "description": "## Primary Location\r\nUnited States (New York City) [Crunchbase, 01](https://www.crunchbase.com/organization/doubleclick)\r\n\r\n## Website\r\n[https://www.doubleclickbygoogle.com](https://www.doubleclickbygoogle.com)\r\n\r\n## About\r\nDoubleClick offers products and services to publishers and advertisers. Publishers use DoubleClick to display advertisements, and advertisers use DoubleClick to control the displaying of their ads by publishers.\r\n\r\n## Ownership\r\nGoogle\r\n\r\n## Documentation\r\n[https://developers.google.com/doubleclick-publishers/docs/start](https://developers.google.com/doubleclick-publishers/docs/start)\r\n\r\n## Products and Services\r\n\r\n### Identification and Analytics\r\n* Through DoubleClick Campaign Manager (DCM), Google uses mobile device IDs to attribute conversions to mobile devices [DoubleClick, 07](https://developers.google.com/doubleclick-advertisers/guides/conversions_overview#using_mobile_device_id).\r\n* DoubleClick segments audiences for targeted advertising [The Guardian, 01](https://www.theguardian.com/technology/2012/apr/23/doubleclick-tracking-trackers-cookies-web-monitoring).\r\n* Google performs cross-device identification (via Google Attribution) [Search Engine Land, 01](https://searchengineland.com/google-attribution-search-marketers-need-know-275751); [DoubleClick, 01](https://www.doubleclickbygoogle.com/articles/google-debuts-new-ad-attribution-service); [Forbes, 01](https://www.forbes.com/sites/roberthof/2017/05/23/did-that-ad-work-google-debuts-new-ai-driven-ad-attribution-service).\r\n* Google connects data to personally identifiable information [ProPublica, 01](https://www.propublica.org/article/google-has-quietly-dropped-ban-on-personally-identifiable-web-tracking).\r\n* DoubleClick offers analytics services for revenue management [DoubleClick, 05](https://www.doubleclickbygoogle.com/solutions/revenue-management/ad-exchange); [DoubleClick, 06](https://support.google.com/dcm/partner/answer/4568975?hl=en); [Online-behavior.com, 01](http://online-behavior.com/analytics/dfp-audience)\r\n\r\n### Store visit tracking\r\nThrough AdWords, Google offers insights on store-visit conversions: \"In DoubleClick Search, you can report on store visit conversions by adding a custom AdWords store visit conversions column to a report\" [Google, 01](https://support.google.com/ds/answer/6348835?hl=en).\r\n\r\n### Advertising Methods\r\n* DoubleClick loads targeted advertisements [Google, 03](https://support.google.com/dfp_premium/answer/2884033?hl=en); [Google, 05, PDF](http://services.google.com/fh/files/misc/case-study-accuweather-delivers-enhanced-value-to-advertisers-with-doubleclick-for-publishers-and-google-analytics-360.pdf); [The Guardian, 01](https://www.theguardian.com/technology/2012/apr/23/doubleclick-tracking-trackers-cookies-web-monitoring).\r\n* Google Attribution integrates information from several Google ad services, including DoubleClick, to evaluate the effectiveness of ads, from search to store visits [Forbes, 01](https://www.forbes.com/sites/roberthof/2017/05/23/did-that-ad-work-google-debuts-new-ai-driven-ad-attribution-service); [Google, 04](https://support.google.com/richmedia/answer/3399874?hl=en)\r\n* Google is using offline and online data sources to conduct real-world location targeting [Google, 01](https://support.google.com/ds/answer/6348835?hl=en); [Google, 02](https://support.google.com/adwords/answer/6100636?co=ADWORDS.IsAWNCustomer%3Dfalse&hl=en-GB); [TechCrunch, 02](https://techcrunch.com/2017/05/23/google-is-now-using-deep-learning-to-measure-store-visits); [DoubleClick, 02](https://support.google.com/adxseller/answer/6016023?hl=en)\r\n* Google conducts real-time targeting [DoubleClick, 04](https://www.doubleclickbygoogle.com/articles/bt-sport-dynamic-ad-insertion-google)\r\n* Google uses artificial intelligence (via Google Attribution) [Forbes, 01](https://www.forbes.com/sites/roberthof/2017/05/23/did-that-ad-work-google-debuts-new-ai-driven-ad-attribution-service); [TechCrunch, 01](https://techcrunch.com/2017/05/23/google-attribution-is-a-free-and-easy-way-to-evaluate-marketing-efforts); [TechCrunch, 02](https://techcrunch.com/2017/05/23/google-is-now-using-deep-learning-to-measure-store-visits)\r\n* Google targets across devices and channels [Forbes, 01](https://www.forbes.com/sites/roberthof/2017/05/23/did-that-ad-work-google-debuts-new-ai-driven-ad-attribution-service)\r\n* DoubleClick provids bidding services [DoubleClick, 05](https://www.doubleclickbygoogle.com/solutions/revenue-management/ad-exchange)\r\n\r\n### Advertising Networks\r\n* Google conducts data sharing and integration [DoubleClick, 05](https://www.doubleclickbygoogle.com/solutions/revenue-management/ad-exchange); [The Guardian, 01](https://www.theguardian.com/technology/2012/apr/23/doubleclick-tracking-trackers-cookies-web-monitoring); [DoubleClick, 03](https://support.google.com/dfp_premium/answer/6281539?hl=en); [AppsFlyer, 01](https://support.appsflyer.com/hc/en-us/articles/115003213726-DoubleClick-Integration-Guide)\r\n\r\n## Privacy Policy\r\nA Google search for \"DoubleClick Privacy Policy\" brings the user to the general Google privacy policy web page.\r\n\r\n_Cookies:_ Google's privacy policy states that Google uses cookies in web broswers for targeted advertising. They also store a record of the ads they serve in their logs. Log data includes \"your web request, IP address, browser type, browser language, the date and time of your request, and one or more cookies that may uniquely identify your browser.\" They anonymize the log data by \"removing part of the IP address (after 9 months) and cookie information (after 18 months)\". Google services, such as AdWords, AdSense, and a range of DoubleClick-branded services, may send cookies to your bro]]wser when you visit a page or see an ad that uses one of these services. \r\n\r\n_Other technologies:_ Google may \"select advertising based on information about your computer or device, such as your device model, browser type, or sensors in your device like the accelerometer.\" \r\n\r\n_Location:_ Google may infer your location \"from a variety of sources\", including your IP address, search queries, as well as you \"precise location from your mobile device\" and \"websites or apps that you use may send information about your location\" to Google. Google \"uses location information in our ads products to infer demographic information, to improve the relevance of the ads you see, to measure ad performance and to report aggregate statistics to advertiser.\" \r\n\r\n_Mobile tracking:_ When cookies are not available (eg, in mobile devices), Google \"may use technologies that perform similar functions to cookies. Sometimes Google links the identifier used for advertising on mobile applications to an advertising cookie on the same device in order to coordinate ads across your mobile apps and mobile browser. This can happen, for example, when you see an ad within an app that launches a web page in your mobile browser. This also helps us improve the reports we give to our advertisers on the effectiveness of their campaigns.\"\r\n\r\n_Opt-out and user control:_ Users can control cookie tracking through Google Ad Settings, consumer choice tools created under self-regulation programs in many countries, and through the management of cookies in web browser settings. Users can opt out of personalized ads in apps through Android and iOS device settings [Google, 06](https://www.google.com/policies/technologies/ads).\r\n\r\n## Details\r\nDoubleClick was founded in 1995 [Crunchbase, 01](https://www.crunchbase.com/organization/doubleclick).\r\n\r\n## References\r\n* _AppsFlyer, 01._ https://support.appsflyer.com/hc/en-us/articles/115003213726-DoubleClick-Integration-Guide \r\n* _Crunchbase, 01._ https://www.crunchbase.com/organization/doubleclick\r\n* _DoubleClick, 01._ https://www.doubleclickbygoogle.com/articles/google-debuts-new-ad-attribution-service \r\n* _DoubleClick, 02._ https://support.google.com/adxseller/answer/6016023?hl=en \r\n* _DoubleClick, 03._ https://support.google.com/dfp_premium/answer/6281539?hl=en \r\n* _DoubleClick, 04._ https://www.doubleclickbygoogle.com/articles/bt-sport-dynamic-ad-insertion-google \r\n* _DoubleClick, 05._ https://www.doubleclickbygoogle.com/solutions/revenue-management/ad-exchange \r\n* _DoubleClick, 06._ https://support.google.com/dcm/partner/answer/4568975?hl=en \r\n* _DoubleClick, 07._ https://developers.google.com/doubleclick-advertisers/guides/conversions_overview#using_mobile_device_id \r\n* _Forbes, 01._ https://www.forbes.com/sites/roberthof/2017/05/23/did-that-ad-work-google-debuts-new-ai-driven-ad-attribution-service \r\n* _Google, 01._ https://support.google.com/ds/answer/6348835?hl=en \r\n* _Google, 02._ https://support.google.com/adwords/answer/6100636?co=ADWORDS.IsAWNCustomer%3Dfalse&hl=en-GB\r\n* _Google, 03._ https://support.google.com/dfp_premium/answer/2884033?hl=en\r\n* _Google, 04._ https://support.google.com/richmedia/answer/3399874?hl=en \r\n* _Google, 05, PDF._ http://services.google.com/fh/files/misc/case-study-accuweather-delivers-enhanced-value-to-advertisers-with-doubleclick-for-publishers-and-google-analytics-360.pdf\r\n* _Google, 06._ https://www.google.com/policies/technologies/ads\r\n* _Online-behavior.com, 01._ http://online-behavior.com/analytics/dfp-audience \r\n* _ProPublica, 01._ https://www.propublica.org/article/google-has-quietly-dropped-ban-on-personally-identifiable-web-tracking \r\n* _Search Engine Land, 01._ https://searchengineland.com/google-attribution-search-marketers-need-know-275751 \r\n* _TechCrunch, 01._ https://techcrunch.com/2017/05/23/google-attribution-is-a-free-and-easy-way-to-evaluate-marketing-efforts \r\n* _TechCrunch, 02._ https://techcrunch.com/2017/05/23/google-is-now-using-deep-learning-to-measure-store-visits \r\n\r\n## External links\r\n* _Crunchbase (DoubleClick):_ [https://www.crunchbase.com/organization/doubleclick](https://www.crunchbase.com/organization/doubleclick)\r\n* _Wikpedia (DoubleClick):_ [https://en.wikipedia.org/wiki/DoubleClick](https://en.wikipedia.org/wiki/DoubleClick)\r\n* _Ghostery (DoubleClick:_ [https://apps.ghostery.com/apps/doubleclick](https://apps.ghostery.com/apps/doubleclick)", "network_signature": "mng-ads\\.com|doubleclick\\.net|doubleclick\\.com|2mdn\\.net|dmtry\\.com", "creation_date": "2017-09-24", "id": 5, "website": "https://www.doubleclickbygoogle.com/", "code_signature": "com.google.android.gms.ads.doubleclick"}, "6": {"name": "Weborama", "description": "## Primary Location\r\nFrance (Paris)\r\n\r\n## About\r\nWeborama \"collect, organise, stock, transform and operate data within the advertising ecosystem, thanks to a 400 million profiles database\" [Weborama, 02](https://www.weborama.com/data/presentation); [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf). They provide ad analytics and behavioral targeting services [Crunchbase, 01](https://www.crunchbase.com/organization/weborama).\r\n\r\n## Ownership\r\nWeborama\r\n\r\n## Documentation\r\n[https://be-interactive.atlassian.net/wiki/spaces/SDK/pages/5931037/Integration+with+DFP](https://be-interactive.atlassian.net/wiki/spaces/SDK/pages/5931037/Integration+with+DFP)\r\n\r\n## Products and Services\r\nWeborama \"specializes in creating and delivering targeted online ads. Weborama identifies the content, services and products that are most likely to match the interest of specific user groups according to their browsing history\" [Weborama, 07](https://www.weborama.com/e-privacy/our-commitment).\r\n\r\nWeborama features an audience-driven advertising platform:\r\n\r\n\"The Weborama platform enables advertisers to create audience segments from Media, Site and/or CRM data. These segments can be enhanced using 3rd party data. Advertisers can use these segments to buy ad space and target their campaigns. The Weborama platform analyses the performance of these campaigns and audiences and optimises them in real time\" [Weborama, 02](https://www.weborama.com/data/presentation). \r\n\r\n\"Weborama has been developing solutions in adserving, data Management Platform (DMP), audience analysis, data segmentation and target segments for 15 years\" [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf). \r\n\r\n_Weborama Audience Manager:_ A Data Management Platform; it is a \"data management platform for segmentation of different sources of 1st party (CRM, media and website) data, enriched by 3rd party data using access to data owned by Weborama.\"\r\n\r\n_Weborama Audience Insight:_ A \"tool for analysing audience behavior on internet sites\" \r\n\r\n_Weborama Campaign Manager:_ \"adserving tool for management and optimisation of advertising campaigns\" \r\n\r\n_Weborama Advanced Rich Media:_ A \"tool for managing rich media/video campaigns\" \r\n\r\n_Weborama Audience Exchange:_ A \" premium multi-device audience platform, on two channels (WaX for agency, WaX for trading desk). Classic formats, rich media and in stream\" \r\n\r\nWeborama offers audience analysis and a targeted marketing proposal for publishers [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf).\r\n\r\n## Privacy Policy\r\n\r\nWeborama's website privacy policy was last updated in 2014 and does not mention mobile.\r\n\r\n_Opt out procedure:_ \"Users can choose to opt out of Weborama\u2019s anonymous data collection program. Once users opt out, Weborama does not collect navigation data or create marketing profiles anymore. Opting out does not prevent users from receiving online ads delivered by Weborama, but these ads are delivered randomly. They are not targeted to a user\u2019s modelled interest or demographics, are not delivered in sequence or delivered according to any previous advertising interaction. When users opt out, Weborama stores a specific cookie on their browser. Weborama\u2019s opt-out cookie has to be downloaded on each computer and each browser used by users. If cookies are disabled, erased, or altered, and if browsers or operating systems are modified or upgraded, the opt-out process might need to be performed again.\" [Weborama, 07](https://www.weborama.com/e-privacy/our-commitment)\r\n\r\n_Opting out:_ \"In accordance with current legislation, internet users can unsubscribe at any moment from Weborama\u2019s data collection programme, either by using the opt-out on the group\u2019s website, or via the icon Ad Choices, which can be found on all targeted advertising, and returning it via website YourOnlineChoices at IAB Europe.\" [\r\n\r\n_Personally identifiable information:_ Weborama \"does not collect personally identifiable information (PII) such as name, email address or phone number. Weborama does not profile users according to their political, philosophical, sexual or religious preferences, ethnic or racial origins, trade union membership or health condition.\r\n\r\n_Segmenting and age:_ Weborama does not intentionally profile or target sensitive audience segments such as children under the age of 13 or any other segments considered sensitive by IAB Europe\u2019s Self-regulation Online Behavioural Advertising (OBA) Framework.*\"\r\n\r\n_Data Usage and Security:_ \"Navigation data is used by Weborama to build users\u2019 marketing profiles. These profiles are used to deliver, target and/or analyse online marketing campaigns. These actions are conducted by Weborama on behalf of its clients, or by business partners with whom Weborama synchronises anonymous user profiles. Measures have been implemented to protect information from unauthorized or unlawful access, use or disclosure, and against accidental loss, damage or destruction. Access to data is restricted to authorized individuals. Weborama is a member of the Internet Advertising Bureau (IAB) and complies with all applicable laws and regulations as well as with IAB principles as described in the Online Behavioural Advertising (OBA) Framework.\"\r\n\r\n_Privacy Policy last updated:_ Weborama was last updated 16th of October 2014\" [Weborama, 07](https://www.weborama.com/e-privacy/our-commitment)\r\n\r\n## Relationships\r\n\"Over 300 clients use Weborama\u2019s innovative solutions to drive and optimise their online investments in France, Spain, Italy, Portugal, Holland, UK and Russia\" [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf).\r\n\r\nOdnoklassniki (the first Russian social network) / Move Publishing [Weborama, 01](https://www.weborama.com) / EDF / MAIF / Pernod Ricard / Medela / Endesa / Findus / Yeppon / Moschin [Weborama, 06](https://www.weborama.com/documents/2017/09/weborama-growth-of-the-operating-profit-in-the-first-half-of-2017.pdf)\r\n\r\n## Details\r\n_Financial details:_ Weborama was founded in 1998 (listed on Alternext since June 2006 as ALWEB) [Weborama, 02](https://www.weborama.com/data/presentation); it had a market capitalization of \u20ac28 million as of 2015 [Wikipedia, 01](https://fr.wikipedia.org/wiki/Weborama](https://fr.wikipedia.org/wiki/Weborama). Weborama recorded revenues of 24.3 million Euros in 2012 [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf); revenues \"reached \u20ac29 million in 2016\" [Weborama, 05](https://www.weborama.com/infos-financieres/financial-figures). Operating income was up in early 2017. A recently signed international agreement with \"a leading media/marketing player...will especially enable Weborama to grow its presence in the United States.\" [Weborama, 06](https://www.weborama.com/documents/2017/09/weborama-growth-of-the-operating-profit-in-the-first-half-of-2017.pdf)\r\n\r\n_Growth:_ Weborama had 110 million profiles in 2013; this suggests a growth of 300 million profiles in just 4 years [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf); [Weborama, 07](https://www.weborama.com/e-privacy/our-commitment)\r\n\r\n_Devices:_ Web browsers / Trackers in mobile apps\r\n\r\n### Methods\r\n_Data assets:_ Weborama has \"400 million profiles in the European database\" and \"More than 200 socio-demo, behavioural and intenders criteria\". This is used for \"data solutions\" for advertisers; the Audience Manager gives \"an exclusive and native access to 400 million profiles in Europe\" with a \"360\u00b0 view of behavioural and socio-demographic data\". Audience Insight \"allows viewing the audience structure by age, gender and occupation, along with the distribution of behavioural segments and clusters\", which \"helps publishers to drill down into their audience profile in real time, and thereby to maximise its monetisation\" [Weborama, 04](https://www.weborama.com/data/the-offering).\r\n\r\nWeborama tags placed on a publisher's website allows them to \"collect raw and anonymous navigation data\". They conduct \"Audience analysis, followed by a relevant and targeted marketing proposal\" to be \"conducted within three weeks from the date Weborama tags\" the website [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf)\r\n\r\nWeborama \"collects anonymous user navigation data via a network of several thousands of partner websites. These websites make it possible for Weborama to store cookies on users\u2019 browsers to allow for their anonymous identification and tracking over the Internet. Navigation data collected by Weborama only includes non-personally identifiable information (NPII) such as URL pages, software equipment, keywords used for searching, geographic location (at state or city level), and advertising interaction history\" [Weborama, 07](https://www.weborama.com/e-privacy/our-commitment).\r\n\r\n_Location targeting:_ \"Generate qualified traffic in store thanks geolocation\" [Weborama, 02](https://www.weborama.com/2017/09/retail-which-dmps-use-cases) \r\n\r\n_Big Data:_ \"Data is at the heart of its expertise, thanks to its strategists, data consultants, computer linguists, statisticians, mathematicians and developers. Big Data is the driver of development today at Weborama, and will continue to be in the future. Great cares are taken to collect data anonymously, internet user benefits from more relevant advertising.\" [Weborama, 02](https://www.weborama.com/data/presentation)\r\n\r\n_Semantic processing: Cookies, segmenting, & survey:_ \"the data is sourced anonymously from 300,000 sites, using cookies, then processed instantly. this audience classification is a critical process within each database. thanks to this methodology Weborama has a database of 110 million profiles of behavioural, socio-demographic, and purchasing intent data in Europe, 70 million of which are from France. Today, Weborama has identified almost 200 clusters (centres of interest) based on the behaviour of internet users, divided into 23 segments (a segment being a \u201cfamily\u201d of clusters). Weborama\u2019s socio-demographic database is built from a sample group of 300,000 active internet users in France who responded willingly to a questionnaire giving their age, gender and socio-professional category. by cross-referencing behavioural clusters with Weborama\u2019s socio-demographic sample group, the sample group data are extrapolated from the database as a whole\" [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf).\r\n\r\n_Patented technologies based on algorithms and the automatic processing of language:_ 33 million active URLs; 300,000 sites analysed each day; 110 million active profiles per month; 3.5 million qualified internet users per day; 25 words per day per internet user.\" [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf) \r\n\r\n_Knowledge: 3rd party & 1st party data:_ The Weborama 3rd party database enriches 1st party data. 3rd party data is \"Data from a third party which do not belong to the advertiser or publisher, but are made available to them for deployment in online marketing\", whereas 1st party data is \"Data belonging to an advertiser or publisher.\"\r\n\r\n_Audience Segmentation & Targeted Advertising:_ With big data collections, Weborama can identify \"look-alikes\" of internet users with a similar profile to those who \"transform\" (\"subscriptions to products offered in the campaign\"). \"This allows them to be offered advertising which is personalised to fit their profile\". Audience segmentation in media campaigns was introducted by an advertiser in 2012; the advertiser was looking to increase the level of transformation while reducing loss of media investments, and called upon Weborama to build a mechanism for its commercial catalogue. Weborama creates a database, including from data collected by advertisers, and builds a targeted advertising model, which includes a model training phase and A/B testing. \r\n\r\nData mining is conducted as follows: \"this database is then enriched with socio-demographic and behavioural criteria for internet users whose profile is known to Weborama, thanks to their database of 70 million qualified profiles in France. this data is cross referenced with the data coming from Weborama Campaign Manager. this anonymous information is accessible as a whole using the internet user identifier (a series of characters for each individual contained in the cookies deposited in the internet explorer). this unique identifier allows Weborama to find the complete profile of the internet user in their database, in real time.\" Search and surf data is used; Weborama then views transactions over weeks, and observes outcomes from users in the database which includes 60 million qualified profiles over approximatley 300 columns, including ads viewed, reactions (visit, click), behavior on the website visited, and socio-demographic and behavioral profile. \r\n\r\nTraining the model is conducted as follows: From the database, build graphic representation and create permanent tree segments. The criteria most relevant to each product or service can be extracted, where the criteria is based on transformation of the internet users exposed to ad campaigns and impressions.\r\n\r\nWeborama's database \"is then enriched with socio-demographic and behavioural criteria for internet users whose profile is known to Weborama, thanks to their database of 70 million qualified profiles in France. this data is cross-referenced with the data coming from Weborama Campaign Manager. this anonymous information is accessible as a whole using the internet user identifier (a series of characters for each individual contained in the cookies deposited in the internet explorer). this unique identifier allows Weborama to find the complete profile of the internet user in their database, in real time.\" \r\n\r\nWeborama runs A/B testing to determine if the model is working, based on confidence intervals. Variation can occur for many reasons, such as a calendar event or a holiday. \r\n\r\n_Segmentation for publishers:_ \"Above all, the aim of publishers is to organise their commercial products so that they can offer advertisers and agencies, in addition to the contextual menu, packs of targeted audiences, enriched by 3rd party data. the second challenge is to build specific audience packs using ad hoc target segments based on both socio-demographic and behavioural targeting (taking account of the internet users\u2019 different areas of interest). \"Segmentation of a site\u2019s audience allows visitor profiles \r\nfrom other areas of interest to be seen. It is highly probable that a current affairs site has, among its audience, people who enjoy other sites (finance, beauty, fashion, cookery, travel...). this will offer the publishers the possibility of assessing their content quality, as well as that of their audience, while expanding their client base. \" \r\n\r\n_Two methods of data enrichment from publishers:_ The first method \"includes the synchronisation and propagation of Weborama\u2019s socio-demographic criteria and behavioural clusters on the publisher\u2019s site audience. this is possible by identifying profiles recognised within the site\u2019s audience, which are already part of the Weborama database. In this particular case, the adserver of the publisher calls the Weborama database for each internet user. If the Weborama database recognises the socio-demographic profile or behaviour of the visitor to the site, the visitor is transferred to the publisher\u2019s adserver. the publisher\u2019s adserver therefore now contains the socio-demographic and behavioural profile of the majority of its internet users.\" \r\n\r\nThe second method \"identifies and analyses the website user\u2019s profiles to create ad hoc target users relevant to the advertisers\u2019 areas of activity.\" Here Weborama creates _ad hoc_ profiles, and then there is a \"transfer of ad hoc target users\": \"the transfer of ad hoc users defined above is possible using a list of different adserver pixels. this transfer is done by a call of the pixels generated by the publisher\u2019s adserver. the volume of profiles per target required are then available directly in the adserver\" [Weborama, 03](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf).\r\n\r\n## References\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/weborama](https://www.crunchbase.com/organization/weborama)\r\n* _Weborama, 01._ [https://www.weborama.com](https://www.weborama.com)\r\n* _Weborama, 02._ [https://www.weborama.com/data/presentation](https://www.weborama.com/data/presentation) \r\n* _Weborama, 03._ [http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf](http://www.weborama.com/documents/2013/06/data-according-to-weborama.pdf) \r\n* _Weborama, 04._ [https://www.weborama.com/data/the-offering](https://www.weborama.com/data/the-offering) \r\n* _Weborama, 05._ [https://www.weborama.com/infos-financieres/financial-figures](https://www.weborama.com/infos-financieres/financial-figures) \r\n* _Weborama, 06._ [https://www.weborama.com/documents/2017/09/weborama-growth-of-the-operating-profit-in-the-first-half-of-2017.pdf](https://www.weborama.com/documents/2017/09/weborama-growth-of-the-operating-profit-in-the-first-half-of-2017.pdf) \r\n* _Weborama, 07._ [https://www.weborama.com/e-privacy/our-commitment](https://www.weborama.com/e-privacy/our-commitment)\r\n \r\n## External Links\r\n* _Wikipedia (Weborama, French):_ [https://fr.wikipedia.org/wiki/Weborama](https://fr.wikipedia.org/wiki/Weborama) \r\n* _Wikipedia (Weborama, English translation):_ [https://translate.google.com/translate?hl=en&sl=fr&u=https://fr.wikipedia.org/wiki/Weborama&prev=search](https://translate.google.com/translate?hl=en&sl=fr&u=https://fr.wikipedia.org/wiki/Weborama&prev=search)", "network_signature": "weborama\\.net|weborama\\.fr", "creation_date": "2017-09-24", "id": 6, "website": "https://www.weborama.com", "code_signature": "com.weborama."}, "7": {"name": "Smart", "description": "## Primary Location\r\nFrance\r\n\r\n## Website\r\n[http://smartadserver.com](http://smartadserver.com)\r\n\r\n## About\r\nSmart uses a \"full stack ad technology\" for digital campaigns [Smart, 03](http://smartadserver.com/request-a-demo). They deliver \"multi-screen and multi-channel advertising\" for clients [Smart, 01](http://smartadserver.com). \r\n\r\n## Ownership\r\nSmart\r\n\r\n## Documentation\r\n[https://github.com/smartadserver/SAS-DFP-Adapter-Android](https://github.com/smartadserver/SAS-DFP-Adapter-Android)\r\n\r\n## Products and Services\r\n_Solutions for publishers:_ Ad Server / Programmatic / Mobile / Video / Ad Formats [Smart, 04](http://smartadserver.com/publisher-platform/holistic-ad-server) \r\n\r\n_Full stack ad technology platform:_ Smart is a full stack ad technology platform: \"We come to work because we want to solve the biggest problem publishers, advertisers and agencies face in online advertising \u2014 control. It\u2019s simple. When other companies sell and resell your ad inventory and data through various parties, you depreciate your company\u2019s value along the way. Smart\u2019s integrated ad server and RTB+ Solution allows you to maintain control over your valuable media assets. We provide you with one robust engine to drive your revenues at any scale. Your ad server is the core of your business. It\u2019s your most important strategic asset. It\u2019s that much more powerful when it is seamlessly integrated with RTB+ and can handle the monetization and delivery of any kind of ads \u2013 display, rich media, video \u2013 on any platform \u2013 web, mobile web or mobile apps\" [Smart, 05](http://smartadserver.com/what-we-do/our-mission). \r\n\r\n_Holistic Ad Server:_ \"One integrated platform to run your entire advertising business, including direct and programmatic campaigns, across all digital formats and screens. Optimize operations without losing time switching between platforms... As the central piece of the puzzle, the ad server gets the big picture. It can optimize the value of each impression by taking absolutely all parameters into account in real time allowing direct sales to compete with programmatic ones. The platform dynamically allocates ads by incorporating all activity on the network: traffic and inventory forecasting, delivery planning, guaranteed campaign commitments, offers, and targeting parameters\" [Smart, 04](http://smartadserver.com/publisher-platform/holistic-ad-server). \r\n\r\n\"The Smart AdServer full stack platform features both an ad server and an SSP. From a single entry point, you can manage all your revenue sources: direct, programmatic and ad network mediation. Our outstanding holistic yield optimization algorithm ensures that each impression is sold through the best sales channel in order to maximize your overall revenue\" [Smart, 06](http://smartadserver.com/publisher-platform/full-stack).\r\n\r\nThe service offers:\r\n \r\n* Cross-platform delivery\r\n* Forecasting \r\n* Ad format builder\r\n* Viewability measurement\r\n* Open and extendable services\r\n* Expert support [Smart, 04](http://smartadserver.com/publisher-platform/holistic-ad-server)\r\n\r\n_Premium Programmatic:_ \"Our cross-platform, cross-device, cross-channel technology is 100% independent, 100% publisher-focused and easy-to-use. Access top quality buyers via an SSP integrated into the ad server.\" This can:\r\n\r\n1. Deliver premium ad campaigns (for rich media, native ads, and video)\r\n2. Manage any type of deal (open auction for unreserved inventory; direct deals of fixed-price unreserved inventory; private auctions for buyers; and guaranteed deals with same options as for direct campaigns)\r\n3. Regain full control of your inventory (granular control over RTB rules, including transparency level of your inventory, setting floor prices, and block-lists; quality monitoring utilizing smart machine learning, 3rd party tools, transparency reports, and a creative control interface)\r\n4. Optimize your advertising revenue (manage all of your revenue sources - direct, programmatic, and ad network mediation - from a single interface). A holistic yield optimization algorithm ensures impressions sold through the best sales channel to maximize revenue; an RTB+ Dashboard offers analytics for insights and revenue decisions; Smart AdServer teams to consult; and Smart Yield+ to optimize rules and price floors [Smart, 08](http://smartadserver.com/publisher-platform/premium-programmatic).\r\n\r\n_RTB Mobile:_ Deliver relevant mobile ad experiences, using rich media templates so \"you can create a campaign even if you don\u2019t have stellar technical skills\" [Smart, 09](http://smartadserver.com/publisher-platform/mobile).\r\n\r\n## Relationships\r\n650+ customers [Smart, 11](http://smartadserver.com/media-buyers) \r\n150+ integrated partners [Smart, 10](http://smartadserver.com/what-we-do/ecosystem) \r\n\r\n_Demand partners:_ Radium one / Turn / AppNexus / DoubleClick bid manager by Google / MediaMath / Adform / criteo (A.I. marketing platform) / nextperf / theTradeDesk / sociomantic / quantcast / Index / BidSwitch / DataXu / AdRoll / Vizury / Sitescout / Liquid M / LDmobile / mediasmart / Trademob / A mob / StikeAd / loopMe / DynAdmic / Zebestof / Pocketmath / adelphic / TLVMedia [Smart, 10](http://smartadserver.com/what-we-do/ecosystem) / himediagroup / aufeminin / Axel Springer / SFR R\u00e9gie / Orange / M-Publicite / L'\u00c9quipe / Clar\u00edn / Genesismedia / Antevenio / [Smart, 13](http://smartadserver.com/company/customers)\r\n\r\n_Others:_ \r\n\r\n* 2nd screen: screenpulse / TVTY Real Time / Visiware International \r\n* 3rd Party Vendors: adform / celtra / DoubleClick by Google / Atlast by Facebook / flashtalking / InMobi / inspired / justAd / MobileAds / S4M / Sizmek / userADgents / weborama / Joule \r\n* Analytics: Keynote / S4M \r\n* Audience Data: AudienceScience / ezakus / Globalfastads.com / navegg / Tail Target / krux \r\n* Brandsafety: adwatchisobar \r\n* Content Delivery Network: Akamai / Level(3) \r\n* Creatives: iab / iab MRAID webTester / iab compliant VAST \r\n* Environment: Android / HTML5 / W3C \r\n* Forecast: Yieldex \r\n* Membership: iab / MMA (Mobile Marketing Association) \r\n* Order management: adlogix.eu / Advendio.com / fivia / nugg.ad \r\n* Privacy: Ghostery / Your Online Choices \r\n* Publishing Networks: Facebook / Google Display Network / msn / Pandora / Q1 Media / The New Yorker / Travel+ Leisure / YouTube \r\n* Video Players: brightcove / Dailymotion / flowplayer / JWPlayer / OOYALA \r\n* Viewability: AppNexus [Smart, 10](http://smartadserver.com/what-we-do/ecosystem)\r\n\r\nAntevenio (ad network that delivers 1.2 billion ad impressions/month to MTV, Paramount, Libertad Digital, Letsbonus, Repsol, BBC, etc. - see [Smart, 07](http://smartadserver.com/uploads/EN_SAS_RTB_Case_study_antevenio_2014_3.pdf)) / access to 50,000 leading global marketer brand buyers through Smart AdServer's Demand Partner Network [Smart, 08](http://smartadserver.com/publisher-platform/premium-programmatic) altitude digital / adikteev [Smart, 11](http://smartadserver.com/media-buyers) / Fraudlogix [Smart, 12](http://smartadserver.com/wp-content/uploads/2017/10/20170606_Brand_Safety_Policy.pdf)\r\n\r\nIn 2012, Smart AdServer teamed up with Rubicon Project for integration into their client base [ExchangeWire, 01](https://www.exchangewire.com/blog/2012/07/23/addressing-the-stack-smart-adserver-teams-up-with-rubicon-project-to-maximise-yield).\r\n\r\n_Industry Affiliations:_ European Interactive Digital Advertising Alliance [Ghostery, 01](https://apps.ghostery.com/apps/smart_adserver)\r\n\r\n## Privacy policy\r\n_Cookies & Web Beacons:_ \"Like most digital marketing solutions, Smart AdServer uses \u201ccookies\u201d and other technologies to enhance users\u2019 experiences on the web, to deliver more relevant ads, and for ad delivery and reporting. We cannot use these technologies to personally identify you, and these technologies do not damage your system or files. Smart AdServer uses these technologies to help recognize a unique computer or device so we are able to deliver relevant advertising and measure the impact of that advertising.\" \r\n\r\n_Cookie Opt-Out:_ The cookie opt-out policy allows users to \"opt out form our advertising network\" and \"ensures you that your browser will not be identify anymore by our system\", see \"http://www.smartadserver.com/diffx/optout/IABOptout.aspx. A blank page will open, confirming the opt-out process has been completed and Smart AdServer will no longer place cookies on your computer.\"\r\n\r\n_Online Behavioral Advertising opt-out via YourOnlineChoices platform:_ \"Smart AdServer is a member of the European Interactive Digital Advertising Alliance (EDAA) and a signatory to the Self-Regulatory Principles for Online Behavioral Advertising (http://www.edaa.eu/european-principles/).\"\r\n\r\nThe EDAA offers a Consumer Choice Page (http://youronlinechoices.eu) (opt-out). To learn more, please visit http://edaa.eu.\" [Smart, 02](http://smartadserver.com/company/privacy-policy)\r\n\r\nSmart promises no personal identity is revealed through their practices: \"Online measurements are compiled and anonymous\"; \"We cannot use [ cookies and other technologies ] to personally identify you\"\r\n\r\n## Details\r\n_Financial Details:_ Smart AdServer was created by Internet portal Aufeminin.com in 2001 [clubic, 01](http://www.clubic.com/actualite-145758-100-clients-francais-smart-adserver.html). In 2007, Axel Springer acquired Aufeminin.com. Smart AdServer became independent from Aufeminin.com when it was acquired by Sino-French private-equity fund Cathay Capital for 37 million \u20ac [Wikipedia, 01](https://en.wikipedia.org/wiki/Smart_Adserver); [JDN, 01](http://www.journaldunet.com/ebusiness/publicite/vente-smart-adserver-cathay-capital.shtml); [Smart, 14](http://smartadserver.com/smart-adserver-officially-becomes-independent-with-the-support-of-cathay-capital); [Cathay, 01](http://www.cathay.fr/en/news/cathay-buy-smart-adserver-e37m). Smart AdServer \"generated turnover of $16 million in 2014\" [Ad Exchanger, 01](https://adexchanger.com/platforms/smart-adserver-goes-independent-via-private-equity-firm). \r\n\r\n## Details\r\n_Financial details:_ Smart was founded in 2001 [Crunchbase, 01](https://www.crunchbase.com/organization/smart-adserver)\r\n\r\n_Scope:_ For programmatic buyers: \r\n* 50 billion auctions per month on desktop 30 billion auctions per month on mobile \r\n* 650+ publishers / 800 million unique visitors \r\n* 30,000 sites and apps [Smart, 11](http://smartadserver.com/media-buyers) \r\n* 150 billion monthly impressions [Smart, 13](http://smartadserver.com/company/customers)\r\n\r\n### Methods\r\nCookies & Web Beacons are used (including pixel tags) [Smart, 02](http://smartadserver.com/company/privacy-policy)\r\n\r\n\"Sites and Advertisers are using the system to manage the delivery of their online advertising campaigns. They can collect anonymous statistical data on their visitors to follow the delivery of their campaign and to increase their performance. We may also collect information including your IP address, your ISP, the browser you used to visit a site, and in some cases, whether you have Flash installed. This is generally used for geotargeting purposes or showing certain ads depending on your browser configuration. Online measurements are compiled and anonymous. They essentially relate to Internet advertising campaign exposure: the number of impression of a banner, the number of clicks or the number of visitors having seen the campaign. Some statistics may relate to the performance of the campaign (\u2018return of investment\u2019). In addition to that, Smart AdServer may use cookies to provide advanced statistical data.\" [Smart, 02](http://smartadserver.com/company/privacy-policy)\r\n\r\n_Mobile:_ \r\n1. _Location targeting based on:_ device type; connection type; location through geotargeting; SDK version; screen size; any sales channel; geofencing (\"Use GPS positioning to pinpoint your target audience based on proximity to a location\"). \r\n\r\n2. Prefetch: Deliver ads to users when offline (eg, during commute)\r\n\r\n3. Viewability: \"Measure the number of viewable impressions and define viewability settings based on parameters such as location and area of ad exposure.\"\r\n\r\n4. Reporting and forecasting: \"Get real-time campaign statistics as well as accurate and reliable forecasts based on date, media type, operator, brand model, location and more.\"\r\n\r\n5. Showcasing: \"Showcase apps by previewing ad on actual devices before it goes live\" [Smart, 09](http://smartadserver.com/publisher-platform/mobile)\r\n\r\n## References\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/smart-adserver](https://www.crunchbase.com/organization/smart-adserver)\r\n* _ExchangeWire, 01._ [https://www.exchangewire.com/blog/2012/07/23/addressing-the-stack-smart-adserver-teams-up-with-rubicon-project-to-maximise-yield](https://www.exchangewire.com/blog/2012/07/23/addressing-the-stack-smart-adserver-teams-up-with-rubicon-project-to-maximise-yield)\r\n* _Ghostery, 01._ [https://apps.ghostery.com/apps/smart_adserver](https://apps.ghostery.com/apps/smart_adserver)\r\n* _Smart, 01._ [http://smartadserver.com](http://smartadserver.com)\r\n* _Smart, 02._ [http://smartadserver.com/company/privacy-policy](http://smartadserver.com/company/privacy-policy)\r\n* _Smart, 03._ [http://smartadserver.com/request-a-demo](http://smartadserver.com/request-a-demo) \r\n* _Smart, 04._ [http://smartadserver.com/publisher-platform/holistic-ad-server](http://smartadserver.com/publisher-platform/holistic-ad-server)\r\n* _Smart, 05._ [http://smartadserver.com/what-we-do/our-mission](http://smartadserver.com/what-we-do/our-mission)\r\n* _Smart, 06._ [http://smartadserver.com/publisher-platform/full-stack](http://smartadserver.com/publisher-platform/full-stack)\r\n* _Smart, 07._ [http://smartadserver.com/uploads/EN_SAS_RTB_Case_study_antevenio_2014_3.pdf](http://smartadserver.com/uploads/EN_SAS_RTB_Case_study_antevenio_2014_3.pdf)\r\n* _Smart, 08._ [http://smartadserver.com/publisher-platform/premium-programmatic](http://smartadserver.com/publisher-platform/premium-programmatic)\r\n* _Smart, 09._ http://smartadserver.com/publisher-platform/mobile](http://smartadserver.com/publisher-platform/mobile)\r\n* _Smart, 10._ [http://smartadserver.com/what-we-do/ecosystem](http://smartadserver.com/what-we-do/ecosystem)\r\n* _Smart, 11._ [http://smartadserver.com/media-buyers](http://smartadserver.com/media-buyers)\r\n* _Smart, 12._ [http://smartadserver.com/wp-content/uploads/2017/10/20170606_Brand_Safety_Policy.pdf](http://smartadserver.com/wp-content/uploads/2017/10/20170606_Brand_Safety_Policy.pdf)\r\n* _Smart, 13._ [http://smartadserver.com/company/customers](http://smartadserver.com/company/customers)\r\n* _Smart, 14._ [http://smartadserver.com/smart-adserver-officially-becomes-independent-with-the-support-of-cathay-capital](http://smartadserver.com/smart-adserver-officially-becomes-independent-with-the-support-of-cathay-capital)\r\n* _Wikipedia, 01._ [https://en.wikipedia.org/wiki/Smart_Adserver](https://en.wikipedia.org/wiki/Smart_Adserver) \r\n\r\n## External Links\r\n* _Ghostery_: [https://apps.ghostery.com/apps/smart_adserver](https://apps.ghostery.com/apps/smart_adserver) \r\n* _Wikipedia_: [https://en.wikipedia.org/wiki/Smart_Adserver](https://en.wikipedia.org/wiki/Smart_Adserver)", "network_signature": "smartadserver\\.com|saspreview\\.com", "creation_date": "2017-09-24", "id": 7, "website": "http://smartadserver.com/", "code_signature": "com.smartadserver."}, "8": {"name": "JW Player", "description": "https://developer.jwplayer.com/android-sdk/", "network_signature": "jwpltx\\.com|p\\.jwpcdn\\.com|g\\.jwpsrv\\.com", "creation_date": "2017-09-24", "id": 8, "website": "https://jwplayer.com", "code_signature": "com.longtailvideo.jwplayer."}, "9": {"name": "Loggly", "description": "\"Loggly is a San Francisco startup developing the world's most popular cloud based logging platform. We have built a highly scalable log management service as a platform which provides great value for the entire organization.\"\r\n\r\n[Privacy Policy](http://loggly.com/privacy/)\r\n\r\n## Data Collected\r\n * Anonymous (Browser Information, Date/Time, Demographic Data, Page Views )\r\n * Pseudonymous (Search History)\r\n\r\n## Data Sharing\r\nAggregate data is shared with 3rd parties.\r\n\r\n## Data Retention\r\nUndisclosed\r\n\r\n[source Ghostery](https://apps.ghostery.com/en/apps/loggly)", "network_signature": "loggly\\.com", "creation_date": "2017-09-24", "id": 9, "website": "http://loggly.com/", "code_signature": "com.github.tony19.timber.loggly|com.github.tony19.loggly|com.visiware.sync2ad.logger.loggly."}, "10": {"name": "Xiti", "description": "## Primary Location\r\nFrance (Bordeaux) [Crunchbase, 01](https://www.crunchbase.com/organization/at-internet)\r\n\r\n## Website\r\n[https://www.xiti.com/en](https://www.xiti.com)\r\n\r\n## About\r\nXiTi is \"a free web analytics solution that provides data and performance indicators, making it possible to have an overview of a website\u2019s traffic. Hundreds of thousands of users all over the world use XiTi\u00ae Free.\" XiTi offers \"the Analytics Suite, which helps some of the world\u2019s largest brands to measure, analyse, and visualise their data and digital performance\" [AT Internet, 05](https://www.atinternet.com/en/glossary/xiti-free-2).\r\n\r\n## Ownership\r\nAT Internet\r\n\r\n## Documentation\r\n[https://developers.atinternet-solutions.com/android-en/getting-started-android-en/configuration-android-en](https://developers.atinternet-solutions.com/android-en/getting-started-android-en/configuration-android-en)\r\n\r\n## Products and Services\r\n\"One of the world\u2019s major players in digital intelligence since 1996, AT Internet helps companies measure their audience and optimise their digital performance across all channels. AT Internet\u2019s expertise extends from collecting raw data to treating it in real time and delivering it for analysis and the sharing of insights. Applications in AT Internet\u2019s Analytics Suite provide reliable, contextualised and actionable information. Scalable and completely modular, AT Internet\u2019s offering adapts to businesses in all industries: e-commerce, media, finance/banking, corporate institutions. Easy-to-use and accessible to all individuals within a company, these solutions help address the challenges facing both novices and experts in digital analytics and data mining\" [XiTi, 01](https://www.xiti.com/en).\r\n\r\n_AT Intenet Analytics Suite:_ \"Our Analytics Suite is a digital analytics solution that gives you a unified, real-time view of what users do on your website, mobile site and mobile app. Whether you\u2019re a marketing manager or a data analyst, the Analytics Suite brings together all the tools you need for actionable analysis, dashboarding, reporting, data mining and big data exports. Armed with analytics data that\u2019s accurate, consistent and completely reliable, you\u2019ll be able to make sound, data-backed decisions for your business\" [AT Internet, 01](https://www.atinternet.com/en/products). \r\n\r\n_XiTi:_ XiTi is an audience measuring and statistics service for websites. It provides audience and usage statistics regarding website traffic, including mobile internet. XiTi \"many indicators of visitor activity: audience, navigation, origin of the visit, geolocation. Like similar services for commercial use, it tracks the return on investment (ROI) of marketing campaigns (e-mailing campaigns, sponsored links, contextual advertising) and measures the evolution of the turnover of a online shopping website\". XiTi Free offers personal websites limited analytics for free, whereas XiTi Pro \"is intended for showcases or small sites, especially for SMEs / SMIs. It offers a first professional evaluation of the performance of a website\" [Wikipedia, 01, translated from French](https://fr.wikipedia.org/wiki/XiTi). \r\n\r\n\"To use XiTi on a given page you must add in its source code a marker in the form of a JavaScript script that will allow the company's servers to access the information to be saved (based on the headers of which Cookies , the IP address , and the JavaScript environment). An alternative is to insert a small logo (visible for the free version and invisible for paid versions) on each page to be audited\" [Wikipedia, 01, translated from French](https://fr.wikipedia.org/wiki/XiTi).\r\n\r\n_AT Analytics Dashboard:_ \r\n\r\n* \"Build Dashboards: Understand and drive your business at a glance! Create digital analytics dashboards that can be customised down to the pixel and shared across your company.\" \r\n* Tag with Agility: Take control of your tagging with our modular, customisable SmartTag for web and mobile. Speed up implementation and improve load times.\" \r\n* App Analytics: Get rich mobile analytics, in-app, app store and benchmark data. Track mobile user engagement and retention over time\" [AT Internet, 01](https://www.atinternet.com/en/products). \r\n\r\n_Explorer Service:_ \r\n\r\nExplorer's \"iterative analysis...means giving analysts \u2013 whether they are beginners or experts \u2013 the ability to gradually access data, by first offering an intelligent analysis recommendation system based on machine learning, and then offering the ability to slice and dice the data as much and however they wish. Our objective here is simple: offer these users a tool which will help them find the value in their data, step by step, and then help them share the data so that the most can be made of it. To that end, Explorer offers tools that let you work with and refine your data indefinitely notably via filters, drill-downs, on-the-fly segmentation, and custom cross-calculations. \r\n\r\n...with just one click, the analyst can access Data Query to extract data via our API, and then activate that data by creating relevant retargeting campaigns, for example.\r\n\r\nThe analyst can also transform the analysis into a KPI to be directly displayed in a dashboard, thanks to Explorer\u2019s integration in the Analytics Suite. This KPI will allow business users to understand what\u2019s happening, follow the KPI\u2019s evolution, and potentially implement actions as a result\" [Ad Internet, 03](https://blog.atinternet.com/en/interview-finding-the-value-in-your-data-step-by-step). \r\n\r\n_Mobile developments:_ \r\n\r\n\"There are also mobile features that continue to be developed. For example, we are working on the analysis of the customer journey, which is now done on several devices. This cross-device tracking is simple in theory, because in practice, it's more complicated than just following log-in users ... Above all, unlike others, we are very concerned about the respect of Internet users, and everything must be done with their consent, in accordance with the law. We have many other features in preparation. We will also work on marking and its reliability, a \"smart SDK\" for mobile apps, a tool to know the traffic pages and links by surfing the site, or a benchmark mobile apps using data from the app stores\" [JDN, 01](http://www.journaldunet.com/solutions/analytics/1179294-mathieu-llorens-at-internet-ces-4-millions-d-euros-vont-nous-aider-a-passer-un-nouveau-cap). \r\n\r\nXiTi will \"examine any profiling activities done on their advertising networks, especially when analytics data is being used to establish this profiling\" [At Internet, 02, PDF](https://www.atinternet.com/uploads/Digital-Analytics-the-GDPR-5-Things-You-Must-Know.pdf).\r\n\r\n_Trackers:_ \r\n\r\n* Android initialisation (see [AT Internet, 06](https://developers.atinternet-solutions.com/android-en/getting-started-android-en/tracker-initialisation-android-en)) \r\n* Apple iOS (see [AT Internet, 07](https://developers.atinternet-solutions.com/apple-en/getting-started-apple-en/configuration-apple-en)) \r\n* JavaScript (see [AT Internet, 08](https://developers.atinternet-solutions.com/javascript-en/getting-started-javascript-en/tracker-initialisation-javascript-en))\r\n\r\n## Privacy Policy\r\n\r\n_Personal Data:_ XiTi states, \"By default, AT Internet considers all data related to IP address, GPS location and cookies as personal data. We store all this data within the EU. \r\n\r\nWe only keep: \r\n\r\n* IP address data for 6 months maximum \r\n* [Learn more about how we process and anonymise IP addresses.](https://www.atinternet.com/en/company/data-protection/data-collection-on-our-customers-sites/#geolocation)\r\n* GPS location data for 6 months maximum \r\nDuring collection, we truncate all GPS coordinates to two decimal degrees \u2013 we never collect GPS coordinates in their entirety. Truncated coordinates are then converted into a heatmap graphic providing country-level-only informa-tion. Full details are never displayed. \r\n* Our cookies are active during a fixed period of 13 months, and are then deleted from a user\u2019s computer AT Internet\u2019s cookie only contains a unique alphanumeric ID \u2013 no other data is stored in the cookie.\" \r\n\r\n_Transparency:_ XiTi states, \"The GDPR requires companies and organisations (\u201cdata controllers\u201d) to be completely transparent, \u201cusing clear and plain language\u201d, when informing end users (\u201cdata subjects\u201d) about which personal data is collected, where it is stored, and for how long it is kept (see previous section).\" \r\n\r\n\"... AT Internet has the resources required to retrieve, edit or erase any personal data in a timely manner. We will liaise directly with end users on this matter when necessary. We communicate clearly and transparently about end users\u2019 rights in our privacy policy. We also offer an opt-out option for end users who do not wish their activity to be tracked via our web analytics solution.\" \r\n\r\n_Storage Location:_ \r\n\r\n\"AT Internet processes and stores all personal data within the European Union, with no personal data being transferred outside the EU. This information is clearly accessible in our privacy policy, and in our customer contracts.\" \r\n\r\n_Co-Responsibility:_ \"Under the GDPR, when two different organisations (\u201cdata controllers\u201d) work together to establish the purpose and means of processing personal data, they are considered \u201cjoint controllers\u201d and share responsibility. Joint controllers must together determine the details of their \u201crespective responsibilities\u201d for GDPR compliance, especially as it relates to their duties in responding to data subject requests.\"\r\n\r\n\"... AT Internet\u2019s Analytics Suite is GDPR-compliant. We therefore commit to sharing full responsibility with our customers for any potential privacy breaches and sanctions under the GDPR. We will provide each of our customers with a contract addendum \u2013 a Data Protection Agreement, or DPA \u2013 to precisely define the scope of responsibility. If you work with a different digital analytics provider, we strongly recommend you verify the terms of your contract to ensure that responsibility is not automatically transferred to you (via limitations on liability clauses).\" \r\n\r\n_Purposes of Analytics / Cominations and Correlations with Other Customer Data:_ \"Under the GDPR, personal data must only be \"collected for specified, explicit and legitimate purposes and not further processed in a manner that is incompatible with those purposes.\" In other words, your visitors\u2019 data should only be used to achieve the specific thing(s) you\u2019ve informed them of, such as (in the case of analytics) improving their experience on your site, or providing them with tailored content. Your visitors\u2019 data should NOT be used in other ways for which they have not given consent.\" Data profiling requires a Data Protection Impact Assessment (DPIA) \" to determine how this profiling affects the protection of your users\u2019 personal data.\" \r\n\r\n\"... With AT Internet, you always remain the owner of your data. We never use or merge our customers\u2019 analytics data for our own purposes. We do not carry out any profiling activities, and in light of the GDPR, we strongly encourage our customers and prospects to carefully any profiling activities done on their advertising networks, especially when analytics data is being used to establish this profiling.\"\r\n\r\n## Relationships\r\n\"AT Internet has more than 3,800 web analytics customers worldwide from all industries, including more than half of the companies listed on the French stock exchange (CAC 40), as well as many other leading international groups.\" \r\n\r\n\"The power of AT Internet\u2019s Analytics Suite and the quality of its services (consulting, training and support) are recognised worldwide.\" XiTi is \" in all industries\", including \"e-commerce, media, finance/banking, corporate institutions... With more than 200 employees, the group is present in 32 countries via its customers, subsidiaries and partners\" [XiTi, 01](https://www.xiti.com/en). \r\n\r\n\"Our solution is used on more than 20,000 sites and apps around the globe. Discover how our clients have improved their results (ROI, conversion rate, online sales\u2026) thanks to our solutions and services. Learn from their experiences and best practices in web marketing, digital intelligence and digital analytics\" [Ad Internet, 04](https://www.atinternet.com/en/resources/customer-success-stories).\r\n\r\n_AT Internet Clients (from \"Case Studies\"):_ L'Equipe / Groupe La Poste / Younited Credit (Pret D'Union) / Vente-Privee / Lagardere Active / Meinestadt.de / Rambler.ru / Soundcloud / Caradisiac / France Televisions / Reed Expositions / Oxybul Eveil et Jeux / Solocal Group / Nexity / Le Parisien / Priceminister / Ryanair / French Government Information Service (SIG) / Total [Ad Internet, 04](https://www.atinternet.com/en/resources/customer-success-stories)\r\n\r\n## Details\r\n_Financial details:_ AT Internet was founded in 1996, and has raised \u20ac10,250,000 from funders [Crunchbase, 01](https://www.crunchbase.com/organization/at-internet). In 2016, AT Internet obtained 4 million Euros in financing to expand its business [French Chamber Singapore, 01](http://www.fccsingapore.com/publications/internet-obtains-4-million-euros-financing-continue-its-international-growth-and), after having raised approximately 6 million Euros over three years prior [JDN, 01](http://www.journaldunet.com/solutions/analytics/1179294-mathieu-llorens-at-internet-ces-4-millions-d-euros-vont-nous-aider-a-passer-un-nouveau-cap).\r\n\r\n_Devices:_ Desktop / Mobile (Android / iOS)\r\n\r\n_History:_ \"For more than 15 years AT Internet has provided website owners with free access to their web traffic data. Thanks to an easy-to-use solution, you can benefit from key information such as traffic sources, visitor geolocation, and more, in order to manage and improve your site\u2019s impact (whether it\u2019s a blog, a personal website, or otherwise).\r\n\r\nThe XiTi Free project was launched back in 2000 by AT Internet, one of the world\u2019s leading digital analytics companies, and today continues to illustrate the company\u2019s desire to make digital analytics accessible to everyone. The decision to continue supporting a free version to the benefit of a large user community has been the success behind XiTi Free, an essential solution for measuring the traffic of personal websites. [XiTi, 01](https://www.xiti.com/en)\r\n\r\n_Slogans:_ \"The leading free solution for measuring website traffic\" [XiTi, 01](https://www.xiti.com/en)\r\n\r\n## References\r\n\r\n* _AT Internet, 01._ [https://www.atinternet.com/en/products](https://www.atinternet.com/en/products) \r\n* _At Internet, 02, PDF._ [https://www.atinternet.com/uploads/Digital-Analytics-the-GDPR-5-Things-You-Must-Know.pdf](https://www.atinternet.com/uploads/Digital-Analytics-the-GDPR-5-Things-You-Must-Know.pdf)\r\n* _Ad Internet, 03._ [https://blog.atinternet.com/en/interview-finding-the-value-in-your-data-step-by-step](https://blog.atinternet.com/en/interview-finding-the-value-in-your-data-step-by-step) \r\n* _Ad Internet, 04._ [https://www.atinternet.com/en/resources/customer-success-stories](https://www.atinternet.com/en/resources/customer-success-stories) \r\n* _AT Internet, 05._ [https://www.atinternet.com/en/glossary/xiti-free-2](https://www.atinternet.com/en/glossary/xiti-free-2) \r\n* _AT Internet, 06._ [https://developers.atinternet-solutions.com/android-en/getting-started-android-en/tracker-initialisation-android-en](https://developers.atinternet-solutions.com/android-en/getting-started-android-en/tracker-initialisation-android-en)\r\n* _AT Internet, 07._ [https://developers.atinternet-solutions.com/apple-en/getting-started-apple-en/configuration-apple-en](https://developers.atinternet-solutions.com/apple-en/getting-started-apple-en/configuration-apple-en)\r\n* _AT Internet, 08._ [https://developers.atinternet-solutions.com/javascript-en/getting-started-javascript-en/tracker-initialisation-javascript-en](https://developers.atinternet-solutions.com/javascript-en/getting-started-javascript-en/tracker-initialisation-javascript-en) \r\n* _French Chamber Singapore, 01._ [http://www.fccsingapore.com/publications/internet-obtains-4-million-euros-financing-continue-its-international-growth-and](http://www.fccsingapore.com/publications/internet-obtains-4-million-euros-financing-continue-its-international-growth-and)\r\n* _JDN, 01._ [http://www.journaldunet.com/solutions/analytics/1179294-mathieu-llorens-at-internet-ces-4-millions-d-euros-vont-nous-aider-a-passer-un-nouveau-cap](http://www.journaldunet.com/solutions/analytics/1179294-mathieu-llorens-at-internet-ces-4-millions-d-euros-vont-nous-aider-a-passer-un-nouveau-cap) \r\n* _Wikipedia, 01, translated from French._ [https://fr.wikipedia.org/wiki/XiTi](https://fr.wikipedia.org/wiki/XiTi) \r\n* _Xiti, 01._ [https://www.xiti.com/en](https://www.xiti.com/en) \r\n\r\n## External Links\r\n* _Wikipedia (AT Internet):_ [https://en.wikipedia.org/wiki/AT_Internet](https://en.wikipedia.org/wiki/AT_Internet)\r\n* _XiTi (AT Internet):_ [https://www.crunchbase.com/organization/at-internet](https://www.crunchbase.com/organization/at-internet)\r\n* _Ghostery (AT Internet):_ [https://apps.ghostery.com/apps/at_internet](https://apps.ghostery.com/apps/at_internet)", "network_signature": "NC", "creation_date": "2017-09-24", "id": 10, "website": "http://Xiti.com", "code_signature": "NC"}, "11": {"name": "OutBrain", "description": "\"Our Mission Help people discover content that they can trust to be interesting, relevant and timely for them. OUTBRAIN BY THE NUMBERS We were first in creating content discovery and we are first in markets across the world. We reach more than a half billion people globally each month. 557 MILLION The global audience Outbrain reaches each month. 200 BILLION The total recommendations we serve consumers monthly. 80% Of the world\u2019s leading brands use Outbrain.\" \r\n\r\n[Privacy Policy](http://www.outbrain.com/legal/privacy)\r\n\r\n## Data Collected\r\n * Anonymous (Ad Views, Analytics, Browser Information, Cookie Data , Date/Time, Demographic Data, Hardware/Software Type, Internet Service Provider, Interaction Data , Page Views , Serving Domains)\r\n * Pseudonymous (IP Address (EU PII), Location Based Data, Clickstream Data, Device ID (EU PII))\r\n * PII (Name , Phone Number, Email Address, Login, EU- IP Address, EU- Unique Device ID )\r\n\r\n## Data Sharing\r\nAggregate data is shared with 3rd parties., Anonymous data is shared with 3rd parties., PII data is shared with 3rd parties.\r\n\r\n## Data Retention\r\nAs long as necessary to fulfill a business need or as required by law.", "network_signature": "outbrain\\.com", "creation_date": "2017-09-24", "id": 11, "website": "http://www.outbrain.com/", "code_signature": "com.outbrain."}, "12": {"name": "AppsFlyer", "description": "## Primary Location\r\nIsrael (Herzliya)\r\n\r\n## Website\r\n[https://www.appsflyer.com](https://www.appsflyer.com)\r\n\r\n## About\r\nA mobile & attribution analytics platform that aims to help marketers make better decisions [AppsFlyer, 01](https://www.appsflyer.com)\r\n\r\n## Ownership\r\nAppsFlyer\r\n\r\n## Documentation\r\n[https://support.appsflyer.com/hc/en-us/articles/207032126-AppsFlyer-SDK-Integration-Android](https://support.appsflyer.com/hc/en-us/articles/207032126-AppsFlyer-SDK-Integration-Android)\r\n\r\n## Products and Services\r\nAppsFlyer provides the following services: \r\n\r\n* Fraud prevention, malware protection [AppsFlyer, 04](https://www.appsflyer.com/product/protect360)\r\n* Identity attribution services. AppsFlyer fingerprints devices by their IDs and tracks across datasets (to solve the problem of fragmentation across devices). This works with all Windows 10 devices (including mobile), Android, and iOS [AppsFlyer, 03](https://www.appsflyer.com/product/mobile-attribution-for-user-acquisition).\r\n* Mobile services for targeted advertising [AppsFlyer, 05](https://www.appsflyer.com/product/mobile-ecosystem)\r\n* Marketing across devices and channels [AppsFlyer, 06](https://www.appsflyer.com/product/marketing-analytics)\r\n* Generates reports based on user behavior [AppsFlyer, 06](https://www.appsflyer.com/product/marketing-analytics)\r\n* Tracks which users install apps; tracks successful re-targeting marketing campaigns [AppsFlyer, 07](https://www.appsflyer.com/product/overview)\r\n\r\nAppsFlyer uses artificial intelligence and machine learning for big data analytics [AppsFlyer, 04](https://www.appsflyer.com/product/protect360); [VentureBeat, 01](https://venturebeat.com/2017/05/25/appsflyer-helps-mobile-advertisers-beat-back-ad-fraud-via-machine-learning).\r\n\r\n## Privacy Policy\r\n_Third Parties:_ AppsFlyer states it does not sell data to third parties [AppsFlyer, 02](https://www.appsflyer.com/we-are-appsflyer)\r\n\r\n## Relationships\r\nOver 2,000 network and analytics partners have integrated with AppsFlyer.\r\n\r\n_Investors include:_ Goldman Sachs / Deutsche Telekom / Qumra Capital / Magma Venture Partners / Pitango [AppsFlyer, 02](https://www.appsflyer.com/we-are-appsflyer) \r\n\r\n_Partners:_ Google [Google, 01](https://adwords.googleblog.com/2015/05/new-media-partnerships-and-ad-solutions.html); [TechCrunch, 02](https://techcrunch.com/2015/05/28/google-expands-its-app-promotion-business-with-universal-app-campaigns-and-new-media-partnerships) / Snap / Tencent / HBO / Playtika / Waze / Alibaba / Kayak / Activision [VentureBeat, 01](https://venturebeat.com/2017/05/25/appsflyer-helps-mobile-advertisers-beat-back-ad-fraud-via-machine-learning) / Facebook / Twitter / Accuweather / AdlQuity/Flipkart / Bing Search / Pandora / Opera Software / Ad4Screen / Cooladata / Fiksu / EveryAds / Nanigans / Fyber / HeyZap / Tapjoy / Adroll / Flurry / GameAnalytics / Jampp / Inmobi / Appnexus / Vserv / AppLovin / Vungle / URX / Mobvista / Inneractive / Aarki / Bidalgo / Avazu / Taptica / NativeX / AirPush / Amobee / PlayHaven / Mobilecore / Accesstrade / ADS / ADSNative / Ad County Media / AccordantMedia / Ad2games / Ad2iction / Abakus / APUS / ADyes / Accruo / AID / Aarki / Ad4Game / APPROUND MOBILE / AML / APPSILON / ART DMP / ActionAds / APPAniac / ADvantage / AdBuddiz / ADRW / ADXMI Exchange / ADSAXIS / APPAVE / AVH digital / Actionpay / Ad2Click / ART Ad Platform / ASB / Ad2c / ADPRESSO / Ad@m (kakao) / ADZ JUNCTION MEDIA / ADVERTISE.RU / Ad County / AWIN / Adbird / AdCorsa / Adamas / Adbert / AdReady / Adbrain / Adacts / AdChakra / AdCare / Adattract / AdTiming / AdWyze / AdTen / Adboosters / Adara / AdDeals / Adblender / AdView / AdTiger / AdFit / AdTriba / AdPacker / and many more. For a longer list, see [AppsFlyer, 03](https://www.appsflyer.com/partners)\r\n\r\n## Details\r\n### Financial details & history \r\nAppsFlyer received early seed funding from Microsoft Accelerator and Magma Venture Partners [CrunchBase, 01](https://www.crunchbase.com/funding_round/appsflyer-seed--4b06b119). As of November 2017, AppsFlyer's website lists $84M raised from Top VC's, $6B+ annual mobile ad spend measured, 3k+ mobile tech partners, and 13 global offices (and growing) [AppsFlyer, 02](https://www.appsflyer.com/we-are-appsflyer).\r\n\r\n### Scope\r\nAccording to VentureBeat, AppsFlyer leverages metadata from 98% of the world's mobile devices [VentureBeat, 01](https://venturebeat.com/2017/05/25/appsflyer-helps-mobile-advertisers-beat-back-ad-fraud-via-machine-learning).\r\n\r\n### Devices\r\nThe AppsFlyer SDK is available for Android, iPhone, and Windows Phone\r\n\r\n## References\r\n* _AppsFlyer, 01_. [https://www.appsflyer.com](https://www.appsflyer.com) \r\n* _AppsFlyer, 02_. [https://www.appsflyer.com/we-are-appsflyer](https://www.appsflyer.com/we-are-appsflyer) \r\n* _AppsFlyer, 03_. [https://www.appsflyer.com/partners](https://www.appsflyer.com/partners) \r\n* _AppsFlyer, 04_. [https://www.appsflyer.com/product/protect360](https://www.appsflyer.com/product/protect360) \r\n* _AppsFlyer, 05_. [https://www.appsflyer.com/product/mobile-ecosystem](https://www.appsflyer.com/product/mobile-ecosystem) \r\n* _AppsFlyer, 06_. [https://www.appsflyer.com/product/marketing-analytics](https://www.appsflyer.com/product/marketing-analytics) \r\n* _AppsFlyer, 07_. [https://www.appsflyer.com/product/overview](https://www.appsflyer.com/product/overview)\r\n* _CrunchBase, 01_. [https://www.crunchbase.com/funding_round/appsflyer-seed--4b06b119](https://www.crunchbase.com/funding_round/appsflyer-seed--4b06b119) \r\n* _Google, 01_. [https://adwords.googleblog.com/2015/05/new-media-partnerships-and-ad-solutions.html](https://adwords.googleblog.com/2015/05/new-media-partnerships-and-ad-solutions.html) \r\n* _TechCrunch, 02_. [https://techcrunch.com/2015/05/28/google-expands-its-app-promotion-business-with-universal-app-campaigns-and-new-media-partnerships](https://techcrunch.com/2015/05/28/google-expands-its-app-promotion-business-with-universal-app-campaigns-and-new-media-partnerships)\r\n* _VentureBeat, 01_. [https://venturebeat.com/2017/05/25/appsflyer-helps-mobile-advertisers-beat-back-ad-fraud-via-machine-learning](https://venturebeat.com/2017/05/25/appsflyer-helps-mobile-advertisers-beat-back-ad-fraud-via-machine-learning)\r\n\r\n## External Links\r\n* _Wikipedia (AppsFlyer)_: [https://en.wikipedia.org/wiki/AppsFlyer](https://en.wikipedia.org/wiki/AppsFlyer)\r\n* _AppBrain_: [https://www.appbrain.com/app/appsflyer-sdk-integration-test/com.appsflyer.referrerSender](https://archive.is/ufCAR)", "network_signature": "appsflyer\\.com", "creation_date": "2017-09-24", "id": 12, "website": "http://AppsFlyer.com", "code_signature": "com.appsflyer."}, "13": {"name": "Ligatus", "description": "\"Ligatus is a performance-marketing system permanently integrated into more than 260 premium-partner portals. Using its own optimisation algorithm, Ligatus enables advertising clients and agencies to position their advertising messages intelligently so that they precisely match the respective target group.\"\r\n\r\n## Data Collected\r\n * Anonymous (Browser Information, Cookie Data )\r\n * Pseudonymous (IP Address (EU PII))\r\n * PII (Name , Address, Phone Number, Email Address)\r\n * Undisclosed \r\n\r\n## Data Sharing\r\nUndisclosed\r\n\r\n## Data Retention\r\nUndisclosed\r\n\r\n[source Ghostery](https://apps.ghostery.com/en/apps/ligatus)", "network_signature": "ligatus\\.com", "creation_date": "2017-09-24", "id": 13, "website": "http://ligatus.com", "code_signature": ".LigatusManager|.LigatusViewClient|com.ligatus.android.adframework"}, "14": {"name": "Widespace", "description": "\"Widespace is an international mobile advertising marketplace connecting mobile advertisers with mobile publishers.\"\r\n\r\n## Data Collected\r\n * Anonymous (Analytics, Browser Information, Hardware/Software Type)\r\n\r\n## Data Sharing\r\nAggregate data is shared with 3rd parties.\r\n\r\n## Data Retention\r\nUndisclosed\r\n\r\n[source Ghostery](https://apps.ghostery.com/en/apps/widespace)", "network_signature": "widespace\\.com", "creation_date": "2017-09-24", "id": 14, "website": "http://widespace.com", "code_signature": "com.widespace."}, "15": {"name": "AppNexus", "description": "## Primary Location\r\nUnited States (New York City) [Bloomberg, 01](https://www.bloomberg.com/research/stocks/private/snapshot.asp?privcapId=48973441)\r\n\r\n## Website\r\n[https://www.appnexus.com](https://www.appnexus.com)\r\n\r\n## About\r\nAppNexus offers services for auction-based and directly negotiated media campaigns across the Internet. According to CEO Brian O'Kelley, \"the AppNexus platform\" is \"a single point where all key stakeholders in our ecosystem -- marketers, ad networks, demand side platforms (DSPs), agency networks, exchanges, inventory aggregators, third party data providers, and more -- connect with one another through a powerful technology platform\" [PR Newswire, 01](https://www.prnewswire.com/news-releases/appnexus-officially-launches-ad-platform-fueling-the-real-time-bidding-revolution-in-display-advertising-87460287.html).\r\n\r\n## Ownership\r\nAppNexus\r\n\r\n## Documentation\r\n[https://wiki.appnexus.com/display/sdk/Integrate+the+SDK](https://wiki.appnexus.com/display/sdk/Integrate+the+SDK)\r\n\r\n## Products and Services\r\nFor publishers:\r\n\r\n* Segments audiences\r\n* Uses data analytics to predict delivery risk (ie, delivery of ads)\r\n* Connects ads across devices\r\n* Run bidding ad processes [AppsNexus, 01](https://www.appnexus.com/en/publishers)\r\n\r\nFor advertisers:\r\n\r\n* Harnesses machine learning for \"targeted ads to tens of millions of users, spread out across billions of interconnected devices, all over the world\"\r\n* Real-time data solutions\r\n* Services are used to \"deliver intelligent and customized campaigns to hundreds of millions of consumers each day\"\r\n* Provide over 100 data points at the (consumer) impression level [AppNexus, 02](https://www.appnexus.com/en/buyers)\r\n* 10 billion impressions transactions each day [AppNexus, 03](https://www.appnexus.com/en)\r\n\r\n## Privacy Policy\r\n_Data use and sharing:_ \"The AppNexus Platform allows clients to collect and use Platform data. The Platform ingests information provided by third-party sources to allow clients to use such data to target ads. To do this, clients and data providers may use ID synching to enable the use of this information through the Platform.\" \r\n\r\n\"... The Platform enables AppNexus's clients to collect, buy, and sell data and to use Platform Data to buy and sell online advertising. Sometime AppNexus staff give \"hands-on\" help to clients using the Platform for these purposes, for example by configuring advertising campaigns for clients to best meet their objectives.\"\r\n\r\n\"... The AppNexus Platform allows clients to provide and share Platform Data with each other. Clients also have access to their Platform Data that they collect, acquire, or use on the Platform, and may remove it from the Platform for their own use. AppNexus may provide Platform Data to service providers in order to provide, operate, manage, maintain, and enhance AppNexus' services. AppNexus may provide, or enable others to collect, information for purposes of protecting the safety and security of the online ecosystem, including to detect and prevent malicious activity or fake traffic. AppNexus may also disclose such information in the event we reasonably suspect malicious activity or fake traffic or when we reasonably believe it is required by law, subpoena or other legal process, including to meet national security or law enforcement requirements. AppNexus may also share aggregated data derived from the Platform, including, for example, statistics about Platform activity. Finally, we may transfer Platform Data to a successor entity in connection with a corporate merger, consolidation, sale of assets, bankruptcy, or other corporate change.\"\r\n\r\n_Precise location data collection:_ \"The Platform may ingest Precise Location Information when, for example, an app makes such information available through the Platform.\" \r\n\r\n_PII:_ \"AppNexus does not collect, use, or allow its clients to transfer to or use on the Platform, data that, by itself, directly identifies an individual, such as name, address, phone number, email address, or government identifier. We also prohibit certain categories of sensitive data from being collected, used, or transferred on the Platform.\" \r\n\r\n_Opt-Out:_ In browsers, AppNexus offers an opt-out web browser cookie to opt out of interest-based advertising. On mobile, AppNexus lists an opt-out option through general device settings in Android and iOS. In Android, the setting is \"Opt out of Interest-Based Ads\". To stop location collection, AppNexus tells users to either change the preferences on their device or adjust settings in individual apps. \r\n\r\n_Data Retention:_ AppNexus retains data according to \"industry standards\". \"Platform Data is stored using generally accepted security standards. It is usually aggregated or deleted within 30-60 days, but may be retained in the Platform for up to 18 months from the date of collection before aggregation or deletion. Aggregated data is used for reporting and analysis, and may be stored in the Platform for up to 2 additional years. When clients remove their data from the Platform, their storage and retention of data is governed by their own privacy policies and applicable laws, rules, or regulations.\"\r\n\r\n_Regulation:_ AppNexus supports industry self-regulation, and is \"a member in good standing of the Network Advertising Initiative (NAI), and adheres to the NAI Code of Conduct for Web and Mobile\" [AppNexus, 04](https://www.appnexus.com/en/company/platform-privacy-policy#choices). \r\n\r\n## Relationships\r\n_Clients:_ Affiperf / Air France / Hearst / MEDIA.figaro / The Guardian / Wayfair [AppNexus, 03](https://www.appnexus.com/en) / Underdog Media / Liftoff / Advance Digital / USA Today / Xaxis / Accuen / Bloomberg / Defy Media / Dow Jones / Spectrum Platform Company / District M / BannerConnect / Hitch Digital / ESPN / Fox News / Saavn [AppNexus, 05](https://www.appnexus.com/en/customer-stories)\r\n\r\n## Details\r\n_History:_ AppNexus is \"Founded and managed by the pioneers of the Web's original and most successful ad exchanges at Yahoo!'s Right Media and Google's DoubleClick\" [PR Newswire, 01](https://www.prnewswire.com/news-releases/appnexus-officially-launches-ad-platform-fueling-the-real-time-bidding-revolution-in-display-advertising-87460287.html). AppNexus claims to be \"The world's largest independent digital marketplace\" [AppsNexus, 01](https://www.appnexus.com/en/publishers). \r\n\r\n_Collection Methods:_ \"The Platform uses cookies, beacons, tags, mobile SDKs, and in some cases non-cookie technologies, to collect Platform Data associated with particular web browsers or devices\" [AppNexus, 04](https://www.appnexus.com/en/company/platform-privacy-policy#choices).\r\n\r\n_AppNexus Platform Data Uses:_\r\n\r\n* Interest-based advertising (To opt out of interest-based advertising on the Platform, go to the \"What are your choices?\" section below.)\r\n* Limiting the number of times a user sees a particular ad\r\n* Showing ads in a particular sequence\r\n* Customizing ads to a particular location\r\n* Showing ads related to the content of the web page on which they are shown\r\n* Determining how users respond to ads\r\n* Reporting aggregated statistics regarding, for example, the effectiveness of online advertising campaigns\r\n* The Platform may use Platform Data for cross-device mapping in order to serve or measure advertising on related devices on behalf of our clients\r\n* Typically, companies using technology like the AppNexus Platform own the data that they provide to and get from the Platform. While the AppNexus Platform is designed to use only certain types of data, and Platform clients are prohibited from bringing data onto the Platform that directly identifies an individual, when clients remove their data from the Platform, their use of that data is governed by their own privacy policies and applicable laws, rules, or regulations [AppNexus, 04](https://www.appnexus.com/en/company/platform-privacy-policy#choices).\r\n\r\n## References\r\n* _AppNexus, 01_. [https://www.appnexus.com/en/publishers](https://www.appnexus.com/en/publishers) \r\n* _AppNexus, 02_. [https://www.appnexus.com/en/buyers](https://www.appnexus.com/en/buyers) \r\n* _AppNexus, 03_. [https://www.appnexus.com/en](https://www.appnexus.com/en) \r\n* _AppNexus, 04_. [https://www.appnexus.com/en/company/platform-privacy-policy#choices](https://www.appnexus.com/en/company/platform-privacy-policy#choices) \r\n* _AppNexus, 05_. [https://www.appnexus.com/en/customer-stories](https://www.appnexus.com/en/customer-stories) \r\n* _Bloomberg, 01_. [https://www.bloomberg.com/research/stocks/private/snapshot.asp?privcapId=48973441](https://www.bloomberg.com/research/stocks/private/snapshot.asp?privcapId=48973441) \r\n* _PR Newswire, 01_. [https://www.prnewswire.com/news-releases/appnexus-officially-launches-ad-platform-fueling-the-real-time-bidding-revolution-in-display-advertising-87460287.html](https://www.prnewswire.com/news-releases/appnexus-officially-launches-ad-platform-fueling-the-real-time-bidding-revolution-in-display-advertising-87460287.html)\r\n\r\n## External Links\r\n* _Wikipedia (AppNexus)_: [https://en.wikipedia.org/wiki/AppNexus](https://en.wikipedia.org/wiki/AppNexus)\r\n* _AppBrain_: [https://www.appbrain.com/dev/AppNexus/](https://archive.is/rI5Hu)", "network_signature": "adnxs\\.com|247realmedia\\.com|appnexus\\.com|appnexus\\.net", "creation_date": "2017-09-24", "id": 15, "website": "https://www.appnexus.com/", "code_signature": "com.appnexus.opensdk."}, "16": {"name": "Localytics", "description": "## Primary Location\r\nUnited States (Boston) [Localytics, 01](https://www.localytics.com/company/about)\r\n\r\n## Website\r\n[https://www.localytics.com](https://www.localytics.com)\r\n\r\n## About\r\nLocalytics offers an analytics and marketing platform for targeted and personalized engagement campaigns on mobile [Localytics, 01](https://www.localytics.com/company/about); [Crunchbase, 01](https://www.crunchbase.com/organization/localytics).\r\n\r\n## Ownership\r\nSelf-owned\r\n\r\n## Documentation\r\n[https://docs.localytics.com/dev/android.html#android](https://docs.localytics.com/dev/android.html#android)\r\n\r\n## Products and Services\r\nLocalytics performs a variety of services for clients: \r\n\r\n* Uniquely identify users and devices via the Localytics tracker: \"The Localytics SDK automatically captures and uploads device IDs which the Localytics backend uses to uniquely identify users. Some apps connect to their own backend systems that use different IDs for uniquely identifying users\" [Localytics, 04](https://docs.localytics.com/dev/android.html#android) \r\n* Store and transmit user personal information, such as end user name [Localytics, 05](http://docs.localytics.com/dev/ios.html#identifying-users-ios) \r\n* Identify users who uninstall an app containing the tracker [Localytics, 06](http://docs.localytics.com/dev/ios.html#uninstall-tracking-ios)\r\n* Track detailed geolocation, even without the use of GPS: \"Most apps don't track user geolocation so Localytics uses an IP-to-location lookup service to determine which country they are located in. If your app does track user geolocation, you can use the following code to set latitude and longitude in Localytics much more precisely\" [http://docs.localytics.com/dev/ios.html#location-ios](http://docs.localytics.com/dev/ios.html#location-ios)\r\n\r\nLocalytics leverages the same tracking platform in iOS and Android.\r\n\r\n## Privacy Policy\r\n\r\n_Personally identifiable information collection (via Services):_ Localytics requests that its Customers not provide to it PII about their End Users. However, Localytics states that End Users should be aware Customers may request PII for their own use for their mobile apps. To the extent that Localytics does receive PII from Customers, it pledges to maintain the confidentiality of the PII. Localytics does obtain information from website log files, and maintains the right to combine automatically collected log data with other information they have about you. \r\n\r\n_Information sharing:_ Localytics \"does not rent, sell or share PII, including your Personal Information, with any third parties\" expect with your express consent, or in the event of \"a merger, acquisition, or sale of all or a portion of its assets\", at which case you will be prominently notified \"of any change in ownership or uses of your Personal Information, as well as any choices you may have regarding your Personal Information\" [Localytics, 07](https://www.localytics.com/privacy-policy)\r\n\r\n## Relationships\r\n_Customers:_ Comcast / A&E / OLA / Runkeeper / Microsoft / CVS Pharmacy / The New York Times / Avis / Salesforce Marketing Cloud / Amazon / Wendy's / Zipcar [Localytics, 02](https://www.localytics.com) / Oracle Marketing Cloud / Adobe Marketing Cloud / Facebook Marketing Partners / Twitter \r\n\r\n_Alliance partners:_ Bitbang / Cainkade / Cube Loco / Epicfy / Exicon / Jackrabbit / Jargon / Kapitec Software / Keystone Solutions / Mobiquity / NorthBay / Northout / Pollfish / Rocket Insights / Scholarly iQ / Scientific Computers Ltd. / Semba Mobile / Social Fulcrum / Somo / SP2 Servi\u00e7os Empresariais Ltda / Stratigent / Vendus Labs Inc.\r\n\r\n_Technology partners:_ Aarki / adjust / Applift / Applovin / AppsFlyer / Apptimize / Apsalar / Branch Metrics / ExactTarget / Facebook / Fiksu / Greystripe / IBM PartnerWorld / Impact Radius / InMobi / Jampp / Kochava / Liftoff / Mag+ / Marketo / Method Mill / Millennial Media / NativeX / Optimizely / Phunware / Pinsight Media+ / Rocket Fule / StrikeAd / Supersonic / Tapstream / Taptica / Textur / TUNE / Twitter / Yozio [Localytics, 03](https://www.localytics.com/company/partners)\r\n\r\n## Details\r\n_Financial details:_ Localytics was founded in 2009 and and has raised over $69 million from funders [Localytics, 01](https://www.localytics.com/company/about); [Crunchbase, 01](https://www.crunchbase.com/organization/localytics).\r\n\r\n## References\r\n* _Localytics, 01._ [https://www.localytics.com/company/about](https://www.localytics.com/company/about) \r\n* _Localytics, 02._ [https://www.localytics.com](https://www.localytics.com) \r\n* _Localytics, 03._ [https://www.localytics.com/company/partners](https://www.localytics.com/company/partners) \r\n* _Localytics, 04._ [https://docs.localytics.com/dev/android.html#android](https://docs.localytics.com/dev/android.html#android) \r\n* _Localytics, 05._ [http://docs.localytics.com/dev/ios.html#identifying-users-ios](http://docs.localytics.com/dev/ios.html#identifying-users-ios) \r\n* _Localytics, 06._ [http://docs.localytics.com/dev/ios.html#uninstall-tracking-ios](http://docs.localytics.com/dev/ios.html#uninstall-tracking-ios) \r\n* _Localytics, 07._ [https://www.localytics.com/privacy-policy](https://www.localytics.com/privacy-policy](https://www.localytics.com/privacy-policy)", "network_signature": "analytics\\.localytics\\.com|manifest\\.localytics\\.com|profile\\.localytics\\.com|sdk-assets\\.localytics\\.com", "creation_date": "2017-09-24", "id": 16, "website": "http://localytics.com", "code_signature": "com.localytics.android."}, "17": {"name": "Braze (formerly Appboy)", "description": "## Primary Location\r\nUnited States (New York City) [Crunchbase, 01](https://www.crunchbase.com/organization/braze)\r\n\r\n## Website\r\n[https://www.braze.com](https://www.braze.com)\r\n\r\n## About\r\nBraze is a mobile marketing company that offers CRM solutions and mobile marketing automation software for mobile applications.\r\n\r\n## Ownership\r\nBraze\r\n\r\n## Documentation\r\n[https://www.braze.com/documentation/Android](https://www.braze.com/documentation/Android)\r\n\r\n## Products and Services\r\n_Cross-Channel Personalization:_ Target customers based on personal interests, location, past purchases, and more [Braze, 02](https://www.braze.com/product/cross-channel-personalization)\r\n\r\n_Identification and Analytics:_ Profile users, segment audiences, and utilize analytics for targeted advertisements [Braze, 02](https://www.braze.com/product/cross-channel-personalization); [Braze, 02](https://www.braze.com/product/cross-channel-personalization); [Braze, 01](https://www.braze.com); [Braze, 02](https://www.braze.com/product/cross-channel-personalization); [Braze, 03](https://www.slideshare.net/Appboy/appboy-urban-outfitters-placeiq-case-study)\r\n\r\n### Advertising Networks\r\n* Data sharing (vague) [Braze, 07](https://www.braze.com/product/integrations)\r\n\r\n## Privacy Policy\r\n_Data Collection:_ Braze collects data through the use of Developer apps. This includes:\r\n\r\n* Device information (OS version, IP address, carrier information, country code) and a unique Braze-generated ID\r\n* Application usage\r\n* Personally identifiable information: Braze \"may collect personally identifiable information shared with Developer Applications. We may also collect personally identifiable information from third parties used for authentication, such as when a user logs in to a Developer Application using a Facebook account, and from third party partners such as Facebook, Twitter, and Klout. Personally identifiable information collected may include information like name, email address, location, gender, interests, device, app usage, user ID, and contact information\".\r\n\r\n_Location Information:_ Braze \"may collect device location information if location services are enabled for any Developer Applications on the device. We use location information to provide Developers with information about the use of their Developer Applications\".\r\n\r\n_Information Use:_ Braze can \"use information we collect to provide partner Developers with information about usage of Developer Applications that integrate the Braze Service.\"\r\n\r\n_Data Sharing:_ Data is shared with app Developers \"in the form of aggregated, anonymous data about the way Developer Applications are used so that Developers can improve their respective Developer Applications.\" Braze may disclose information to third parties as required by law; to trusted service providers working on their behalf; to protect their rights, the safety of others, or in response to a government request; and in conjunction with a merger, acquisition, or sale of Braze.\r\n\r\n_Automatic Data Collection:_ Braze will \"automatically collect information about how Developer Applications are used, such as the frequency and duration of usage. This includes details about mobile devices, such as a unique Braze-generated ID for the mobile device. We share anonymous information about use of their respective Developer Applications with Developers, including which Developer Applications users have downloaded and the way those Developer Applications are used, which facilitates improvements to Developer Applications.\"\r\n\r\n_Opt-Out:_ End users may opt out of location collection by turning off location services for Developer apps in their mobile device. They can opt out of personally identifiable information by not providing that information to the Developer apps, and in the case of third parties, not providing that information to the third parties. Braze states, \"You can prevent collection of all information by uninstalling Developer Applications that integrate the Braze Service.\"\r\n\r\n_Data retention:_ Braze \"will retain information collected throughout the life of each user\u2019s use of Developer Applications except where prohibited by law.\" Users can email privacy@braze.com to request data deletion. Braze \"will keep anonymous information and may need to retain some identifying information to ensure that your request continues to be honored. Your information will be deleted from our active database but may remain in our archives. If we are required to maintain certain information about you, we will comply with your deletion request after fulfilling any legal requirements.\"\r\n\r\n_International Law:_ Braze complies with the U.S.-EU Safe Harbor Framework and the U.S.-Swiss Safe Harbor Framework.\r\n\r\n_Consent:_ Braze states, \"By using a Developer Application, you are consenting to our collection and processing of information as set forth in this Privacy Policy now and as amended by us. 'Processing' means using cookies on a computer/hand held device or using or touching information in any way, including, but not limited to, collecting, storing, deleting, using, combining and disclosing information, all of which activities will take place in the United States. If you reside outside the U.S. your information will be transferred to the U.S., and processed and stored there under U.S. privacy standards. By using the Application and providinginformation to us, you consent to such transfer to, and processing in, the U.S.\" [Braze, 11](https://www.braze.com/privacy).\r\n\r\n## Relationships\r\nABC News / Citi / GAP / Axel Springer / Dominos / Delivery Hero / Hearst / KFC / Microsoft / Nascar / iHeartMedia / RTR / Postmates / OKCupid / Urban Outfitters [Braze, 01](https://www.braze.com) / American Cancer Society / Dots / ibotta / 1-800-Flowers.com / Momondo [Braze, 02](https://www.braze.com/customers)\r\n\r\n## Details\r\n_Financial details:_ Braze was founded in 2011 and has raised over $95 million from funders. Braze changed its name from Appboy in 2017 [Crunchbase, 01](https://www.crunchbase.com/organization/braze).\r\n\r\n### Methods\r\n* Targeted advertisments [Braze, 01](https://www.braze.com) \r\n* Location-based targeting [Braze, 07](https://www.braze.com/product/integrations)\r\n* Real-world location targeting (including real-time targeting) [Braze, 02](https://www.braze.com/product/cross-channel-personalization) [Braze, 03](https://www.slideshare.net/Appboy/appboy-urban-outfitters-placeiq-case-study); [Braze, 07](https://www.braze.com/product/integrations); [Braze, 08](https://www.braze.com/academy/User_Targeting); [Braze, 09](https://www.braze.com/blog/appboy-location-targeting-tool); [Braze, 10](http://www.prweb.com/releases/2013/10/prweb11275487.htm)\r\n* Targeted advertising based on consumer actions [Braze, 02](https://www.braze.com/product/cross-channel-personalization)\r\n* Timed advertisements [Braze, 02](https://www.braze.com/product/cross-channel-personalization)\r\n* Targeting across devices and channels [Braze, 02](https://www.braze.com/product/cross-channel-personalization)\r\n* Real-time services [Braze, 04](https://www.braze.com/customers/postmates); [Braze, 05](https://www.braze.com/product/lifecycle-engagement-orchestration)\r\n* Artificial intelligence for analytics [Braze, 06](https://www.braze.com/product/optimization-ai)\r\n* Reports for clients [Braze, 06](https://www.braze.com/product/optimization-ai)\r\n\r\n## References\r\n* _Braze, 01._ [https://www.braze.com](https://www.braze.com)\r\n* _Braze, 02._ [https://www.braze.com/product/cross-channel-personalization](https://www.braze.com/product/cross-channel-personalization)\r\n* _Braze, 03._ [https://www.slideshare.net/Appboy/appboy-urban-outfitters-placeiq-case-study](https://www.slideshare.net/Appboy/appboy-urban-outfitters-placeiq-case-study) \r\n[Braze, 04._ [https://www.braze.com/customers/postmates](https://www.braze.com/customers/postmates)\r\n* _Braze, 05._ [https://www.braze.com/product/lifecycle-engagement-orchestration](https://www.braze.com/product/lifecycle-engagement-orchestration)\r\n* _Braze, 06._ [https://www.braze.com/product/optimization-ai](https://www.braze.com/product/optimization-ai)\r\n* _Braze, 07._ [https://www.braze.com/product/integrations](https://www.braze.com/product/integrations)\r\n* _Braze, 08._ [https://www.braze.com/academy/User_Targeting](https://www.braze.com/academy/User_Targeting)\r\n* _Braze, 09._ [https://www.braze.com/blog/appboy-location-targeting-tool](https://www.braze.com/blog/appboy-location-targeting-tool)\r\n* _Braze, 10._ [http://www.prweb.com/releases/2013/10/prweb11275487.htm](http://www.prweb.com/releases/2013/10/prweb11275487.htm)\r\n* _Braze, 11._ [https://www.braze.com/privacy](https://www.braze.com/privacy)\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/braze](https://www.crunchbase.com/organization/braze)\r\n\r\n## External Links\r\n* _Crunchbase (Braze):_ [https://www.crunchbase.com/organization/braze](https://www.crunchbase.com/organization/braze)", "network_signature": "appboy\\.com", "creation_date": "2017-09-24", "id": 17, "website": "https://www.braze.com", "code_signature": "com.appboy"}, "18": {"name": "MParticle", "description": "## Primary location\r\nUnited States (New York) [Crunchbase, 01](https://www.crunchbase.com/organization/mparticle)\r\n\r\n## Website\r\n[https://www.mparticle.com](https://www.mparticle.com)\r\n\r\n## About\r\nmParticle offers \"a customer data platform built for mobile and native apps across all devices\" [mParticle, 04](https://www.mparticle.com/news/mparticle-raises-15-million-series-a-led-by-social-capital)\r\n\r\n## Ownership\r\nmParticle\r\n\r\n## Documentation\r\n[https://docs.mparticle.com/developers/sdk/android/getting-started](https://docs.mparticle.com/developers/sdk/android/getting-started)\r\n\r\n## Products and Services\r\nmParticle's core features include:\r\n\r\n* _Simplicity and organization:_ Clients \"collect and control all\" their \"customer data through a single API\"\r\n* _Cross-device identification:_ \"Recognize customers at every step of the buying process\"\r\n* _Market orchestration:_ \"Personalize experiences across channels, partners, and screens\"\r\n\r\nProducts and services include:\r\n\r\n* _Customer Data Platform (CDP):_\r\n* * _Understand the entire buying process:_ Merge online and offline data through collection of digital and offline customer journey data; stream it to platforms and systems\r\n* * _Understand and predict customers:_ \"Link customer identities and profile information across internal and external systems for...customer insights\"\r\n* * _Integration:_ \"Integrate with 175+ of the leading marketing, analytics and data warehousing solutions\"\r\n* * _Control your data:_ \"Set rules to transform and filter data without having to make changes to client-side code, and monitor all integrations in real-time\"\r\n* * * _IDSync:_ \"Create fine-grained identity mappings and logic to meet nuanced business requirements and share them across providers\"\r\n* * * _AudienceSync:_ \"Transform raw data into actionable audience segments and sync them across paid media, CRM, and other platforms\"\r\n* * * _Enrichment:_ \"Manage integrations with third-party profile enrichment providers and supplement existing data with additional customer insights\"\r\n* * * _Warehouses:_ \"Instantly load data into Amazon Redshift, BigQuery and other data warehouses, BI tools, and machine learning extensions\" [mParticle, 05](https://www.mparticle.com/product)\r\n* _Enhance analytics:_ \"Unify data around a single customer profile to fuel better insights and attribution reporting\" \r\n* _Segmentation:_ Build and sync audience segments across platforms [mParticle, 06](https://www.mparticle.com/marketer)\r\n* _Data integration:_ \"Unite disparate data sources to better understand the customer and key business metrics\" [mParticle, 07](https://www.mparticle.com/productmanager)\r\n* _Cross-device identification:_ \"Improve media measurement, customer journey analytics, lifetime value modeling, and more by resolving customer identity data across disparate sources\" [mParticle, 08](https://www.mparticle.com/analytics)\r\n\r\n* _Location tracking with SafeGraph integration:_ By integrating with SafeGraph, clients have the tools to track user physical locations, and harness machine learning to analyze the data: \"mParticle customers can now create, monitor, and control server-to-server integrations with SafeGraph via the mParticle platform. With the integration enabled, brands can stream real-time mobile location data directly from their apps to SafeGraph, which will then translate long/lat coordinates into known locations and use machine learning to help brands understand their customers offline movement patterns\" [mParticle, 10](https://www.mparticle.com/integrations/integration-safegraph)\r\n\r\n## Privacy Policy\r\n\r\n_Data Collection:_ Clients \"collect information based on User interaction with their mobile application(s), mobile website(s) or other digital properties where Clients have integrated with the\" mParticle Platform. mParticle calls this \"Client Digital Properties\". Data collected through \"via Client Digital Properties for the Platform includes: the date/time for a visit to a Client Digital Property, referrer information such as what search engine and search keywords Users may have used to get to a Client Digital Property, information about the browser or device your User is on such as their Operating System, as well as the city/country location of Users, and any pseudonymous tokens and mobile advertising IDs (e.g., IDFA in iOS). In addition, our Clients can choose what other User data they want to collect and store on the platform such as an IP address, location information, a User\u2019s age, user names, real names, email addresses and other custom data points as determined by each Client.\" \r\n\r\nmParticle places restrictions on data practices. They state, \"We contractually prohibit Clients from placing sensitive information (e.g., passwords, authentication credentials, credit cards, social security or driver\u2019s license numbers) or information that is deemed sensitive by applicable law or self-regulatory codes such as the Digital Advertising Alliance. mParticle functions strictly as the data processing agent of our Clients. Accordingly, other than those aforementioned restrictions, the data stored on the Platform is subject to the privacy policies of each Client\".\r\n\r\n_Information sharing:_ Third party sharing may proceed as follows:\r\n\r\n* Third-party agents working as subprocessors (who must adhere to mParticle's privacy policy)\r\n* \"To protect the rights and property of mParticle, our agents, Clients and others \"\r\n* \"In an emergency, including protection of the personal safety of any person\"\r\n* \"For the purposes of a business deal (or negotiation of a business deal) involving sale or transfer of all or a part of our business or assets\"\r\n* In response to a lawful request by public authorities\r\n* mParticle \"may also share aggregate or anonymous information without restriction\"\r\n\r\n_Security:_ mParticle asserts that they take reasonable steps to protect information. They state, \"We encrypt transmission of data on pages where you provide payment information or otherwise provide sensitive information. However, no security or encryption method can be guaranteed to protect information from hackers or human error. Information we collect may be stored or processed on computers located in any country where we do business\".\r\n\r\n_Data retention:_ mParticle \"retains Client data for so long as you remain are a Client and will delete Client\u2019s information within 12 months of either party\u2019s termination of applicable Client agreement upon written request. We retain User level data on the Platform as directed by our Clients and for a reasonable time thereafter for audit purposes and as otherwise required by law\".\r\n\r\n_Opt-out:_ mParticle has an email-based opt-out procedure for Clients, but does not list opt-out procedures for End Users on its Privacy Policy web page. The opt-out procedure for Clients is as follows: \"You may opt out of receiving promotional emails from mParticle by following the instructions in those emails. If you opt out, we may still send you non-promotional emails, such as emails about your mParticle projects or our ongoing business relationship. An individual wishing to limit the use or sharing of their data should contact email support@mparticle.com. mParticle will respond within ninety (90) days to any request to delete your information. Individuals who have provided information directly to one of mParticle\u2019s Clients must send follow-up requests to change or delete such information to that particular mParticle Client\"\r\n\r\n_International law:_ mParticle complies with the EU-US Privacy Shield Framework and the Swiss-US Privacy Shield Framework [mParticle, 12](https://www.mparticle.com/privacypolicy).\r\n\r\n## Relationships\r\n_Customers:_ Airbnb / King / Spotify / Jet / EA / SeatGeek / Ticketmaster / Gilt / Bleacher Report / Chick-fil-A / Postmates / Lilly Pulitzer [mParticle, 01](https://www.mparticle.com) / Venmo / Via / Stash / Starwood Preferred Guest / Draft / StockTwits / OKCupid / NBCUniversal / Turner / theSkimm / Lakes Fifth Avenue / Lululemon Athletica / Goat / Live Nation [mParticle, 02](https://www.mparticle.com/customers) / Walmart [mParticle, 03](https://www.mparticle.com/news/mparticle-gartner-magic-quadrant-digital-marketing-hubs) / iHeartRadio / Starwood / SoulCycle [mParticle, 04](https://www.mparticle.com/news/mparticle-raises-15-million-series-a-led-by-social-capital) \r\n\r\n_Integrations:_ mParticle offers \"Full-featured integrations with the top marketing, advertising, analytics, and data warehousing platforms\". Integrations include: Amazon Redshift / Amplitude / Appboy / Kahuna / Kochava / SendGrid [mParticle, 04](https://www.mparticle.com/news/mparticle-raises-15-million-series-a-led-by-social-capital) / Facebook / Snap / Twitter / TUNE / Adobe Marketing Cloud / Oracle Marketing Cloud / Salesforce Marketing Cloud / Zendesk / MailChimp / Google Analytics / Looker / Mixpanel / comScore [mParticle, 01](https://www.mparticle.com). For a detailed database of integrations, see [mParticle, 09](https://www.mparticle.com/integrations).\r\n\r\n_Key partnerships:_ Some key partnerships include integration with SafeGraph [mParticle, 10](https://www.mparticle.com/integrations/integration-safegraph) and Salesforce Marketing Cloud [mParticle, 11](https://www.mparticle.com/blog/salesforce-partnership).\r\n\r\n## Details\r\n_Financial details:_ mParticle was founded in 2013 and has raised over $76 million from funders [Crunchbase, 01](https://www.crunchbase.com/organization/mparticle). \r\n\r\n_Location-based tracking:_ Via, an \"on-demand ride-sharing app based in NYC\", integrates with mParticle for geofencing services [mParticle, 13](https://www.mparticle.com/blog/via-predictive-analytics-radar).\r\n\r\n## References\r\n* _mParticle, 01._ [https://www.mparticle.com](https://www.mparticle.com) \r\n* _mParticle, 02._ [https://www.mparticle.com/customers](https://www.mparticle.com/customers) \r\n* _mParticle, 03._ [https://www.mparticle.com/news/mparticle-gartner-magic-quadrant-digital-marketing-hubs](https://www.mparticle.com/news/mparticle-gartner-magic-quadrant-digital-marketing-hubs) \r\n* _mParticle, 04._ [https://www.mparticle.com/news/mparticle-raises-15-million-series-a-led-by-social-capital](https://www.mparticle.com/news/mparticle-raises-15-million-series-a-led-by-social-capital) \r\n* _mParticle, 05._ [https://www.mparticle.com/product](https://www.mparticle.com/product) \r\n* _mParticle, 06._ [https://www.mparticle.com/marketer](https://www.mparticle.com/marketer) \r\n* _mParticle, 07._ [https://www.mparticle.com/productmanager](https://www.mparticle.com/productmanager) \r\n* _mParticle, 08._ [https://www.mparticle.com/analytics](https://www.mparticle.com/analytics) \r\n* _mParticle, 09._ [https://www.mparticle.com/integrations](https://www.mparticle.com/integrations) \r\n* _mParticle, 10._ [https://www.mparticle.com/integrations/integration-safegraph](https://www.mparticle.com/integrations/integration-safegraph) \r\n* _mParticle, 11._ [https://www.mparticle.com/blog/salesforce-partnership](https://www.mparticle.com/blog/salesforce-partnership)\r\n\r\n## External Links\r\n* _Crunchbase (mParticle):_ [https://www.crunchbase.com/organization/mparticle](https://www.crunchbase.com/organization/mparticle)", "network_signature": "mparticle\\.com", "creation_date": "2017-09-24", "id": 18, "website": "http://MParticle.com", "code_signature": "com.mparticle"}, "20": {"name": "S4M", "description": "## Websites\r\n * http://www.s4m.io/", "network_signature": "sam4m\\.com|s4m.io", "creation_date": "2017-09-24", "id": 20, "website": "http://www.s4m.io/", "code_signature": "com.sam4mobile."}, "22": {"name": "Sizmek", "description": "\"Sizmek (NASDAQ: SZMK) fuels digital advertising campaigns for advertisers and agencies around the world with the most cutting-edge technology to engage audiences across any screen. ...Sizmek has proudly pioneered industry firsts in digital, including rich media, video and online targeted advertising across channels. Sizmek's open ad management stack delivers the most creative and impactful multiscreen digital campaigns, across mobile, display, rich media, video and social, all powered by an unrivaled data engine.\"\r\n\r\n[Privacy Policy](http://www.sizmek.com/privacy-policy/)\r\n\r\n## Data Collected\r\n * Anonymous (Browser Information, Date/Time, Demographic Data, Hardware/Software Type, Page Views )\r\n * Pseudonymous (IP Address (EU PII), Location Based Data)\r\n\r\n## Data Sharing\r\nAnonymous data is shared with 3rd parties., PII data is shared with 3rd parties.\r\n\r\n## Data Retention\r\n0-3 Months\r\n\r\n[source Ghostery](https://apps.ghostery.com/en/apps/sizmek)", "network_signature": "serving-sys\\.com", "creation_date": "2017-09-24", "id": 22, "website": "https://www.sizmek.com", "code_signature": ".sizmek."}, "23": {"name": "Batch", "description": "## Websites\r\n * https://batch.com", "network_signature": "batch\\.com", "creation_date": "2017-09-24", "id": 23, "website": "https://batch.com", "code_signature": "com.batch.android."}, "24": {"name": "Sync2Ad", "description": "## Websites\r\n * https://www.sync2ad.com/\r\n\r\n## Infos\r\n * https://www.crunchbase.com/organization/sync2television#/entity", "network_signature": "sync2ad\\.com", "creation_date": "2017-09-24", "id": 24, "website": "https://www.sync2ad.com/", "code_signature": "com.visiware.sync2ad.dmp."}, "25": {"name": "Flurry", "description": "## Primary Location\r\nUnited States\r\n\r\n## Website\r\n[https://developer.yahoo.com](https://developer.yahoo.com)\r\n\r\n## About\r\nFlurry is part of the Yahoo Developer network suite. Flurry's product, Flurry Analytics, offers mobile analytics, monetization, and advertising services [Yahoo, 01](https://developer.yahoo.com/analytics); [Yahoo, 14](https://developer.yahoo.com/flurry/docs); [Wikipedia, 01](https://en.wikipedia.org/wiki/Flurry_(company)).\r\n\r\n## Ownership\r\nOath Inc. (subsidiary of Verizon Communications; Oath includes Yahoo and AOL) [Wikipedia, 01](https://en.wikipedia.org/wiki/Oath_Inc.); [Ars Technica, 01](https://arstechnica.com/information-technology/2017/06/oath-verizon-completes-4-5-billion-buy-of-yahoo-and-merges-it-with-aol)\r\n\r\n## Products and Services\r\nFlurry Analytics:\r\n\r\n* Utilizes tracking to analyze user interaction, correlating with other users\r\n* Groups and correlates user data\r\n* Tracks in-app actions of users\r\n* Segments users\r\n* Funnels users into specific in-app paths\r\n* Monitors user churn and retention\r\n* Determines user \"personas\"\r\n* Predicts user demographics\r\n* Monitors user acquisition efforts\r\n* Measures the impact of advertising campaigns or channels [Yahoo, 02](https://developer.yahoo.com/analytics/features.html).\r\n\r\nAnalytics services cover in-app behaviors like \"making a purchase, playing a song, or sharing on Facebook\" [Yahoo, 03](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/events/android). \r\n\r\nFlurry Pulse provides \"the ability to share your app data with integrated partners\" [Yahoo, 13](https://developer.yahoo.com/flurry-pulse). \r\n\r\n## Privacy Policy\r\n_Data sharing:_ As of September 18, 2017, Yahoo stated that Yahoo and Oath \"plan to share some user information within the Verizon family of companies which will enable us to integrate our business, allowing us to coordinate more and improve your experiences\". Yahoo further explained, \"We will share the same information that our companies have previously collected and used for the development and operation of our products and services. This may include your account registration information (such as your user ID, gender, name, email address, postcode & age), your content and advertising interests, content associated with your account, the types of services you use and how you engage with them, cookie and device IDs, IP addresses, geolocation information and activity information from across our websites, apps, software and other services. All of the information that we collect about you may be shared across the various Oath brands and within our Verizon family of companies\" [Yahoo, 02](https://policies.yahoo.com/ie/en/yahoo/privacy/euoathnoticefaq). \r\n\r\nYahoo shares data with third parties, and allows third parties to place tracking technologies like cookies, web beacons, applicaitons (or \"widgets), SDKs, and similar technologies on Yahoo sites and apps. Yahoo adds that \"We do not share your personally identifiable information from your Yahoo account with our advertisers or our partners as part of our analytics programs. We may, however, share pseudonymous information - including demographic information - with our advertisers or partners\" [Yahoo, 04](https://policies.yahoo.com/ie/en/yahoo/privacy/topics/thirdparties/index.htm). \r\n\r\n_Opt-out:_ Yahoo offers an option to opt out of \"interest-based advertising, analysis of communications content for advertising purposes, and the sharing of your information with partners for data matching and appends using the tools\" on their Ad Interest Manager website. This includes \"Your advertising choices\" both \"across the web\" and \"On Yahoo\" [Yahoo, 05](https://aim.yahoo.com/aim/ie/en/optout). Their Privacy Controls page offers settings for Marketing Preferences, Ad Interest Manager, Content preferences, Search history, and Location management [Yahoo, 06](https://policies.yahoo.com/ie/en/yahoo/privacy/tools/index.htm). \r\n\r\n\"You must allow cookies from Yahoo in order to opt out. To make your opt-out apply to every computer that you use, you must be signed in to your Yahoo account\". Yahoo's opt out page also includes \"Your interest categories\" [Yahoo, 05](https://aim.yahoo.com/aim/ie/en/optout).\r\n\r\nYahoo offers opt-out options for third parties, including the recommendation to visit their websites individually [Yahoo, 04](https://policies.yahoo.com/ie/en/yahoo/privacy/topics/thirdparties/index.htm).\r\n\r\n## Relationships\r\n_Yahoo partners:_ Adxpose (comScore product) / Audience Science / comScore/ScorecardResearch / DoubleVerify / Integral Ads / KN Dimestore / Nielsen / Facebook / Google+ / LinkedIn / Pinterest / Twitter / 30 Boxes / Amazon / Basil (Backstage Technologies) / Bunchball Games / ChitChat (Monusoft) / CoverGirl Beauty Consultant Live Chat / Dropbox / eBay / enDICEr / Love Match/Fun Center (B4U.com) / NDCSA / NewsGator / OtherInBox / Pandaf Games / StumbleUpon / WackyB Twitter Sync / WebEx Co-Browse / YouSendIt / ABC / Astrology.com/iVillage / Cars.com / Healthline / Match.com / Monster Inc. / Nokia Maps / Orbitz / PriceGrabber / Shopzilla / Spotify / Team Fan Shop (Pro Football Weekly) / Tenor / TripAdvisor / TrueCar / Turner / Vast (Autos) / Zillow / ABC News / Blastro.com / Blip.tv / CNBC / CNN / CollegeHumor.com / Dailymotion / Ebaumsworld.com / Ehow.com / Fox News / Gametrailers.com / Good Morning America / Guardian News / Hulu / Metacafe / Metatube.com / Myspace.com / NBC / NFL / PBS / Ustream / Vevo / Videobash.com / Vimeo / Washington Post / Worldstarhiphop.com / YouTube / Chitika / Google / Media.net / Microsoft / NetSeer / Yandex / Abaca Technology Corporation / AOL / Authentication Metrics / Aviary / Bankrate / Bloomreach (Commerce SEO) / Branch.io / Detroit Trading Company / Dropbox / Google / HelloWorld, Inc. / HortonWorks / Lashback / Luminate / Manilla / Outbrain / Paypal / Project Slice / SigFig / Symantec / Trend Micro / Truedomain / Urban Airship / Vantage (Yahoo Real Estate) [Yahoo, 04](https://policies.yahoo.com/ie/en/yahoo/privacy/topics/thirdparties/index.htm)\r\n\r\n## Details\r\n_Financial Details:_ Flurry was founded in 2005. By December 2013, it had raised $62.5 million [TechCrunch, 01](https://techcrunch.com/2013/12/06/flurry-funding). On July 21, 2014 Yahoo bought Flurry for a reported $200-300 million [TechCrunch, 02](https://techcrunch.com/2014/07/21/yahoo-is-buying-mobile-analytics-firm-flurry-for-north-of-200m). Flurry partnered with Research Now, a digital data collecting firm, in 2014, for the purpose of \"to track mobile app users, offline\" [AdAge, 01](http://adage.com/article/digital/flurry-research-build-mobile-app-advertising-database/292287). \r\n\r\n_Scope:_ By December 6, 2013, Flurry told TechCrunch \"400,000 apps are using its analytics product, with 20,000 additions each month, and that it's tracking activity from 1.2 billion smartphones and tablets. It also said that it's working with 125,000 developers\" [TechCrunch, 01](https://techcrunch.com/2013/12/06/flurry-funding). \r\n\r\n_Additional services:_ Additional Flurry Analytics features for Android include:\r\n\r\n* Revenue Analytics [Yahoo, 07](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/revenue/android)\r\n* Crash Analytics [Yahoo, 08](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/trackcrashes/android)\r\n* Track Geographic Location (at the city level where the app is being used; or, without that level of detail, the country level as based on IP address)\r\n* Track user ID and demographics\r\n* Track page views [Yahoo, 09](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/technicalquickstart/android)\r\n* Object-based API for Native, Interstatial and Banner ads [Yahoo, 10](https://developer.yahoo.com/flurry/docs/publisher/code/android-ad-publishing)\r\n* User paths reporting [Yahoo, 11](https://developer.yahoo.com/flurry/docs/analytics/lexicon/analyticsusage)\r\n* Utilizes mobile SDK in apps to inject advertising, including video: \"Monetize your app with native and video ads from Yahoo, Flurry, and BrightRoll advertisers\" [Yahoo, 12](https://developer.yahoo.com/monetize)\r\n\r\n## References\r\n* _AdAge, 01_. [http://adage.com/article/digital/flurry-research-build-mobile-app-advertising-database/292287](http://adage.com/article/digital/flurry-research-build-mobile-app-advertising-database/292287) \r\n* _Ars Technica, 01_. [https://arstechnica.com/information-technology/2017/06/oath-verizon-completes-4-5-billion-buy-of-yahoo-and-merges-it-with-aol](https://arstechnica.com/information-technology/2017/06/oath-verizon-completes-4-5-billion-buy-of-yahoo-and-merges-it-with-aol) \r\n* _TechCrunch, 01_. [https://techcrunch.com/2013/12/06/flurry-funding](https://techcrunch.com/2013/12/06/flurry-funding) \r\n* _TechCrunch, 02_. [https://techcrunch.com/2014/07/21/yahoo-is-buying-mobile-analytics-firm-flurry-for-north-of-200m](https://techcrunch.com/2014/07/21/yahoo-is-buying-mobile-analytics-firm-flurry-for-north-of-200m) \r\n* _Yahoo, 01_. [https://developer.yahoo.com/analytics](https://developer.yahoo.com/analytics) \r\n* _Yahoo, 02_. [https://policies.yahoo.com/ie/en/yahoo/privacy/euoathnoticefaq](https://policies.yahoo.com/ie/en/yahoo/privacy/euoathnoticefaq) \r\n* _Yahoo, 03_. [https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/events/android](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/events/android) \r\n* _Yahoo, 04_. [https://policies.yahoo.com/ie/en/yahoo/privacy/topics/thirdparties/index.htm](https://policies.yahoo.com/ie/en/yahoo/privacy/topics/thirdparties/index.htm) \r\n* _Yahoo, 05_. [https://aim.yahoo.com/aim/ie/en/optout](https://aim.yahoo.com/aim/ie/en/optout) \r\n* _Yahoo, 06_. [https://policies.yahoo.com/ie/en/yahoo/privacy/tools/index.htm](https://policies.yahoo.com/ie/en/yahoo/privacy/tools/index.htm) \r\n* _Yahoo, 07_. [https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/revenue/android](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/revenue/android) \r\n* _Yahoo, 08_. [https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/trackcrashes/android](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/trackcrashes/android) \r\n* _Yahoo, 09_. [https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/technicalquickstart/android](https://developer.yahoo.com/flurry/docs/analytics/gettingstarted/technicalquickstart/android) \r\n* _Yahoo, 10_. [https://developer.yahoo.com/flurry/docs/publisher/code/android-ad-publishing](https://developer.yahoo.com/flurry/docs/publisher/code/android-ad-publishing) \r\n* _Yahoo, 11_. [https://developer.yahoo.com/flurry/docs/analytics/lexicon/analyticsusage](https://developer.yahoo.com/flurry/docs/analytics/lexicon/analyticsusage) \r\n* _Yahoo, 12_. [https://developer.yahoo.com/monetize](https://developer.yahoo.com/monetize) \r\n* _Yahoo, 13_. [https://developer.yahoo.com/flurry-pulse](https://developer.yahoo.com/flurry-pulse) \r\n* _Yahoo, 14_. [https://developer.yahoo.com/flurry/docs](https://developer.yahoo.com/flurry/docs)\r\n\r\n## External links\r\n* _Ghostery_: [https://apps.ghostery.com/apps/flurry](https://apps.ghostery.com/apps/flurry) \r\n* _Wikipedia_: [https://en.wikipedia.org/wiki/Flurry_(company)](https://en.wikipedia.org/wiki/Flurry_(company)) \r\n* _Flurry FAQ_: [https://developer.yahoo.com/flurry/docs/faq](https://developer.yahoo.com/flurry/docs/faq)\r\n* _AppBrain_: [https://www.appbrain.com/dev/Yahoo/](https://archive.is/7BNpX)", "network_signature": "flurry\\.com", "creation_date": "2017-09-24", "id": 25, "website": "https://developer.yahoo.com/flurry/", "code_signature": "com.flurry."}, "26": {"name": "HockeyApp", "description": "## Primary Location\r\nMicrosoft: United States (Seattle) / Bit Stadium: Germany (Stuttgart) [Crunchbase, 01](https://www.crunchbase.com/organization/bit-stadium-gmbh)\r\n\r\n## Website\r\n[https://www.hockeyapp.net](https://www.hockeyapp.net)\r\n\r\n## About\r\nHockeyApp is utilized for crash reporting, app distribution, user feedback, and the collection of user metrics. \"HockeyApp is a service for app developers to support them in various aspects of their development process, including the management and recruitment of testers, the distribution of apps and the collection of crash reports.\" [HockeyApp 01](https://support.hockeyapp.net/kb/general-account-management-2/general-questions)\r\n\r\n## Ownership\r\nBit Stadium is a subsidiary of Microsoft [Bloomberg, 01](https://www.bloomberg.com/research/stocks/private/snapshot.asp?privcapId=279701634)\r\n\r\n## Documentation\r\n[https://support.hockeyapp.net/kb/client-integration-android/hockeyapp-for-android-sdk](https://support.hockeyapp.net/kb/client-integration-android/hockeyapp-for-android-sdk)\r\n\r\n## What it does\r\nAnalyzes user behavior and app usage. \"Understand user behavior to improve your\r\napp. Track app adoption through daily active users, monthly active users, and net\r\nnew users. Measure customer engagement through session count and verify your apps\r\nreliability day by day with Crash Free Users.\" [HockeyApp, 02](https://www.hockeyapp.net/features/user-metrics/)\r\n\r\n\"When enabled, the SDK anonymously tracks the users of your app by creating a UUID that is then securely stored. The UUID is securely stored in the preferences of the client app.\" [HockeyApp, 03](https://support.hockeyapp.net/kb/app-management-2/what-data-is-collected-with-the-hockeysdks-2#data-collected-for-the-user-metrics-features)\r\n\r\n## Privacy Policy\r\n\r\nMicrosoft Privacy Statement [https://privacy.microsoft.com/en-us/PrivacyStatement](https://privacy.microsoft.com/en-us/PrivacyStatement)\r\n\r\nDevelopers can opt out of statistical analysis of their app's users. \"Just in case you want to opt-out of the automatic collection of anonymous users and sessions statistics, there is a way to turn this functionality off at any time.\" [HockeyApp, 04](https://support.hockeyapp.net/kb/general-account-management-2/getting-started-with-user-metrics)\r\n\r\n## Details\r\n\r\nHockeyApp was launched in 2012. It was acquired by Microsoft in 2014 [Crunchbase, 01](https://www.crunchbase.com/organization/bit-stadium-gmbh). The company existed in some form in 2011, with Microsoft as a customer [HockeyApp, 05](https://www.hockeyapp.net/blog/2014/12/11/hockeyapp-joins-microsoft.html).\r\n\r\n\"HockeyApp does not collect any PII (Personable Identifiable Information) and the user tracking is done anonymously... Keep in mind that whenever the HockeySDK sends metric data to our backend, a corresponding app version gets automatically added to the app.\" [HockeyApp, 04](https://support.hockeyapp.net/kb/general-account-management-2/getting-started-with-user-metrics)\r\n\r\n\"You can get more insights into user behavior for the testers of your app. You can see basic user metrics, gauge customer engagements and even check your app\u2019s reliability throughout the day. More than that, you can drill down on the users that have experienced a particular crash type or a crash that happened during a specific time period. This will help you know if the crash has affected a lot of people over a cross section of your users or if there are specific groups of people who experience the same type of crashes repeatedly.\" [Stackify, 01](https://stackify.com/what-is-hockeyapp/)\r\n\r\n## References\r\n* _HockeyApp, 01._ [https://support.hockeyapp.net/kb/general-account-management-2/general-questions](https://support.hockeyapp.net/kb/general-account-management-2/general-questions)\r\n* _HockeyApp, 02._ [https://www.hockeyapp.net/features/user-metrics/](https://www.hockeyapp.net/features/user-metrics/)\r\n* _HockeyApp, 03._ [https://support.hockeyapp.net/kb/app-management-2/what-data-is-collected-with-the-hockeysdks-2#data-collected-for-the-user-metrics-features](https://support.hockeyapp.net/kb/app-management-2/what-data-is-collected-with-the-hockeysdks-2#data-collected-for-the-user-metrics-features)\r\n* _HockeyApp, 04._ [https://support.hockeyapp.net/kb/general-account-management-2/getting-started-with-user-metrics](https://support.hockeyapp.net/kb/general-account-management-2/getting-started-with-user-metrics)\r\n* _HockeyApp, 05._ [https://www.hockeyapp.net/blog/2014/12/11/hockeyapp-joins-microsoft.html](https://www.hockeyapp.net/blog/2014/12/11/hockeyapp-joins-microsoft.html)\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/bit-stadium-gmbh](https://www.crunchbase.com/organization/bit-stadium-gmbh)\r\n* _Bloomberg, 01._ [https://www.bloomberg.com/research/stocks/private/snapshot.asp?privcapId=279701634](https://www.bloomberg.com/research/stocks/private/snapshot.asp?privcapId=279701634)\r\n* _Stackify, 01._ [https://stackify.com/what-is-hockeyapp/](https://stackify.com/what-is-hockeyapp/)\r\n\r\n## External Links\r\n* _Crunchbase (HockeyApp):_ [https://www.crunchbase.com/organization/bit-stadium-gmbh](https://www.crunchbase.com/organization/bit-stadium-gmbh)\r\n* _Wikipedia (List of mergers and acquisitions by Microsoft):_ [https://en.wikipedia.org/wiki/List_of_mergers_and_acquisitions_by_Microsoft#cite_note-195](https://en.wikipedia.org/wiki/List_of_mergers_and_acquisitions_by_Microsoft#cite_note-195)\r\n* _Owler company profile:_ [https://www.owler.com/iaApp/1149223/hockeyapp-company-profile](https://www.owler.com/iaApp/1149223/hockeyapp-company-profile)", "network_signature": "hockeyapp\\.net", "creation_date": "2017-09-24", "id": 26, "website": "http://hockeyapp.net", "code_signature": "net.hockeyapp."}, "27": {"name": "Google CrashLytics", "description": "## Primary Location\r\nUnited States (Boston) [Crunchbase, 01](https://www.crunchbase.com/organization/crashlytics)\r\n\r\n## Website\r\n[http://try.crashlytics.com](http://try.crashlytics.com)\r\n\r\n## About\r\nCrashlytics offers a crash reporting solution for app developers.\r\n\r\n## Ownership\r\nGoogle [Recode, 01](https://www.recode.net/2017/1/18/14313164/google-twitter-acquisition-fabric-crashlytics)\r\n\r\n## Documentation\r\n[https://fabric.io/kits/android/crashlytics](https://fabric.io/kits/android/crashlytics)\r\n\r\n## Products and Services\r\nCrashlytics offers a variety of services for app developers. Crashlytics:\r\n\r\n* Receives and analyzes app crash reports which may contain user and device-specific data.\r\n\r\n* Performs analytics on app logs \"even the exact line of code your app crashed on\" [Crashlytics, 03](https://fabric.io/kits/ios/crashlytics)\r\n\r\n* Performs analytics on app users and utilizes social media advertising. \"Get insight into your users, what they\u2019re doing, and inject live social content to delight them\" [Fabric, 01](https://get.fabric.io)\r\n\r\n* Performs cross-device user identity and authentication via \"Fabric\" [Wired, 01](https://www.wired.com/2014/10/twitter-fabric-sdk)\r\n\r\n## Privacy Policy\r\nCrashlytics Privacy Policy can be viewed at [Crashlytics, 04](https://try.crashlytics.com/terms/privacy-policy.pdf).\r\n\r\n## Relationships\r\n_Customers:_ Square / Walmart / Paypal / Yelp / Paperless Post / Blackboard / Path / Groupon / Domino's / Expedia / Orbitz / Kayak / 5 Infinity / Waze / OpenTable [Crashlytics, 01](https://try.crashlytics.com)\r\n\r\n_Integrations:_ Redmine / Pivotal Tracker / Jira / PagerDuty / Asana / OpsGenie / GitHub / Campfire / Sprintly / Hall / YouTrack / Bitbucket / Trello / FogBugz / Zoho / Slack / GitLab / Asana / YouTrack / Sprint.ly / Bitbucket / HipChat [Crashlytics, 02](http://try.crashlytics.com/integrations)\r\n\r\n## Details\r\n_Financial details:_ Crashlytics was founded in 2011 and had raised $6 million from funders. Twitter acquired Crashlytics in in 2013 for a reported $38 million [Crunchbase, 01](https://www.crunchbase.com/organization/crashlytics); [Boston Business Journal, 01](https://www.bizjournals.com/boston/blog/techflash/2013/10/twitter-crashlytics-bluefin-labs.html). In 2017, Google acquired Twitter's developer suite Fabric, which included Crashlytics, for integration into Google Firebase. The details of the deal were not publicly disclosed [Recode, 01](https://www.recode.net/2017/1/18/14313164/google-twitter-acquisition-fabric-crashlytics). Crashlytics is a business division of Google, Inc. [Crashlytics, 04](https://try.crashlytics.com/terms/privacy-policy.pdf).\r\n\r\n## References\r\n* _Boston Business Journal, 01._ [https://www.bizjournals.com/boston/blog/techflash/2013/10/twitter-crashlytics-bluefin-labs.html](https://www.bizjournals.com/boston/blog/techflash/2013/10/twitter-crashlytics-bluefin-labs.html) \r\n* _Crashlytics, 01._ [https://try.crashlytics.com](https://try.crashlytics.com) \r\n* _Crashlytics, 02._ [http://try.crashlytics.com/integrations](http://try.crashlytics.com/integrations) \r\n* _Crashlytics, 03._ [https://fabric.io/kits/ios/crashlytics](https://fabric.io/kits/ios/crashlytics) \r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/crashlytics](https://www.crunchbase.com/organization/crashlytics) \r\n* _Fabric, 01._ [https://get.fabric.io](https://get.fabric.io) \r\n* _Recode, 01._ [https://www.recode.net/2017/1/18/14313164/google-twitter-acquisition-fabric-crashlytics](https://www.recode.net/2017/1/18/14313164/google-twitter-acquisition-fabric-crashlytics) \r\n* _Wired, 01._ [https://www.wired.com/2014/10/twitter-fabric-sdk](https://www.wired.com/2014/10/twitter-fabric-sdk) \r\n\r\n## External Links\r\n* _Crunchbase (Crashlytics):_ [https://www.crunchbase.com/organization/crashlytics](https://www.crunchbase.com/organization/crashlytics) \r\n* _Wikipedia (Crashlytics):_ [https://en.wikipedia.org/wiki/Crashlytics](https://en.wikipedia.org/wiki/Crashlytics) \r\n* _TechCrunch, 01:_ [https://techcrunch.com/2013/01/28/twitter-acquires-crash-reporting-tool-crashalytics-development-of-the-product-will-continue-unabated](https://techcrunch.com/2013/01/28/twitter-acquires-crash-reporting-tool-crashalytics-development-of-the-product-will-continue-unabated) \r\n* _Fabric, 02:_ [https://blog.twitter.com/developer/en_us/a/2015/fabric-leading-the-sdk-market-in-performance-and-mobile-analytics.html](https://blog.twitter.com/developer/en_us/a/2015/fabric-leading-the-sdk-market-in-performance-and-mobile-analytics.html) \r\n* _The Register, 01:_ [https://www.theregister.co.uk/2017/01/19/google_buys_twitters_mobile_app_development_team_fabric](https://www.theregister.co.uk/2017/01/19/google_buys_twitters_mobile_app_development_team_fabric)", "network_signature": "crashlytics\\.com", "creation_date": "2017-09-24", "id": 27, "website": "http://crashlytics.com", "code_signature": "io.fabric.|com.crashlytics."}, "28": {"name": "LeanPlum", "description": "## Primary Location\r\nUnited States (San Francisco)\r\n\r\n## Website\r\n[https://www.leanplum.com](https://www.leanplum.com)\r\n\r\n## About\r\nLeanplum offers a mobile marketing platform with solutions for mobile messaging, in-app experiences, and detailed analytics.\r\n\r\n## Ownership\r\nLeanplum\r\n\r\n## Documentation\r\n[https://www.leanplum.com/docs/android](https://www.leanplum.com/docs/android)\r\n\r\n## Products and Services\r\nLeanplum has a number of services. They include:\r\n\r\n* _Messaging:_ Send push notifications, in-app messages, email, and more, using wide broadcasts or personalized content. Deliver messages with \"triggers or drip campaigns across the customer lifecycle\". Other targeting strategies include \"onboarding, engagement, conversion, reactivation, and loyalty\" [Leanplum, 05](https://www.leanplum.com/platform/push-notifications-messaging).\r\n* _Mobile Marketing Automation:_ Create \"context-rich campaigns that understand and respond to user actions\". Target users based on \"what users do and who they are\", and engage along the full customer journey. Tailor interactions based on behavior, location, timing, and channel. Automate self-activating messages in response to \"personalized behaviors\" [Leanplum, 06](https://www.leanplum.com/platform/mobile-marketing-automation).\r\n* _App Experience Command Center:_ A mobile content management system [Leanplum, 07](https://www.leanplum.com/platform/app-editor).\r\n* _App Personalization:_ Leanplum \"provides context and personalization enabled by individual user profiles that get richer over time. Demographic, behavior, location, time, and external data provide the deep insights that power relevance. The key to meaningful engagement is understanding who users are and what they do inside your app.\" They \"capture limitless user events and behaviors to fuel highly contextual messaging campaigns\" [Leanplum, 08](https://www.leanplum.com/platform/personalization).\r\n* _A/B Testing:_ Leanplum claims to have \"the most extensive mobile A/B testing solution in the industry\". Their product \"comes equipped with the ability to run A/B and multivariate tests\" to maximize return on investment [Leanplum, 09](https://www.leanplum.com/platform/mobile-ab-testing-optimization).\r\n* _Analytics:_ Leanplum's approach is to \"capture all events and behaviors associated with a user, without limits or data point costs\" in order to \"inspire real-time action\". Clients can \"customize parameters, reports, and metrics\". Insights examine \"engagement, retention, revenue, uninstalls, and more\" [Leanplum, 10](https://www.leanplum.com/platform/mobile-app-analytics).\r\n\r\nLeanplum gathers detailed user profile information and correlates with behavioral data [Leanplum, 11](https://leanplum-wordpress.storage.googleapis.com/Pers_new@1x-min.png). Their platoform is \"built on a foundation of A/B Testing and Analytics\" to deliver \"deep customer understanding\" [Leanplum, 12](https://www.leanplum.com/platform).\r\n\r\n## Privacy Policy\r\nIt is not clear if Leanplum's Privacy Policy listed on its website also applies to its mobile tracker. The Privacy Policy posted on their website covers a number of topics:\r\n\r\n_PII collection:_ Leanplum collects both PII (\"personal information\") and non-PII data. They collect information that is voluntarily provided (eg, through email newsletters, accounts, or profiles users sign up for), passively provided (eg, IP address, mobile device ID, server logs, cookies, web beacons, user actions like clicks, and so on).\r\n\r\n_Third party collection:_ Leanplum \"may receive information about you, including Personal Information, from third parties (e.g., opt-in lists where you have requested information about Leanplum or the Service while visiting a Third-Party Site). We may combine this information with other Personal Information we maintain about you. If we do so, this Policy governs any combined information that we maintain in personally identifiable format\".\r\n\r\n_Data sharing:_ Leanplum states, \"Except as described in this Policy, we will not disclose your Personal Information that we collect on the Service to third parties without your consent. We may disclose your Personal Information to third parties if you consent to us doing so, as well as in...circumstances\" involving service providers, business transfers, the protection of Leanplum's interests, and public authorities.\r\n\r\n_Opt-out:_ Leanplum offers an ability to opt out from the disclosure of information to third parties, as well as for use cases that are \"incompatible with the purpose(s) for which it was originally collected or subsequently authorized\". Individuals must contact Leanplum by email to exercise their choice.\r\n\r\n_Access and retention:_ Individuals with user accounts or profiles on the Leanplum Service can email Leanplum requesting access to their Personal Information; they can also request to amend or update the data. Users can also request Leanplum delete their data. However, Leanplum states they \"may need to retain some of your Personal Information in order to satisfy our legal obligations, or where we reasonably believe that we have a legitimate reason to do so\".\r\n\r\n_International law:_ Leanplum states it is in compliance with the EU-U.S. Privacy Shield and the Swiss-U.S. Privacy Shield.\r\n\r\n_Security:_ Leanplum states it takes reasonable security measures, but also states that \"no data security measures can be guaranteed to be completely effective. Consequently, we cannot ensure or warrant the security of any information that you provide to us. You transmit information to us at your own risk\" [Leanplum, 13](https://www.leanplum.com/privacy).\r\n\r\n## Relationships\r\n_Customers:_ Grab / NBC / QVC / TED / Tinder / Zynga [Leanplum, 01](https://www.leanplum.com) / Bleacher Report / Hotwire / Macy's / Red Bull [Leanplum, 02](https://www.leanplum.com/customers) / Tesco / App Annie / Last Minute Travel / Pixowl / Mixbook / Wanelo / Pixelberry Studios / Big Fish / TextNow / MobilityWare / Fetch Rewards / Via [Leanplum, 03](https://www.leanplum.com/customers/case-studies)\r\n\r\n## Details\r\n_Financial details:_ Leanplum was founded in 2012. It has raised over $93 million [Crunchbase, 01](https://www.crunchbase.com/organization/leanplum). In November 2017, it raised $47 million from investors. The company was founded by former Google engineers [Business Insider, 01](http://www.businessinsider.com/why-i-quit-google-to-become-a-startup-founder-2015-11). \r\n\r\n_Scope:_ Leanplum says it handles 14 billion events per day. \r\n\r\n_Infrastructure:_ Leanplum built their service on the Google Cloud Platform \"to optimize for fault-tolerance and availability\" [Leanplum, 04](https://www.leanplum.com/plans).\r\n\r\n## References\r\n* _Business Insider, 01_. [http://www.businessinsider.com/why-i-quit-google-to-become-a-startup-founder-2015-11](http://www.businessinsider.com/why-i-quit-google-to-become-a-startup-founder-2015-11) \r\n* _Crunchbase, 01_. [https://www.crunchbase.com/organization/leanplum](https://www.crunchbase.com/organization/leanplum) \r\n* _Leanplum, 01_. [https://www.leanplum.com](https://www.leanplum.com) \r\n* _Leanplum, 02_. [https://www.leanplum.com/customers](https://www.leanplum.com/customers) \r\n* _Leanplum, 03_. [https://www.leanplum.com/customers/case-studies](https://www.leanplum.com/customers/case-studies) \r\n* _Leanplum, 04_. [https://www.leanplum.com/plans](https://www.leanplum.com/plans) \r\n* _Leanplum, 05_. [https://www.leanplum.com/platform/push-notifications-messaging](https://www.leanplum.com/platform/push-notifications-messaging) \r\n* _Leanplum, 06_. [https://www.leanplum.com/platform/mobile-marketing-automation](https://www.leanplum.com/platform/mobile-marketing-automation)\r\n* _Leanplum, 07_. [https://www.leanplum.com/platform/app-editor](https://www.leanplum.com/platform/app-editor) \r\n* _Leanplum, 08_. [https://www.leanplum.com/platform/personalization](https://www.leanplum.com/platform/personalization) \r\n* _Leanplum, 09_. [https://www.leanplum.com/platform/mobile-ab-testing-optimization](https://www.leanplum.com/platform/mobile-ab-testing-optimization) \r\n* _Leanplum, 10_. [https://www.leanplum.com/platform/mobile-app-analytics](https://www.leanplum.com/platform/mobile-app-analytics) \r\n* _Leanplum, 11_. [https://leanplum-wordpress.storage.googleapis.com/Pers_new@1x-min.png](https://leanplum-wordpress.storage.googleapis.com/Pers_new@1x-min.png) \r\n* _Leanplum, 12_. [https://www.leanplum.com/platform](https://www.leanplum.com/platform)\r\n\r\n## External Links\r\n* _Crunchbase (Leanplum)_: [https://www.crunchbase.com/organization/leanplum](https://www.crunchbase.com/organization/leanplum)", "network_signature": "leanplum\\.com", "creation_date": "2017-09-24", "id": 28, "website": "https://www.leanplum.com/", "code_signature": "com.leanplum."}, "29": {"name": "Tinder Analytics", "description": "## Primary Location\r\nUnited States\r\n\r\n## Website\r\n[https://www.tinder.com](https://www.tinder.com)\r\n\r\n## About\r\nTinder is a location-based social search mobile app geared towards dating and hook-up culture.\r\n\r\n## Ownership\r\nMatch Group (a division of IAC/InterActiveCorp) [BusinessInsider, 01](http://www.businessinsider.com/match-the-company-that-owns-tinder-just-filed-to-go-public-2015-10); [CrunchBase, 01](https://www.crunchbase.com/organization/match-group)\r\n\r\n## Documentation\r\nNot public\r\n\r\n## Products and Services\r\nIt is note entirely clear what the Tinder Analytics SDK does. Some news outlets have published details about Tinder analytical practices, often in conjunction with third parties. Minor press about Tinder and \"swiping right\" offers clues:\r\n\r\n\"Earlier this year, to combat this collection of overzealous swipers, the company set a limit on the number of right swipes users could make daily. Then it rounded up profiles of the most prolific right-swipers and watched what happened. Would they get upset and leave? Would they stop using for a while and lick their wounds? Or would they realize the error in their ways and be a little more discriminating in suggesting possible hookups?\" [Fortune, 01](http://fortune.com/2015/09/29/tinder-interana-analytics/)\r\n\r\n## Privacy Policy\r\nThe privacy policy for the Tinder Analytics SDK tracker is not public. In September 2017, French journalist Judith Duportail published details about her data request from Tinder which revealed that Tinder had 800 pages of information about her. The profile was created over four years of use, and included information about her Facebook \"likes\", links to (now-deleted) Instagram photos, her education, the age-rank of men she was interested in, number of Facebook friends, the when and where of every one of her Tinder match conversations, and more [The Guardian, 01](https://www.theguardian.com/technology/2017/sep/26/tinder-personal-data-dating-app-messages-hacked-sold).\r\n\r\n### General Tinder Privacy Policy\r\n_PII:_ Tinder collects Personal Information (Personally Identifiable Information), including Sensitive Data, and other information. Sensitive Data includes \"information, comments or content (e.g. photographs, video, profile, lifestyle) that you optionally provide that may reveal your ethnic origin, nationality, religion and/or sexual orientation\". Users consent to the \"collection, use, and disclosure of Sensitive Data\" in accordance with the law. \r\n\r\n_Geolocation:_ Tinder states \"We may also collect your geolocation information with your consent. We may collect this information through a website, mobile application, or other online services... the information may be sent to servers located in the United States and countries around the world\". \r\n\r\n_Collection of data through Facebook:_ By registering with Tinder, you authorize Tinder to access certain Facebokk information, such as \"your public Facebook profile (consistent with your privacy settings in Facebook), your email address, interests, likes, gender, birthday, education history, relationship interests, current city, photos, personal description, friend list, and information about and photos of your Facebook friends who might be common Facebook friends with other Tinder users\". \r\n\r\n_Collection of conversations:_ \"If you chat with other Tinder users, you provide us the content of your chats\".\r\n\r\n_Third Party data collection:_ \"Tinder is part of The Match Group family of businesses, which as of the date of this policy includes websites and apps such as OurTime.com, BlackPeopleMeet.com, OkCupid, Twoo, POF, Meetic, LoveScout24, Match and ParPerfeito. We may obtain both personal and non-personal information about you from other Match businesses, business partners and other third parties.\" \r\n\r\n_Technologies used to collect data:_ \r\n\r\n* When visiting Tinder's Service, you automatically provide Tinder with your \"IP address, device ID and type, your browser type and language, the operating system used by your device, access times, your mobile device\u2019s geographic location while our application is actively running, and the referring website address.\"\r\n* _Cookies_ are used track users. They state, \"If we advertise, we (or third parties) may use certain data collected on our Service to show you Tinder advertisements on other sites or applications\".\r\n* _Pixel tags_ (aka, web beacons or clear GIFs) are used in web pages, ads, and emails. These are used to access cookies and track user activities.\r\n* _Mobile device IDs_ are used to store your preferences and track your use of the Tinder app. \r\n * \"Ad companies also use device IDs or Advertising IDs to track your use of the app, track the number of ads displayed, measure ad performance and display ads that are more relevant to you. Analytics companies use device IDs to track information about app usage.\"\r\n\r\n_Third Party data collecting:_ \"We may allow service providers, advertising companies and ad networks, and other third parties to display advertisements on our Service and elsewhere. These companies may use tracking technologies, such as cookies or web beacons, to collect information about users who view or interact with their advertisements. We do not provide any non-masked or non-obscured personal information to third parties.\" \r\n\r\n_Data Sharing with Third Parties:_ Tinder may share information with: \r\n\r\n* _Service providers:_ Third parties that perform services on behalf of Tinder may include \"fulfilling orders, providing customer service and marketing assistance, performing business and sales analysis, ad tracking and analytics, member screenings, supporting our Service functionality, and supporting contests, sweepstakes, surveys and other features offered through our Service. These service providers may have access to personal information needed to perform their functions but are not permitted to share or use such information for any other purposes.\"\r\n* _Other Match Group businesses:_ Including \"Match.com, OkCupid, OurTime.com, BlackPeopleMeet.com, Twoo, Meetic, POF, LoveScout24, ParPerfeito and others... subject to your consent where required under applicable law.\"\r\n* _Other situations:_ Some other situations include actions in response to a subpeona or similar investigative demand; when Tinder believes it is appropriate in connection with illegal activity; and \"In connection with a substantial corporate transaction, such as the sale of our business, a divestiture, merger, consolidation, or asset sale, or in the unlikely event of bankruptcy\". \r\n\r\n_Aggregated and non-personal Information:_ Tinder states, \"We may use and share non-personal information we collect under any of the above circumstances. We may also share it with other Match Group companies and third parties to develop and deliver targeted advertising on our Service and on websites or applications of third parties, and to analyze and report on advertising you see. We may combine non-personal information we collect with additional non-personal information collected from other sources. We also may share aggregated, non-personal information, or personal information in hashed, non-human readable form, with third parties, including advisors, advertisers and investors, for the purpose of conducting general business analysis, advertising, marketing, or other business purposes. For example, we may engage a data provider who may collect web log data from you (including IP address and information about your browser or operating system), or place or recognize a unique cookie on your browser to enable you to receive customized ads or content. The cookies may re\ufb02ect de-identified demographic or other data linked to data you voluntarily have submitted to us (such as your email address), that we may share with a data provider solely in hashed, non-human readable form. We may also share your geolocation information in de-identified form with Match Group companies and third parties for the above purposes.\" \r\n\r\n_Opt-Out (geolocation:_ \"To opt out of the sharing of your geolocation information, please discontinue use of the Tinder application\".\r\n\r\n_Opt-Out (third party):_ Some \"third-party advertising companies may be advertising networks that are members of the Network Advertising Initiative, which offers a single location to opt out of ad targeting from member companies (www.networkadvertising.org). Opting out will not decrease the number of advertisements you see. To opt-out of cookies that may be set by third party data or advertising partners, please go to http://www.aboutads.info/choices\". \r\n\r\n_Security:_ Tinder states that \"although we take steps to secure your information, we do not promise, and you should not expect, that your personal information, chats, or other communications will always remain secure\" \r\n\r\n_Data Retention:_ Tinder states, \"We keep your information only as long as we need it for legitimate business purposes and as permitted by applicable legal requirements. If you close your account, we will retain certain data for analytical purposes and recordkeeping integrity, as well as to prevent fraud, enforce our Terms of Use, take actions we deem necessary to protect the integrity of our Service or our users, or take other actions otherwise permitted by law. In addition, if certain information has already been provided to third parties as described in this Privacy Policy, retention of that information will be subject to those third parties\u2019 policies.\" \r\n\r\n_Jurisdictional issues:_ Tinder states, \"we cannot always know where personal information may be accessed or processed. While our primary data centers are in the United States, we may transfer personal information or other information to our offices outside of the United States. In addition, we may employ other companies and individuals to perform functions on our behalf. If we disclose personal information to a third party or to our employees outside of the United States, we will seek assurances that any information we may provide to them is safeguarded adequately and in accordance with this Privacy Policy and the requirements of applicable privacy laws.\r\n\r\nIf you are visiting from the European Union or other regions with laws governing data collection and use, please note that you are agreeing to the transfer of your personal data, including sensitive data, by Tinder from your region to countries which do not have data protection laws that provide the same level of protection that exists in countries in the European Economic Area, including the United States. By providing your personal information, you consent to any transfer and processing in accordance with this Policy\" [Tinder, 01](https://www.gotinder.com/privacy).\r\n\r\n## Relationships\r\n_Match Group businesses:_ Match.com / OkCupid / OurTime.com / BlackPeopleMeet.com / Twoo / Meetic / POF / LoveScout24 / ParPerfeito [Tinder, 01](https://www.gotinder.com/privacy)\r\n\r\n## Details\r\n_Usage requirements:_ Tinder users are required to have a Facebook account and turn on loction-based tracking in order to use the app. [Tinder, 01](https://www.gotinder.com/privacy) \r\n\r\n_Analytics:_ Tinder uses Spotify and Facebook data to match users [Tech Times, 01](http://www.techtimes.com/articles/199964/20170302/tinder-users-finding-more-matches-thanks-spotify-popular-anthems-include.htm)\r\n\r\n## References\r\n* _BusinessInsider, 01._ [http://www.businessinsider.com/match-the-company-that-owns-tinder-just-filed-to-go-public-2015-10](http://www.businessinsider.com/match-the-company-that-owns-tinder-just-filed-to-go-public-2015-10) \r\n* _CrunchBase, 01._ [https://www.crunchbase.com/organization/match-group](https://www.crunchbase.com/organization/match-group) \r\n* _Fortune, 01._ [http://fortune.com/2015/09/29/tinder-interana-analytics/](http://fortune.com/2015/09/29/tinder-interana-analytics/])\r\n* _Tech Times, 01._ [http://www.techtimes.com/articles/199964/20170302/tinder-users-finding-more-matches-thanks-spotify-popular-anthems-include.htm](http://www.techtimes.com/articles/199964/20170302/tinder-users-finding-more-matches-thanks-spotify-popular-anthems-include.htm) \r\n* _The Guardian, 01._ [https://www.theguardian.com/technology/2017/sep/26/tinder-personal-data-dating-app-messages-hacked-sold](https://www.theguardian.com/technology/2017/sep/26/tinder-personal-data-dating-app-messages-hacked-sold) \r\n* _Tinder, 01._ [https://www.gotinder.com/privacy](https://www.gotinder.com/privacy)\r\n\r\n## External Links\r\n* _Wikipedia (Tinder app):_ [https://en.wikipedia.org/wiki/Tinder_(app)](https://en.wikipedia.org/wiki/Tinder_(app))", "network_signature": "etl\\.tindersparks\\.com", "creation_date": "2017-09-24", "id": 29, "website": "http://tinder.com", "code_signature": "com.tinder.analytics|com.tinder.ads"}, "30": {"name": "Schibsted", "description": "## Websites\r\n * http://www.schibsted.com/en/ir/", "network_signature": "schibsted\\.com|schibsted\\.io", "creation_date": "2017-09-25", "id": 30, "website": "http://www.schibsted.com/en/ir/", "code_signature": ".schibsted."}, "31": {"name": "ATInternet", "description": "## Websites\r\n * https://www.atinternet.com/en/", "network_signature": "ati-host\\.net", "creation_date": "2017-09-25", "id": 31, "website": "https://www.atinternet.com/en/", "code_signature": "com.atinternet."}, "32": {"name": "Tealium", "description": "## Primary location\r\nUnited States (San Diego) [Crunchbase, 01](https://www.crunchbase.com/organization/tealium)\r\n\r\n## Website\r\n[https://www.tealium.com](https://www.tealium.com)\r\n\r\n## About\r\nTealium offers a universal data hub that unites its clients' tools and teams with \"universally acceptable, real-time customer data\" [Tealium, 01](https://www.tealium.com).\r\n\r\n## Ownership\r\nTealium\r\n\r\n## Documentation\r\nhttps://community.tealiumiq.com/t5/Tealium-for-Android/Adding-Tealium-to-Your-Android-App/ta-p/16846\r\n\r\n## Products and Services\r\nTealium integrates technologies and services. Products and services include:\r\n\r\n* Build & Stitch Profiles\r\n* Define Audiences\r\n* Trigger Actions\r\n* Analytics\r\n* Big Data\r\n* Customer Relations Management\r\n* Display Ad\r\n* Email\r\n* Personalization\r\n* Search\r\n* Social [Tealium, 01](https://www.tealium.com)\r\n\r\nProducts include:\r\n\r\n* _Tealium iQ Tag Management:_ Integrate with other vendors through tags [Telium, 02](https://tealium.com/products/tealium-iq-tag-management-system).\r\n* _Tealium Event Stream:_ Data collection from any source (web, mobile, OTT), monitor data stream in real time, and leverage data in real time, especially for use on mobile devices [Tealium, 03](https://tealium.com/products/tealium-eventstream).\r\n* _Tealium AudienceStream Customer Data Platform:_ A CDP that offers \"robust audience management and data enrichment capabilities resulting in unified customer profiles and the ability to take immediate, relevant action... Tealium AudienceStream allows users to connect all of their customer data, creating a single view of customers and the ability to automate actions across every channel, touchpoint and vendor in your entire digital ecosystem\". Tealium's Audience Sizing \"allows users to connect all of their customer data, creating a single view of customers and the ability to automate actions across every channel, touchpoint and vendor in your entire digital ecosystem\" [Tealium, 04](https://tealium.com/products/audiencestream).\r\n* _Tealium DataAccess:_ DataAccess \"offers the richest source of clean and correlated omnichannel, event and audience data collected across web and mobile touch points, and makes that data available for real-time action\". It focuses on unifying data and offers the capacity to \"Correlate and stitch online and offline data assets to provide a rich \u201cready to query\u201d visitor dataset\" [Tealium, 05](https://tealium.com/products/tealium-dataaccess).\r\n\r\nTealium's \"Visitor Stitching\" tracks user behavior on and offline, across devices. With this technology, Tealium states, \"Previously anonymous visitor behavior will fulfill critical gaps in customer knowledge when cross device activity is merged with known customer profiles\". Tealium has a patent on their visitor stitching approach that combines the details from two or more profiles into one. Their \"proprietary technology \u2018replays\u2019 the data from each of the stitched profiles back in order, so that the profile can be built taking into account the sequence of the customer\u2019s journey\". \r\n\r\nTealium \"tracks visitor IDs from a variety of sources including Facebook, Amazon, Twitter, LinkedIn, Google Plus and more. When any known ID is matched, visitors, their behaviors, and devices are automatically stitched together. AudienceStream then enables you to take actions using these profile-based attributes and create unique audiences, facilitating compelling omnichannel campaigns that may begin on a mobile device and follow the user to his or her desktop\" [Tealium, 06](https://tealium.com/resources/visitor-stitching).\r\n\r\n## Privacy Policy\r\nTealium lists a Privacy Policy on its website; it is unclear if there are any differences in policy as it applies to their mobile tracker. \r\n\r\n_Data collection:_ Tealium collects both PII and non-PII from individuals visiting its website or using its services. PII may be collected when signing up for Tealium services. Non-PII may be collected when visiting the Tealium website from a web browser or mobile device. Tealium collects information from web browser through the use of cookies and web beacons. They also collect data on IP addresses to \" administer the Tealium Website, analyze trends, track visitor movements, and gather broad demographic information that assists us in identifying visitor preferences\". They \"may collect aggregated data regarding use of the Services and the Tealium Website, including, without limitation, number of Site Visitors, frequency and patterns of use, tag usage, feedback request trends, etc. (\u201cAggregated Data\u201d)\". They state they use \"Aggregated Data as a statistical measure and not in a manner that would identify you personally\" and that they \"may make use of, or make such Aggregated Data available to, third parties, in any manner in our sole discretion\". Details on what constitutes \"aggregated data\" or not available. \r\n\r\n_Data sharing:_ Tealium shares data with service providers, affiliates, partners and affiliated businesses not controlled by Tealium, billing, and when compelled by authorities.\r\n\r\n_International law:_ Tealium \"participates in and has certified its compliance with the EU-U.S. Privacy Shield Framework (Privacy Shield) and Swiss Safe Harbor\".\r\n\r\n_Opt-out:_ Tealium states, \"You may correct, update and delete your Customer Information, change your choices for alerts and other messages, choose whether to receive offers and promotions from us or you may request access to the Personal Information we hold about you and ask us to amend or delete such Personal Information. You can send your request to support@tealium.com.\" They also honor Do Not Track headers and \"allows its users to opt\u2010out of having their personal information collected by Tealium\". It is not clear how individuals could opt-out of data collection from the Telium mobile device tracker.\r\n\r\n_Data retention:_ Tealium \" retains the information we receive as described in this Privacy Statement for as long as needed to provide our Services, comply with our legal obligations, resolve disputes, establish legal defenses, conduct audits, pursue legitimate business purposes, and enforce our agreements\".\r\n\r\n_Security:_ Tealium states that it \"takes precautions, including administrative, technical, and physical measures \u2013 to help safeguard Customer Information against loss, theft, and misuse as well as unauthorized access, disclosure, alteration, and destruction. While we follow generally accepted standards to protect information submitted to us, no method of storage or transmission is 100% secure. Users are solely responsible for protecting their passwords, limiting access to their computers, and signing out of the Services after their sessions\" [Tealium, 07](https://tealium.com/privacy).\r\n\r\n## Relationships\r\n_Integrations (technological):_ Amazon Web Services / Bronto / Campaign Monitor / Twitter Campaigns / Facebook / CheetahMail / Criteo / Demandware [Tealium, 01](https://www.tealium.com).\r\n\r\n## Details\r\n_Financial details:_ Tealium was founded in 2008 and has raised over $112 million from funders [Crunchbase, 01](https://www.crunchbase.com/organization/tealium).\r\n\r\n## References\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/tealium](https://www.crunchbase.com/organization/tealium) \r\n* _Tealium, 01._ [https://www.tealium.com](https://www.tealium.com) \r\n* _Tealium, 02._ [https://tealium.com/products/tealium-iq-tag-management-system](https://tealium.com/products/tealium-iq-tag-management-system) \r\n* _Tealium, 03._ [https://tealium.com/products/tealium-eventstream](https://tealium.com/products/tealium-eventstream) \r\n* _Tealium, 04._ [https://tealium.com/products/audiencestream](https://tealium.com/products/audiencestream) \r\n* _Tealium, 05._ [https://tealium.com/products/tealium-dataaccess](https://tealium.com/products/tealium-dataaccess) \r\n* _Tealium, 06._ [https://tealium.com/resources/visitor-stitching](https://tealium.com/resources/visitor-stitching) \r\n* _Tealium, 07._ [https://tealium.com/privacy](https://tealium.com/privacy)\r\n\r\n## External Links\r\n* _Wikipedia (Tealium):_ [https://en.wikipedia.org/wiki/Tealium](https://en.wikipedia.org/wiki/Tealium) \r\n* _Ghostery (Tealium):_ [https://apps.ghostery.com/apps/tealium](https://apps.ghostery.com/apps/tealium)\r\n* _Crunchbase (Tealium):_ [https://www.crunchbase.com/organization/tealium](https://www.crunchbase.com/organization/tealium)", "network_signature": "tiqcdn.com|tealiumiq.com", "creation_date": "2017-09-25", "id": 32, "website": "https://tealium.com/", "code_signature": ".tealium."}, "33": {"name": "Nexage", "description": "## Primary Location\r\nUnited States (Boston) [Crunchbase, 01](https://www.crunchbase.com/organization/nexage)\r\n\r\n## Website\r\n[http://www.nexage.com](http://www.nexage.com)\r\n\r\n## About\r\nNexage \"offers a mobile advertising platform that provides private and public exchanges, data enrichment, and real-time targeting solutions\" [Crunchbase, 01](https://www.crunchbase.com/organization/nexage).\r\n\r\n## Ownership\r\nMillenial Media, which became part of ONE by AOL; the AOL company name has changed to Oath, which is a subsidiary of Verizon Communications [AOL, 01](http://privacy.aol.com)\r\n\r\n## Documentation\r\n[http://docs.onemobilesdk.aol.com/android-ad-sdk/integration-guide.html](http://docs.onemobilesdk.aol.com/android-ad-sdk/integration-guide.html)\r\n\r\n## Products and Services\r\nServices (ostensibly now under Millenial Media):\r\n\r\n* Real-time bidding to help automate the buying and selling of mobile advertising [MillenialMedia, 01](http://www.millennialmedia.com/press/millennial-media-to-acquire-nexage-a-leading-mobile-ssp-and-advertising-exchange).\r\n* Millenial Media has a \"mobile-first\" data management platform (DMP) which can \"ingest publisher and advertiser data to enable re-targeting, audience extensions, and cross-device attribution\" [MillenialMedia, 01](http://www.millennialmedia.com/press/millennial-media-to-acquire-nexage-a-leading-mobile-ssp-and-advertising-exchange).\r\n* Targeted advertising through channel and demographic segments: \"Leveraging Millennial Media's audience and channel targeting, the campaign reached women ages 25-55 with an emphasis on the following conditions: pregnancy, stress, and bleaching/coloring. The consumer interaction garnered from the precise targeting far exceeded expectations.\" [MillenialMedia, 02](http://www.millennialmedia.com/mobile-insights/client-stories/fall-for-unilever-singapore-dove-hair-rescue)\r\n\r\n## Privacy Policy\r\nNexage's current privacy policy links to a URL at AOL.com, which displays privacy policy for \"Oath: A Verizon company\" [AOL, 01](http://privacy.aol.com). \r\n\r\n_Location tracking:_ According to Oath, \"Depending on how you access and use our Services, we may receive... _Location Information._ This information can include your device's GPS signal and information about Bluetooth connections, nearby WiFi networks, cell towers, and other types of precise location. We get this information, for example, when you use location-enabled services\" [AOL, 04](http://privacy.aol.com/privacy-policy). \r\n\r\nThey further state, \"With your consent, we may use available services on your device to determine or derive your precise location, including cellular, Wi-Fi, Bluetooth, and GPS information. In addition and with your consent, we may share your precise location information or personal information with third parties for their independent use. You may opt-out of providing precise location information to Oath, and having that information shared with third parties, at any time by adjusting the settings on your device. Please note that you may need to adjust multiple settings, and not just your location preference, to opt out of providing precise location information to Oath. If you subsequently opt in to sharing location information for an individual service, your location information will be shared with that service. Note that if you consent to share your location information within a particular app, your location information collected from within that app may continue to be shared even after you have opted-out on your device. If you opt-out of providing precise location information to Oath, we may continue to derive your approximate location from your IP address and other information we may collect. For more information, please review your app and device settings.\" \r\n\r\n_Location tracking and third parties:_ Oath states, \"We may use third-party providers to help operate our Services, including to deliver ads and understand how people use our Services on various devices. These providers may collect information about other apps on your various devices, the websites you visit, location information, inaudible audio waves, and other information in order to help analyze usage and target advertising on the site or app and elsewhere across your devices. These providers may use cookies, web beacons, and other technologies (including audio beacons) to collect this information\" [AOL, 07](http://legal.aol.com/mobileTOS).\r\n\r\n_Other information collected:_ \r\n\r\n* Log information (interactions with web sites, search queries, information about your operating system, IP address, etc)\r\n* Device information (the type of device, such as iPhone; device identifiers which may be unique to your device; your Internet Service Provider)\r\n* \"Other information\" (such as information from AOL Mail or Instant Messenger, but not the private communications without your consent)\r\n* Third Party data: Oath states, \"We may receive additional information about you that is publicly or commercially available and combine it along with the information we have collected or received about you in other ways. Also, we receive information about you when you choose to connect with social networking services while using our Services\" [AOL, 04](http://privacy.aol.com/privacy-policy).\r\n\r\n_Mobile device information:_ Oath states, \"When you use our Services on a mobile device, Oath, our partners, and service providers may collect certain information automatically, such as the type of device you use, unique device ID, wireless mobile subscriber ISDN numbers, Verizon Wireless UIDH, IP address, operating system, browser type, and information about your use of our Services. We may use this information as described in the Oath Privacy Policy, which explains, among other things, that we may combine information about your use of our various Services in all the ways you may connect to Oath.\r\n\r\nCertain Services may require the collection of the phone number of your device. We may associate that phone number with other information; however, we will not use that number for telemarketing to you without your consent\" [AOL, 07](http://legal.aol.com/mobileTOS).\r\n\r\n_Oath Standard Categories (segments) for targeted advertising:_ See Oath website for their list of Standard Categories [AOL, 05](https://advertising.aol.com/advisibility/standard-categories).\r\n\r\n_Opt-out on mobile:_ Oath states users can opt out of interest-based (targeted) advertising through general device settings in iOS and Android. However, to stop data collection of an Oath app, users must uninstall the app. \r\n\r\n_PII vs non-PII:_ Oath defines PII as \"name, address, telephone number, email address, payment card number, and government-issued identification number\", and non-PII to include \"without limitation cookie IDs, device identifiers, hashed values (such as email addresses and other types of information that are transformed into a sequence of random-looking characters that are no longer recognizable as an email address), and IP addresses\" [AOL, 02](http://privacy.aol.com/definitions). \r\n\r\nOath states it abides by \"standards restricting the use of sensitive financial account number data and other types of sensitive data as defined by these programs. For example, we do not use or allow others to use sensitive data to determine eligibility for health insurance, life insurance, or employment. We also do not target ads to users based on sensitive health data, including cancer, mental health-related conditions, and sexually-related areas\". They add, \"If a user appears interested in non-sensitive, health-related topics, (such as, by visiting pages related to a topic) an ad relevant to those interests may be displayed. We may also display non-sensitive, health-related ads to users who we or our advertisers believe may be an appropriate audience for such topics\" [AOL, 06](http://privacy.aol.com/advertising-and-privacy).\r\n\r\n_Information sharing:_ Oath states it \"may share your information in limited circumstances, including when we have your consent to do so or when sharing is necessary to protect Oath or comply with the law. Our agents and contractors may have access to your information, but only to perform services for Oath. We do not sell or rent your personal information to third parties. We may, however, share non-personally identifiable information with select business partners\" [AOL, 01](http://privacy.aol.com). Oath also states it does not \"rent or sell personal information to third parties for their marketing purposes. But we may share certain information we collect or receive with our affiliates and others to respond to your requests, provide our Services, when we have your consent, or as described in\" their Privacy Policy.\r\n\r\nParties Oath may share data with include:\r\n\r\n* Affiliates (any company that is controlled by or under common control with Oath Inc. Oath is part of the Verizon family of companies, which includes Yahoo Inc. For a list of Oath's major content brands\") [AOL, 02](http://privacy.aol.com/definitions)\r\n* Business partners (non-personally identifiable information)\r\n* Other parties in response to legal process or when necessary to protect our Services\r\n* Companies that provide services to Oath\r\n\r\nThird Parties that Provide Content, Advertising Services, or Functionality on Our Services:\r\n\r\n* Advertising providers (for targeted advertising or analytics)\r\n* Audience-measurement companies (to measure and compare usage on Oath Services, in comparison to other online services)\r\n* Social networking services \" (like Facebook, Twitter, LinkedIn, and Google) that enable you to login to certain of our Services and to share things you find on our Services with your social network. If you choose to connect with a social networking service, we may share information with that service, and that service may share information about you with us. We may use the information for the reasons explained in this Privacy Policy, including to make your experience on our Services more personal and social. For example, we might show you what content is popular among your connections on the social networking service or give you a glimpse of what your friends are saying about that content.\"\r\n\r\nAccording to Oath, \"These and other third parties may collect or receive information about your use of our Services, including through the use of cookies, web beacons and other technologies, and this information may be collected over time and combined with information collected on different websites and online services across your devices\" [AOL, 04](http://privacy.aol.com/privacy-policy). \r\n\r\nKey third parties Oath works with include, but are not limited to: \r\n\r\nAnalytics Providers:\r\n\r\n* Google Analytics\r\n* Nielsen Digital Measurement\r\n* Scorecard Research\r\n\r\nOther companies:\r\n\r\n* Acxiom\r\n* Session M\r\n* Taboola\r\n* Tapad \r\n\r\nOath states that, \"like Oath, these companies and other third parties not listed above may use cookies, web beacons, and similar technologies on or in connection with our Services\" [AOL, 06](http://privacy.aol.com/advertising-and-privacy).\r\n\r\n_Regulation:_ Oath is committed to self-regulatory requiremets for online advertising, including the Digital Advertising Alliance's Self-Regulatory Program for Online Behavioral Advertising and the Network Advertising Initiative's Self-Regulatory Code of Conduct.\r\n\r\n_Retention:_ Oath states, \"Data used to create segments for ad targeting is retained for no longer than 2 years. Other data (for example, data used to determine long-term or seasonal trends) may be retained for as long as Oath has a legitimate business reason for retaining it\" [AOL, 06](http://privacy.aol.com/advertising-and-privacy).\r\n\r\n_Tracking technologies:_ Oath Services use cookies, web beacons, and other technologies, as well as device fingerprinting and a \"device graph\" to link multiple devices to the same user [AOL, 03](http://privacy.aol.com/cookies-web-beacons).\r\n\r\n## Relationships\r\n_Media relationships:_ Oath offers free Services such as Oath.com, HuffPost, Moviefone, and TechCrunch with support from ads displayed on those Services. \r\n\r\nOath brands include: #BuiltByGirls / Yahoo! Finance / Yahoo! / AOL / Yahoo! Sports / Yahoo! Mail / TechCrunch / Yahoo! News / HuffPost / Yahoo! Fantasy / Flurry / Yahoo! Gemini / Verizon / BrightRoll by Yahoo! / ONE by AOL / kanvas / flickr / tumblr / Yahoo! Weather / Alto / Yahoo! Messenger / engadet / Style Me Pretty / autoblog / Polyvore / Makers / Moviefone / Build / Ryot / Convertro / BBG Ventures / Cambio / rivals / alephd by AOL [Oath, 01](https://www.oath.com/our-brands)\r\n\r\n## Details\r\n_Financial details:_ Nexage was founded in 2006 and had raised $19.5 million by 2012. It was acquired by Millenial Media for approximately $108 million in 2014 [Crunchbase, 01](https://www.crunchbase.com/organization/nexage); [AdExchanger.com, 01](https://adexchanger.com/mobile/millennial-media-to-buy-nexage-mobile-ssp-and-exchange-for-108m). \r\n\r\n## References\r\n* _AdExchanger.com, 01._ [https://adexchanger.com/mobile/millennial-media-to-buy-nexage-mobile-ssp-and-exchange-for-108m](https://adexchanger.com/mobile/millennial-media-to-buy-nexage-mobile-ssp-and-exchange-for-108m)\r\n* _AOL, 01._ [http://privacy.aol.com](http://privacy.aol.com)\r\n* _AOL, 02._ [http://privacy.aol.com/definitions](http://privacy.aol.com/definitions)\r\n* _AOL, 03._ [http://privacy.aol.com/cookies-web-beacons](http://privacy.aol.com/cookies-web-beacons)\r\n* _AOL, 04._ [http://privacy.aol.com/privacy-policy](http://privacy.aol.com/privacy-policy)\r\n* _AOL, 05._ [https://advertising.aol.com/advisibility/standard-categories](https://advertising.aol.com/advisibility/standard-categories)\r\n* _AOL, 06._ [http://privacy.aol.com/advertising-and-privacy](http://privacy.aol.com/advertising-and-privacy) \r\n* _AOL, 07._ [http://legal.aol.com/mobileTOS](http://legal.aol.com/mobileTOS)\r\n* _Millenial Media, 01._ [http://www.millennialmedia.com/press/millennial-media-to-acquire-nexage-a-leading-mobile-ssp-and-advertising-exchange](http://www.millennialmedia.com/press/millennial-media-to-acquire-nexage-a-leading-mobile-ssp-and-advertising-exchange)\r\n* _Millenial Media, 02._ [http://www.millennialmedia.com/mobile-insights/client-stories/fall-for-unilever-singapore-dove-hair-rescue](http://www.millennialmedia.com/mobile-insights/client-stories/fall-for-unilever-singapore-dove-hair-rescue)\r\n* _Oath, 01._ [https://www.oath.com/our-brands](https://www.oath.com/our-brands)\r\n\r\n## External Links\r\n* _Ghostery (Nexage)_: [https://apps.ghostery.com/apps/nexage](https://apps.ghostery.com/apps/nexage)", "network_signature": "nexage\\.com", "creation_date": "2017-09-27", "id": 33, "website": "http://nexage.com/", "code_signature": "com.nexage.android.|org.nexage."}, "34": {"name": "Ogury Presage", "description": "*\"Ogury is activating proprietary true mobile data from more than 300 million global users.\r\nNo other player in the market has such an ultra-granular knowledge of the complete mobile user journey.\r\nOgury\u2019s omniscient mobile data platform gives businesses the tools to harness the power of mobile data.\r\nBetter Insights = Better Targeting = Better App Monetisation = Better Mobile Experience.\"* - from Ogury website", "network_signature": "presage\\.io", "creation_date": "2017-09-27", "id": 34, "website": "http://www.presage.io/", "code_signature": "io.presage."}, "35": {"name": "Twitter MoPub", "description": "## Primary location\r\nUnited States\r\n\r\n## Website\r\n[https://www.mopub.com](https://www.mopub.com)\r\n\r\n## About\r\nMoPub offers services aimed th help publishers acquire and serve advertisements and advertisers to reach audiences that may be interested in their products and services [MoPub, 03](https://www.mopub.com/legal/privacy).\r\n\r\n## Ownership\r\nTwitter\r\n\r\n## Documentation\r\n[https://www.mopub.com/resources/docs/android-sdk-integration](https://www.mopub.com/resources/docs/android-sdk-integration)\r\n\r\n## Products and Services\r\nMopub describes itself as \"The leading monetization platform for mobile app publishers and developers\" [MoPub, 01](https://www.mopub.com). \r\n\r\n* They connect publishers with advertisers in a way aimed to \"drive the highest price for every ad impression\" [MoPub, 01](https://www.mopub.com).\r\n* They \"flexible mediation system allows publishers to target the right inventory with the right network partner, based on each publisher\u2019s unique business goals\" [MoPub, 01](https://www.mopub.com).\r\n* They offer \"ad serving tools, interface, and analytics.\"\r\n\r\nFor publishers: [Mopub, 02](https://www.mopub.com/publishers/overview)\r\n* Offer a \"dependable back-end systems powered by Twitter\u2019s world-class data center strength.\"\r\n* Offer consultative services.\r\n* Offer a creative dashboard for ad serving tools, interface, and ad formats.\r\n* Offer publishers access to over 180 demand-side platforms.\r\n* Help publishers reach an audience across 49,000 apps and 1.5 billion devices [MoPub, 03](https://www.mopub.com/dsp/overview).\r\n\r\n## Privacy Policy\r\n\r\n### Section 1: End User Policies\r\n_Information Collection on End Users:_ MoPub states, \"we may collect information about your device and the ads you view or click. The MoPub Services are designed to avoid collecting information that identifies you personally, such as your name, address, or email address, but the information we collect does enable us to recognize your device over time\". Data collected includes, but is not limited to:\r\n\r\n* \"Information about your device, such as the type and model, manufacturer, operating system (e.g. iOS or Android), carrier name, IP address, mobile browser (e.g. Chrome, Safari), applications using the MoPub Services and the version of such applications, and identifiers assigned to your device, such as its iOS Identifier for Advertising (IDFA), Android Advertising ID, or unique device identifier (a number uniquely allocated to your device by your device manufacturer).\r\n* Log information, including the app or website visited, session start/stop time, time zone, and network connection type (e.g., WiFi, cellular), and cookie information.\r\n* The geo-location of your device (using GPS or other geo-location data), when location services have been enabled for the mobile app or website that uses the MoPub Services.\r\n* Information about ads served, viewed, or clicked on, such as the type of ad, where the ad was served, whether you clicked on it, and whether you visited the advertiser\u2019s website or purchased the product or service advertised.\r\n* Information that MoPub Customers and other third parties have collected and share with MoPub, such as information about activity in their services. This may include the content you view or searches you made, the language you prefer, or other non-personally identifying demographic or interest information, to help make the ads served to you more relevant.\" \r\n\r\n_Information Use on End Users:_ This includes for the following purposes:\r\n\r\n* Serving Ads\r\n* Ad Reporting and Conversations\r\n* Frequency Capping\r\n* Fraud Detection and Prevention\r\n* Interest-Based Advertising\r\n* Geo-Targeting\r\n* Providing and Improving MoPub Services\r\n\r\n_PII:_ \"MoPub will not combine the non-personally identifiable information collected to provide the MoPub Services with your personally-identifying information without your express consent.\" \r\n\r\n_Information sharing:_ \r\n\r\n* With advertiser customers: for the purposes of the ad bidding process.\r\n* Aggregated and non-PII data: \"We share aggregate or non-personally identifiable information about the use of our Services with MoPub Customers. For example, we provide advertisers reports showing how many users viewed or clicked on their ads. We also provide publishers reports about the types of ads served to their apps.\"\r\n* With partners: who help with anti-fraud, quality, and security efforts.\r\n* With partners: who help MoPub improve mobile advertising exchange services.\r\n* Within \"our corporate family to provide, understand, or improve their or our services.\"\r\n\r\nMoPub also shares data as described in Section 3 of the Privacy Policy (see below). \r\n\r\n_Opt-Out:_ \"Your iOS mobile device may provide a 'Limit Ad Tracking' setting. On Android devices, your settings may allow you to 'Opt out of Interest-Based Ads.' When you have opted out using this setting on a device, MoPub will not use in-app information collected from that device to infer your interests or serve ads to that device that are targeted based on your inferred interests.\" MoPub also observes \"Do Not Track\" requests in web browsers. MoPub \"requires its advertising customers to honor opt-out preferences expressed using these controls.\" \r\n\r\n_Requirements of MoPub Customers:_ \"MoPub requires MoPub Customers to comply with all applicable laws and regulations and to provide end users with notice of the collection of data for advertising purposes as outlined in this Privacy Policy. We encourage all users to review the privacy policies of sites and apps they visit for information about those sites\u2019 and apps\u2019 data collection and use practices.\" \r\n\r\n### Section 3: General Information\r\n_Other sharing policies:_ MoPub \"may preserve or disclose information if we believe that it is reasonably necessary to comply with a law, regulation, legal process, or governmental request; to protect the safety of any person; to address fraud, security or technical issues; or to protect the rights or property of MoPub, MoPub Customers, users of our website, or end users.\"\r\n\r\n_Information from Third Parties:_ MoPub \"may receive information about you from third parties, including MoPub Customers, data partners, and our corporate family. This information may include, for example, browser cookie IDs, mobile device IDs, demographic or interest data, and content viewed or actions taken on a website or app.\" \r\n\r\n_Other sites:_ MoPub \"is not responsible for the privacy practices or content of these other sites.\" \r\n\r\n_Confidentiality and Security:_ MoPub \"has implemented reasonable security measures in order to protect both personal and non-personal information from loss, misuse and unauthorized access, disclosure, alteration or destruction.\"\r\n\r\n## Relationships\r\n_Clients:_ Apalon / ASKfm / FEO Media / First Touch Games / glu / Gram Games / Jorudan / LA Place Media / Lotum / Lovoo / MeetMe / Miniclip / MobilityWare / Outfit7 / theScore / Simeji / Spinrilla / timehop / truecaller / tunein / Ubisoft / Paper.io / The Weather Channel / Zynga [MoPub, 04](https://www.mopub.com/publishers/clients)\r\n\r\n## Details\r\n_Financial history:_ MoPub was founded in 2010 [CrunchBase, 01](https://www.crunchbase.com/organization/mopub). It was acquired by Twitter in 2013; the details of the deal were not disclosed. Media outlets estimated the deal at around $300 million [CCN Tech, 01](http://money.cnn.com/2013/09/10/technology/social/twitter-acquisition/index.html)\r\n\r\n## References\r\n* _CNN Tech, 01_. [http://money.cnn.com/2013/09/10/technology/social/twitter-acquisition/index.html](http://money.cnn.com/2013/09/10/technology/social/twitter-acquisition/index.html) \r\n* _CrunchBase, 01_. [https://www.crunchbase.com/organization/mopub](https://www.crunchbase.com/organization/mopub)\r\n* _MoPub, 01_. [https://www.mopub.com](https://www.mopub.com) \r\n* _MoPub, 02_. [https://www.mopub.com/publishers/overview](https://www.mopub.com/publishers/overview) \r\n* _MoPub, 03_. [https://www.mopub.com/legal/privacy](https://www.mopub.com/legal/privacy) \r\n* _MoPub, 04_. [https://www.mopub.com/publishers/clients](https://www.mopub.com/publishers/clients)\r\n\r\n## External Links\r\n* _Ghostery (MoPub)_: [https://apps.ghostery.com/ko/apps/mopub](https://apps.ghostery.com/ko/apps/mopub)", "network_signature": "mopub\\.com", "creation_date": "2017-09-27", "id": 35, "website": "https://www.mopub.com/", "code_signature": "com.mopub.mobileads."}, "36": {"name": "Add Apt Tr", "description": "", "network_signature": "aatkit\\.com", "creation_date": "2017-09-27", "id": 36, "website": "https://www.addapptr.com", "code_signature": "com.intentsoftware.addapptr."}, "37": {"name": "Vectaury", "description": "", "network_signature": "vectaury\\.io", "creation_date": "2017-09-28", "id": 37, "website": "http://vectaury.io/", "code_signature": "io.vectaury."}, "38": {"name": "Tune", "description": "## Primary Location\r\nUnited States (Seattle) [Crunchbase, 01](https://www.crunchbase.com/organization/tune)\r\n\r\n## Website\r\n[https://www.tune.com](https://www.tune.com)\r\n\r\n## About\r\nTUNE offers products and services for the digital marketing and advertising industry, including the TUNE Marketing Console, a mobile marketing technology stack [TUNE, 08](https://www.tune.com/who-we-are).\r\n\r\n## Ownership\r\nTUNE\r\n\r\n## Documentation\r\n[https://developers.tune.com/sdk/android-quick-start](https://developers.tune.com/sdk/android-quick-start)\r\n\r\n## Products and Services\r\nMany of TUNE's services are provided through the TUNE Marketing Console (TMC). The TMC \"is designed to collect and use data such as Unique Advertising Identifiers, Statistical Identifiers, Geographic Location Data, Email Addresses, and other data provided by the Advertiser for attribution, app store optimization, and in-app marketing. Advertisers are able to view and measure data provided by TUNE, as well as third-party Partners that the Advertiser selects, in the TMC. For instance, an Advertiser can compare the results of advertising campaigns conducted with different Partners in the TMC. Advertisers and Partners may also send information to the TMC via Postback\" [TUNE, 10](https://www.tune.com/resources/data-and-privacy/privacy-policies/tmc-privacy-policy).\r\n\r\nTUNE products and services offered include:\r\n\r\n* _In-App Marketing:_ Leverage customer segmentation tools and contextual insight to send personalized messages, guide users through from onboarding to conversion, and take action with real-time reporting, A/B testing, and optimization. Features include location-based triggers, deep links, automatic actions, automated triggers, and scheduled campaigns [TUNE, 02](https://www.tune.com/solutions/tune-marketing-console/in-app-marketing).\r\n* _TUNE Marketing Console:_ \r\n* * Track user behavior on and offline, across devices, via TUNE's understanding of the \"customer journey\".\r\n* * Uniques identify users and target their \"proximity\" via location tracking.\r\n* * Help clients to \"Streamline your mobile marketing and measurement\" with services that are \"people-centric\". \r\n* * Unify data into one place, and give ownership of the data to the client. \r\n* * TUNE's APIs allows clients to sync with thousands of integrated partners [TUNE, 03](https://www.tune.com/solutions/tune-marketing-console/our-difference).\r\n* _Attribution Analytics:_ TUNE offers mobile analytics based on detailed performance reports and people-centric segmentation to maximize return on investment; analytics for re-engagement; analytics for return on ad spend; as well as analytics for fraud prevention [TUNE, 04](https://www.tune.com/solutions/tune-marketing-console/attribution-analytics).\r\n* _App Store Analytics:_ TUNE provides tools to optimize success in app stores [ TUNE, 05](https://www.tune.com/solutions/tune-marketing-console/app-store-analytics).\r\n* _Fraud prevention:_ TUNE Fraud services identify install and click fraud, allows businesses to set custom fraud rules, and provides analytics to detect and classify potential fraud [TUNE, 06](https://www.tune.com/solutions/tune-marketing-console/mobile-ad-fraud-detection-prevention) \r\n\r\nTUNE is \"a 'data processor' that collects and analyzes End User data at the specific request of our client Advertisers, the 'data controllers'\" [TUNE, 10](https://www.tune.com/resources/data-and-privacy/privacy-policies/tmc-privacy-policy).\r\n\r\nTUNE also tracks in-app user behavior and correlates it with a unique identifier [TUNE, 07](https://developers.tune.com/sdk/measuring-in-app-events).\r\n\r\nA simple version of TUNE's targeted advertising is provided on their opt-out website. It is explained as follows: \r\n\r\n\"Within the TMC, two features allow advertisers to use data to target advertising to an end user:\r\n\r\n1. AUDIENCES allows Advertisers to build segments based on previously acquired attribution data (from the TMC's Attribution Analytics feature)...\r\n2. IN APP MARKETING allows advertisers to send end users push notifications outside of the app environment, as well as in-app messages - for promotional and other activities...\" [TUNE, 09](http://www.optoutmobile.com).\r\n\r\nIn this context, TMC covers \"Attribution Analytics, App Store Analytics, Audiences, and In-App Marketing\" [TUNE, 10](https://www.tune.com/resources/data-and-privacy/privacy-policies/tmc-privacy-policy).\r\n\r\n## Privacy Policy\r\nTUNE \"defines privacy as the end user\u2019s rights to receive notice, give consent, and opt-out of the collection, use, and sharing of data that is about or can identify that end user\".\r\n\r\n_Opt-out:_ TUNE has an opt-out website, www.optoutmobile.com, which details how end users can opt out of features in the TUNE Marketing Console (TMC) that target users online. Users can opt out of the \"audiences\" segment-based targeted advertising if they \"enable Limit Ad Tracking or \u201cLAT\u201d or re-set their ad identifier on their device OR opt out within the app itself\". They can opt out of \"in app marketing\" if they \"use the appropriate settings on their mobile platform (Android, iPhone, or Windows)\". Additional details of how to opt out of mobile on the outoutmobile.com website. TUNE will pass on LAT requests to Advertisers, and will honor opt-outs provided to them by Advertisers. They also honor push notification opt outs set by the End User on their device. \r\n\r\nOpting out of the TMC \"will not stop those users from receiving interest-based advertisements from Advertisers or other publishers or ad networks. End Users who want to opt out of a particular ad network, publisher, or Advertiser\u2019s ads must contact those companies directly to opt out.\"\r\n\r\n_Data ownership (TMC):_ \"Unless otherwise specified, and pursuant to the TUNE Data Pledge, Advertisers own the data that they provide to and collect through the TMC. When Advertisers remove or export their data from the TMC, their use of End User data is governed by their own privacy policies and applicable laws, rules, or regulations.\" \r\n\r\n_Data collected (TMC):_ The TMC \"is designed to collect and use data such as Unique Advertising Identifiers, Statistical Identifiers, Geographic Location Data, Email Addresses, and other data provided by the Advertiser for attribution, app store optimization, and in-app marketing.\" \r\n\r\n_Data sharing (TMC):_ Advertisers \"are able to view and measure data provided by TUNE, as well as third-party Partners that the Advertiser selects, in the TMC. For instance, an Advertiser can compare the results of advertising campaigns conducted with different Partners in the TMC. Advertisers and Partners may also send information to the TMC via Postback\"... Advertisers can share all data collected through the TMC with Partners via Postback, data exports, and/or API calls\". TUNE itself may provide or disclose, or enable others to provide, End User Data for the purposes of detecting and preventing malicious activity of invalid traffic, or believe that we are legally required to do so.\" \r\n\r\n_Personally identifiable information:_ \"The TMC does not primarily rely on data that is considered \u201cpersonal\u201d in other jurisdictions for Attribution and App Store Optimization. The TMC does support automatic hashing in cases where the Advertiser chooses to upload \u201cpersonal\u201d data into the TMC to ensure that the TMC does not process such data in raw form\". A detailed list of what TUNE considers PII and non-PII can be found at their data & security web page [TUNE, 13](https://help.tune.com/marketing-console/the-importance-of-securing-data-in-the-tmc). \r\n\r\n_Advertiser data use permissions (TMC):_ Advertisers can use information collected through by the TMC for:\r\n\r\n* Attribution (eg, ad campaign analytics, cross-device attribution)\r\n* App Store Analytics (eg, A/B testing, analytics)\r\n* Audiences (eg, segments, behavioral and demographic profiling)\r\n* In-App Marketing (eg, push notifications, A/B testing of push notifications)\r\n\r\n_Regulation:_ TUNE complies with the Digital Advertising Alliance self-regulatory requirements.\r\n\r\n_International Law:_ TUNE adheres to the Privacy Shield Principles. \r\n\r\n_Security:_ TUNE \" uses commercially reasonable efforts including a variety of security technologies and procedures to secure client and End User Data from unauthorized access, use or disclosure\" [TUNE, 10](https://www.tune.com/resources/data-and-privacy/privacy-policies/tmc-privacy-policy).\r\n\r\n## Relationships\r\n_Customers:_ ebay / Sony / Expedia / LINE / Supercell / Flipkart / Staples / Zillow / Sephora / Kabam / Starz / Draft Kings [TUNE, 01](https://www.tune.com) / MovieStarPlanet / Zoosk / Cheerz / SaferVPN / Schoold / Appromoters [TUNE, 12](https://www.tune.com/resources/resource-library/#customer-stories)\r\n\r\n## Details\r\n_Financial details:_ TUNE was founded in 2009 and has raised over $36 million from funders [Crunchbase, 01](https://www.crunchbase.com/organization/tune). \r\n\r\n_Innovation:_ TUNE claims to be at the forefront of many innovations in the advertising industry. They state they are \"the first self-service performance marketing platform, the original mobile app measurement product, and the first multi-touch attribution for app advertising. We were also the first to combine app and web measurement, and the first to measure performance on nearly every mobile advertising platform like Google, Twitter, Snapchat and others\" [TUNE, 08](https://www.tune.com/who-we-are).\r\n\r\n## References\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/tune](https://www.crunchbase.com/organization/tune) \r\n* _TUNE, 01._ [https://www.tune.com](https://www.tune.com) \r\n* _TUNE, 02._ [https://www.tune.com/solutions/tune-marketing-console/in-app-marketing](https://www.tune.com/solutions/tune-marketing-console/in-app-marketing) \r\n* _TUNE, 03._ [https://www.tune.com/solutions/tune-marketing-console/our-difference](https://www.tune.com/solutions/tune-marketing-console/our-difference) \r\n* _TUNE, 04._ [https://www.tune.com/solutions/tune-marketing-console/attribution-analytics](https://www.tune.com/solutions/tune-marketing-console/attribution-analytics) \r\n* _TUNE, 05._ [https://www.tune.com/solutions/tune-marketing-console/app-store-analytics](https://www.tune.com/solutions/tune-marketing-console/app-store-analytics) \r\n* _TUNE, 06._ [https://www.tune.com/solutions/tune-marketing-console/mobile-ad-fraud-detection-prevention](https://www.tune.com/solutions/tune-marketing-console/mobile-ad-fraud-detection-prevention) \r\n* _TUNE, 07._ [https://developers.tune.com/sdk/measuring-in-app-events](https://developers.tune.com/sdk/measuring-in-app-events) \r\n* _TUNE, 08._ [https://www.tune.com/who-we-are](https://www.tune.com/who-we-are) \r\n* _TUNE, 09._ [http://www.optoutmobile.com](http://www.optoutmobile.com) \r\n* _TUNE, 10._ [https://www.tune.com/resources/data-and-privacy/privacy-policies/tmc-privacy-policy](https://www.tune.com/resources/data-and-privacy/privacy-policies/tmc-privacy-policy) \r\n* _TUNE, 11._ [https://www.tune.com/resources/data-and-privacy](https://www.tune.com/resources/data-and-privacy) \r\n* _TUNE, 12._ [https://www.tune.com/resources/resource-library/#customer-stories](https://www.tune.com/resources/resource-library/#customer-stories) \r\n* _TUNE, 13._ [https://help.tune.com/marketing-console/the-importance-of-securing-data-in-the-tmc](https://help.tune.com/marketing-console/the-importance-of-securing-data-in-the-tmc)\r\n\r\n## External Links\r\n* _Crunchbase (TUNE):_ [https://www.crunchbase.com/organization/tune](https://www.crunchbase.com/organization/tune)", "network_signature": "mobileapptracking\\.com", "creation_date": "2017-11-02", "id": 38, "website": "https://www.tune.com", "code_signature": "com.tune|com.mobileapptracker"}, "39": {"name": "Pushwoosh", "description": "## Primary Location\r\nUnited States (Washington, DC) [CrunchBase, 01](https://www.crunchbase.com/organization/pushwoosh)\r\n\r\n## Website\r\n[https://www.pushwoosh.com](https://www.pushwoosh.com)\r\n\r\n## About\r\nPushwoosh pushes in-app messaging across platforms [Pushwoosh, 01](https://www.pushwoosh.com)\r\n\r\n## Ownership\r\nPushwoosh\r\n\r\n## Documentation\r\n[http://docs.pushwoosh.com/docs/fcm-integration](http://docs.pushwoosh.com/docs/fcm-integration)\r\n\r\n## Products and services\r\nFeatures include:\r\n\r\n* _Data collection (via tags):_ \"Collect additional data from your users as Tags - gender, city and DOB, or the amount of money spent on in-app purchases. Then use this data for precise segmentation, personal communication, push automation and analytics.\"\r\n* _Real world location targeting:_ \"Try real-time location-based feature to send automated push notifications to users entering a specific area. Send your sale offers, discount alerts and welcoming messages automatically\" [Pushwoosh, 02](https://www.pushwoosh.com/features). \r\n * _Targeting in geozones:_ \"pins on the map that allow sending automatically triggered push notifications right at the moment a user enters the specified area on the map. Its range can be set from 50 to 1000 meters, and it has an adjustable cooldown period\" [Pushwoosh, 03](http://docs.pushwoosh.com/docs/geozones).\r\n * _iBeacon micro-targeting_ [Pushwoosh, 10](https://www.pushwoosh.com/blog/features-guides/ibeacons)\r\n* _Segmentation of audiences for marketing campaigns_ [Pushwoosh, 02](https://www.pushwoosh.com/features). Segments could include \"username, ID, city, favorite football team, preferred news categories, or any other piece of information about your users\" [Pushwoosh, 04](http://docs.pushwoosh.com/docs/segmentation-tags-and-filters).\r\n* _In-apps tracking:_ In-app purchases (\"The total amount of money spent on in-app purchases for the device\"); Last In-App Purchase Date (\"The date of the last in-app purchase made on the device\"); and In-App Product (\"Names of in-app products that were purchased on the device\") [Pushwoosh, 05](https://docs.pushwoosh.com/v1.0/docs/in-apps-tracking).\r\n* 250+ million pushes per day.\r\n* _Personalized messages:_ \"Address your users by name, and use any of their preferences in the message to make it relevant for every single user\"\r\n* _Statistics:_ \"Measure app installs and opens, push subscription, sent & open rates, all tag data statistics, and much more.\"\r\n* _In-app messaging:_ \"deeply customizable rich content in-app banners and full-screen interstitials.\"\r\n* _A/B Tests:_ \"Perform A/B tests on your audience to figure out which push configuration works better for you.\"\r\n* _Multiple languages_ [Pushwoosh, 02](https://www.pushwoosh.com/features)\r\n* _Conversion Tracking:_ Track \"the number of users who perform specific actions in your application or on your website after opening the push\" [Pushwoosh, 06](https://www.pushwoosh.com/conversion-tracking)\r\n* _Push Recovery Campaigns:_ Target abandon carts by returning customers to finish the transaction [Pushwoosh, 07](https://www.pushwoosh.com/abandoned-cart).\r\n* _Loyalty:_ Boost audience loyalty with personalized messages.\r\n* _Targeted messaging:_ Send targeted messages to segments [Pushwoosh, 09](https://www.pushwoosh.com/business-cases).\r\n\r\n## Privacy Policy\r\nPrivacy policy is listed at [Pushwoosh, 08](https://www.pushwoosh.com/privacy-policy). The Privacy Policy web page does not address opt-out; it appears to be directed at prospective business clients.\r\n\r\n## Relationships\r\nNissan / Mercedes / Leica / Bosch / Sabre / runtastic / Abbyy / Silicon Beach Media / Reaktor / redBit games / Saatchi & Saatchi / RTL Group / Skyjey / STC / SurfStitch / rtve / Ubisoft / Unaversidad APEC / Tripcase / Suzuki / VANSO / Veikkaus / Urban Rivals / XiMad / Sony Entertainment Television / MSC Cruises / Rayman Jungle Run / World Wide Fund for Nature (WWF) / Red Cross / Diner Dash / Plymouth University / Playscape / MLB.com / Marmalade / Mastercard / Hewlett-Packard / MTN / 3rd Sense / ixigo.com / JDG / Elektromarked / LOT Polish Airlines / FX Guru / G5 Games / Haaretz / Frima Studio / FunPlus / Concentra / Fanfair / Deloitte Digital / Exhibit Force / Firezoo / AppPresser / Autoliv / Bag It! / Carrefour / Chicago Tribune Trivia [Pushwoosh, 01](https://www.pushwoosh.com)\r\n\r\n## Details\r\n_Financial details:_ Pushwoosh was founded in 2011 [Crunchbase, 01](https://www.crunchbase.com/organization/pushwoosh).\r\n\r\n## References\r\n* _CrunchBase, 01._ [https://www.crunchbase.com/organization/pushwoosh](https://www.crunchbase.com/organization/pushwoosh) \r\n* _Pushwoosh, 01._ [https://www.pushwoosh.com](https://www.pushwoosh.com) \r\n* _Pushwoosh, 02._ [https://www.pushwoosh.com/features](https://www.pushwoosh.com/features)\r\n* _Pushwoosh, 03._ [http://docs.pushwoosh.com/docs/geozones](http://docs.pushwoosh.com/docs/geozones) \r\n* _Pushwoosh, 04._ [http://docs.pushwoosh.com/docs/segmentation-tags-and-filters](http://docs.pushwoosh.com/docs/segmentation-tags-and-filters) \r\n* _Pushwoosh, 05._ [https://docs.pushwoosh.com/v1.0/docs/in-apps-tracking](https://docs.pushwoosh.com/v1.0/docs/in-apps-tracking) \r\n* _Pushwoosh, 06._ [https://www.pushwoosh.com/conversion-tracking](https://www.pushwoosh.com/conversion-tracking) \r\n* _Pushwoosh, 07._ [https://www.pushwoosh.com/abandoned-cart](https://www.pushwoosh.com/abandoned-cart) \r\n* _Pushwoosh, 08._ [https://www.pushwoosh.com/privacy-policy](https://www.pushwoosh.com/privacy-policy) \r\n* _Pushwoosh, 09._ [https://www.pushwoosh.com/business-cases](https://www.pushwoosh.com/business-cases)\r\n\r\n## External Links\r\n* Owler company profile: [https://www.owler.com/iaApp/4589235/pushwoosh-company-profile](https://www.owler.com/iaApp/4589235/pushwoosh-company-profile)\r\n* Pushwoosh on Github: [https://github.com/Pushwoosh](https://github.com/Pushwoosh)", "network_signature": "pushwoosh\\.com", "creation_date": "2017-11-12", "id": 39, "website": "https://www.pushwoosh.com/", "code_signature": "com.pushwoosh"}, "40": {"name": "Demdex", "description": "## Primary Location\r\nUnited States\r\n\r\n## Website\r\n[https://www.adobe.com/data-analytics-cloud/audience-manager.html](https://www.adobe.com/data-analytics-cloud/audience-manager.html)\r\n\r\n## About\r\nDemdex offers audience management solutions for parts of Adobe's advertising ecosystem.\r\n\r\n## Ownership\r\nAdobe Systems Incorporated\r\n\r\n## Documentation\r\n[https://marketing.adobe.com/developer/get-started/mobile/c-measuring-mobile-applications](https://marketing.adobe.com/developer/get-started/mobile/c-measuring-mobile-applications)\r\n\r\n## Products and Services\r\nAdobe's Audience Manager service was build on top of the Demdex data bank product they acquired in 2011 [Analytics Demystified, 01](http://analyticsdemystified.com/adobe-analytics/adobes-new-marketing-cloud-visitor-id-how-does-it-work). Some services include:\r\n\r\n* _Segmenting:_ \"Build, test, and activate...audiences...based on a set of traits\". \"Divide millions of records into trait-specific categories\" like \"moms of grade school kids\". Find new prospects with \"look-alike modeling\"; \"pinpoint your most frequent users, as well as how recently they've interacted with your marketing.\" \r\n* _Cross-device identification:_ Use the \"profiling feature\" in Audience Manager \"to tie one profile to multiple devices\" and \"discover if users are sharing a device, for instance, within a household\". Target customers \"after they may logged off your site or app.\"\r\n* _Reports:_ Generate reports like Optimal Frequency reports, Advertiser Performance Reports to gain insight about user interactions like impressions, clicks, and conversions \r\n* _Predictive analytics:_ Performs predictive analytics\r\n* Organize your own first party data and augment it with second or third party data with the Audience Marketplace feature\r\n* Price your data for sale and partners [Adobe, 19](https://www.adobe.com/data-analytics-cloud/audience-manager.html)\r\n* _Geotargeting and location-based targeting:_ Adobe Mobile Marketing offers \"support for many location services, including GPS, geofencing, beacons, and more\". Geolocation services allow marketers to \"measure and respond to user engagement in mobile apps connected to beacons in sports stadiums, retail stores, and other points of interest. Marketers can also easily deliver \u201clocal\u201d notifications and promotions based on proximity to a beacon. In addition, companies can tie app interactions to all other app engagement data in Adobe Analytics\" [Adobe, 23](https://blogs.adobe.com/digitalmarketing/mobile/10-things-you-need-to-know-about-adobes-mobile-marketing). Adobe states that \"app targeting based on GPS location and proximity to a particular area in a store or event venue\", built into Analytics and Target products [MarketWatch, 01](https://www.marketwatch.com/story/adobe-launches-mobile-services-for-adobe-marketing-cloud-2013-11-07); [Forbes, 01](https://www.forbes.com/sites/roberthof/2013/11/07/adobe-takes-its-marketing-cloud-services-mobile); [PCWorld, 01](https://www.pcworld.com/article/2061880/adobe-adds-geolocation-targeting-to-marketing-cloud.html).\r\n* Real-time geo- and location-based targeting: Adobe's in-app messaging feature \" allows marketers to promote real-time content (e.g., new video, breaking news) or cross-promote apps, products, or services to people who are actively using their app. Messages, such as full-screen communications, alerts, and local notifications, can be triggered by analytics data, including user behavior, lifecycle metrics, or location (GPS or iBeacons), that is collected with the Mobile Services SDK. In-app messaging can be deployed without the need for app development or a new app update in the app store\" [Adobe, 23](https://blogs.adobe.com/digitalmarketing/mobile/10-things-you-need-to-know-about-adobes-mobile-marketing)\r\n* A/B testing [Forbes, 01](https://www.forbes.com/sites/roberthof/2013/11/07/adobe-takes-its-marketing-cloud-services-mobile) \r\n\r\nA variety of other services extend across the Adobe Marketing & Analytics ecosystem. The Demdex SDK may collect information for those services, including Adobe Campaign and Adobe Experience Manager [MarketWatch, 01](https://www.marketwatch.com/story/adobe-launches-mobile-services-for-adobe-marketing-cloud-2013-11-07). See \"Details\" below.\r\n\r\n## Privacy Policy\r\nAdobe business customers \"use Adobe Marketing Cloud services to collect and analyze information, such as clicks made by visitors on their websites\" [Adobe, 21](https://www.adobe.com/privacy/opt-out.html).\r\n\r\n_Data Privacy:_ \"App publishers can easily manage opt-in or opt-out functionality to enable compliance with data collection and privacy laws for specific countries including the Children's Online Privacy Protection Act (COPPA). In addition, Adobe Mobile services customers own their data - not Adobe\" [Forbes, 01](https://www.forbes.com/sites/roberthof/2013/11/07/adobe-takes-its-marketing-cloud-services-mobile). \r\n\r\nIn 2013, Adobe's Ray Pun stated that users must opt-in for geotargeting services, and that companies must write their terms in conditions \"in a language that a normal person can understand, not an attorney\" [PCWorld, 01](https://www.pcworld.com/article/2061880/adobe-adds-geolocation-targeting-to-marketing-cloud.html). \r\n\r\n_Mobile privacy policy:_ Adobe Marketing Cloud states that a \"company may also use Adobe Marketing Cloud technologies within its mobile apps. These technologies allow the company to send information to its Adobe Marketing Cloud account -- for example, how you use the company\u2019s mobile apps as well as other information your mobile device may make available to apps, such as location information.\"\r\n\r\n_Mobile opt-out:_ For opting out of mobile data collection and use in connection with Adobe Marketing Cloud, Adobe states that \"Most mobile devices allow you to the limit use of mobile advertising identifiers for interest-based advertising. For more information, please review the instructions provided by your mobile device manufacturer. The Digital Advertising Alliance\u2019s AppChoices app may also provide you with more options to opt out of receiving interest-based advertising within mobile apps. Please see Your Privacy Choices to learn more about your choices for opting out of companies\u2019 use of Adobe Marketing Cloud solutions.\"\r\n\r\nAdobe has an opt-out web page [Adobe, 21](https://www.adobe.com/privacy/opt-out.html) and a page for Audience Manager privacy policy [Adobe, 22](https://marketing.adobe.com/resources/help/en_US/aam/faq_privacy.html).\r\n\r\nAdobe suggests users \"review the privacy policy\" of the mobile app company \"as well as privacy information provided by your mobile device manufacturer\" [Adobe, 20](http://www.adobe.com/privacy/marketing-cloud.html). They also recommend \"self-regulatory sites\" like the Digital Advertising Alliance to opt out of advertising solutions by companies who are members of those groups [Adobe, 21](https://www.adobe.com/privacy/opt-out.html).\r\n\r\n## Relationships\r\n_Clients:_ Princess / Conde Nast / Lenovo [Adobe, 17](http://www.adobe.com/data-analytics-cloud/audience-manager.html) \r\n\r\n_Partners:_ Accenture Interactive / Cognizant / Deloitte Digital / dentsu aegis network / Epsilon / Havas / IBM / iCrossing / Infosys / IPG / OmnicomGroup / Publicis Groupe / pwc / Tata Consultancy Services / wipro / WPP [Adobe, 24](http://www.adobe.com/experience-cloud/service-support/partners.html)\r\n\r\n## Details\r\n### Financial details & history\r\nIn 2011, Adobe acquired Demdex for $109 million [Crunchbase, 01](https://www.crunchbase.com/organization/demdex). Demdex offered a \"behavioral data bank\" for advertising purposes. The data bank was used for audience segmenting, and could be plugged into ad servers or services, giving websites and advertisers control over the data. DemDex was added to Adobe's \"Online Marketing Suite\" (powered by Adobe-acquired Omniture) [TechCrunch, 01](https://techcrunch.com/2011/01/18/adobe-buys-behavioral-data-management-platform-demdex). \r\n\r\n### Adobe Audience Manager\r\nAdobe Audience Manager is Adobe's data management platform, built on top of the Demdex product they acquired in 2011 [Analytics Demystified, 01](http://analyticsdemystified.com/adobe-analytics/adobes-new-marketing-cloud-visitor-id-how-does-it-work). Audience Manager:\r\n\r\n* Gives a \"complete view\" of an audience by combining clients' data sources into one place [Adobe, 17](http://www.adobe.com/data-analytics-cloud/audience-manager.html)\r\n* Segments audiences for \"smart targeting\" and \"personalization\" for targeted advertisements [Adobe, 02](https://www.adobe.com/data-analytics-cloud/audience-manager/audience-segmentation.html)\r\n* Targets \"specific segments on any platform\" [Adobe, 19](https://www.adobe.com/data-analytics-cloud/audience-manager.html)\r\n\r\nIt aims to provide \"a seamless experience and a seamless profile for all the different marketing cloud solutions to use. It's also a gateway for the broader ecosystem\" such that clients with their own proprietary platforms or working with other technologies outside of Adobe, \"audience manager helps with the syndication and consistency of that audience regardless of the actual technology that is serving and delivering that audience experience. Ultimately Audience Manager allows marketers to take this vast amount of information, transform it into meaningful audience segments, to deliver the most effective message at the right time\" [Adobe, 18](https://www.adobe.com/data-analytics-cloud/audience-manager.html#m226a251c23c15530b6f70ef20da2003c)\r\n\r\nProducts it integrates with include Adobe Target and Adobe Media Optimizer, as well as solutions beyond the Marketing Cloud [Adobe, 19](https://www.adobe.com/data-analytics-cloud/audience-manager.html#x).\r\n\r\n### Adobe Marketing & Analytics ecosystem: The Adobe Experience Cloud\r\nThe Adobe Experience Cloud provides \"access to an integrated set of solutions to build campaigns, manage your advertising, and gain deep intelligence about your business. And it\u2019s all unified through powerful core services that give you access to your customer profiles, centralized assets, powerful tagging, and an ecosystem of partners and developers to extend the value of all the solutions\". Adobe's Experience Cloud website features the Adobe Advertising Cloud, Adobe Analytics Cloud, and Adobe Marketing Cloud [Adobe, 07](www.adobe.com/experience-cloud/overview.html).\r\n\r\n#### Adobe Marketing Cloud\r\nProvides a \"set of integrated digital marketing solutions...to organize, access, and personalize your marketing content\". Adobe Marketing Cloud solutions fall into four categories:\r\n\r\n* _Measurement solutions_, \"which help companies measure and understand how you use their websites, apps, social networking pages, as well as how you interact with their online marketing campaigns\"\r\n* _Personalization solutions_, \"which help companies test new content and make their websites, apps, social networking pages, and emails more relevant to you\"\r\n* _Content management solutions_, \"which help companies store, update, and deliver images and other content on their websites, within their apps, and in online marketing materials\"\r\n* _Advertising solutions_, which help companies improve their online advertising on websites, search engines, and social media platforms. These solutions also help companies send emails, text messages, and other online and offline marketing campaigns\" [Adobe, 20](http://www.adobe.com/privacy/marketing-cloud.html)\r\n\r\nProducts include:\r\n\r\n* _Adobe Experience Manager:_ \"helps you manage all your assets, build websites and mobile apps, and integrate content from online communities\" [Adobe, 03](http://www.adobe.com/marketing-cloud.html); [Adobe, 10](http://www.adobe.com/marketing-cloud/experience-manager.html)\r\n* _Adobe Campaign:_ \"helps you personalize and deliver your campaigns across all your channels, from web and mobile to email and display\" [Adobe, 03](http://www.adobe.com/marketing-cloud.html); [Adobe, 11](http://www.adobe.com/marketing-cloud/campaign.html)\r\n* _Adobe Target:_ \"helps you turn data into results by testing and personalizing your content so you can deliver the best content to the right audience\" [Adobe, 03](http://www.adobe.com/marketing-cloud.html); [Adobe, 12](http://www.adobe.com/marketing-cloud/target.html)\r\n* _Adobe Primetime:_ \"helps you create, deliver, and monetize personal video experiences\" [Adobe, 03](http://www.adobe.com/marketing-cloud.html); [Adobe, 13](http://www.adobe.com/marketing-cloud/primetime.html)\r\n* _Adobe Social:_ \"helps you create relevant social content and quantify your social marketing results\" [Adobe, 03](http://www.adobe.com/marketing-cloud.html)\r\n\r\n#### Adobe Advertising Cloud\r\nAdobe states this is \"the industry\u2019s first end-to-end platform for managing advertising across traditional TV and digital formats\". It is a cross-channel platform that delivers \"video, display, and search advertising across any screen in any format\"; \"media planning and buying are integrated into one programmatic solution\" [Adobe, 04](http://www.adobe.com/advertising-cloud.html). Produce include:\r\n\r\n* _Demand Side Platform:_ A \"unified cross-channel, software-based solution\" to \"streamline global advertising from a single platform\" [Adobe, 05](https://www.adobe.com/advertising-cloud/media-optimizer/demand-side-platform.html)\r\n* _Adobe Media Optimizer:_ This \"uses unified campaign tracking and reporting, real-time bidding, impression-level decisioning abilities, attribution reporting and simulations, and integration with the top ad exchanges to help you meet display objectives\" [Adobe, 06](https://www.adobe.com/advertising-cloud/media-optimizer/display-advertising-management.html)\r\n* _Brand Safety:_ Prevent advertising campaigns from \"mixing with content and properties that don't align with your brand's image\" [Adobe, 08](https://www.adobe.com/advertising-cloud/protecting-brand-equity.html)\r\n* _Dynamic creative optimization:_ Reach \"specific audiences with flexible ad creative that\u2019s personalized in real time to drive user engagement, conversions, and integrated experiences\". Use dynamic creatives to \"target customers with flexible ad creative that\u2019s personalized in real time based on site actions, customer and partner data, and third-party demographic data\" [Adobe, 09](https://www.adobe.com/advertising-cloud/media-optimizer/dynamic-creative-optimization.html)\r\n\r\n#### Adobe Analytics Cloud\r\nAdobe Analytics Cloud aims to provide a business' \"core intelligence engine\". It strives to bring \"context to online and offline data\" and build \"loyalty with customers\". It offers \"intelligence\" and \"precise audience creation\" to help put \"real-time insights into action\". \r\n\r\nServices include:\r\n\r\n* _Accessible analytics:_ \"Make enterprise-level marketing analytics understandable and accessible to everyone in your organization\"\r\n* _Precise segmentation:_ \"Continuously refine the view of your customers. As you do, you\u2019ll discover and create high-value audiences and understand the best way to reach them\"\r\n* _Real-time tageting:_ \"Connect your analytics with real-time activation so the transition from insight to action is as fast as it can be\"\r\n* _Next-generation attribution:_ \"To understand your ROI, you need an objective view of the customer journey across every device and channel \u2014 paid, earned, and owned\" [Adobe, 15](http://www.adobe.com/data-analytics-cloud.html)\r\n\r\nProducts include:\r\n\r\n* _Adobe Analytics:_ \"Discover your most valuable customer segments and use these insights to steer your entire business with customer intelligence\" [Adobe, 16](http://www.adobe.com/data-analytics-cloud/analytics.html)\r\n* _Adobe Audience Manager:_ A \"data management platform (DMP) that helps you build unique audience profiles so you can identify your most valuable segments and use them across any digital channel\" [Adobe, 17](http://www.adobe.com/data-analytics-cloud/audience-manager.html)\r\n\r\n### Device support\r\nAdobe's platform support \"includes Apple App Store, Google Play, Amazon Appstore, Windows Store, and Windows Phone Store, as well as analytics support for Roku, Xbox, AppleTV, PlayStation, and other connected devices\" [Adobe, 23](https://blogs.adobe.com/digitalmarketing/mobile/10-things-you-need-to-know-about-adobes-mobile-marketing)\r\n\r\n## References\r\n* _Adobe, 01_. [http://www.adobe.com/marketing-cloud.html](http://www.adobe.com/marketing-cloud.html) \r\n* _Adobe, 02_. [https://www.adobe.com/data-analytics-cloud/audience-manager/audience-segmentation.html](https://www.adobe.com/data-analytics-cloud/audience-manager/audience-segmentation.html) \r\n* _Adobe, 03_. [http://www.adobe.com/marketing-cloud.html](http://www.adobe.com/marketing-cloud.html) \r\n* _Adobe, 04_. [http://www.adobe.com/advertising-cloud.html](http://www.adobe.com/advertising-cloud.html) \r\n* _Adobe, 05_. [https://www.adobe.com/advertising-cloud/media-optimizer/demand-side-platform.html](https://www.adobe.com/advertising-cloud/media-optimizer/demand-side-platform.html) \r\n* _Adobe, 06_. [https://www.adobe.com/advertising-cloud/media-optimizer/display-advertising-management.html](https://www.adobe.com/advertising-cloud/media-optimizer/display-advertising-management.html) \r\n* _Adobe, 07_. [https://www.adobe.com/experience-cloud/overview.html](https://www.adobe.com/experience-cloud/overview.html) \r\n* _Adobe, 08_. [https://www.adobe.com/advertising-cloud/protecting-brand-equity.html](https://www.adobe.com/advertising-cloud/protecting-brand-equity.html) \r\n* _Adobe, 09_. [https://www.adobe.com/advertising-cloud/media-optimizer/dynamic-creative-optimization.html](https://www.adobe.com/advertising-cloud/media-optimizer/dynamic-creative-optimization.html) \r\n* _Adobe, 10_. [http://www.adobe.com/marketing-cloud/experience-manager.html](http://www.adobe.com/marketing-cloud/experience-manager.html) \r\n* _Adobe, 11_. [http://www.adobe.com/marketing-cloud/campaign.html](http://www.adobe.com/marketing-cloud/campaign.html) \r\n* _Adobe, 12_. [http://www.adobe.com/marketing-cloud/target.html](http://www.adobe.com/marketing-cloud/target.html) \r\n* _Adobe, 13_. [http://www.adobe.com/marketing-cloud/primetime.html](http://www.adobe.com/marketing-cloud/primetime.html) \r\n* _Adobe, 14_. [http://www.adobe.com/marketing-cloud/social.html](http://www.adobe.com/marketing-cloud/social.html) \r\n* _Adobe, 15_. [http://www.adobe.com/data-analytics-cloud.html](http://www.adobe.com/data-analytics-cloud.html) \r\n* _Adobe, 16_. [http://www.adobe.com/data-analytics-cloud/analytics.html](http://www.adobe.com/data-analytics-cloud/analytics.html) \r\n* _Adobe, 17_. [http://www.adobe.com/data-analytics-cloud/audience-manager.html](http://www.adobe.com/data-analytics-cloud/audience-manager.html) \r\n* _Adobe, 18_. [https://www.adobe.com/data-analytics-cloud/audience-manager.html#m226a251c23c15530b6f70ef20da2003c](https://www.adobe.com/data-analytics-cloud/audience-manager.html#m226a251c23c15530b6f70ef20da2003c) \r\n* _Adobe, 19_. [https://www.adobe.com/data-analytics-cloud/audience-manager.html#x](https://www.adobe.com/data-analytics-cloud/audience-manager.html#x) \r\n* _Adobe, 20_. [http://www.adobe.com/privacy/marketing-cloud.html](http://www.adobe.com/privacy/marketing-cloud.html) \r\n* _Adobe, 21_. [https://www.adobe.com/privacy/opt-out.html](https://www.adobe.com/privacy/opt-out.html) \r\n* _Adobe, 22_. [https://marketing.adobe.com/resources/help/en_US/aam/faq_privacy.html](https://marketing.adobe.com/resources/help/en_US/aam/faq_privacy.html) \r\n* _Adobe, 23_. [https://blogs.adobe.com/digitalmarketing/mobile/10-things-you-need-to-know-about-adobes-mobile-marketing](https://blogs.adobe.com/digitalmarketing/mobile/10-things-you-need-to-know-about-adobes-mobile-marketing) \r\n* _Adobe, 24_. [http://www.adobe.com/experience-cloud/service-support/partners.html](http://www.adobe.com/experience-cloud/service-support/partners.html) \r\n* _Analytics Demystified, 01_. [http://analyticsdemystified.com/adobe-analytics/adobes-new-marketing-cloud-visitor-id-how-does-it-work](http://analyticsdemystified.com/adobe-analytics/adobes-new-marketing-cloud-visitor-id-how-does-it-work) \r\n* _Crunchbase, 01_. [https://www.crunchbase.com/organization/demdex](https://www.crunchbase.com/organization/demdex) \r\n* _Forbes, 01_. [https://www.forbes.com/sites/roberthof/2013/11/07/adobe-takes-its-marketing-cloud-services-mobile](https://www.forbes.com/sites/roberthof/2013/11/07/adobe-takes-its-marketing-cloud-services-mobile) \r\n* _MarketWatch, 01_. [https://www.marketwatch.com/story/adobe-launches-mobile-services-for-adobe-marketing-cloud-2013-11-07](https://www.marketwatch.com/story/adobe-launches-mobile-services-for-adobe-marketing-cloud-2013-11-07) \r\n* _PCWorld, 01_. [https://www.pcworld.com/article/2061880/adobe-adds-geolocation-targeting-to-marketing-cloud.html](https://www.pcworld.com/article/2061880/adobe-adds-geolocation-targeting-to-marketing-cloud.html) \r\n* _TechCrunch, 01_. [https://techcrunch.com/2011/01/18/adobe-buys-behavioral-data-management-platform-demdex](https://techcrunch.com/2011/01/18/adobe-buys-behavioral-data-management-platform-demdex)\r\n\r\n## External links\r\n* _Wikipedia (Adobe Marketing Cloud_: [https://en.wikipedia.org/wiki/Adobe_Marketing_Cloud](https://en.wikipedia.org/wiki/Adobe_Marketing_Cloud) \r\n* _Adobe Audience Manager_: [https://www.adobe.com/data-analytics-cloud/audience-manager.html](https://www.adobe.com/data-analytics-cloud/audience-manager.html) \r\n* _Adobe Marketing Cloud_: [http://www.adobe.com/marketing-cloud.html](http://www.adobe.com/marketing-cloud.html)", "network_signature": "demdex\\.net", "creation_date": "2017-11-15", "id": 40, "website": "https://www.adobe.com/data-analytics-cloud/audience-manager.html", "code_signature": "com.adobe.mobile.Analytics"}, "41": {"name": "AdsWizz", "description": "", "network_signature": "adswizz\\.com|cdn\\.adswizz.com\\.edgesuite\\.net", "creation_date": "2017-11-15", "id": 41, "website": "http://www.adswizz.com/", "code_signature": ".adswizz."}, "42": {"name": "ExactTarget", "description": "Belongs to SalesForce", "network_signature": "\\.exacttarget\\.", "creation_date": "2017-11-16", "id": 42, "website": "http://help.exacttarget.com/en/technical_library/API_Overview/", "code_signature": "com.exacttarget."}, "43": {"name": "Omniture", "description": "## About\r\n\r\nOmniture, originally a online marketing and web analytics company, was acquired by Adobe in 2009 and it was run as a separate business unit until 2012 when it was integrated into the Adobe Marketing Cloud. Several of Omniture's LLC filings remain active. [Source: OpenCorporates](https://opencorporates.com/companies/us_de/3077923)\r\n\r\n## Ownership\r\n\r\nAdobe (NASDAQ: ADBE) is a publicly-traded multinational software company. \r\n\r\n## What it does\r\n\r\n* Behavioral Analytics\r\n* Online Marketing\r\n* Machine-learning Analysis\r\n\r\n## Privacy Policy\r\n\r\n[Onminture's Privacy Policy is the same as Adobe's. Policy dated 3/5/18 and reviewed 17/11/2018:](https://www.adobe.com/privacy/policy.html)\r\n\r\n* Adobe's Privacy Policy is broad and covers the span of its wide-ranging services. It is unclear what is specifially covered by the Omniture business line. \r\n\r\n* Users must opt-out of each segment of data collection individually: Desktop Identifiable Data Collection, Device Identifiable Data Collection, Mobile Data Collection, Experience Cloud service usage data, \r\nMachine learning analysis of user content, Interest-based ads, and Adobe websites. [Link to opt-out](https://www.adobe.com/privacy/opt-out.html)\r\n\r\n* Data may be shared with fraud prevention services, law enforcement services in the context of an investigation, social media marketers and platforms, sales and advertising partners, retailers, research organizations, advertisers, ad agencies, advertising networks and platforms, information service providers, publishers, and non-profit organizations.", "network_signature": "omtrdc\\.net|omniture\\.com", "creation_date": "2017-11-16", "id": 43, "website": "http://www.omniture.com", "code_signature": "com.omniture.|com.adobe.adms.measurement."}, "44": {"name": "Safe Graph", "description": "* Website: https://www.safegraph.com, https://github.com/OpenLocate\r\n* Comment: SafeGraph specializes in the collection of physical location data for data mining and analytics. OpenLocate is the SDK announced in 2017.\r\n* Category: [Location]\r\n* Code signature: `com.safegraph.|com.openlocate`\r\n* Network signature: `api\\.safegraph\\.com`\r\n* Maven repository: `https://s3-us-west-2.amazonaws.com/openlocate-android/`\r\n* Artifact ID: `openlocate-android`\r\n* Group ID: `com.openlocate` \r\n* Gradle: `com.openlocate:openlocate:1.+`\r\n* Additional links: [OpenLocate SDK repo](https://github.com/OpenLocate/openlocate-android/), [Crunchbase](https://www.crunchbase.com/organization/safegraph), [Stanford economics paper](https://web.archive.org/web/20171116110210if_/https://economics.stanford.edu/sites/default/files/sharable_fulldraft.pdf), [Washington Post](https://www.washingtonpost.com/news/wonk/wp/2017/11/15/politics-really-is-ruining-thanksgiving-according-to-data-from-10-million-cellphones), [The Outline](https://theoutline.com/post/2490/why-is-this-company-tracking-where-you-are-on-thanksgiving)\r\n* Notes: SafeGraph collected 17 trillion location markers for 10 million smartphones in November 2016. OpenLocate SDK for Android is MIT/Expat licensed.\r\n\r\n## Primary Location\r\nUnited States (San Francisco) [Crunchbase, 01](https://www.crunchbase.com/organization/safegraph)\r\n\r\n## Website\r\n[https://www.safegraph.com](https://www.safegraph.com)\r\n\r\n## About\r\nSafeGraph specializes in the collection of physical location data for data mining and analytics.\r\n\r\n## Ownership\r\nSafeGraph\r\n\r\n## Documentation\r\n[https://github.com/OpenLocate/openlocate-android](https://github.com/OpenLocate/openlocate-android)\r\n\r\n## Products and Services\r\nSafeGraph is a data company which aims to build a robust and detailed location-based tracking service for advertisers, industry, government and researchers. Products and services include:\r\n\r\n* _SafeGraph Movement Panel:_ SafeGraph's \"database of ultra-accurate GPS-location data that comes from anonymized mobile devices.\" The Movement panel offers:\r\n * _Sink detection:_ Detection of inaccurate location data based on \" specific coordinates occurring at impossibly high rates\".\r\n * _Teleporting detection:_ Detection of inaccurate location data when \"devices appear to move at impossibly fast speeds, ostensibly traveling large distances between data points that occur next to each other\" in data streams like bid streams.\r\n * _Jumpiness detection:_ Detection of innacurate location data when \"we see two consecutive points in time that are fairly close but still implausibly spaced\" (eg, \"the GPS receiver in your phone lags or if a nearby skyscraper interferes with the location signal\") [SafeGraph, 01](https://blog.safegraph.com/less-than-10-of-bid-stream-location-data-is-high-quality-and-we-know-how-to-find-it-3a2c0df35475)\r\n* _SafeGraph Places API:_ This \"to easily find the places of interest that are near a given lat/long, ordered by distance or relevance\" [SafeGraph, 03](https://developers.safegraph.com/docs/places.html).\r\n* _OpenLocate:_ The OpenLocate SDK will \"collect location data (like GPS) from phones\" [SafeGraph, 04](https://github.com/OpenLocate). This includes an Android and iOS SDK. The service is built to provide developers complete control over their location data. Developers can build location-enabled features into their apps and \"maintain complete control over how end-user data is collected, where it is stored, and which APIs it will be sent to\". This includes sending to storage services (like Amazon S3) or APIs (such as Google Places API or SafeGraph's Places API) [SafeGraph, 05](https://blog.safegraph.com/introducing-openlocate-the-open-source-location-sdk-f5c5d2739a48).\r\n\r\nOther services include:\r\n* \"Detailed polygon maps on 50+ million U.S. places of interest\r\n* Understanding of each business's popularity, taxonomy, hours, etc.\r\n* Core investments in benchmarking via truth sets\"\r\n * This includes Explicit Truth Sets (Check-ins, Daily diaries, Web surveys) and Implicit Truth Sets (Credit card data, Receipt data, First-party transactions) \r\n\r\nData from visits may include:\r\n\r\n* _Core truth set for matching:_\r\n * High-res GPS data\r\n * Deterministic data\r\n * Explicit and implicit truth\r\n * Data collected in background from large population\r\n* _Deep places map:_\r\n * Best polygons\r\n * Footprint geometries\r\n * Metadata\r\n * Categories\r\n * Hours of operation\r\n* Machine learning technology\r\n * Cross-validated against multiple independent 3rd party truth sets about where people go\r\n* _Truth and accuracy_\r\n * High Precision // Low false positive rate; High recall // Low false negative rate\" [SafeGraph, 06](https://www.safegraph.com/truth)\r\n\r\n## Privacy Policy\r\n_Data collection (method and use):_ SafeGraph collects data from \"trusted third-party data partners such as mobile application developers, through APIs and other delivery methods\". The data collection and use is \"governed by the privacy policy and legal terms of the data collector and the website using the data; it is not governed by SafeGraph.\" SafeGraph \"aggregates data collected from our data partners, and allows third party customers to access the Data for a variety of purposes such as ad targeting, traffic analysis, and market research.\" SafeGraph may also use data for their own \"internal and operational purposes\", and share data in response to requests from law enforcement or a governmental agency, \"to protect or enforce our rights or those of others, or to investigate potential wrongdoing.\" Data can also be transferred to a successor entity in the event of a merger or acquisition.\r\n\r\n_Information collected:_ Information collected includes \"data regarding a device\u2019s precise geographic location, as well as other mobile identifiers such as Apple IDFAs and Google Android IDs, and other information about users and their devices.\" \r\n\r\n_Jurisdictions:_ \"SafeGraph stores and processes information on servers in many countries around the world. We therefore may process your information on a server located outside the country where you live... Our customers (or companies that help us process the Data) may be located in other countries, so the Data we provide may be processed or used in a variety of countries, other than those our users reside in.\" Customers of SafeGraph may create cross-device capabilities \"to enable marketers to target users across various channels and devices.\"\r\n\r\n_Opt-out:_ SafeGraph informs users of opt-out procedures for interest-based advertising and location tracking. To opt out of interest-based advertising, they state, users can adjust settings in their Android or iOS devices. This procedure, which they note may change, is mentioned in the SafeGraph privacy policy \"purely for informational purposes.\" SafeGraph further notes that \"You also can remove your consent to having your location data collected by changing the settings on your device. (Certain services may lose functionality as a result.)\" SafeGraph's Privacy Policy provides links to the Network Advertising Initiative and the Digital Advertising Alliance, as well as www.youronlinechoices.com. It informs users that these websites may provide additional opt-out options.\r\n\r\n_Retention:_ Information SafeGraph collects is \"retained indefinitely unless there has been a direct opt-out with us as directed above.\"\r\n\r\n_Security:_ SafeGraph has security policies and procedures to \" ensure compliance with industry best practices.\" They state, \"no physical or technological safeguards are 100 percent secure, we do not guarantee the security of any particular elements of Data that we hold\" [SafeGraph, 07](https://www.safegraph.com/privacy-policy).\r\n\r\n## Relationships\r\n_Clients and partners:_ Statiq / AirSage / Stanford University / GroundTruth (formerly xAd) / UCLA / Baylor University / Weborama / Tufts University / The University of Chicago / Alphonzo / Freckle IoT / Georgia Tech / Esri / Appnext / 4Info / Research Now / Tapfwd / Arrivalist / Placecast / ThinkNear by Telenav / Pitney Bowes / Columbia University / Purdue University / UC San Diego / Sidewalk Labs / Temple University / Citilabs / PlaceIQ / Moovit / Skyhook / Postie / PicsArt / Oklahoma State University / Santa Clara University / OpenLocate\r\n\r\n## Details\r\n_Financial details:_ SafeGraph was founded in 2016, and has raised $16 million from funders [Crunchbase, 01](https://www.crunchbase.com/organization/safegraph); [SafeGraph, 02](https://blog.safegraph.com/safegraph-raises-16-million-series-a-e8e88eeb7beb) \r\n\r\n_Scope:_ SafeGraph \"has access to super-accurate, anonymized location data on over 5% of all mobile phones in the U.S. (as of August 2017)\" and is \"increasing that percentage every day\" [SafeGraph, 01](https://blog.safegraph.com/less-than-10-of-bid-stream-location-data-is-high-quality-and-we-know-how-to-find-it-3a2c0df35475).\r\n\r\n_Slogans:_\r\n\r\n* \"SafeGraph maintains the ground truth dataset for human movement across the globe\"\r\n* \"We provide high-quality location data products to help organizations make better decisions and improve lives\"\r\n\r\n## References\r\n* _Crunchbase, 01._ [https://www.crunchbase.com/organization/safegraph](https://www.crunchbase.com/organization/safegraph) \r\n* _SafeGraph, 01._ [https://blog.safegraph.com/less-than-10-of-bid-stream-location-data-is-high-quality-and-we-know-how-to-find-it-3a2c0df35475](https://blog.safegraph.com/less-than-10-of-bid-stream-location-data-is-high-quality-and-we-know-how-to-find-it-3a2c0df35475) \r\n* _SafeGraph, 02._ [https://blog.safegraph.com/safegraph-raises-16-million-series-a-e8e88eeb7beb](https://blog.safegraph.com/safegraph-raises-16-million-series-a-e8e88eeb7beb) \r\n* _SafeGraph, 03._ [https://developers.safegraph.com/docs/places.html](https://developers.safegraph.com/docs/places.html) \r\n* _SafeGraph, 04._ [https://github.com/OpenLocate](https://github.com/OpenLocate) \r\n* _SafeGraph, 05._ [https://blog.safegraph.com/introducing-openlocate-the-open-source-location-sdk-f5c5d2739a48](https://blog.safegraph.com/introducing-openlocate-the-open-source-location-sdk-f5c5d2739a48) \r\n* _SafeGraph, 06._ [https://www.safegraph.com/truth](https://www.safegraph.com/truth) \r\n* _SafeGraph, 07._ [https://www.safegraph.com/privacy-policy](https://www.safegraph.com/privacy-policy)\r\n\r\n## External Links\r\n* _Crunchbase (SafeGraph):_ [https://www.crunchbase.com/organization/safegraph](https://www.crunchbase.com/organization/safegraph) \r\n* _Gigya:_ [https://www.gigya.com/blog/exploring-future-identity](https://www.gigya.com/blog/exploring-future-identity) \r\n* _Even:_ [https://evenfinancial.com/press/mit-brings-together-fintech-financial-services-first-ever-hackathon](https://evenfinancial.com/press/mit-brings-together-fintech-financial-services-first-ever-hackathon) \r\n* _SafeGraph:_ [https://blog.safegraph.com/less-than-10-of-bid-stream-location-data-is-high-quality-and-we-know-how-to-find-it-3a2c0df35475](https://blog.safegraph.com/less-than-10-of-bid-stream-location-data-is-high-quality-and-we-know-how-to-find-it-3a2c0df35475) \r\n* _Stanford Economics:_ [https://web.archive.org/web/20171116110210if_/https://economics.stanford.edu/sites/default/files/sharable_fulldraft.pdf](https://web.archive.org/web/20171116110210if_/https://economics.stanford.edu/sites/default/files/sharable_fulldraft.pdf) \r\n* _Washington Post:_ [https://www.washingtonpost.com/news/wonk/wp/2017/11/15/politics-really-is-ruining-thanksgiving-according-to-data-from-10-million-cellphones](https://www.washingtonpost.com/news/wonk/wp/2017/11/15/politics-really-is-ruining-thanksgiving-according-to-data-from-10-million-cellphones) \r\n* _The Outline:_ [https://theoutline.com/post/2490/why-is-this-company-tracking-where-you-are-on-thanksgiving](https://theoutline.com/post/2490/why-is-this-company-tracking-where-you-are-on-thanksgiving)", "network_signature": "api\\.safegraph\\.com", "creation_date": "2017-11-16", "id": 44, "website": "https://www.safegraph.com/", "code_signature": "com.safegraph.|com.openlocate"}, "45": {"name": "Tag Commander", "description": "", "network_signature": "\\.commander1\\.com", "creation_date": "2017-11-28", "id": 45, "website": "https://www.commandersact.com/en/", "code_signature": "com.tagcommander."}, "46": {"name": "CrowdTangle", "description": "We can only detect network activity of this tracker.\r\n\r\n * [API doc](https://github.com/CrowdTangle/API/wiki)\r\n * [Mediapart article](https://www.mediapart.fr/journal/france/011217/comment-facebook-achete-la-presse-francaise)", "network_signature": "api\\.crowdtangle\\.com", "creation_date": "2017-12-03", "id": 46, "website": "https://www.crowdtangle.com/", "code_signature": "."}, "47": {"name": "Facebook Audience", "description": "", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-03", "id": 47, "website": "https://developers.facebook.com/docs/android/", "code_signature": "com.facebook.audiencenetwork"}, "48": {"name": "Google Analytics", "description": "", "network_signature": "google-analytics\\.com", "creation_date": "2017-12-03", "id": 48, "website": "http://www.google.com/analytics/", "code_signature": "com.google.android.apps.analytics.|com.google.android.gms.analytics."}, "49": {"name": "Google Firebase Analytics", "description": "[API documentation](https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/package-summary)", "network_signature": "firebase\\.com", "creation_date": "2017-12-03", "id": 49, "website": "https://firebase.google.com/", "code_signature": "com.google.firebase.analytics.|com.google.android.gms.measurement."}, "51": {"name": "Eulerian", "description": "## About\r\n\r\nEulerian Technologies is a privately-held e-marketing and web analytics company based in France. [Source: OpenCorporates](https://opencorporates.com/companies/gb/04437532) It has offices in Paris, Madrid, Lille, and staff in Canada. [Source: Linkedin](https://www.linkedin.com/company/eulerian-technologies/])\r\n\r\n## Ownership\r\n\r\nGuillaume Fougnies and Mathieu Jondet founded Eulerian Technologies in 2002. [Source: Eulerian.com](https://www.eulerian.com/en/about-us/)\r\n\r\n## What it does\r\n\r\n* Behavioral Analytics \r\n* Data Collection\r\n* Attribution Modeling\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 5/9/2018](https://www.eulerian.com/en/privacy/):\r\n\r\n* Eulerian's policy acknowledges that it may receive (\"including personal data\") data from from its clients' partners for statistical and analytical reporting. It states that it acts as a \"data processor\" on behalf of its clients' instructions.\r\n\r\n* Collected data is the \"property of our clients, [who] are data controllers, at all times.\" It is \"not used on behalf of Eulerian Technologies.\"\r\n\r\n* Users looking to request deletion of their data are referred to contact their clients directly using the contact details on their respective websites. The policy then provides a list of websites that use their software.", "network_signature": "eulerian\\.com", "creation_date": "2017-12-03", "id": 51, "website": "https://www.eulerian.com/en/", "code_signature": "com.eulerian.android.sdk"}, "52": {"name": "Adjust", "description": "", "network_signature": "adjust\\.com|adj\\.st", "creation_date": "2017-12-03", "id": 52, "website": "https://www.adjust.com/", "code_signature": "com.adjust.sdk."}, "53": {"name": "ChartBoost", "description": "", "network_signature": "\\.chartboost\\.com", "creation_date": "2017-12-03", "id": 53, "website": "https://answers.chartboost.com/en-us/", "code_signature": "com.chartboost.sdk."}, "54": {"name": "Backelite", "description": "By *CapGemini*", "network_signature": "backelite\\.com", "creation_date": "2017-12-03", "id": 54, "website": "https://www.backelite.com/", "code_signature": "com.backelite.android.|com.backelite.bkdroid."}, "55": {"name": "Areametrics", "description": "[SDK documentation](https://areametrics-android-sdk.readme.io/)\r\nMaven repository: `https://dl.bintray.com/areametrics/AreaMetricsSDK`\r\nArtifact: `com.areametrics:sdk:2.2.2`", "network_signature": "areametrics\\.com", "creation_date": "2017-12-03", "id": 55, "website": "https://areametrics.com/", "code_signature": "com.areametrics.areametricssdk|com.areametrics.nosdkandroid"}, "56": {"name": "ComScore", "description": "", "network_signature": "comscore\\.com", "creation_date": "2017-12-03", "id": 56, "website": "https://comscore.com/", "code_signature": "com.comscore."}, "57": {"name": "Cuebiq", "description": "", "network_signature": "cuebiq\\.com", "creation_date": "2017-12-03", "id": 57, "website": "http://www.cuebiq.com/", "code_signature": "com.cuebiq.cuebiqsdk.model.Collector|com.cuebiq.cuebiqsdk.receiver.CoverageReceiver"}, "58": {"name": "HelpShift", "description": "", "network_signature": "helpshift.com", "creation_date": "2017-12-03", "id": 58, "website": "https://www.helpshift.com", "code_signature": "com.helpshift"}, "59": {"name": "Kontakt", "description": "Bluetooth Beacons & Location Solutions", "network_signature": "kontakt.io", "creation_date": "2017-12-03", "id": 59, "website": "https://kontakt.io/", "code_signature": "com.kontakt.sdk.android."}, "60": {"name": "Locuslabs", "description": "Indoor location", "network_signature": "locuslabs\\.com", "creation_date": "2017-12-03", "id": 60, "website": "http://locuslabs.com", "code_signature": "com.locuslabs.sdk"}, "61": {"name": "Moat", "description": "Track what ads users are viewing", "network_signature": "moat\\.com", "creation_date": "2017-12-03", "id": 61, "website": "https://moat.com/analytics", "code_signature": "com.moat.analytics.mobile."}, "62": {"name": "Segment", "description": "Collect behavioral data", "network_signature": "segment.com|api.segment.io", "creation_date": "2017-12-03", "id": 62, "website": "https://segment.com/", "code_signature": "com.segment.analytics."}, "63": {"name": "Mobile Engagement", "description": "Microsoft", "network_signature": "login\\.microsoftonline\\.com|management\\.azure\\.com", "creation_date": "2017-12-04", "id": 63, "website": "https://docs.microsoft.com/en-us/azure/mobile-engagement/mobile-engagement-android-sdk-overview", "code_signature": "com.ubikod.capptain.|com.microsoft.azure.engagement."}, "64": {"name": "Colocator", "description": "", "network_signature": "colocator\\.net", "creation_date": "2017-12-04", "id": 64, "website": "https://developers.colocator.net", "code_signature": "net.crowdconnected.androidcolocator"}, "65": {"name": "Facebook Ads", "description": "", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-05", "id": 65, "website": "https://developers.facebook.com/docs/android", "code_signature": "com.facebook.ads"}, "66": {"name": "Facebook Analytics", "description": "", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-05", "id": 66, "website": "https://developers.facebook.com/docs/android", "code_signature": "com.facebook.appevents"}, "67": {"name": "Facebook Login", "description": "", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-05", "id": 67, "website": "https://developers.facebook.com/docs/android", "code_signature": "com.facebook.login"}, "68": {"name": "Facebook Notifications", "description": "", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-05", "id": 68, "website": "https://developers.facebook.com/docs/android", "code_signature": "com.facebook.notifications"}, "69": {"name": "Facebook Places", "description": "", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-05", "id": 69, "website": "https://developers.facebook.com/docs/android", "code_signature": "com.facebook.places"}, "70": {"name": "Facebook Share", "description": "", "network_signature": "\\.facebook\\.com", "creation_date": "2017-12-05", "id": 70, "website": "https://developers.facebook.com/docs/android", "code_signature": "com.facebook.share"}, "71": {"name": "Google Ads", "description": "https://developers.google.com/admob/android/mediation", "network_signature": "\\.google\\.com", "creation_date": "2017-12-05", "id": 71, "website": "https://developers.google.com/admob/android", "code_signature": "com.google.android.gms.ads.mediation."}, "72": {"name": "AppLovin", "description": "* Website: https://www.applovin.com/\r\n* Comment: AppLovin is a mobile advertising technology company that enables brands to create mobile marketing campaigns that are fueled by data. \r\n* Category: Advertising\r\n* Code signature: `com.applovin.`\r\n* Network signature: `applovin\\.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `applovin-sdk`\r\n* Group ID: `com.applovin` \r\n* Gradle: `com.applovin:applovin-sdk:7.6.0`\r\n* Additional links: [Crunchbase](https://www.crunchbase.com/organization/applovin)\r\n* Notes: AppLovin SDK requires Google Ads Identifier `com.google.android.gms.ads.identifier.*`", "network_signature": "applovin\\.com|applvn\\.com", "creation_date": "2018-01-05", "id": 72, "website": "https://www.applovin.com/", "code_signature": "com.applovin"}, "73": {"name": "Glispa Connect (Formerly Avocarrot)", "description": "* Website: https://www.avocarrot.com/\r\n* Comment: Avocarrot is a native mobile advertising platform which provides real rewards on mobile apps. \r\n* Category: Advertising\r\n* Code signature: `com.avocarrot.sdk`\r\n* Network signature: `\\.avocarrot\\.com`\r\n* Maven repository: `https://s3.amazonaws.com/avocarrot-android-builds/dist/`\r\n* Artifact ID: `mediation-sdk-nativead`\r\n* Group ID: `com.avocarrot.sdk` \r\n* Gradle: `com.avocarrot.sdk:mediation-sdk-nativead:4.7.1`\r\n* Additional links: [Crunchbase](https://www.crunchbase.com/organization/avocarrot) [Dev doc](https://docs.avocarrot.com/android/native-list-feed)\r\n* Notes: Uses Google Ads", "network_signature": "\\.avocarrot\\.com|ads\\.glispa\\.com|exp\\.glispa\\.com|rtb\\.platform\\.glispa\\.com|trk\\.glispa\\.com|templates\\.glispaconnect\\.com", "creation_date": "2018-01-05", "id": 73, "website": "https://www.glispa.com", "code_signature": "com.avocarrot.sdk"}, "74": {"name": "NativeX", "description": "* Website: http://www.nativex.com/\r\n* Comment: NativeX is the leading ad technology for mobile games. \r\n* Category: Advertising\r\n* Code signature: `com.nativex.`\r\n* Network signature: `mobvista\\.com|nativex\\.com`\r\n* Maven repository: `NC`\r\n* Artifact ID: `NC`\r\n* Group ID: `NC` \r\n* Gradle: `NC`\r\n* Additional links: [Crunchbase](https://www.crunchbase.com/organization/nativex) [NativeX Android SDK](https://github.com/nativex/NativeX-Android-SDK/archive/master.zip) [Dev doc](http://www.help.nativex.com/monetize/android-monetization/android-sdk-integration-guide/)\r\n* Notes: Acquired by MobVista", "network_signature": "nativex\\.com", "creation_date": "2018-01-05", "id": 74, "website": "http://www.nativex.com/", "code_signature": "com.nativex"}, "75": {"name": "Baidu Maps", "description": "* Website: https://map.baidu.com\r\n* Comment: Baidu is the Web giant in China, the homegrown counterpart to Google.\r\n* Category: Maps, Location\r\n* Code signature: `com.baidu.BaiduMap`\r\n* Network signature: `map.baidu\\.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.baidu` \r\n* Gradle: `NC`\r\n* Additional links: [Android SDK documentation](http://lbsyun.baidu.com/index.php?title=android-locsdk), [iOS SDK](https://github.com/iosmvn/BaiduMap-iOS-SDK)\r\n* Notes: [\"Baidu uses millions of users\u2019 location data to make predictions\", New Scientist](https://www.newscientist.com/article/2098206-baidu-uses-millions-of-users-location-data-to-make-predictions/)", "network_signature": "map\\.baidu\\.com", "creation_date": "2018-01-05", "id": 75, "website": "https://map.baidu.com", "code_signature": "com.baidu.BaiduMap"}, "76": {"name": "WeChat Location", "description": "* Website: https://wechat.com, https://weixin.qq.com\r\n* Comment: WeChat is the most popular chat client in China and may become the official app for state identification.\r\n* Category: Maps, Location\r\n* Code signature: `com.tencent.map.geolocation|com.tencent.mm.plugin.location.|com.tencent.mm.plugin.location_soso.|com.tencent.mm.plugin.location_google.`\r\n* Network signature: `map.qq\\.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.tencent` \r\n* Gradle: `NC`\r\n* Additional links: [Reverse-engineered WeChat code](https://github.com/reverseengineeringer/com.tencent.mm)\r\n* Notes: [\"WeChat poised to become China\u2019s official electronic ID system\", South China Morning Post](http://www.scmp.com/tech/social-gadgets/article/2125736/wechat-poised-become-chinas-official-electronic-id-system)", "network_signature": "map\\.qq\\.com", "creation_date": "2018-01-05", "id": 76, "website": "https://wechat.com", "code_signature": "com.tencent.map.geolocation|com.tencent.mm.plugin.location.|com.tencent.mm.plugin.location_soso.|com.tencent.mm.plugin.location_google"}, "77": {"name": "HyperTrack", "description": "* Website: http://hypertrack.com, https://github.com/hypertrack\r\n* Comment: HyperTrack implements live location sharing and activity tracking.\r\n* Category: [Maps, Location]\r\n* Code signature: `com.hypertrack.|com.hypertracklive.|io.hypertrack.`\r\n* Network signature: `trck.at|hypertrack\\.amazonaws.com|api\\.hypertrack\\.com`\r\n* Maven repository: `http://hypertrack-android-sdk.s3-website-us-west-2.amazonaws.com/`\r\n* Artifact ID: `hypertrack-live-android`\r\n* Group ID: `com.hypertrack` \r\n* Gradle: `com.hypertrack:android:0.4.22:release@aar`\r\n* Additional links: [HyperTrack SDK repo](https://github.com/hypertrack/hypertrack-live-android), [Documentation](https://docs.hypertrack.com/)\r\n* Notes: HyperTrack SDK for Android is MIT/Expat licensed.", "network_signature": "trck\\.at|hypertrack\\.amazonaws\\.com|api\\.hypertrack\\.com", "creation_date": "2018-01-05", "id": 77, "website": "http://hypertrack.com", "code_signature": "com.hypertrack|com.hypertracklive.|io.hypertrack"}, "78": {"name": "Uber Analytics", "description": "* Website: https://uber.com\r\n* Comment: Uber Analytics tracks location and behavior as part of its suite of apps such as Uber, UberEATS, and Uber Driver.\r\n* Category: Location, Analytics\r\n* Code signature: `com.ubercab.analytics.|com.ubercab.library.metrics.analytics.|com.ubercab.client.core.analytics.`\r\n* Network signature: `events.uber.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.ubercab` \r\n* Gradle: `NC`\r\n* Additional links: [Dissassembled Uber code](https://github.com/IRMobydick/AndroidDissambleApps/tree/master/com.ubercab), [Reverse-engineered Uber code](https://github.com/reverseengineeringer/com.ubercab)\r\n* Notes: Uber acquired map and location startup deCarta, which included data and maps from TomTom.", "network_signature": "events\\.uber\\.com", "creation_date": "2018-01-05", "id": 78, "website": "https://uber.com", "code_signature": "com.ubercab.analytics.|com.ubercab.library.metrics.analytics.|com.ubercab.client.core.analytics."}, "79": {"name": "Lisnr", "description": "* Website: http://lisnr.com\r\n* Comment: LISNR tracks users via audio beacons in retail outlets, as well as collecting behavioral data on a mobile device. Retailers broadcast a \"Smart Tone\" on speaker systems and LISNR reacts to the sound.\r\n* Category: [Audio Beacon, Analytics]\r\n* Code signature: `com.lisnr.|com.lisnr.sdk.`\r\n* Network signature: `lisnr\\.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.lisnr.sdk` \r\n* Gradle: `com.lisnr.sdk:sdk:5.0.0.+`\r\n* Additional links: [LISNR demo app repo](https://github.com/LISNR/LISNR-Auth-Demo-Android), [\"Privacy Threats through Ultrasonic Side Channels on Mobile Devices\", Technische Universit at Braunschweig](http://christian.wressnegger.info/content/projects/sidechannels/2017-eurosp.pdf)\r\n* Notes:", "network_signature": "lisnr\\.com", "creation_date": "2018-01-05", "id": 79, "website": "http://lisnr.com", "code_signature": "com.lisnr."}, "80": {"name": "SilverPush", "description": "* Website: http://silverpush.co, http://silverpush.com\r\n* Comment: SilverPush tracks users via audio beacons in retail outlets, as well as collecting behavioral and location data on a mobile device. Retailers broadcast a ultrasonic tone on speaker systems and SilverPush reacts to the sound.\r\n* Category: [Audio Beacon, Analytics]\r\n* Code signature: `com.silverpush.|com.silverpush.location|com.silverpush.sdk.android.SPService`\r\n* Network signature: `silverpush\\.co|silverpush\\.com|54.243.73.253:8080/SilverPush/`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.silverpush` \r\n* Gradle: `NC`\r\n* Additional links: [\"SilverPush Unmasked\" repo](https://github.com/MAVProxyUser/SilverPushUnmasked), [\"Privacy Threats through Ultrasonic Side Channels on Mobile Devices\", Technische Universit at Braunschweig](http://christian.wressnegger.info/content/projects/sidechannels/2017-eurosp.pdf)\r\n* Notes:", "network_signature": "silverpush\\.co|silverpush\\.com|54\\.243\\.73\\.253:8080/SilverPush/", "creation_date": "2018-01-05", "id": 80, "website": "http://silverpush.co", "code_signature": "com.silverpush.|com.silverpush.location|com.silverpush.sdk.android.SPService"}, "81": {"name": "Shopkick", "description": "* Website: https://shopkick.com\r\n* Comment: Shopkick tracks users via \"shopBeacon\" beacons (Apple iBeacons) in retail outlets, as well as collecting behavioral and location data on a mobile device.\r\n* Category: [Audio Beacon, Bluetooth Beacon, Analytics]\r\n* Code signature: `com.shopkick.sdk.api.|com.shopkick.fetchers.`\r\n* Network signature: `shopkick\\.com|shopkick\\.de|sdk.shopkick.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.shopkick` \r\n* Gradle: `NC`\r\n* Additional links: [Shopkick on Github](https://github.com/shopkick), [Shopkick on Anaconda Cloud](https://anaconda.org/shopkick), [Shopkick on Docker Hub](https://hub.docker.com/r/shopkick/), [\"Privacy Threats through Ultrasonic Side Channels on Mobile Devices\", Technische Universit at Braunschweig](http://christian.wressnegger.info/content/projects/sidechannels/2017-eurosp.pdf)\r\n* Notes: Shopkick is a very popular shopping app \"companion\" used by millions. Shopkick has a close relationship with Scandit barcode scanner SDK.", "network_signature": "shopkick\\.com|shopkick\\.de|sdk.shopkick.com", "creation_date": "2018-01-05", "id": 81, "website": "https://shopkick.com", "code_signature": "com.shopkick.sdk.api.|com.shopkick.fetchers."}, "82": {"name": "Alphonso", "description": "* Website: http://alphonso.tv\r\n* Comment: Alphonso listens to audio signals in TV advertisements and is included in games and other apps for children.\r\n* Category: [Audio Beacon, Analytics]\r\n* Code signature: `tv.alphonso.service`\r\n* Network signature: `prov.alphonso.tv|api.alphonso.tv`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `tv.alphonso` \r\n* Gradle: `NC`\r\n* Additional links: [Presentation about TV ads data from Alphonso](https://github.com/kupagulova/alphonso-analysis-demo), [\"That Game on Your Phone May Be Tracking What You\u2019re Watching on TV\", New York Times](https://www.nytimes.com/2017/12/28/business/media/alphonso-app-tracking.html)\r\n* Notes: Alphonso SDK makes heavy use of the Google Admob mediation service.", "network_signature": "prov.alphonso.tv|api.alphonso.tv", "creation_date": "2018-01-05", "id": 82, "website": "http://alphonso.tv", "code_signature": "tv.alphonso.service"}, "83": {"name": "Smaato", "description": "* Website: https://smaato.com\r\n* Comment: Smaato is a mobile ad platform that includes video ads.\r\n* Category: [Advertising, Analytics]\r\n* Code signature: `com.smaato.soma.`\r\n* Network signature: `soma.smaato.net|smaato.net`\r\n* Maven repository: `NA`\r\n* Artifact ID: `NC`\r\n* Group ID: `com.smaato.soma` \r\n* Gradle: `NC`\r\n* Additional links: [Smaato SDK Documentation](https://wiki.smaato.com/display/IN/Android)\r\n* Notes:", "network_signature": "soma.smaato.net|smaato.net", "creation_date": "2018-01-05", "id": 83, "website": "https://smaato.com", "code_signature": "com.smaato.soma."}, "84": {"name": "Scandit", "description": "* Website: https://scandit.com\r\n* Comment: Scandit is a barcode scanner SDK that offers real-time analytics (\"scanalytics\") to track what barcodes users have scanned and profile users for targeted advertising.\r\n* Category: [Barcode Scanner, Analytics]\r\n* Code signature: `com.scandit.`\r\n* Network signature: `scandit\\.com`\r\n* Maven repository: `NA`\r\n* Artifact ID: `scanditsdk-android`\r\n* Group ID: `com.scandit` \r\n* Gradle: `ScanditBarcodeScanner`\r\n* Additional links: [Scandit SDK Documentation](https://docs.scandit.com/stable/android/), [\"Scandit launches first-of-its-kind barcode scanning analytics\", Analytics Magazine](http://analytics-magazine.org/scandit-launches-first-of-its-kind-barcode-scanning-analytics/), [\"Shopkick Partners with Scandit to Boost Consumer Engagement with Products in Store\", PRWeb](http://www.prweb.com/releases/2012/10/prweb9954971.htm), [Shopkick Case Study](https://www.scandit.com/resources/case-studies/shopkick/)\r\n* Notes: Shopkick is a close partner with Scandit.", "network_signature": "scandit\\.com", "creation_date": "2018-01-05", "id": 84, "website": "https://scandit.com", "code_signature": "com.scandit."}, "85": {"name": "Inrix", "description": "* Website: http://inrix.com/\r\n* Comment: INRIX offers real-time traffic information solutions that help develop traffic data and traffic speed for freeways, highways and arterials. \r\n* Category: Location\r\n* Code signature: `com.inrix.sdk`\r\n* Network signature: `inrix\\.com|inrix\\.io`\r\n* Maven repository: `NC`\r\n* Artifact ID: `NC`\r\n* Group ID: `NC` \r\n* Gradle: `NC`\r\n* Additional links: [Inrix on Crunchbase](https://www.crunchbase.com/organization/inrix), [Inrix population analytics](http://inrix.com/resources/inrix-population-analytics-video/)\r\n* Notes:", "network_signature": "inrix\\.com|inrix\\.io", "creation_date": "2018-01-06", "id": 85, "website": "http://inrix.com/", "code_signature": "com.inrix.sdk"}, "86": {"name": "Signal360", "description": "* Website: http://www.signal360.com\r\n* Comment: Signal360 (formerly Sonic Notify) is a leader in proximity marketing via audio beacons and bluetooth beacons in sports stadiums, retail outlets, and vending machines.\r\n* Category: [Audio Beacon, Bluetooth Beacon]\r\n* Code signature: `com.signal360.sdk.core.|com.sonicnotify.sdk.core.|com.rnsignal360|`\r\n* Network signature: `signal360\\.com|sonicnotify\\.com`\r\n* Maven repository: `NA`\r\n* Gradle: `NA`\r\n* Group ID: `com.signal360.sdk` \r\n* Gradle: `NA`\r\n* Additional links: [React Native Bridge for Signal 360 SDK on Github](https://github.com/EwyynTomato/react-native-signal360), [\"Scandit launches first-of-its-kind barcode scanning analytics\", Sport Techie](https://www.sporttechie.com/signal360-is-bringing-sponsor-messaging-to-nba-teams-and-heres-how-to-get-creative-with-it/)\r\n* Notes: Signal360 has partnerships with PlayNetwork, YinzCam, and Coca-Cola Amatil.", "network_signature": "signal360\\.com|sonicnotify\\.com", "creation_date": "2018-01-13", "id": 86, "website": "http://www.signal360.com", "code_signature": "com.signal360.sdk.core.|com.sonicnotify.sdk.core.|com.rnsignal360"}, "87": {"name": "TeleQuid", "description": "* Website: http://www.telequid.com/\r\n* Comment: Ads synced to the TV\r\n* Category: Advertising\r\n* Code signature: `com.telequid.`\r\n* Network signature: `mars\\.telequid\\.com`\r\n* Maven repository: `xxx.com`\r\n* Artifact ID: `xxx`\r\n* Group ID: `xxx` \r\n* Gradle: `xxx`\r\n* Additional links: xxx xxx\r\n* Notes: \r\n> TAAS (Telequid Augmented Advertising Server) can be embedded in an existing app to detect images in any printed document or TV spots and display related multimedia content on mobile screen.", "network_signature": "mars\\.telequid\\.com", "creation_date": "2018-03-04", "id": 87, "website": "http://www.telequid.com/", "code_signature": "com.telequid."}, "88": {"name": "Retency", "description": "* Website: http://retency.com\r\n* Comment: xxxx\r\n* Category: Analytics\r\n* Code signature: `com.retency.sdk.android`\r\n* Network signature: `NC`\r\n* Maven repository: `NC`\r\n* Artifact ID: `NC`\r\n* Group ID: `NC` \r\n* Gradle: `NC`\r\n* Additional links: \r\n* Notes:", "network_signature": "NC", "creation_date": "2018-03-04", "id": 88, "website": "http://retency.com", "code_signature": "com.retency.sdk.android"}, "89": {"name": "MAdvertise", "description": "* Website: http://madvertise.com\r\n* Comment: xxxx\r\n* Category: Advertising\r\n* Code signature: `com.mngads.sdk|com.mngads.views|com.mngads.`\r\n* Network signature: `NC`\r\n* Maven repository: `NC`\r\n* Artifact ID: `NC`\r\n* Group ID: `NC` \r\n* Gradle: `NC`\r\n* Additional links: \r\n* Notes:", "network_signature": "dispatcher\\.mng\\-ads\\.com|mobile\\.mng\\-ads\\.com", "creation_date": "2018-03-04", "id": 89, "website": "http://madvertise.com", "code_signature": "com.mngads.sdk|com.mngads.views|com.mngads."}, "90": {"name": "AdColony", "description": "_AdColony delivers zero-buffering, full-screen Instant-Play\u2122 HD video, interactive Aurora\u2122 Video, and Aurora\u2122 Playable ads that can be displayed anywhere within your application. Our advertising SDK is trusted by the world\u2019s top gaming and non-gaming publishers, delivering them the highest monetization opportunities from brand and performance advertisers. AdColony\u2019s SDK can monetize a wide range of ad formats including in-stream/pre-roll, out-stream/interstitial and V4VC\u2122, a secure system for rewarding users of your app with virtual currency upon the completion of video and playable ads._ from [AdColony on Github](https://github.com/AdColony/).", "network_signature": "adc3-launch.adcolony.com|ads30.adcolony.com|androidads20.adcolony.com|androidads21.adcolony.com|androidads23.adcolony.com|events3alt.adcolony.com|wd.adcolony.com|adcolony.com", "creation_date": "2018-03-04", "id": 90, "website": "http://adcolony.com/", "code_signature": "com.adcolony"}, "91": {"name": "AccountKit", "description": "## About\r\n\r\nAccountKit is a product of Facebook lets users quickly register/login to apps by using just their phone number or email address. No password is needed. [Link to weblink](https://www.accountkit.com/faq/)\r\n\r\n## Ownership\r\n\r\nAccountKit is owned by Facebook (NASDAQ: FB). \r\n\r\nNote: there is an unaffiliated Australian Accounting firm of the same name. \r\n\r\n## What it does\r\n\r\n* User Verification\r\n* Phone number collection\r\n* Permits direct app logins without SMS code\r\n\r\n## Data Policy\r\n\r\n[Policy as of 8/9/2018:](https://www.facebook.com/privacy/explanation/)\r\n\r\n* Identical to Facebook's Policy. This provides controls for users to opt out but no actual commitment to reduce the collection and use of personal data. \r\n\r\n* Data will be used to \"reasearch and innovate for social good\", \"promote satety, integrity and security\", personalize advertising, communicate with users, and measure analytics for business services. \r\n\r\n* Third-party apps and websites integrated with Facebook and its products receive information on what users post and share. This \"information collected by these third-party services is subject to their own terms and policies, not this one.\" \r\n\r\n* Facebook's policy states that it doesn't \"sell any of your information to anyone and we never will.\" It imposes \"strict restrictions\" on how partners use and disclose the data it provides. \r\n\r\n* Information may be accessed, preserved, and shared with regulators, law enforcement, and others in response to legal requests (including those in outside jurisdictions if there is a \"good faith belief\" they're required to respond), prevention of fraud, unauthorized use of products or services, breaches of Terms or Policies, to prevent harm to Facebook or its property, and harmful or illegal activity.", "network_signature": "graph.accountkit.com", "creation_date": "2018-03-04", "id": 91, "website": "https://www.accountkit.com/", "code_signature": "com.facebook.accountkit"}, "92": {"name": "Amazon Advertisement", "description": "", "network_signature": "NC", "creation_date": "2018-03-04", "id": 92, "website": "https://developer.amazon.com/public/apis/earn/mobile-ads/docs/quick-start", "code_signature": "com.amazon.device.ads"}, "93": {"name": "Amazon Mobile Associates", "description": "Advertisement", "network_signature": "NC", "creation_date": "2018-03-04", "id": 93, "website": "https://developer.amazon.com/mobile-associates", "code_signature": "com.amazon.device.associates"}, "94": {"name": "Radius Networks", "description": "* Website: https://www.radiusnetworks.com/\r\n* Comment: Radius Networks offers a wide range of hardware, software and proximity services designed to enable hyper-proximity, micro-location engagement capabilities and analytics in today's leading mobile apps, products and technologies\r\n* Category: Analytics, Tracking, Beacons, Location\r\n* Code signature: `com.radiusnetworks`\r\n* Network signature: `proximitykit.radiusnetworks.com`\r\n* Maven repository: `xxx.com`\r\n* Artifact ID: `xxx`\r\n* Group ID: `xxx` \r\n* Gradle: `org.altbeacon:android-beacon-library:2+`\r\n* Additional links: http://developer.radiusnetworks.com/ , http://altbeacon.github.io/android-beacon-library/\r\n* Notes: xxx", "network_signature": "proximitykit.radiusnetworks.com", "creation_date": "2018-03-04", "id": 94, "website": "https://www.radiusnetworks.com/", "code_signature": "com.radiusnetworks"}, "95": {"name": "Amazon Analytics", "description": "Analytics", "network_signature": "mobileanalytics.us-east-1.amazonaws.com", "creation_date": "2018-03-04", "id": 95, "website": "https://developer.amazon.com/public/apis/manage/analytics/docs/analytics-for-android-fire-os", "code_signature": "com.amazon.insights|com.amazonaws.mobileconnectors.pinpoint.analytics."}, "96": {"name": "Baidu APPX", "description": "Advertisement", "network_signature": "NC", "creation_date": "2018-03-04", "id": 96, "website": "https://app.baidu.com/", "code_signature": "com.baidu.appx"}, "97": {"name": "Baidu Location", "description": "Map/LBS", "network_signature": "NC", "creation_date": "2018-03-04", "id": 97, "website": "https://developer.baidu.com/", "code_signature": "com.baidu.location"}, "99": {"name": "Baidu Map", "description": "Map/LBS", "network_signature": "NC", "creation_date": "2018-03-04", "id": 99, "website": "http://lbsyun.baidu.com/", "code_signature": "com.baidu.mapapi"}, "100": {"name": "Baidu Mobile Ads", "description": "Advertisement", "network_signature": "NC", "creation_date": "2018-03-04", "id": 100, "website": "https://developer.baidu.com/", "code_signature": "com.baidu.mobads"}, "101": {"name": "Baidu Mobile Stat", "description": "Analytics", "network_signature": "NC", "creation_date": "2018-03-04", "id": 101, "website": "https://developer.baidu.com/", "code_signature": "com.baidu.mobstat"}, "102": {"name": "Estimote", "description": "## About\r\n\r\nEstimote is private company that creates and sells sensor-based proximity tracking devices. These \"physical world\" beacons allow retailers to track users by compelling their cell phone microphones to emit high-frequency tones that are inaudible to humans. \r\n\r\nEstimote is registered in Delaware [Source:OpenCorporates](https://opencorporates.com/companies/us_de/5201683) and has offices in San Francisco, New York, and Krakow, Poland. In 2017, the company registered in the Dominican Republic. [Source:OpenCorporates](https://opencorporates.com/companies/do/491544)\r\n\r\n## Ownership\r\n\r\nEstimote's founders are Jakub Krzych and Lukasz Kostka. [Source: website](https://estimote.com/about/)\r\n\r\n## What it does\r\n\r\n* Ultrasonic proximity tracking\r\n* Indoor location beacons for use in retail stores, museums, and stadiums. Also deployed with in conjunction with robotic technology.\r\n* Integrates wireless APIs that take control over nearby displays\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 15/9/2018, last modified 13/5/15](https://estimote.com/legal/privacy-policy.html)\r\n\r\n* Estimote's policy mainly concerns its relationship with business affiliates and account holders. It does, however, refer to \"Customer Data\" collected from its services.\r\n\r\n* Personal data collected is treated by Estimote as \"strictly confidential\" and subject to internal controls and protections. This may include \"latitude/longitude coordinates\", the time of day, and user locations when their device is near a beacon. \r\n\r\n* If users do not want Estimote's beacon to identify their device, it directs them to \"(a) delete the Customer app or adjust the in-app settings of the Customer app if the app makes that option available, or (b) turn \u201coff\u201d Bluetooth through [their] device\u2019s Settings feature.\"\r\n\r\n* In the event of a data breach, Estimote will \"take reasonable steps to investigate the situation and to notify our Customers if the security, integrity or confidentiality of personal information has been compromised, in accordance with any applicable laws and regulations.\"", "network_signature": "NC", "creation_date": "2018-03-04", "id": 102, "website": "https://estimote.com/", "code_signature": "com.estimote."}, "103": {"name": "Baidu Navigation", "description": "Map/LBS", "network_signature": "NC", "creation_date": "2018-03-04", "id": 103, "website": "http://lbsyun.baidu.com/index.php?title=android-navsdk", "code_signature": "com.baidu.navi"}, "104": {"name": "Fyber", "description": "Advertisement", "network_signature": "adproxy.fyber.com|appengage-video.fyber.com|banner.fyber.com|engine.fyber.com|interstitial.fyber.com|mbe-cdn.fyber.com|offer.fyber.com|service.fyber.com|tracker.fyber.com|video.fyber.com|video-interstitial-assets-cdn.fyber.com", "creation_date": "2018-03-04", "id": 104, "website": "https://www.fyber.com/", "code_signature": "com.fyber."}, "105": {"name": "Google Tag Manager", "description": "Analytics", "network_signature": "www.googletagmanager.com|www.googletagservices.com", "creation_date": "2018-03-04", "id": 105, "website": "https://www.google.com/analytics/tag-manager/", "code_signature": "com.google.tagmanager"}, "106": {"name": "Inmobi", "description": "## About\r\n\r\n[InMobi](https://www.inmobi.com/) is a private, Indian-based advertising behemoth. It has relationships with over 30,000 companies and app developers. It has approximately 1,500 employees in offices in 12 different countries. [See also: OpenCorporates](https://opencorporates.com/companies/us_ca/C3422070)\r\n\r\nInMobi's founder, in a recent [Forbes article,](http://www.forbesindia.com/article/leaderboard/inmobi-wants-to-glue-your-attention-to-your-lock-screen/53095/1) stated that \"Consumers will move from seeking content to consuming what is shown to them.\" \r\n\r\n## Ownership\r\n\r\nInMobi was founded in Mumbai, India, as mKhoj, in 2007 by Naveen Tewari, Abhay Singhal, Amit Gupta and Mohit Saxena. Its investors include Softbank and its debt financier is Tennenbaum Capital Partners. \r\n\r\n## What it does\r\n\r\n* Native/Targeted Advertising\r\n* E-Commerce\r\n* In-app Mobile Advertising\r\n* Market Research Platform\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 17/2/2017, reviewed 21/4/2019:](https://www.inmobi.com/privacy-policy/)\r\n\r\n* InMobi's opt-out is [located here.](https://www.inmobi.com/page/opt-out/) Users will need their iOS or Android ID. \r\n\r\n* InMobi's privacy policy states that it collects information about the \"device type (e.g. smartphone, tablet, etc.),operating system (e.g. iOS, Android, Windows, Blackberry), network provider, mobile browser used (e.g. Safari, Internet Explorer etc.),platform, SDK version, timestamp, API key (identifier for application), application version, iOS Identifier for Advertising, iOS Identifier for Vendors, model, manufacture of device, OS version of device, session start/stop time, locale (specific location where a given language is spoken), time zone, network status such as WiFi, the geo-location of your device (using GPS or other geo-location data) and the Identifier for Advertising (IDFA) or the Google Advertising ID (AAID) etc\" which it may infer from WiFi identifiers in the area. \r\n\r\n* It also collects information regarding \"(i) the content type of the ad (what the ad is about, e.g. games, finance, entertainment, news); (ii) the ad type (e.g. whether the ad is a text, image, or video based ad); (iii) where the ad is being served (e.g. the address of the site on which the ad appears); and (iv) certain information about post-click activity in relation to the ad including user interaction with such ad.\" It may also collect email addresses in a hashed format. \r\n\r\n* This information is shared with \"Publishers, Developers, Advertisers, Data Partners, Measurement Companies, InMobi Affiliates, and third parties such as advisors and law enforcement authorities.\" \r\n\r\n* Data is kept for a 13-month period, after which InMobi \"may retain and use such data in an aggregated format, as necessary for internal analytical purposes, to comply with its legal obligations, resolve disputes and enforce agreements.\"\r\n\r\n## Lawsuits and Settlements\r\n\r\n* In 2016, InMobi settled with the FTC (US Federal Trade Commission) for $950,000 over the Children's Online Privacy Protection Act violations (\"COPPA\"). [See more information](https://www.ftc.gov/news-events/press-releases/2016/06/mobile-advertising-network-inmobi-settles-ftc-charges-it-tracked)", "network_signature": "config-ltvp.inmobi.com|sdkm.w.inmobi.com|inmobi.com|inmobi.info|inmobi.us", "creation_date": "2018-03-04", "id": 106, "website": "http://inmobi.com", "code_signature": "com.inmobi"}, "107": {"name": "Millennial Media", "description": "## About\r\n\r\nMillennial Media was founded in 2006 and publicly acquired by AOL in 2015. Oath Inc., a Verizon subsidiary, acquired AOL in 2017. \r\n\r\n## Ownership\r\n\r\nOath, Inc., owns Millennial Media as a legacy product. Oath is a subsidiary of Verizon Communications. [See: OpenCorporates](https://opencorporates.com/companies/us_de/4107146)\r\n\r\n## What it does\r\n\r\n* Behavorial Analytics\r\n* Personalized Advertising\r\n* Data Collection\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 27/12/2018:](https://policies.oath.com/us/en/oath/privacy/index.html)\r\n\r\n* Oath's policy states that it collects device and location information; \"the kind of content or ads served, viewed or clicked on; the frequency and duration of your activities; the sites or apps you used before accessing our Services and where you went next; whether you engaged with specific content or ads; and whether you went on to visit an advertiser's website, downloaded an advertiser\u2019s app, purchased a product or service advertised, or took other actions.\"\r\n\r\n* Information may be collected from third-parties and affilates, publicly-available sources, and appended and matched data from [other companies.](https://policies.oath.com/us/en/oath/privacy/topics/appenddata/index.html)\r\n\r\n* Oath states that it has \"technical, administrative and physical safeguards in place to help protect against unauthorized access, use or disclosure of customer information we collect or store.\" It also states that while it may share aggregated or pseudonymous information with other companies, this is not personally identifiable information (example given: \"name or email address\").\r\n\r\n* Oath's privacy controls and opt-out can be found [here.](https://policies.oath.com/us/en/oath/privacy/controls/index.html)", "network_signature": "contextual.media.net|media.net|millennialmedia.com|adtech\\.de", "creation_date": "2018-03-04", "id": 107, "website": "https://www.millennialmedia.com/", "code_signature": "com.millennialmedia."}, "108": {"name": "Snowplow", "description": "* Website: https://snowplowanalytics.com/\r\n* Comment: Cloud-native web, mobile and event analytics, running on AWS and on-premise with Kafka\r\n* Category: Analytics, Trackers\r\n* Code signature: `com.snowplowanalytics`\r\n* Network signature: `xxx.com`\r\n* Maven repository: `xxx`\r\n* Artifact ID: `xxx`\r\n* Group ID: `xxx` \r\n* Gradle: ``\r\n* Additional links: https://github.com/snowplow/snowplow\r\n* Notes: Mobile, Web, Game, IoT trackers", "network_signature": "NC", "creation_date": "2018-03-04", "id": 108, "website": "https://snowplowanalytics.com/", "code_signature": "com.snowplowanalytics."}, "109": {"name": "Fyber SponsorPay", "description": "Advertisement", "network_signature": "appengage-video.sponsorpay.com|cdn1.sponsorpay.com|cdn2.sponsorpay.com|cdn3.sponsorpay.com|cdn4.sponsorpay.com|engine.sponsorpay.com", "creation_date": "2018-03-04", "id": 109, "website": "http://www.sponsorpay.com", "code_signature": "com.sponsorpay"}, "110": {"name": "Supersonic Ads", "description": "Advertisement", "network_signature": "tag-mediation.supersonic.com|click-haproxy.supersonicads.com|init.supersonicads.com|outcome.supersonicads.com|ow-gateway.supersonicads.com|rv-gateway.supersonicads.com|pixel-tracking.sonic-us.supersonicads.com|ua.supersonicads.com|www.supersonicads.com|supersonic.com", "creation_date": "2018-03-04", "id": 110, "website": "https://www.supersonic.com/", "code_signature": "com.supersonic.adapters.supersonicads|com.supersonicads.sdk"}, "111": {"name": "Carnival", "description": "* Website: http://carnival.io/\r\n* Comment: Carnival mobile marketing automation drives app engagement and customer conversions.\r\n* Category: Analytics, Advertising\r\n* Code signature: `com.carnival.sdk, com.carnivalmobile`\r\n* Network signature: `xxx.com`\r\n* Maven repository: `xxx.com`\r\n* Artifact ID: `xxx`\r\n* Group ID: `xxx` \r\n* Gradle: `xxx`\r\n* Additional links: https://devices.carnivalmobile.com\r\n* Notes: FakePhoneCallActivity, \"fake_call_message\"", "network_signature": "devices.carnivalmobile.com", "creation_date": "2018-03-04", "id": 111, "website": "http://carnival.io/", "code_signature": "com.carnival.sdk|com.carnivalmobile"}, "112": {"name": "Tencent Map LBS", "description": "Map/LBS", "network_signature": "NC", "creation_date": "2018-03-04", "id": 112, "website": "https://lbs.qq.com/", "code_signature": "com.tencent.lbs"}, "113": {"name": "Tencent MobWin", "description": "Advertisement", "network_signature": "NC", "creation_date": "2018-03-04", "id": 113, "website": "https://www.tencent.com/en-us/", "code_signature": "com.tencent.mobwin"}, "114": {"name": "Tencent MTA", "description": "Analytics", "network_signature": "NC", "creation_date": "2018-03-04", "id": 114, "website": "https://mta.qq.com/", "code_signature": "com.tencent.mta"}, "115": {"name": "Apptentive", "description": "* Website: https://www.apptentive.com/\r\n* Comment: Build brands customers love by understanding their behavior and expectations\r\n* Category: [Analytics, Engagment]\r\n* Code signature: `com.apptentive`\r\n* Network signature: `?`\r\n* Maven repository: `?`\r\n* Artifact ID: `?`\r\n* Group ID: `?` \r\n* Gradle: `com.apptentive:apptentive-android:5.0.2`\r\n* Additional links: https://github.com/apptentive/apptentive-android\r\n* Notes: Founded 2011, Seattle, USA. Total Funding 11.9M$", "network_signature": "api.apptentive.com", "creation_date": "2018-03-04", "id": 115, "website": "https://www.apptentive.com/", "code_signature": "com.apptentive."}, "116": {"name": "Tencent Stats", "description": "Analytics", "network_signature": "NC", "creation_date": "2018-03-04", "id": 116, "website": "http://stat.qq.com/", "code_signature": "com.tencent.stat"}, "117": {"name": "Tencent Weiyun", "description": "Analytics", "network_signature": "NC", "creation_date": "2018-03-04", "id": 117, "website": "https://www.weiyun.com", "code_signature": "com.tencent.weiyun"}, "118": {"name": "MixPanel", "description": "## About\r\n\r\nMixPanel, Inc. is a privately-held marketing technology company with 250+ employees and offices in San Francisco, New York, Seattle, Salt Lake City, and London, UK. [Source: OpenCorporates](https://opencorporates.com/companies/us_de/4689044); [Source: Linkedin](https://www.linkedin.com/company/mixpanel-inc-)\r\n\r\n## Ownership\r\n\r\nMixPanel was founded in 2009 by Suhail Doshi and Tim Trefren. [Source: website](https://mixpanel.com/about/)\r\n\r\n## What it does\r\n\r\n* Behavioral Analytics\r\n* Data Collection\r\n* Media Trend analysis [See: Forbes article on 2018 report](https://www.forbes.com/sites/curtissilver/2018/05/08/mixpanel-2018-media-benchmarks-report-reveals-the-truth-of-our-media/#19fc268d2349)\r\n* Anonymous Profiling \"Firmographics\"\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of May 2018, reviewed 25/10/18:](https://mixpanel.com/legal/privacy-policy/)\r\n\r\n* MixPanel's privacy policy does not apply to end-users. Its policy refers to \"Customers\", who are MixPanel's clients. MixPanel tracks its clients by default but they have the right to delete their personal information at any time. Personal information includes location, name, email, pixel tag, and online tracking data. \r\n\r\n* End-users who are tracked by MixPanel's \"Customers\" have no right to delete their personal information and are refered to their individual client privacy policies. MixPanel's clients are not identifed anywhere in the policy. The client is referred to as the \"data controller.\"\r\n\r\n* Interestingly, MixPanel's policy notes that it \"does not respond\" to its clients' Do Not Track signals, by default, since there is \"no standard that governs what, if anything, websites should do if they receive these signals.\"\r\n\r\n* Per the [Terms of Use](https://mixpanel.com/legal/terms-of-use/) end-users can opt-out of MixPanel website tracking through this [link.](https://mixpanel.com/optout) NOTE: this is strictly limited to the use of Mixpanel's website and does not apply to tracking done by their clients or through MixPanel's services.", "network_signature": "api\\.mixpanel\\.com|decide\\.mixpanel\\.com|switchboard\\.mixpanel\\.com|mixpanel\\.com", "creation_date": "2018-03-04", "id": 118, "website": "https://mixpanel.com/", "code_signature": "com.mixpanel."}, "119": {"name": "Umeng Analytics", "description": "## About\r\n\r\nUmeng is a Private company founded by Fan Jiang in April 2010 and acquired by Alibaba Group in 2013. [(Source)](https://techcrunch.com/2013/11/20/umeng-alibaba/) It is based in Beijing, China and has approxmately 50-100 employees. \r\n\r\nTwo company filings were found in Hong Kong: [here](https://opencorporates.com/companies/hk/1579937) and [here.](https://opencorporates.com/companies/hk/2756553) \r\n\r\n## Ownership\r\n\r\nUmeng is owned by the Alibaba Group. Alibaba is listed on the NYSE under the ticker BABA. \r\n\r\n## What it does\r\n\r\n* Behavioral analytics\r\n* Data Collection and usage statistics\r\n* Advertising platforms\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 12/27/2018:](http://mobile.umeng.com/privacypolicy/)\r\n\r\n* An english-version of Umeng's privacy policy could not be located. As such, it was not reviewed. \r\n\r\n* An opt-out page in Mandarin language was located [here.](https://outdip.umeng.com/opt_out.html?spm=a211g2.181323.0.0.3cb23604DDAijH)", "network_signature": "alog.umeng.com|alogs.umeng.com|ar.umeng.com|oc.umeng.com|uop.umeng.com|umeng.com", "creation_date": "2018-03-04", "id": 119, "website": "https://www.umeng.com/analytics", "code_signature": "com.umeng.analytics"}, "120": {"name": "Umeng Feedback", "description": "## About\r\n\r\nUmeng is a Private company founded by Fan Jiang in April 2010 and acquired by Alibaba Group in 2013. [(Source)](https://techcrunch.com/2013/11/20/umeng-alibaba/) It is based in Beijing, China and has approxmately 50-100 employees. \r\n\r\nTwo company filings were found in Hong Kong: [here](https://opencorporates.com/companies/hk/1579937) and [here.](https://opencorporates.com/companies/hk/2756553) \r\n\r\n## Ownership\r\n\r\nUmeng is owned by the Alibaba Group. Alibaba is listed on the NYSE under the ticker BABA. \r\n\r\n## What it does\r\n\r\n* Behavioral analytics\r\n* Data Collection and usage statistics\r\n* Advertising platforms\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 12/27/2018:](http://mobile.umeng.com/privacypolicy/)\r\n\r\n* An english-version of Umeng's privacy policy could not be located. As such, it was not reviewed. \r\n\r\n* An opt-out page in Mandarin language was located [here.](https://outdip.umeng.com/opt_out.html?spm=a211g2.181323.0.0.3cb23604DDAijH)", "network_signature": "alog.umeng.com|alogs.umeng.com|ar.umeng.com|oc.umeng.com|uop.umeng.com|umeng.com", "creation_date": "2018-03-04", "id": 120, "website": "http://dev.umeng.com/feedback", "code_signature": "com.umeng.fb"}, "121": {"name": "Unity3d Ads", "description": "Advertisement", "network_signature": "analytics.social.unity.com|api.uca.cloud.unity3d.com|config.uca.cloud.unity3d.com|stats.unity3d.com|adserver.unityads.unity3d.com|auction.unityads.unity3d.com|cdn.unityads.unity3d.com|cdn-highwinds.unityads.unity3d.com|config.unityads.unity3d.com|webview.unityads.unity3d.com", "creation_date": "2018-03-04", "id": 121, "website": "https://unity3d.com/", "code_signature": "com.unity3d.services|com.unity3d.ads"}, "122": {"name": "Countly", "description": "* Website: https://count.ly/\r\n* Comment: Countly is the best analytics platform for tracking customer journeys in web, desktop and mobile applications. We process billions of data points every day and help businesses across the globe understand their product usage and act on highly detailed data.\r\n* Category: [Analytics]\r\n* Code signature: `ly.count.android`\r\n* Network signature: `xxx.com`\r\n* Maven repository: `http://dl.bintray.com/countly/maven`\r\n* Artifact ID: `xxx`\r\n* Group ID: `ly.count.android` \r\n* Gradle: `xxx`\r\n* Additional links: https://github.com/Countly/countly-sdk-android\r\n* Notes: Open Source. Founded 2013, London, England", "network_signature": "NC", "creation_date": "2018-03-04", "id": 122, "website": "https://count.ly/", "code_signature": "ly.count.android."}, "123": {"name": "Urbanairship", "description": "Analytics", "network_signature": "device-api.urbanairship.com|urbanairship.com", "creation_date": "2018-03-04", "id": 123, "website": "https://www.urbanairship.com/", "code_signature": "com.urbanairship"}, "124": {"name": "Yandex Ad", "description": "## About\r\n\r\nYandex (NASDAQ: YNDX) is a multinational corporation dealing in Internet-related products and services. It is the largest technology company in Russia. Its parent company, Yandex N.V., is based in the Netherlands. [Source: OpenCorporates](https://opencorporates.com/companies/nl/27265167) \r\n\r\n## Ownership\r\n\r\nYandex's current CEO and founder is Arkady Volozh. In 2018, Volozh was added the US Treasury Department's list of Russian \"oligarchs\" linked to Russian President Vladmir Putin. [Source: Boston Globe](https://www.bostonglobe.com/news/world/2018/01/30/releases-putin-list-russian-politicians-oligarchs/PUw8A93TCiXGMMOMNSKTUI/story.html) \r\n\r\n## What it does\r\n\r\n* Behavioral Analytics\r\n* Mobile Advertising\r\n* Enables tracking by unspecified third parties\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 29/8/2018](https://yandex.ru/legal/confidential/):\r\n\r\n* Yandex's policy does not define personal information but refers the reader to \"applicable laws and regulations.\" \r\n\r\n* Personal information can be obtained by advertising partners. \r\n\r\n* Yandex \"does not actively collect any sensitive personal data (such as racial origins, political opinions, health or biometric data).\" They \"do not engage in any form of profiling that has the potential to significantly impact your rights and freedoms.\" Employees must follow internal rules and protocols to ensure confidentiality when processing personal information. \r\n\r\n* Yandex may transfer personal information to business partners, advertisers, any third party with whom they contract, and to any governmental body, regulatory or enforcement agency at their request or as required by law. \r\n\r\n* If provided by law within the user's jurisdiction, users may: request erasure of their personal information and restriction of its processing. Users may also request a copy of the Standard Contractual Clauses enabling the transfer of their personal information to Russia. \r\n\r\n* Users may possess other rights not mentioned within this policy to the extent provided by applicable law.", "network_signature": "appmetrica.yandex.com|report.appmetrica.yandex.net|analytics.mobile.yandex.net|banners.mobile.yandex.net|banners-slb.mobile.yandex.net|startup.mobile.yandex.net|mc.yandex.ru", "creation_date": "2018-03-04", "id": 124, "website": "https://www.yandex.com/", "code_signature": "com.yandex.mobile.ads"}, "125": {"name": "Amplitude", "description": "Analytics", "network_signature": "api.amplitude.com|amplitude.com", "creation_date": "2018-03-04", "id": 125, "website": "http://www.amplitude.com", "code_signature": "com.amplitude."}, "126": {"name": "AppSee", "description": "* Website: https://www.appsee.com\r\n* Comment: Via user session recordings, touch heatmaps, and single-user journey data, mobile professionals get a complete picture of what\u2019s going on in their app, without having to guess the \u201cwhys\u201d behind certain KPIs. Instead of focusing on tracking everything, these tools support an actionable, lean approach to being \u201cdata-driven\u201d. \r\n* Category: [Analytics]\r\n* Code signature: `com.appsee`\r\n* Network signature: `?`\r\n* Maven repository: `NA`\r\n* Artifact ID: `?`\r\n* Group ID: `?` \r\n* Gradle: `com.appsee:appsee-android:+`\r\n* Additional links: https://www.appsee.com/docs/android/native\r\n* Notes: Founded 2012, Israel Total Funding Amount 3M$", "network_signature": "api.appsee.com", "creation_date": "2018-03-04", "id": 126, "website": "https://www.appsee.com/", "code_signature": "com.appsee."}, "127": {"name": "Kochava", "description": "Analytics", "network_signature": "control\\.kochava\\.com|kvinit\\-prod\\.api\\.kochava\\.com", "creation_date": "2018-03-04", "id": 127, "website": "https://www.kochava.com/", "code_signature": "com.kochava.base.Tracker|com.kochava.android.tracker."}, "129": {"name": "Webtrends", "description": "Analytics", "network_signature": "dc.webtrends.com|webtrends.com", "creation_date": "2018-03-04", "id": 129, "website": "https://www.webtrends.com/", "code_signature": "com.webtrends.mobile.analytics.|com.webtrends.mobile.android"}, "130": {"name": "New Relic", "description": "* Website: https://www.newrelic.com\r\n* Comment: App usage stats\r\n* Category: Analytics\r\n* Code signature: `com.newrelic.agent`\r\n* Network signature: `nr-data.net|newrelic.com`\r\n* Maven repository: \r\n* Artifact ID: `android-agent`\r\n* Group ID: `com.newrelic.agent.android` \r\n* Gradle: `com.newrelic.agent.android:android-agent` `com.newrelic.agent.android:agent-gradle-plugin`\r\n* Additional links: \r\n* Notes: Requires `android.permission.INTERNET` and `android.permission.ACCESS_NETWORK_STATE`", "network_signature": "js-agent.newrelic.com|mobile-collector.newrelic.com|newrelic.com|nr-data.net", "creation_date": "2018-03-04", "id": 130, "website": "http://www.newrelic.com", "code_signature": "com.newrelic.agent."}, "131": {"name": "AppAnalytics", "description": "* Website: http://appanalytics.io\r\n* Comment: Real-time mobile app analytics for the entire customer lifecycle with event-based analytics, crash analytics, heat map analytics and gesture recognition!\r\n* Category: [Analytics]\r\n* Code signature: `io.appanalytics.sdk`\r\n* Network signature: `?`\r\n* Maven repository: `?`\r\n* Artifact ID: `?`\r\n* Group ID: `?` \r\n* Gradle: `NA`\r\n* Additional links: http://appanalytics.io/Support#IntegratingSDK\r\n* Notes: Founded 2015, USA (San Jose) Seed round 300k$ \r\nApp Analytics records all touch events of your users and shows as a heat map. App Analytics allows you to see all specific touches (first touch, second touch, etc.) as a heat map analytics", "network_signature": "NC", "creation_date": "2018-03-04", "id": 131, "website": "http://appanalytics.io/", "code_signature": "io.appanalytics.sdk"}, "132": {"name": "Applause", "description": "Analytics", "network_signature": "NC", "creation_date": "2018-03-04", "id": 132, "website": "http://www.applause.com", "code_signature": "com.applause.android."}, "133": {"name": "Quantcast", "description": "Analytics", "network_signature": "quantcast.com|quantcast.net", "creation_date": "2018-03-04", "id": 133, "website": "http://www.quantcast.com", "code_signature": "com.quantcast.measurement.service."}, "135": {"name": "Apptimize", "description": "Analytics", "network_signature": "brahe.apptimize.com|md-a-c.apptimize.com|md-a-s.apptimize.com", "creation_date": "2018-03-04", "id": 135, "website": "http://www.apptimize.com", "code_signature": "com.apptimize."}, "136": {"name": "AppBrain", "description": "* Website: https://www.appbrain.com/info/help/sdk/index.html\r\n* Comment: The AppBrain SDK is present in over 50,000 apps and is downloaded onto millions of phones every day. 2 main services: Promotion: pay-per-install based app promotion to drive installs of your Android app. Monetization: earn money with your app using the interstitials and banners of the AppBrain SDK. \r\n* Category: [Analytics, Advertising]\r\n* Code signature: `com.appbrain`\r\n* Network signature: `?`\r\n* Maven repository: `?`\r\n* Artifact ID: `NA`\r\n* Group ID: `NA`\r\n* Gradle: `com.appbrain:appbrain-sdk:+@aar`\r\n* Additional links: https://github.com/swisscodemonkeys/appbrain-sdk http://www.appbrain.com/ \r\n* Notes: Launched in 2009 by two former Googlers. Suisse (Zurich)\r\nAppBrain is saying to dev that integrate the SDK: *It is your sole responsibility to communicate the privacy implications of your use of the AppBrain SDK to your users.* http://www.appbrain.com/info/help/sdk/policy.html\r\nThe potentially privacy sensitive data that\u2019s collected includes the phone model information, phone identifier (Google Advertiser ID), IP address of the phone, country and carrier of the connected mobile network and of the SIM card, and the AppBrain AppMetric\u2122, a token that conveys information about which categories of apps a user is interested in in a privacy-conserving way. Demographic data (gender, age) is only collected when the developer receives this information and forwards it to the AppBrain SDK. When the app has permission to acquire geographic location, this is collected and deleted at most seven days after collection. IP address and phone identifier for COPPA-enabled apps are also deleted at most 7 days after collection.", "network_signature": "sdk.appbrain.com", "creation_date": "2018-03-04", "id": 136, "website": "https://www.appbrain.com/info/help/sdk/index.html", "code_signature": "com.appbrain."}, "137": {"name": "Dynatrace", "description": "Analytics", "network_signature": "NC", "creation_date": "2018-03-04", "id": 137, "website": "http://www.dynatrace.com", "code_signature": "com.dynatrace.android.app."}, "138": {"name": "Matomo (Piwik)", "description": "* Website: https://matomo.org/mobile\r\n* Comment: Matomo (formerly Piwik) is the leading open-source analytics platform.\r\n* Category: Analytics\r\n* Code signature: `org.piwik|org.piwik.mobile|org.matomo`\r\n* Network signature: `matomo\\.org`\r\n* Maven repository: `NA`\r\n* Gradle: `NA`\r\n* Group ID: `org.piwik` \r\n* Gradle: `NA`\r\n* Additional links: [Piwik SDK on Github](https://github.com/matomo-org/piwik-sdk-android), [Matomo Analytics on Github](https://github.com/matomo-org), [Matomo Documentation](https://developer.matomo.org/integration), [Matomo API Reference](https://developer.matomo.org/api-reference), [Matomo on English Wikipedia](https://en.wikipedia.org/wiki/Matomo_(software)), [Piwik PRO on English Wikipedia](https://en.wikipedia.org/wiki/Piwik_PRO)\r\n* Notes: [Piwik PRO](https://piwik.pro) is an enterprise fork of Piwik with proprietary components.", "network_signature": "matomo\\.org", "creation_date": "2018-03-04", "id": 138, "website": "https://matomo.org/mobile", "code_signature": "org.piwik|org.piwik.mobile|org.matomo"}, "140": {"name": "AppMetrica", "description": "Analytics", "network_signature": "appmetrica.yandex.com|report.appmetrica.yandex.net|analytics.mobile.yandex.net|banners.mobile.yandex.net|banners-slb.mobile.yandex.net|startup.mobile.yandex.net|mc.yandex.ru", "creation_date": "2018-03-04", "id": 140, "website": "https://tech.yandex.com/metrica-mobile-sdk/", "code_signature": "com.yandex.metrica."}, "142": {"name": "Singlespot", "description": "Capabilities:\r\n* Targets users via geotargeting\r\n* Tracks users using GPS\r\n* Tracks users using WiFi\r\n* Tracks users using location data\r\n\r\nAdvertising:\r\n* Location-based ad pushing\r\n* Real-world location targeting\r\n* Targeted advertising based on consumer actions\r\n\r\nAnalytic:\r\n* Identifies users via Google ID (AAID)\r\n* Identifies users via iOS ID (IDFA)", "network_signature": "singlespot\\.com", "creation_date": "2018-08-16", "id": 142, "website": "https://www.singlespot.com/", "code_signature": "com.sptproximitykit."}, "143": {"name": "Sensoro", "description": "*SENSORO is committed to the convergence of the physical and digital world through the application of sensing technologies. SENSORO\u2019s Alpha Product Suite delivers a comprehensive solution for implementing an easily managed and monitored IoT sensor network.*\r\n\r\nCapability:\r\n* Tracks users using bluetooth\r\n* Tracks users using location data", "network_signature": "NC", "creation_date": "2018-08-16", "id": 143, "website": "https://www.sensoro.com/", "code_signature": "com.sensoro.beacon.kit.|com.sensoro.cloud"}, "144": {"name": "Sense360", "description": "*At the core of our research is our sensor-technology which uses the mobile sensors built into smartphones to understand a user\u2019s location and activity. We have trained our algorithms with hundreds of thousands of labeled data points and incorporate data from GPS, accelerometer, gyroscope, barometer, wifi, ambient light, and many other sensors. This provides us with an anonymous, but highly accurate understanding of where, how, and when people interact with physical locations and businesses.\r\nSense360\u2019s sensor-technology is on dozens of apps and more than 2 million devices in the US. Our panel generates more than a terabyte of sensor data every single day and provides a detailed view of more than 150 million anonymous user visits a month.*\r\n\r\nCapability:\r\n* Tracks users using bluetooth", "network_signature": "quinoa-personal-identify-prod.sense360eng.com|android-quinoa-config-prod.sense360eng.com|incoming-data-sense360.s3.amazonaws.com", "creation_date": "2018-08-16", "id": 144, "website": "https://sense360.com/", "code_signature": "com.sense360.android.quinoa.lib.Sense360"}, "145": {"name": "Rubicon Project", "description": "Capability:\r\n* Tracks users using GPS", "network_signature": "ads.rubiconproject.com|stats.aws.rubiconproject.com|fastlane.rubiconproject.com|optimized-by.rubiconproject.com|pixel.rubiconproject.com|tap2-cdn.rubiconproject.com|video-ads.rubiconproject.com", "creation_date": "2018-08-16", "id": 145, "website": "https://rubiconproject.com", "code_signature": "com.rfm.sdk"}, "146": {"name": "ironSource", "description": "*ironSource builds monetization, engagement, analytics and discovery tools for app developers, device manufacturers, mobile carriers and advertisers. We empower content creators across platforms to turn their digital content into viable businesses without having to charge for them. Our technologies make free-to-play and free-to-use possible for the internet community.*", "network_signature": "NC", "creation_date": "2018-08-16", "id": 146, "website": "https://www.ironsrc.com", "code_signature": "com.ironsource."}, "147": {"name": "Heyzap (bought by Fyber)", "description": "", "network_signature": "ads.heyzap.com|fyc.heyzap.com|med.heyzap.com|x.heyzap.com|img-cloudflare.haizap.com|img-cloudflare-2.haizap.com", "creation_date": "2018-08-16", "id": 147, "website": "https://www.heyzap.com", "code_signature": "com.heyzap.sdk.ads."}, "148": {"name": "Gigya", "description": "", "network_signature": "cdn.gigya.com|cdn1.gigya.com|cdn2.gigya.com|cdn3.gigya.com|cdns.us1.gigya.com", "creation_date": "2018-08-16", "id": 148, "website": "https://www.gigya.com", "code_signature": "com.gigya."}, "149": {"name": "Foresee", "description": "", "network_signature": "4seeresults.com|analytics.foresee.com|i.4see.mobi|rec.replay.answerscloud.com|foreseeresults.com|foresee.com", "creation_date": "2018-08-16", "id": 149, "website": "https://www.foresee.com", "code_signature": "com.foresee.sdk.ForeSee"}, "150": {"name": "Fiksu", "description": "Analytic:\r\n* Audience segmenting", "network_signature": "a.fiksu.com|sdk.fiksu.com", "creation_date": "2018-08-16", "id": 150, "website": "https://fiksu.com", "code_signature": "com.fiksu.asotracking"}, "151": {"name": "Ensighten", "description": "Analytic:\r\n* Offers analytics activity to app developers\r\n* Offers reports to app developers", "network_signature": "nexus.ensighten.com", "creation_date": "2018-08-16", "id": 151, "website": "https://www.ensighten.com", "code_signature": "com.ensighten."}, "152": {"name": "Dynamic Yield", "description": "Capability:\r\n* Targets user location and proximity via geofencing\r\n* Targets users via geotargeting\r\n* Tracks users using GPS\r\n* Tracks users using WiFi\r\n* Tracks users using location data\r\n\r\nAdvertising:\r\n* Alters app functionality based upon user profiles\r\n* Loads advertisements\r\n* Loads targeted advertisements\r\n* Location-based ad pushing\r\n* Real-world location targeting\r\n* Targeted advertising based on consumer actions\r\n* Targets across devices, channels and/or platforms (omni-channel marketing, customer journey)\r\n* Timed advertisements\r\n\r\nAnalytic:\r\n* Analytics AI and machine learning\r\n* Audience segmenting\r\n* Collects Personally Identifiable Information (PII)\r\n* Collects Sensitive Personal Information (SPI)\r\n* Identifies users via Google ID (AAID)\r\n* Identifies users via iOS ID (IDFA)\r\n* Offers analytics activity to app developers\r\n* Offers reports to app developers\r\n* Performs cross-device identification\r\n* Profiles users via Personally Identifiable Information (PII)\r\n* Profiles users via Sensitive Personal Information (SPI)\r\n* Stores personal profile data (name, address, phone)", "network_signature": "cdn.dynamicyield.com|adm.dynamicyield.com|api.dynamicyield.com|px.dynamicyield.com|st.dynamicyield.com", "creation_date": "2018-08-16", "id": 152, "website": "https://www.dynamicyield.com", "code_signature": "com.dynamicyield."}, "153": {"name": "BlueKai (acquired by Oracle)", "description": "", "network_signature": "stags.bluekai.com|tags.bluekai.com", "creation_date": "2018-08-16", "id": 153, "website": "http://bluekai.com/registry/", "code_signature": "com.bluekai.sdk."}, "154": {"name": "BlueConic", "description": "## About\r\n\r\nBlueConic, Inc. is a privately-held e-marketing company that sells targeted advertising through marketing management systems, or CDPs (Customer Data Platforms). The company has 50-100 employees and is headquartered in Boston, MA with a European office in Nijmegen, The Netherlands. [For more information, see OpenCorporates.](https://opencorporates.com/companies/us_ma/001126438)\r\n\r\nBlueConic's customers include the Boston Globe, Hearst Newspapers, Moen, T-Mobile, ING, America's Test Kitchen, and the American Kennel Club. [Source: website](https://www.blueconic.com/about/)\r\n\r\n## Ownership\r\n\r\nBlueConic was founded by Bart Heilbron and Martjin van Berkum in 2010. [Source: website](https://www.blueconic.com/about/)\r\n\r\n## What it does\r\n\r\n* Behavioral Analytics\r\n* Customer Data Platform (CDP) Marketing Management Systems\r\n* Targeted Advertising/Personalization\r\n\r\n## Privacy Policy\r\n\r\n[Policy as of 1/11/2018, last updated 1/11/2017:](https://www.blueconic.com/privacy-policy/)\r\n\r\n* BlueConic's privacy policy applies to both its website and its services platform. It is not clear to what extent end users have rights under the policy separate from clients.\r\n\r\n* Personal data is not defined in the policy. It may be used by third party affiliates in the ordinary course of business, however, \"the use of information collected through BlueConic Services Platform shall be limited to the purpose of providing the service for which the Client has engaged BlueConic.\"\r\n\r\n* Infomation gathered may include \"Internet Protocol (IP) addresses, browser type and language, Internet service provider (ISP), referring and exit pages, operating system, date/time stamp, and other data\", including \"social networking pages.\" \r\n\r\n* BlueConic may \"share or publish aggregate information that doesn\u2019t specifically identify you, such as statistical information about visitors to our Websites or statistical information about how customers use our applications.\"\r\n\r\n* The policy states that BlueConic will \"follow generally accepted standards to protect the personal information submitted to us, both during transmission and once it is received, including requiring our suppliers to meet such standards to protect your personal data from unauthorized access, use, and disclosure. If you have questions about the security of your personal data, you can contact us at info@blueconic.com. \"\r\n\r\n* BlueConic has certified its compliance with the EU-U.S. Privacy Shield Framework and the Swiss-U.S. Privacy Shield Framework.", "network_signature": "NC", "creation_date": "2018-08-16", "id": 154, "website": "https://www.blueconic.com", "code_signature": "com.blueconic"}, "155": {"name": "Apteligent by VMWare (formerly Crittercism)", "description": "Formerly **Crittercism**", "network_signature": "api.crittercism.com|appload.ingest.crittercism.com|txn.ingest.crittercism.com", "creation_date": "2018-08-16", "id": 155, "website": "http://www.apteligent.com", "code_signature": "com.crittercism.app.Crittercism"}, "156": {"name": "AdFit (Daum)", "description": "", "network_signature": "analytics.ad.daum.net|statistics.videofarm.daum.net", "creation_date": "2018-08-16", "id": 156, "website": "https://www.daum.net", "code_signature": "com.kakao.adfit.ads."}, "157": {"name": "Adform", "description": "", "network_signature": "track.adform.net|adformdsp.net|adform.com|adx.adform.net|files.adform.net", "creation_date": "2018-08-16", "id": 157, "website": "https://site.adform.com", "code_signature": "com.adform.sdk."}, "158": {"name": "Adfurikun", "description": "", "network_signature": "ginf.adfurikun.jp|adfurikun.jp", "creation_date": "2018-08-16", "id": 158, "website": "https://adfurikun.jp/adfurikun/", "code_signature": "jp.tjkapp.adfurikunsdk."}, "159": {"name": "Mobvista", "description": "Mobvista is a leading technology platform providing mobile advertising and mobile analytics services to the app developers globally.\r\nAdvanced real-time data analysis and predictive technology let you target the right users for your products.\r\nLeverage our robust big data and AI capabilities to deliver better engagement.\r\nPowerful audience profiling, optimization and retargeting are combined to amplify your campaigns\u2019 impact and achieve a higher ROI\r\nPowering leading companies in driving more growth through massive coverage of media, innovation ad formats and predictive analytics, all fueled by advanced AI intelligence.", "network_signature": "mobvista\\.com", "creation_date": "2019-03-10", "id": 159, "website": "https://www.mobvista.com/", "code_signature": "com.mobvista."}, "160": {"name": "Placed", "description": "Placed - The Leader in Offline Attribution\r\nPlaced is trusted by 350+ publishers, networks, and platforms, and 500+ advertisers and agencies to measure advertising's impact on store visits\r\nConsumer Path from TV Screen to Store\r\nPartnering with Inscape and Kantar, Placed closes the loop to store visitation across mobile devices used by 1 in 3 U.S. adults.\r\nPlaced Insights - Analytics for the Real World\r\nOpen-source location analytics platform mapping the real-world relationship between people and places\r\n\r\nBy leveraging one of the world's largest location platforms, billions of directly measured locations, and patent-pending statistical models, Placed is able to turn complex location data into actionable insights for our clients.\r\nPlaced is the leading provider of directly-measured location insights, analyzing billions of locations from its opt-in audience. Accurately measuring location is more than just data volume; it requires models, real-world context, and the ability to observe the complete path of consumer activity.\r\n\r\nBy measuring location continuously, Placed observes when data signals shift from a single point to a cluster of points; identifying a visit has occurred.\r\n\r\nOnce a visit is identified, Placed searches its database of hundreds of millions of business features to determine the likely place of the visit.\r\n\r\nPlaced understands that location accuracy is more than a latitude and longitude. Leveraging the intelligence from Data Clustering and Place Search, the Placed Inference Model applies a statistical probability to each and every visit, bringing the highest level of accuracy to consumer location insights. The Placed Inference Model is continuously trained against millions of first-hand validation points confirmed by panelists in the field.", "network_signature": "NC", "creation_date": "2019-03-10", "id": 160, "website": "http://placed.com/", "code_signature": "com.placed.client"}, "161": {"name": "Adot", "description": "Adot (formerly Adotmob) is a technology company founded in 2014 in Paris that provides agencies and advertisers with powerful insights on their audiences for a more accurate media activation.\r\n\r\nAdot (formerly Adotmob) uses both online and offline data sources.\r\n\r\nThanks to its exclusive partnership with vente-privee, Adot (formerly Adotmob) has access to a pool of exclusive e-commerce data: declared socio-demographic data and e-commerce intent data. Our last online data source arises from our earned bid requests, that allows the company to identify navigation media patterns, in particular through the analysis of keywords based on the visited pages and media interest by topic. Lastly, Adot (formerly Adotmob) owns geolocation data generated through proprietary technology integrated in partners\u2019 mobile apps.", "network_signature": "sdk\\.adotmob\\.com|sync\\.adotmob\\.com|tracker\\.adotmob\\.com", "creation_date": "2019-03-10", "id": 161, "website": "https://we-are-adot.com/", "code_signature": "com.adotmob"}, "162": {"name": "Appodeal", "description": "## About\r\nA Full Stack Ad Monetization Platform. Take full control of your monetization strategy with Appodeal\u2019s complete suite of tools.\r\n\r\n## Category\r\nAnalyitics, Location, Advertising, Identity\r\n\r\n## Additional links\r\nhttps://s3.amazonaws.com/appodeal-unity/\r\n\r\n## Notes\r\nAppodeal supports iOS, Android, and Amazon devices. Unity3D and Corona Labs.", "network_signature": "appodeal.com|appodealx.com", "creation_date": "2019-03-10", "id": 162, "website": "https://www.appodeal.com", "code_signature": "com.appodeal.ads."}, "163": {"name": "AppMonet", "description": "AppMonet is a Container technology that enables publishers to have fewer SDKs while maximizing and diversifying their Brand Advertising demand sources. Simply put, almost all of the top 100 brand advertising demand sources work with AppMonet. All of those Video and Display demand sources simply plug into our Container \u2013 No SDKs required", "network_signature": "NC", "creation_date": "2019-03-10", "id": 163, "website": "http://appmonet.com", "code_signature": "com.monet."}, "164": {"name": "Soomla", "description": "\"Our mission is to help publishers make data-driven decisions for their monetization efforts.\r\n\r\nAt SOOMLA we aim to give mobile app publishers insights into the revenue they are making from advertising. We specifically help track revenue per user, per segment, per cohort and per traffic source. With the help of this data, we want to help facilitate better monetization and marketing decisions for our clients. More often than not, publishers are leaving money on the table. It's time to take control.\"", "network_signature": "\\soom.la", "creation_date": "2019-03-10", "id": 164, "website": "https://soomla.com/", "code_signature": "com.soomla."}, "165": {"name": "Adincube", "description": "AdinCube has been acquired by Ogury.\r\nhttps://www.ogury.com/ogury_resources/ogury-acquires-adincube-faq/\r\n\r\nWhat does Adincube do?\r\n\r\nDespite the abundance of mediation solution options available, mobile publishers still struggle to optimize ad revenue and fill 100% of their inventory. Maximum yield is not being realized, and valuable revenue is being left on the table. Adincube Intelligent Mediation solves this problem.\r\n\r\nThrough one simple integration, Adincube Intelligent Mediation uses artificial intelligence to boost publishers' ad revenue by an average of 218%. The SDK optimizes revenue between all demand sources and buying metrics on the market, ensuring maximum yield from every single impression. Additionally, it gathers publishers\u2019 earnings and pays out immediately.\r\n\r\nHow does Adincube Intelligent Mediation work?\r\n\r\nOne SDK plugs publishers into all demand sources on the market eliminating the need for adapters or manual set up of individual accounts. Adincube Intelligent Mediation technology then analyses every available campaign, ad network, ad exchange, buying metric, and creative format in real-time, at ad request level.", "network_signature": "sdk.adincube.com", "creation_date": "2019-03-10", "id": 165, "website": "https://www.adincube.com/", "code_signature": "com.adincube.sdk."}, "166": {"name": "Persona.ly", "description": "Persona.ly is a global mobile ad-tech company. We create mobile monetization solutions and acquire engaged users for top grossing app developers. Our team is full of vibrant, proactive and passionate developers and marketers with diverse backgrounds and vast experience in the mobile monetization field, allowing us to overcome almost any challenge and create solutions that exceed our partners' expectations, developers and advertisers alike.\r\n\r\nhttp://knowledge.persona.ly/", "network_signature": "dev\\.persona\\.ly|dev-api\\.persona\\.ly|dev\\.dsp\\.persona\\.ly|dsp\\.persona\\.ly|rtb\\.persona\\.ly|sdk\\.persona\\.ly|persona\\.ly", "creation_date": "2019-03-10", "id": 166, "website": "http://persona.ly/", "code_signature": "ly.persona.sdk"}, "167": {"name": "Branch", "description": "View https://branch.io/\r\n\r\n(branch has acquired TUNE)\r\n\r\nSend Local IP, device_fingerprint_id, identity_id, hardware_id, brand, model, screen_dpi, screen_height and other\r\n\r\nIncrease mobile revenue with enterprise-grade links built to acquire, engage, and measure across all devices, channels, and platforms.", "network_signature": "api.branch.io", "creation_date": "2019-03-10", "id": 167, "website": "https://branch.io/", "code_signature": "io.branch."}, "168": {"name": "Cheetah Ads", "description": "Cheetah Ads is Cheetah Mobile's self-operated ad platform offering a wide range of ad formats, from high-performing display and native ads, to beautiful, full-screen vertical video. Cheetah Ads offers diverse, global reach with over 600 million users from 200+ countries and regions across Cheetah Mobile's owned and operated inventory, including Clean Master, CM Security, Cheetah Keyboard and LiveMe. Enhanced by Cheetah Mobile's artificial intelligence and big data capabilities, Cheetah Ads helps brands reach the right audience, at the right time, in the right format throughout the entire purchase cycle.", "network_signature": "cmcm.com", "creation_date": "2019-03-10", "id": 168, "website": "https://www.cmcm.com/", "code_signature": "com.cmcm."}, "169": {"name": "Vungle", "description": "Target high-value consumers with our proprietary LTV optimization technology.\r\nGet transparent user acquisition reporting with our third-party UA data integrations.\r\nReach unique consumers globally with our first-party supply in the world's top apps.\r\n\r\nAdditional links:\r\nhttps://support.vungle.com/hc/en-us\r\nhttps://github.com/Vungle/Android-SDK\r\nhttps://bintray.com/vungle/com.vungle/publisher-sdk-android\r\nhttps://vungle.bintray.com/com.vungle", "network_signature": "ads\\.api\\.vungle\\.com|akamai\\.vungle\\-cdn\\.vungle\\.com|api\\.vungle\\.akadns\\.net|api\\.vungle\\.com|bd\\.vungle\\.com|billboard\\.vungle\\.com|cdn\\-lb\\.vungle\\.com|ci\\.vungle\\.com|data\\.vungle\\.com|ingest\\.vungle\\.com|jaeger\\.vungle\\.com|ltv\\-data\\-api\\.kube\\-prod\\.vungle\\.com|monitoring\\.vungle\\.com|ssl\\.vungle\\.com|v\\.vungle\\.com", "creation_date": "2019-03-10", "id": 169, "website": "https://vungle.com", "code_signature": "com.vungle.publisher."}, "170": {"name": "Criteo", "description": "https://en.wikipedia.org/wiki/Criteo\r\n\r\nCriteo is a personalized retargeting company that works with Internet retailers to serve personalized online display advertisements to consumers who have previously visited the advertiser's website. The company currently operates in a total of 30 markets around the world and is headquartered in Paris, FranceCriteo enables online businesses to follow up visitors who have left their website without making a purchase using personalized banners which aim to drive potential customers back to the business website.", "network_signature": "criteo.com", "creation_date": "2019-03-10", "id": 170, "website": "https://www.criteo.com/", "code_signature": "com.criteo."}, "171": {"name": "Mapbox", "description": "Our tools let developers build a new world powered by location data. Real-time updates. Total customization. Developers first.\r\n\r\nhttps://docs.mapbox.com/android/maps/overview/\r\nhttps://github.com/mapbox/mapbox-gl-native", "network_signature": "a.tiles.mapbox.com|api.tiles.mapbox.com", "creation_date": "2019-03-10", "id": 171, "website": "https://www.mapbox.com/", "code_signature": "com.mapbox.mapboxsdk."}, "172": {"name": "Optimizely", "description": "Optimizely is the world\u2019s leading experimentation platform, enabling businesses to deliver continuous experimentation and personalization across websites, mobile apps and connected devices. Optimizely enables businesses to experiment deeply into their technology stack and broadly across the entire customer experience.\r\n\r\nhttps://optimizely.bintray.com/optimizely\r\nhttps://www.optimizely.com/products/mobile/\r\nhttps://docs.developers.optimizely.com/full-stack/docs", "network_signature": "optimizely.com", "creation_date": "2019-03-10", "id": 172, "website": "https://www.optimizely.com/", "code_signature": "com.optimizely."}, "173": {"name": "Taboola", "description": "Thousands of leading publishers, marketers, and agencies utilize Taboola\u2019s predictive technology to increase user engagement, monetize their traffic, and distribute their content to engaged audiences across the web. Together, our teams have pioneered a major new marketing channel alongside \u201csearch\u201d and \u201csocial,\u201d proving that \u201cdiscovery\u201d can power successful campaigns for companies of all sizes, throughout the customer journey.\r\n\r\nhttps://sdk.taboola.com/taboolasdk/docs", "network_signature": "\\taboola.com", "creation_date": "2019-03-10", "id": 173, "website": "https://www.taboola.com/", "code_signature": "com.taboola."}, "174": {"name": "CleverTap", "description": "CleverTap brings together real-time user insights, an advanced segmentation engine, and easy-to-use marketing tools in one mobile marketing platform \u2014 giving your team the power to create amazing experiences that deepen customer relationships. \r\nCleverTap enables growth and retention teams to manage and improve the impact of mobile marketing across the entire customer lifecycle. Leverage user data, automation, AI/ML, and personalization techniques in one enterprise platform.", "network_signature": "wzrkt.com", "creation_date": "2019-03-10", "id": 174, "website": "https://clevertap.com/", "code_signature": "com.clevertap."}, "175": {"name": "myTracker", "description": "Mobile app marketing platform with predictive analytics.", "network_signature": "tracker-api.my.com", "creation_date": "2019-03-10", "id": 175, "website": "https://tracker.my.com/", "code_signature": "com.my.tracker."}, "176": {"name": "Cloudmobi", "description": "Cloudmobi provides CloudTech SDK, integrated with Facebook Audience Network and Admob ads resource.\r\n\r\nhttps://github.com/cloudmobi/AndroidSDK/blob/master/AndroidSDK_Integration_Guide.md\r\n\r\nConnections:\r\nhttps://api.cloudmobi.net\r\nhttp://logger.cloudmobi.net", "network_signature": "api\\.cloudmobi\\.net|logger\\.cloudmobi\\.net|vast\\.cloudmobi\\.net|cloudmobi\\.net", "creation_date": "2019-03-10", "id": 176, "website": "http://www.cloudmobi.net/", "code_signature": "com.cloudtech."}, "177": {"name": "ADLIB", "description": "https://developer.adlibr.com/guide/Android", "network_signature": "adlibr\\.com", "creation_date": "2019-03-10", "id": 177, "website": "https://adlibr.com", "code_signature": "com.mocoplex.adlib."}, "178": {"name": "Brightcove", "description": "## About\r\nIdentify your best content and uncover actionable audience behaviors with comprehensive analytics and reporting. Dive into your viewer\u2019s engagement data at an individual level with Brightcove\u2019s advanced profile analytics.\r\n\r\n## Category\r\nAnalytics, Identity, Location\r\n\r\n## Additional links\r\nhttps://www.brightcove.com/en/online-video-platform/analytics https://www.brightcove.com/en/partners?pages=2 https://support.brightcove.com/ https://github.com/BrightcoveOS/android-player-samples\r\n\r\n## Notes\r\nVideo delivery, DRM, Video Streaming, Monetization, partner integration", "network_signature": "metrics.brightcove.com/v2/tracker", "creation_date": "2019-03-19", "id": 178, "website": "https://www.brightcove.com", "code_signature": "com.brightcove"}, "179": {"name": "DOV-E", "description": "## About\r\nDOV-E\u2019s patented technology utilizes these speakers and provides secure, quick, easy to use mobile payment and interactive mobile engagement on any platform.\r\n\r\n## Category\r\nBeacon, Advertising\r\n\r\n## Notes\r\nMobile payment methods, advertising cross-device triggers, reference hardware for vendors, browser, iOS", "network_signature": ".dov-e.com", "creation_date": "2019-03-19", "id": 179, "website": "https://www.dov-e.com/", "code_signature": "com.dv."}, "180": {"name": "Inmarket", "description": "## About\r\nInspire shoppers when it matters most - as they enter the store, ready to make purchase decisions. Just as restaurants know to advertise before the lunch rush instead of after, Preceptivity personalizes receptivity for your customer based on unique shopping patterns and how they relate to the product category.\r\n\r\n## Category\r\nLocation, Beacon, Advertising\r\n\r\n## Additional links\r\nhttp://data.altbeacon.org/android-distance.json \r\n\r\n## Notes\r\nintegration with Moat", "network_signature": "m2m-api.inmarket.com", "creation_date": "2019-03-19", "id": 180, "website": "https://inmarket.com/", "code_signature": "com.inmarket"}, "181": {"name": "Pilgrim", "description": "## About\r\nEmbed the most comprehensive location awareness engine into your app to engage users with contextually-relevant and geo-aware content.\r\n\r\n## Category\r\nAdvertising, Location, Identity, Tracking, Beacon\r\n\r\n## Additional links\r\nhttps://github.com/foursquare/pilgrim-unity-sdk https://developer.foursquare.com/docs/pilgrim-sdk/android\r\n\r\n## Notes\r\nFoursquare's location tracker for iOS, Android and Unity3D", "network_signature": "sdk.foursquare.com", "creation_date": "2019-03-19", "id": 181, "website": "https://enterprise.foursquare.com/products/pilgrim", "code_signature": "com.foursquare.pilgrim|com.foursquare.pilgrimsdk.android"}, "182": {"name": "OtherLevels", "description": "## About\r\nOtherLevels provides the platform and the knowledge to help you increase conversion and deliver the right content, to the right user, at the right time, on the right channel. Engage and retain your customers better, with relevant, omni-channel campaigns across mobile app, mobile web and desktop.\r\n\r\n## Category\r\nTracking, Location, Messaging, Advertising.\r\n\r\n## Additional links\r\nhttps://www.otherlevels.com/partners/ https://beacons.otherlevels.com/ https://github.com/OtherLevels\r\n\r\n## Notes\r\nrecent promotions of In-Play Messaging Solution for gambling and betting companies.", "network_signature": "api.otherlevels.com|rich.otherlevels.com|geodata.otherlevels.com|tags.otherlevels.com|ws.otherlevels.com|mdn.otherlevels.com", "creation_date": "2019-03-19", "id": 182, "website": "https://www.otherlevels.com/", "code_signature": "com.otherlevels."}, "183": {"name": "PubNative", "description": "Mobile monetization", "network_signature": "pubnative.net", "creation_date": "2019-03-19", "id": 183, "website": "https://pubnative.net/", "code_signature": "net.pubnative"}, "184": {"name": "Appnext", "description": "App marketing and mobile monetization", "network_signature": "\\appnext.com", "creation_date": "2019-03-19", "id": 184, "website": "https://www.appnext.com/", "code_signature": "com.appnext."}, "185": {"name": "MobFox", "description": "Advertising platform", "network_signature": "NC", "creation_date": "2019-03-19", "id": 185, "website": "https://www.mobfox.com/", "code_signature": "com.mobfox."}, "186": {"name": "ShallWeAD", "description": "Mobile Advertising Platform\r\n\r\nMain Features\r\n- Mobile Ad Server\r\n- In-Application Banner(CPC, CPI, CPA, CPM)\r\n- Mobile App PR(Direct Download)\r\n- iOS & Android(Google Play, T-Store) Promotion", "network_signature": "NC", "creation_date": "2019-03-19", "id": 186, "website": "http://www.shallwead.com", "code_signature": "com.jm.co.shallwead.sdk.|com.co.shallwead.sdk."}, "187": {"name": "deltaDNA", "description": "Game Analytics and Marketing", "network_signature": "deltadna.net", "creation_date": "2019-03-19", "id": 187, "website": "https://deltadna.com/", "code_signature": "com.deltadna"}, "188": {"name": "Display", "description": "Mobile marketing", "network_signature": "\\display.io", "creation_date": "2019-03-19", "id": 188, "website": "https://www.display.io/en/", "code_signature": "io.display."}, "189": {"name": "HyprMX", "description": "HyprMX brings brand advertising to mobile apps. Part of Jun Group, an Advantage Solutions company. Founded in 2012, we're headquartered on Fifth Avenue in New York City, with offices in Seattle and San Francisco.\r\n\r\nhttps://documentation.hyprmx.com/", "network_signature": "hyprmx.com", "creation_date": "2019-04-15", "id": 189, "website": "https://www.hyprmx.com", "code_signature": "com.hyprmx.android.sdk."}, "190": {"name": "Bugly", "description": "Bugly is a software manufacturing company specializing in detecting and tracking bug issues\r\nhttps://www.crunchbase.com/organization/bugly", "network_signature": "bugly.qq.com", "creation_date": "2019-04-15", "id": 190, "website": "https://bugly.qq.com/v2/", "code_signature": "com.tencent.bugly."}, "191": {"name": "Duapps", "description": "Analysis\r\nApp Monetization", "network_signature": "duapps.com", "creation_date": "2019-04-15", "id": 191, "website": "http://ad.duapps.com/", "code_signature": "com.duapps."}, "192": {"name": "Swrve", "description": "Swrve real-time marketing automation increases customer engagement through dynamic campaigns that deliver relevant, personalized messages in micromoments that matter across mobile, email, web, TV and emerging digital channels.", "network_signature": "content.swrve.com|api.swrve.com", "creation_date": "2019-04-15", "id": 192, "website": "https://www.swrve.com/", "code_signature": "com.swrve.sdk"}, "193": {"name": "OneSignal", "description": "Mobile Push Notifications, Web Push, and In-App Messaging", "network_signature": "onesignal.com", "creation_date": "2019-04-15", "id": 193, "website": "https://onesignal.com/", "code_signature": "com.onesignal."}, "194": {"name": "Appdynamics", "description": "AppDynamics is a application performance management (APM) company based in San Francisco.\r\nAppDynamics is now a part of Cisco.", "network_signature": "NC", "creation_date": "2019-04-15", "id": 194, "website": "https://www.appdynamics.com/", "code_signature": "com.appdynamics."}, "195": {"name": "Startapp", "description": "Data driven mobile media, marketing and monetization.", "network_signature": "c2i.startappnetwork.com|c2s.startappnetwork.com|click.startappservice.com|dts.startappservice.com|events.startappservice.com|images.startappservice.com|imp.startappservice.com|init.startappservice.com|va.origin.startappservice.com|req.startappservice.com|soda.startappservice.com|info.static.startappservice.com|startappservice.com", "creation_date": "2019-04-15", "id": 195, "website": "https://www.startapp.com", "code_signature": "com.startapp.android.publish"}, "196": {"name": "AerServ", "description": "Advertisement.\r\nAcquired by InMobi.", "network_signature": "ads.aerserv.com|debug.aerserv.com", "creation_date": "2019-04-15", "id": 196, "website": "https://www.aerserv.com/", "code_signature": "com.aerserv.sdk."}, "197": {"name": "INFOnline", "description": "INFOnline is the specialist provider of Digital Audience Measurement Services in Germany.", "network_signature": "de.ioam.de", "creation_date": "2019-04-15", "id": 197, "website": "https://www.infonline.de", "code_signature": "de.infonline."}, "198": {"name": "myTarget", "description": "myTarget is an advertising platform provided by Mail.Ru Group. It includes all the major social networks on the Runet (Russian-speaking Internet) and services that reach more than 140 million people.", "network_signature": "NC", "creation_date": "2019-04-15", "id": 198, "website": "https://target.my.com/", "code_signature": "com.my.target."}, "199": {"name": "Tapjoy", "description": "Engagement and monetization for advertisers and app developers.", "network_signature": "tapjoy.com|tapjoyads.com|www.5rocks.io", "creation_date": "2019-04-15", "id": 199, "website": "https://www.tapjoy.com/", "code_signature": "com.tapjoy."}, "200": {"name": "Mintegral", "description": "Mintegral is a programmatic advertising platform in the mobile marketing world.", "network_signature": "analytics.rayjump.com|cdn-adn.rayjump.com|de.rayjump.com|de01.rayjump.com|detect.rayjump.com|fk-mtrack.rayjump.com|hybird.rayjump.com|jssdk.rayjump.com|net.rayjump.com|online.rayjump.com|setting.rayjump.com|sg.rayjump.com|sg-mtrack.rayjump.com|sg01.rayjump.com|tknet.rayjump.com|us01.rayjump.com|rayjump.com", "creation_date": "2019-04-15", "id": 200, "website": "https://www.mintegral.com/en/", "code_signature": "com.mintegral."}, "201": {"name": "Gimbal", "description": "Advertisement.", "network_signature": "analytics-server.gimbal.com|api.gimbal.com|registration.gimbal.com|sdk-info.gimbal.com", "creation_date": "2019-04-15", "id": 201, "website": "https://gimbal.com/", "code_signature": "com.gimbal.android"}, "202": {"name": "Conviva", "description": "The real-time measurement and intelligence platform for the streaming TV industry.", "network_signature": "cws.conviva.com", "creation_date": "2019-04-15", "id": 202, "website": "https://www.conviva.com/", "code_signature": "com.conviva."}, "203": {"name": "Auditude", "description": "## About\r\nThe Adobe\u00ae Auditude\u00ae platform is used by companies that want to provide relevant content and advertisements in videos you watch on the web.\r\n\r\nLegacy, superceded by Adobe Primetime\r\n\r\n## Category\r\nAdvertising, Location, Identity, Tracking", "network_signature": "auditude.com", "creation_date": "2019-05-02", "id": 203, "website": "https://www.adobe.com/privacy/policies/auditude.html", "code_signature": "com.auditude.ads"}, "204": {"name": "Instreamatic", "description": "## About\r\nVoice-enabled audio technology is the biggest breakthrough in audio advertising in the last 70 years. Voice-enabled audio ads allow users to interact with ads, literally speaking with the brand\r\n\r\n## Category\r\nAdvertising, Tracking", "network_signature": "instreamatic.com", "creation_date": "2019-05-02", "id": 204, "website": "http://instreamatic.com/", "code_signature": "com.instreamatic"}, "205": {"name": "GameAnalytics", "description": "GameAnalytics is a service that helps game developers learn about their players, improve how their games are monetized, and make their games more enjoyable.", "network_signature": "NC", "creation_date": "2019-06-12", "id": 205, "website": "https://gameanalytics.com/features", "code_signature": "com.gameanalytics.sdk"}, "206": {"name": "Instabug", "description": "Whenever your app crashes, Instabug reports this with all the stack trace information on all the running threads.", "network_signature": "NC", "creation_date": "2019-06-12", "id": 206, "website": "https://instabug.com/crash-reporting", "code_signature": "com.instabug.library.tracking|com.instabug.bug"}, "207": {"name": "Bugsnag", "description": "Bugsnag monitors apps for errors that impact customers & reports all diagnostic data.", "network_signature": "NC", "creation_date": "2019-06-12", "id": 207, "website": "https://www.bugsnag.com/", "code_signature": "com.bugsnag."}, "208": {"name": "Moodmedia", "description": "## About\r\nIn-store Media Solutions to help you connect with your customers, enhance your brand image and grow your business.\r\n\r\n## Category\r\nLocation, Tracking, Advertising, Beacon\r\n\r\n## Additional links\r\nhttps://moodmedia.com.au/\r\n\r\n## Notes\r\n\"Sound masking is specifically engineered to match the frequencies of human speech and sound comfortable to the human ear.\"\r\nbeacon tracking via Presence SDK (com.moodmedia.moodpresence)", "network_signature": "moodpresence.com", "creation_date": "2019-06-20", "id": 208, "website": "https://us.moodmedia.com/", "code_signature": "com.moodmedia"}, "209": {"name": "Houndify", "description": "## About\r\nIntegrate voice and conversational intelligence into your products through an independent platform that is always learning. Customize, innovate, and differentiate while maintaining your own brand and users.\r\n\r\n## Additional links\r\nhttps://www.soundhound.com/about\r\nhttps://www.midomi.com/\r\nhttps://www.houndify.com/maven/hound/android/\r\n\r\n## Notes\r\nPrivate beta features include: beam forming, echo cancellation, emotion detection, fingerprint identification, automatic language translation, voice biometrics, iris recognition, image recognition, face recognition, and more.\r\nCollective AI TM offers comprehensive knowledge, that is always learning, is crowdsourced to domain experts, and is larger than the sum of its parts \u2014 ensuring that your solutions and smart IoT devices continue to grow smarter into the future.", "network_signature": "houndify.com", "creation_date": "2019-06-20", "id": 209, "website": "https://www.houndify.com/", "code_signature": "com.hound"}, "210": {"name": "OpenX", "description": "## About\r\nCreating Quality Programmatic Advertising Markets That Drive Superior Monetization for Publishers & App Developers\r\n\r\n## Additional links\r\nhttps://docs.openx.com/Content/developers/android-sdk/android-sdk.html https://docs.openx.com/Content/developers/containers/prebid-adapter.html https://community.openx.com/s/article/Mobile-SDK-Integration-Instructions\r\n\r\n## Notes\r\nMRAID compliance", "network_signature": "NC", "creation_date": "2019-06-20", "id": 210, "website": "https://www.openx.com/", "code_signature": "com.openx.view.plugplay|com.openx.android_sdk_openx"}, "211": {"name": "Taplytics", "description": "## About\r\nTaplytics is an intelligent customer experience cloud specializing in turning first-time users into lifetime customers through magical moments\r\n\r\n## Category\r\nAnalytics, Advertising\r\n\r\n## Additional links\r\nhttps://api.taplytics.com , https://github.com/taplytics , https://js.taplytics.com/jssdk/\r\n\r\n## Notes\r\nMobile, Web, TV and Over The Top devices.", "network_signature": "api.taplytics.com|ping.tapylitics.com", "creation_date": "2019-06-20", "id": 211, "website": "https://taplytics.com", "code_signature": "com.taplytics.sdk"}, "212": {"name": "Yinzcam Sobek", "description": "## About\r\nOur proprietary real-time analytics platform allows administrators to track page-views, dwell-time, social-media shares, push-analytics, and ad clicks, anytime, anywhere. Our analytics platform also helps with segmentation and delivery of content by segment, and the personalization of mobile apps to fans. \r\n\r\n## Category\r\nAnalytics, Location, Beacon, Advertising\r\n\r\n## Additional links\r\nPrivacy policy - http://www.yinzcam.com/?page_id=234 , http://files.yinzcam.com/nathan/csae.js , sobek_base_url: http://172.17.5.204:3002 , http://44.129.0.193:8003/track \r\n\r\n## Notes\r\nPower tracker, System tracker, Telephony tracker, Video tracker, Wifi tracker, video tracking sent to ampr.org held address range", "network_signature": "analytics.yinzcam.com", "creation_date": "2019-06-20", "id": 212, "website": "http://www.yinzcam.com/", "code_signature": "com.yinzcam.sobek"}, "213": {"name": "Ooyala", "description": "Ooyala Flex Media Platform: an open and extensible platform to manage, curate, orchestrate, publish and monetize your content", "network_signature": "ooyala.com", "creation_date": "2019-07-01", "id": 213, "website": "https://www.ooyala.com/", "code_signature": "com.ooyala"}}} \ No newline at end of file diff --git a/MalwareAnalyzer/views/Trackers.py b/MalwareAnalyzer/views/Trackers.py index f0d1932c..21d5972c 100644 --- a/MalwareAnalyzer/views/Trackers.py +++ b/MalwareAnalyzer/views/Trackers.py @@ -1,34 +1,31 @@ -import os -import re -import io -import subprocess import glob +import io import itertools import json import logging -import tempfile -import requests +import os +import re import shutil +import subprocess +import tempfile from collections import namedtuple +import requests + from django.conf import settings -from MobSF.utils import ( - sha256, - upstream_proxy, - isFileExists, - PrintException, -) +from MobSF.utils import is_file_exists, log_exception, sha256, upstream_proxy logger = logging.getLogger(__name__) class Trackers: def __init__(self, apk_dir, tools_dir): - TRACKERS_DB_DIR = os.path.join(settings.BASE_DIR, 'MalwareAnalyzer/trackersdb/') + trackers_db_dir = os.path.join( + settings.BASE_DIR, 'MalwareAnalyzer/trackersdb/') self.apk = None self.apk_dir = apk_dir - self.tracker_db = os.path.join(TRACKERS_DB_DIR, 'exodus_trackers') + self.tracker_db = os.path.join(trackers_db_dir, 'exodus_trackers') self.signatures = None self.nb_trackers_signature = 0 self.compiled_tracker_signature = None @@ -37,15 +34,15 @@ class Trackers: self._update_tracker_db() def _update_tracker_db(self): - """Update Trackers DB""" + """Update Trackers DB.""" try: proxies, verify = upstream_proxy('http') - except: - PrintException("[ERROR] Setting upstream proxy") + except Exception: + log_exception('[ERROR] Setting upstream proxy') try: exodus_url = settings.TRACKERS_DB_URL res = requests.get(exodus_url, timeout=3, proxies=proxies, - allow_redirects=True, verify=verify) + allow_redirects=True, verify=verify) data = res.content tmp_dwd = tempfile.NamedTemporaryFile() tmp_dwd.write(data) @@ -54,28 +51,32 @@ class Trackers: if sha256(tmp_dwd.name) != sha256(self.tracker_db): # DB needs update # Check2: DB Syntax Changed - data = json.loads(tmp_dwd.read().decode("utf-8", "ignore")) + data = json.loads(tmp_dwd.read().decode('utf-8', 'ignore')) is_db_format_good = False - if "trackers" in data: - if "1" in data["trackers"]: - if "code_signature" in data["trackers"]["1"]: + if 'trackers' in data: + if '1' in data['trackers']: + if 'code_signature' in data['trackers']['1']: is_db_format_good = True if is_db_format_good: # DB Format is not changed. Let's update DB - logger.info("Updating Tracker Database....") + logger.info('Updating Tracker Database....') shutil.copyfile(tmp_dwd.name, self.tracker_db) else: - logger.info("Tracker Database format from reports.exodus-privacy.eu.org has changed. Database is not updated. " - "Please report to: https://github.com/MobSF/Mobile-Security-Framework-MobSF/issues") + logger.info('Tracker Database format from ' + 'reports.exodus-privacy.eu.org has changed.' + ' Database is not updated. ' + 'Please report to: https://github.com/MobSF/' + 'Mobile-Security-Framework-MobSF/issues') else: - logger.info("Tracker Database is up-to-date.") + logger.info('Tracker Database is up-to-date.') tmp_dwd.close() - except: - PrintException("[ERROR] Tracker DB Update") - + except Exception: + log_exception('[ERROR] Tracker DB Update') def _compile_signatures(self): """ + Compile Signatures. + Compiles the regex associated to each signature, in order to speed up the trackers detection. :return: A compiled list of signatures. @@ -85,36 +86,46 @@ class Trackers: self.compiled_tracker_signature = [re.compile(track.code_signature) for track in self.signatures] except TypeError: - logger.error("compiling tracker signature failed") + logger.error('compiling tracker signature failed') def load_trackers_signatures(self): """ Load trackers signatures from the official Exodus database. + :return: a dictionary of signatures. """ self.signatures = [] - with io.open(self.tracker_db, mode='r', encoding="utf8", errors="ignore") as flip: + with io.open(self.tracker_db, + mode='r', + encoding='utf8', + errors='ignore') as flip: data = json.loads(flip.read()) for elm in data['trackers']: - self.signatures.append(namedtuple('tracker', data['trackers'][elm].keys())( - *data['trackers'][elm].values())) + self.signatures.append( + namedtuple('tracker', + data['trackers'][elm].keys())( + *data['trackers'][elm].values())) self._compile_signatures() self.nb_trackers_signature = len(self.signatures) def get_embedded_classes(self): """ Get the list of Java classes from all DEX files. + :return: list of Java classes """ if self.classes is not None: return self.classes for dex_file in glob.iglob(os.path.join(self.apk_dir, '*.dex')): - if len(settings.BACKSMALI_BINARY) > 0 and isFileExists(settings.BACKSMALI_BINARY): + if (len(settings.BACKSMALI_BINARY) > 0 + and is_file_exists(settings.BACKSMALI_BINARY)): bs_path = settings.BACKSMALI_BINARY else: bs_path = os.path.join(self.tools_dir, 'baksmali-2.2.7.jar') - args = [settings.JAVA_PATH + 'java', '-jar', bs_path, 'list', 'classes', dex_file] - classes = subprocess.check_output(args, universal_newlines=True).splitlines() + args = [settings.JAVA_PATH + 'java', '-jar', + bs_path, 'list', 'classes', dex_file] + classes = subprocess.check_output( + args, universal_newlines=True).splitlines() if self.classes is not None: self.classes = self.classes + classes else: @@ -124,6 +135,7 @@ class Trackers: def detect_trackers_in_list(self, class_list): """ Detect embedded trackers in the provided classes list. + :return: list of embedded trackers """ if self.signatures is None: @@ -151,6 +163,7 @@ class Trackers: def detect_trackers(self): """ Detect embedded trackers. + :return: list of embedded trackers """ if self.signatures is None: @@ -158,15 +171,12 @@ class Trackers: return self.detect_trackers_in_list(self.get_embedded_classes()) def get_trackers(self): - """ - Get Trackers - """ + """Get Trackers.""" logger.info('Detecting Trackers') trackers = self.detect_trackers() - tracker_dict = {"detected_trackers": len(trackers), - "total_trackers": self.nb_trackers_signature, - "trackers": []} + tracker_dict = {'detected_trackers': len(trackers), + 'total_trackers': self.nb_trackers_signature, + 'trackers': []} for trk in trackers: - tracker_dict["trackers"].append({trk.name: trk.website}) + tracker_dict['trackers'].append({trk.name: trk.website}) return tracker_dict - diff --git a/MalwareAnalyzer/views/VirusTotal.py b/MalwareAnalyzer/views/VirusTotal.py index c88510c9..522d9c2b 100755 --- a/MalwareAnalyzer/views/VirusTotal.py +++ b/MalwareAnalyzer/views/VirusTotal.py @@ -1,7 +1,11 @@ -import requests import logging -from MobSF.utils import PrintException, upstream_proxy + +import requests + from django.conf import settings + +from MobSF.utils import log_exception, upstream_proxy + logger = logging.getLogger(__name__) @@ -11,6 +15,8 @@ class VirusTotal: def get_report(self, file_hash): """ + Get Report from VT. + :param file_hash: md5/sha1/sha256 :return: json response / None """ @@ -18,90 +24,107 @@ class VirusTotal: url = self.base_url + 'report' params = { 'apikey': settings.VT_API_KEY, - 'resource': file_hash - } - headers = {"Accept-Encoding": "gzip, deflate"} + 'resource': file_hash} + headers = {'Accept-Encoding': 'gzip, deflate'} try: proxies, verify = upstream_proxy('https') - except: - PrintException("Setting upstream proxy") + except Exception: + log_exception('Setting upstream proxy') try: response = requests.get( - url, params=params, headers=headers, proxies=proxies, verify=verify) + url, + params=params, + headers=headers, + proxies=proxies, + verify=verify) if response.status_code == 403: - logger.error("VirusTotal Permission denied, wrong api key?") + logger.error( + 'VirusTotal Permission denied, wrong api key?') return None - except: - logger.error("VirusTotal ConnectionError, check internet connectivity") + except Exception: + logger.error( + 'VirusTotal ConnectionError, check internet connectivity') return None try: json_response = response.json() return json_response except ValueError: return None - except: - PrintException("VirusTotal get_report") + except Exception: + log_exception('VirusTotal get_report') return None def upload_file(self, file_path): """ + Upload File to VT. + :param file_path: file path to upload :return: json response / None """ try: - url = self.base_url + "scan" - files = { - 'file': open(file_path, 'rb') - } - headers = { - "apikey": settings.VT_API_KEY - } + url = self.base_url + 'scan' + files = {'file': open(file_path, 'rb')} + headers = {'apikey': settings.VT_API_KEY} try: proxies, verify = upstream_proxy('https') - except: - PrintException("Setting upstream proxy") + except Exception: + log_exception('Setting upstream proxy') try: response = requests.post( - url, files=files, data=headers, proxies=proxies, verify=verify) + url, + files=files, + data=headers, + proxies=proxies, + verify=verify) if response.status_code == 403: - logger.error("VirusTotal Permission denied, wrong api key?") + logger.error( + 'VirusTotal Permission denied, wrong api key?') return None - except: - logger.error("VirusTotal Connection Error, check internet connectivity") + except Exception: + logger.error( + 'VirusTotal Connection Error, check internet connectivity') return None json_response = response.json() return json_response - except: - PrintException("VirusTotal upload_file") + except Exception: + log_exception('VirusTotal upload_file') return None def get_result(self, file_path, file_hash): """ - Uoloading a file and getting the approval msg from VT or fetching existing report + Get Results from VT. + + Uploading a file and getting the approval msg from VT + or fetching existing report :param file_path: file's path :param file_hash: file's hash - md5/sha1/sha256 :return: VirusTotal result json / None upon error """ try: - logger.info("VirusTotal: Check for existing report") + logger.info('VirusTotal: Check for existing report') report = self.get_report(file_hash) # Check for existing report if report: if report['response_code'] == 1: - logger.info("VirusTotal: " + report['verbose_msg']) + logger.info('VirusTotal: %s', report['verbose_msg']) return report if settings.VT_UPLOAD: - logger.info("VirusTotal: file upload") + logger.info('VirusTotal: file upload') upload_response = self.upload_file(file_path) if upload_response: - logger.info("VirusTotal: {}".format(upload_response['verbose_msg'])) + logger.info('VirusTotal: %s', + upload_response['verbose_msg']) return upload_response else: - logger.info("MobSF: VirusTotal Scan not performed as file upload is disabled in settings.py. " - "To enable file upload, set VT_UPLOAD to True.") + logger.info('MobSF: VirusTotal Scan not performed as file' + ' upload is disabled in settings.py. ' + 'To enable file upload, set VT_UPLOAD to True.') report = { - "verbose_msg": "Scan Not performed, VirusTotal file upload disabled in settings.py", "positives": 0, "total": 0} + 'verbose_msg': ('Scan Not performed, VirusTotal file' + ' upload disabled in settings.py'), + 'positives': 0, + 'total': 0} return report - except: - PrintException("VirusTotal get_result") + except Exception: + log_exception('VirusTotal get_result') diff --git a/MalwareAnalyzer/views/apkid.py b/MalwareAnalyzer/views/apkid.py index 5d947f30..d6fc7567 100644 --- a/MalwareAnalyzer/views/apkid.py +++ b/MalwareAnalyzer/views/apkid.py @@ -1,22 +1,23 @@ # -*- coding: utf_8 -*- -import os import logging +import os + from django.conf import settings logger = logging.getLogger(__name__) def apkid_analysis(app_dir, apk_file, apk_name): - """APKiD Analysis of DEX files""" + """APKID Analysis of DEX files.""" if not settings.APKID_ENABLED: return {} try: import apkid except ImportError: - logger.error("APKiD - Could not import APKiD") + logger.error('APKiD - Could not import APKiD') return {} if not os.path.exists(apk_file): - logger.error("APKiD - APK not found") + logger.error('APKiD - APK not found') return {} apkid_ver = apkid.__version__ @@ -24,17 +25,17 @@ def apkid_analysis(app_dir, apk_file, apk_name): from apkid.output import OutputFormatter from apkid.rules import RulesManager - logger.info("Running APKiD %s", apkid_ver) + logger.info('Running APKiD %s', apkid_ver) options = Options( timeout=30, verbose=False, entry_max_scan_size=100 * 1024 * 1024, - recursive=True + recursive=True, ) output = OutputFormatter( json_output=True, output_dir=None, - rules_manager=RulesManager() + rules_manager=RulesManager(), ) rules = options.rules_manager.load() scanner = Scanner(rules, options) diff --git a/MalwareAnalyzer/views/domain_check.py b/MalwareAnalyzer/views/domain_check.py index bac19400..b0151e7a 100644 --- a/MalwareAnalyzer/views/domain_check.py +++ b/MalwareAnalyzer/views/domain_check.py @@ -1,34 +1,33 @@ # -*- coding: utf_8 -*- # Module for Malware Analysis -from urllib.parse import urlparse -import logging -import shutil import io +import logging import os import re +import shutil import tempfile +from urllib.parse import urlparse + import requests + from django.conf import settings -from MobSF.utils import ( - PrintException, - isInternetAvailable, - upstream_proxy, - sha256 -) +from MobSF.utils import (is_internet_available, log_exception, sha256, + upstream_proxy) logger = logging.getLogger(__name__) + # PATH MALWARE_DB_DIR = TOOLS_DIR = os.path.join( settings.BASE_DIR, 'MalwareAnalyzer/malwaredb/') def update_malware_db(): - """Check for update in malware DB""" + """Check for update in malware DB.""" try: proxies, verify = upstream_proxy('http') - except: - PrintException("[ERROR] Setting upstream proxy") + except Exception: + log_exception('[ERROR] Setting upstream proxy') try: url = settings.MALWARE_DB_URL response = requests.get(url, timeout=3, proxies=proxies, verify=verify) @@ -41,81 +40,89 @@ def update_malware_db(): if sha256(tmp_dwd.name) != sha256(mal_db): # DB needs update # Check2: DB Syntax Changed - line = tmp_dwd.readline().decode("utf-8", "ignore") + line = tmp_dwd.readline().decode('utf-8', 'ignore') lst = line.split('",') if len(lst) == 10: # DB Format is not changed. Let's update DB - logger.info("Updating Malware Database....") + logger.info('Updating Malware Database....') shutil.copyfile(tmp_dwd.name, mal_db) else: - logger.info("Malware Database format from malwaredomainlist.com has changed. Database is not updated. " - "Please report to: https://github.com/MobSF/Mobile-Security-Framework-MobSF/issues") + logger.info('Malware Database format from ' + 'malwaredomainlist.com has changed.' + ' Database is not updated. ' + 'Please report to: https://github.com/' + 'MobSF/Mobile-Security-Framework-MobSF/issues') else: - logger.info("Malware Database is up-to-date.") + logger.info('Malware Database is up-to-date.') tmp_dwd.close() - except: - PrintException("[ERROR] Malware DB Update") + except Exception: + log_exception('[ERROR] Malware DB Update') def malware_check(urllist): result = {} try: - if settings.DOMAIN_MALWARE_SCAN == False: - logger.info("Domain Malware Check disabled in settings") + if not settings.DOMAIN_MALWARE_SCAN: + logger.info('Domain Malware Check disabled in settings') return result domainlist = get_domains(urllist) - if domainlist: - if isInternetAvailable(): - update_malware_db() - else: - logger.warning( - "No Internet Connection. Skipping Malware Database Update.") - mal_db = os.path.join(MALWARE_DB_DIR, 'malwaredomainlist') - with io.open(mal_db, mode='r', encoding="utf8", errors="ignore") as flip: - entry_list = flip.readlines() - for entry in entry_list: - enlist = entry.split('","') - if len(enlist) > 5: - details_dict = dict() - details_dict["domain_or_url"] = enlist[1] - details_dict["ip"] = enlist[2] - details_dict["desc"] = enlist[4] - details_dict["bad"] = "yes" - for domain in domainlist: - if (domain in details_dict["domain_or_url"] or - (details_dict["domain_or_url"] in domain and - (len(details_dict["domain_or_url"]) > 1)) or - details_dict["ip"].startswith(domain)): - result[domain] = details_dict - # Good Domains - for domain in domainlist: - if domain not in result: - tmp_d = dict() - tmp_d["bad"] = "no" - result[domain] = tmp_d - except: - PrintException("[ERROR] Performing Malware Check") + if not domainlist: + return result + if is_internet_available(): + update_malware_db() + else: + logger.warning( + 'No Internet Connection. Skipping Malware Database Update.') + mal_db = os.path.join(MALWARE_DB_DIR, 'malwaredomainlist') + with io.open(mal_db, + mode='r', + encoding='utf8', + errors='ignore') as flip: + entry_list = flip.readlines() + for entry in entry_list: + enlist = entry.split('', '') + if len(enlist) > 5: + details_dict = {} + details_dict['domain_or_url'] = enlist[1] + details_dict['ip'] = enlist[2] + details_dict['desc'] = enlist[4] + details_dict['bad'] = 'yes' + for domain in domainlist: + if (domain in details_dict['domain_or_url'] + or (details_dict['domain_or_url'] in domain + and (len(details_dict['domain_or_url']) > 1)) + or details_dict['ip'].startswith(domain)): + result[domain] = details_dict + # Good Domains + for domain in domainlist: + if domain not in result: + tmp_d = {} + tmp_d['bad'] = 'no' + result[domain] = tmp_d + except Exception: + log_exception('[ERROR] Performing Malware Check') return result # Helper Functions def get_domains(urls): - """Get Domains""" + """Get Domains.""" try: domains = [] for url in urls: parsed_uri = urlparse(url) if not urlparse(url).scheme: - url = "//"+url + url = '//' + url parsed_uri = urlparse(url) domain = '{uri.netloc}'.format(uri=parsed_uri) - if ((domain not in domains) and - (len(domain) > 2) and - ("." in domain) and - (domain.endswith(".") is False and re.search('[a-zA-Z0-9]', domain))): + if (domain not in domains + and len(domain) > 2 + and '.' in domain + and (domain.endswith('.') is False + and re.search('[a-zA-Z0-9]', domain))): domains.append(domain) return domains - except: - PrintException("[ERROR] Extracting Domain form URL") + except Exception: + log_exception('[ERROR] Extracting Domain form URL') diff --git a/MobSF/forms.py b/MobSF/forms.py index 1b2304dd..cb57c989 100755 --- a/MobSF/forms.py +++ b/MobSF/forms.py @@ -12,7 +12,8 @@ class FormUtil(object): @staticmethod def errors_message(form): - """ + """Form Errors. + :param form forms.Form form.errors.get_json_data() django 2.0 or higher @@ -20,7 +21,7 @@ class FormUtil(object): example { "error": { - "file": "This field is required.", + "file": "This field is required.", "test": "This field is required." } } diff --git a/MobSF/models.py b/MobSF/models.py index 0f022274..e69de29b 100755 --- a/MobSF/models.py +++ b/MobSF/models.py @@ -1 +0,0 @@ -from django.db import models \ No newline at end of file diff --git a/MobSF/settings.py b/MobSF/settings.py index fc60bb62..241a7b76 100755 --- a/MobSF/settings.py +++ b/MobSF/settings.py @@ -1,3 +1,4 @@ +# noqa: E800 """ Django settings for MobSF project. @@ -5,43 +6,39 @@ MobSF and Django settings """ import imp -import os import logging -from MobSF.utils import ( - first_run, - FindJava, - FindVbox, - getMobSFHome, - PrintException, -) +import os + +from MobSF.utils import (find_java_binary, find_vboxmange_binary, first_run, + get_mobsf_home, log_exception) logger = logging.getLogger(__name__) -#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # MOBSF CONFIGURATIONS -#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -MOBSF_VER = "v1.1.2 Beta" +MOBSF_VER = 'v1.1.3 Beta' BANNER = """ - __ __ _ ____ _____ _ _ + __ __ _ ____ _____ _ _ | \/ | ___ | |__/ ___|| ___| __ __ / | / | | |\/| |/ _ \| '_ \___ \| |_ \ \ / / | | | | | | | | (_) | |_) |__) | _| \ V / | |_| | |_| |_|\___/|_.__/____/|_| \_/ |_(_)_| -""" +""" # noqa: W291 # ASCII Standard -#============================================== +# ============================================== BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -#==========MobSF Home Directory================= +# ==========MobSF Home Directory================= USE_HOME = False # True : All Uploads/Downloads will be stored in user's home directory # False : All Uploads/Downloads will be stored in MobSF root directory # If you need multiple users to share the scan results set this to False -#=============================================== +# =============================================== -MobSF_HOME = getMobSFHome(USE_HOME) +MobSF_HOME = get_mobsf_home(USE_HOME) # Logs Directory LOG_DIR = os.path.join(MobSF_HOME, 'logs/') # Download Directory @@ -55,7 +52,7 @@ DB_DIR = os.path.join(MobSF_HOME, 'db.sqlite3') # Tools Directory TOOLS_DIR = os.path.join(BASE_DIR, 'DynamicAnalyzer/tools/') # Secret File -SECRET_FILE = os.path.join(MobSF_HOME, "secret") +SECRET_FILE = os.path.join(MobSF_HOME, 'secret') # Database # https://docs.djangoproject.com/en/dev/ref/settings/#databases @@ -65,12 +62,12 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': DB_DIR, - } + }, } # End Sqlite3 support # Postgres DB - Install psycopg2 -''' +""" DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', @@ -82,40 +79,41 @@ DATABASES = { } } # End Postgres support -''' -#=============================================== +""" +# =============================================== -#==========LOAD CONFIG FROM MobSF HOME========== +# ==========LOAD CONFIG FROM MobSF HOME========== try: # Update Config from MobSF Home Directory if USE_HOME: USER_CONFIG = os.path.join(MobSF_HOME, 'config.py') sett = imp.load_source('user_settings', USER_CONFIG) locals().update( - {k: v for k, v in list(sett.__dict__.items()) if not k.startswith("__")}) + {k: v for k, v in list(sett.__dict__.items()) + if not k.startswith('__')}) CONFIG_HOME = True else: CONFIG_HOME = False -except: - PrintException("Reading Config") +except Exception: + log_exception('Reading Config') CONFIG_HOME = False -#=============================================== +# =============================================== -#===MOBSF SECRET GENERATION AND DB MIGRATION==== +# ===MOBSF SECRET GENERATION AND DB MIGRATION==== SECRET_KEY = first_run(SECRET_FILE, BASE_DIR, MobSF_HOME) -#============================================= +# ============================================= -#=============ALLOWED EXTENSIONS================ +# =============ALLOWED EXTENSIONS================ ALLOWED_EXTENSIONS = { - ".txt": "text/plain", - ".png": "image/png", - ".zip": "application/zip", - ".tar": "application/x-tar" + '.txt': 'text/plain', + '.png': 'image/png', + '.zip': 'application/zip', + '.tar': 'application/x-tar', } -#=============================================== +# =============================================== -#=============ALLOWED MIMETYPES================= +# =============ALLOWED MIMETYPES================= APK_MIME = [ 'application/octet-stream', @@ -139,19 +137,18 @@ ZIP_MIME = [ APPX_MIME = [ 'application/octet-stream', 'application/vns.ms-appx', - 'application/x-zip-compressed' + 'application/x-zip-compressed', ] -#=============================================== - -#============DJANGO SETTINGS ================= +# =============================================== +# ============DJANGO SETTINGS ================= DEBUG = True DJANGO_LOG_LEVEL = DEBUG ALLOWED_HOSTS = ['127.0.0.1', 'mobsf', '*'] # Application definition INSTALLED_APPS = ( - #'django.contrib.admin', + # 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', @@ -190,44 +187,46 @@ TEMPLATES = [ 'APP_DIRS': True, 'DIRS': [ - os.path.join(BASE_DIR, 'templates') + os.path.join(BASE_DIR, 'templates'), ], 'OPTIONS': { 'debug': True, - } + }, }, ] MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads') MEDIA_URL = '/uploads/' -STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")] +STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')] STATIC_URL = '/static/' STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' # 256MB DATA_UPLOAD_MAX_MEMORY_SIZE = 268435456 -#=================== +# =================== # USER CONFIGURATION -#=================== +# =================== if CONFIG_HOME: - logger.info("Loading User config from: {}".format(USER_CONFIG)) + logger.info('Loading User config from: %s', USER_CONFIG) else: - ''' + """ IMPORTANT - If 'USE_HOME' is set to True, then below user configuration settings are not considered. - The user configuration will be loaded from config.py in MobSF Home directory. - ''' - #^CONFIG-START^: Do not edit this line - #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + If 'USE_HOME' is set to True, + then below user configuration settings are not considered. + The user configuration will be loaded from + config.py in MobSF Home directory. + """ + # ^CONFIG-START^: Do not edit this line + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # MOBSF USER CONFIGURATIONS - #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - #------------------------- + # ------------------------- # STATIC ANALYZER SETTINGS - #------------------------- + # ------------------------- - #==========ANDROID SKIP CLASSES========================== + # ==========ANDROID SKIP CLASSES========================== # Common third party classes that will be skipped during static analysis SKIP_CLASSES = [ r'com[\\\/]{1}google[\\\/]{1}', @@ -244,117 +243,106 @@ else: r'org[\\\/]{1}apache[\\\/]{1}', r'oauth[\\\/]{1}signpost[\\\/]{1}', r'org[\\\/]{1}chromium[\\\/]{1}', - r'com[\\\/]{1}facebook[\\\/]{1}' + r'com[\\\/]{1}facebook[\\\/]{1}', ] - #==========DECOMPILER SETTINGS================= + # ==========DECOMPILER SETTINGS================= - DECOMPILER = "cfr" + DECOMPILER = 'cfr' # Three Decompilers are available # 1. jd-core # 2. cfr # 3. procyon - #============================================== + # ============================================== - #==========Dex to Jar Converter================ - JAR_CONVERTER = "d2j" + # ==========Dex to Jar Converter================ + JAR_CONVERTER = 'd2j' # Two Dex to Jar converters are available # 1. d2j # 2. enjarify - #============================================== + # ============================================== - #======WINDOWS STATIC ANALYSIS SETTINGS =========== + # ======WINDOWS STATIC ANALYSIS SETTINGS =========== # Private key WINDOWS_VM_SECRET = 'MobSF/windows_vm_priv_key.asc' # IP and Port of the MobSF Windows VM - # eg: WINDOWS_VM_IP = '127.0.0.1' + # example: WINDOWS_VM_IP = '127.0.0.1' WINDOWS_VM_IP = None WINDOWS_VM_PORT = '8000' - #================================================== + # ================================================== - #==============3rd Party Tools================= - ''' + # ==============3rd Party Tools================= + """ If you want to use a different version of 3rd party tools used by MobSF. You can do that by specifying the path here. If specified, MobSF will run the tool from this location. - ''' + """ # Android 3P Tools - DEX2JAR_BINARY = "" - BACKSMALI_BINARY = "" - CFR_DECOMPILER_BINARY = "" - JD_CORE_DECOMPILER_BINARY = "" - PROCYON_DECOMPILER_BINARY = "" - APKTOOL_BINARY = "" - ADB_BINARY = "" - ENJARIFY_DIRECTORY = "" + DEX2JAR_BINARY = '' + BACKSMALI_BINARY = '' + CFR_DECOMPILER_BINARY = '' + JD_CORE_DECOMPILER_BINARY = '' + PROCYON_DECOMPILER_BINARY = '' + APKTOOL_BINARY = '' + ADB_BINARY = '' + ENJARIFY_DIRECTORY = '' # iOS 3P Tools - OTOOL_BINARY = "" - JTOOL_BINARY = "" - CLASSDUMPZ_BINARY = "" - CLASSDUMP_SWIFT_BINARY = "" + OTOOL_BINARY = '' + JTOOL_BINARY = '' + CLASSDUMPZ_BINARY = '' + CLASSDUMP_SWIFT_BINARY = '' # COMMON - JAVA_DIRECTORY = "" - VBOXMANAGE_BINARY = "" - PYTHON3_PATH = "" + JAVA_DIRECTORY = '' + VBOXMANAGE_BINARY = '' + PYTHON3_PATH = '' - ''' + """ Examples: - JAVA_DIRECTORY = "C:/Program Files/Java/jdk1.7.0_17/bin/" - JAVA_DIRECTORY = "/usr/bin/" - DEX2JAR_BINARY = "/Users/ajin/dex2jar/d2j-dex2jar.sh" - ENJARIFY_DIRECTORY = "D:/enjarify/" - VBOXMANAGE_BINARY = "/usr/bin/VBoxManage" - CFR_DECOMPILER_BINARY = "/home/ajin/tools/cfr.jar" - PYTHON3_PATH = "C:/Users/Ajin/AppData/Local/Programs/Python/Python35-32/" - ''' - #=============================================== + JAVA_DIRECTORY = 'C:/Program Files/Java/jdk1.7.0_17/bin/' + JAVA_DIRECTORY = '/usr/bin/' + DEX2JAR_BINARY = '/Users/ajin/dex2jar/d2j-dex2jar.sh' + ENJARIFY_DIRECTORY = 'D:/enjarify/' + VBOXMANAGE_BINARY = '/usr/bin/VBoxManage' + CFR_DECOMPILER_BINARY = '/home/ajin/tools/cfr.jar' + PYTHON3_PATH = 'C:/Users/Ajin/AppData/Local/Programs/Python/Python35-32/' + """ + # =============================================== - #------------------------- + # ------------------------- # DYNAMIC ANALYZER SETTINGS - #------------------------- + # ------------------------- - #========ANDROID DYNAMIC ANALYSIS SETTINGS================================ + # ========ANDROID DYNAMIC ANALYSIS SETTINGS================================ - ANDROID_DYNAMIC_ANALYZER = "MobSF_VM" + ANDROID_DYNAMIC_ANALYZER = 'MobSF_VM' # You can choose any of the below # 1. MobSF_VM - # 2. MobSF_AVD - # 3. MobSF_REAL_DEVICE + # 2. MobSF_REAL_DEVICE - ''' - MobSF_VM - x86 Android 4.4.2 running on VirtualBox (Fast, not all Apps work) - MobSF_AVD - ARM Android 6 running on Android Emulator (Slow, Most Apps work) - MobSF_REAL_DEVICE - Rooted Android 4.03 - 4.4 Device (Very Fast, All Apps work) + """ + MobSF_VM x86 Android 4.4.2 running on VirtualBox(Fast, not all Apps work) + MobSF_REAL_DEVICE - Rooted Android 4.03 4.4 Device + (Very Fast, All Apps work) Supports Android 5+ for real device. Not tested! - ''' + """ - #========================================================================= + # ========================================================================= - #=======ANDROID REAL DEVICE SETTINGS=========== + # =======ANDROID REAL DEVICE SETTINGS=========== DEVICE_IP = '192.168.1.18' DEVICE_ADB_PORT = 5555 DEVICE_TIMEOUT = 300 - #============================================== + # ============================================== - #===========ANDROID EMULATOR SETTINGS =========== - # Android-Studio 'emulator' binary path - # Not Supported any more - AVD_EMULATOR = "/Users/[USERNAME]/Library/Android/sdk/tools/emulator" - AVD_NAME = "MobSFAPI23armV1" - AVD_ADB_PORT = 5554 - AVD_SNAPSHOT = "" - AVD_COLD_BOOT = True - #================================================ - - #====ANDROID MOBSF VIRTUALBOX VM SETTINGS ===== + # ====ANDROID MOBSF VIRTUALBOX VM SETTINGS ===== # VM UUID UUID = '408e1874-759f-4417-9453-53ef21dc2ade' # Snapshot UUID @@ -364,70 +352,71 @@ else: VM_ADB_PORT = 5555 VM_TIMEOUT = 100 VBOX_HEADLESS = False - #============================================== + # ============================================== - #-------------------------- + # -------------------------- # MobSF MITM PROXY SETTINGS - #-------------------------- + # -------------------------- - #================HOST/PROXY SETTINGS =============== + # ================HOST/PROXY SETTINGS =============== PROXY_IP = '192.168.56.1' # Host/Server/Proxy IP PORT = 1337 # Proxy Port ROOT_CA = '0026aabb.0' SCREEN_IP = PROXY_IP # ScreenCast IP SCREEN_PORT = 9339 # ScreenCast Port(Do not Change) - #=================================================== + # =================================================== - #========UPSTREAM PROXY SETTINGS ============== + # ========UPSTREAM PROXY SETTINGS ============== # If you are behind a Proxy UPSTREAM_PROXY_ENABLED = False UPSTREAM_PROXY_SSL_VERIFY = True - UPSTREAM_PROXY_TYPE = "http" - UPSTREAM_PROXY_IP = "127.0.0.1" + UPSTREAM_PROXY_TYPE = 'http' + UPSTREAM_PROXY_IP = '127.0.0.1' UPSTREAM_PROXY_PORT = 3128 - UPSTREAM_PROXY_USERNAME = "" - UPSTREAM_PROXY_PASSWORD = "" - #============================================== + UPSTREAM_PROXY_USERNAME = '' + UPSTREAM_PROXY_PASSWORD = '' + # ============================================== - #-------------------------- + # -------------------------- # MALWARE ANALYZER SETTINGS - #-------------------------- + # -------------------------- DOMAIN_MALWARE_SCAN = True - #----------APKiD------------------------------- + # ----------APKiD------------------------------- APKID_ENABLED = True - #============================================== + # ============================================== - #========DISABLED COMPONENTS=================== + # ========DISABLED COMPONENTS=================== - #----------VirusTotal-------------------------- + # ----------VirusTotal-------------------------- VT_ENABLED = False VT_API_KEY = 'XXXXXXXXXXXXXX' VT_UPLOAD = False # Before setting VT_ENABLED to True, # Make sure VT_API_KEY is set to your VirusTotal API key # register at: https://www.virustotal.com/#/join-us - # You can get your API KEY from https://www.virustotal.com/en/user//apikey/ - # BE AWARE - if you enable VT, in case the file wasn't already uploaded to VirusTotal, - # It will be uploaded if you set VT_UPLOAD to True! - #============================================== + # You can get your API KEY from: + # https://www.virustotal.com/en/user//apikey/ + # Files will be uploaded to VirusTotal + # if VT_UPLOAD is set to True. + # ============================================== - #-----External URLS-------------------------- + # -----External URLS-------------------------- MALWARE_DB_URL = 'http://www.malwaredomainlist.com/mdlcsv.php' VIRUS_TOTAL_BASE_URL = 'https://www.virustotal.com/vtapi/v2/file/' TRACKERS_DB_URL = 'https://reports.exodus-privacy.eu.org/api/trackers' - #^CONFIG-END^: Do not edit this line + # ^CONFIG-END^: Do not edit this line # The below code should be loaded last. -#============JAVA SETTINGS====================== -JAVA_PATH = FindJava(False) -#=============================================== +# ============JAVA SETTINGS====================== +JAVA_PATH = find_java_binary(False) +# =============================================== -#================VirtualBox Settings============ -VBOX = FindVbox(False) -#=============================================== +# ================VirtualBox Settings============ +VBOX = find_vboxmange_binary(False) +# =============================================== # Better logging LOGGING = { @@ -435,18 +424,19 @@ LOGGING = { 'disable_existing_loggers': True, 'formatters': { 'standard': { - 'format': "[%(levelname)s] %(asctime)-15s - %(message)s", - 'datefmt': "%d/%b/%Y %H:%M:%S" + 'format': '[%(levelname)s] %(asctime)-15s - %(message)s', + 'datefmt': '%d/%b/%Y %H:%M:%S', }, 'color': { '()': 'colorlog.ColoredFormatter', - 'format': '%(log_color)s[%(levelname)s] %(asctime)-15s - %(message)s', - 'datefmt': "%d/%b/%Y %H:%M:%S", + 'format': + '%(log_color)s[%(levelname)s] %(asctime)-15s - %(message)s', + 'datefmt': '%d/%b/%Y %H:%M:%S', 'log_colors': { - 'DEBUG': 'cyan', - 'INFO': 'green', - 'WARNING': 'yellow', - 'ERROR': 'red', + 'DEBUG': 'cyan', + 'INFO': 'green', + 'WARNING': 'yellow', + 'ERROR': 'red', 'CRITICAL': 'red,bg_white', }, }, @@ -496,5 +486,5 @@ LOGGING = { 'level': 'DEBUG', 'propagate': False, }, - } + }, } diff --git a/MobSF/urls.py b/MobSF/urls.py index 162b6351..062762bf 100755 --- a/MobSF/urls.py +++ b/MobSF/urls.py @@ -1,44 +1,30 @@ from django.conf.urls import url -from DynamicAnalyzer.views.android import ( - dynamic -) +from DynamicAnalyzer.views.android import dynamic + from MobSF import utils -from MobSF.views import ( - home, -) -from MobSF.views.api import ( - rest_api -) +from MobSF.views import home +from MobSF.views.api import rest_api + from StaticAnalyzer import tests -from StaticAnalyzer.views import ( - shared_func, - windows -) -from StaticAnalyzer.views.android import ( - static_analyzer as android_sa, - view_source, - smali, - java, - find, - manifest_view -) -from StaticAnalyzer.views.ios import ( - static_analyzer as ios_sa, - view_source as io_view_source -) +from StaticAnalyzer.views import shared_func, windows +from StaticAnalyzer.views.android import find, java, manifest_view, smali +from StaticAnalyzer.views.android import static_analyzer as android_sa +from StaticAnalyzer.views.android import view_source +from StaticAnalyzer.views.ios import static_analyzer as ios_sa +from StaticAnalyzer.views.ios import view_source as io_view_source urlpatterns = [ # Examples: - url(r'^$', home.index, name="home"), + url(r'^$', home.index, name='home'), url(r'^upload/$', home.Upload.as_view), url(r'^download/', home.download), - url(r'^about$', home.about, name="about"), - url(r'^api_docs$', home.api_docs, name="api_docs"), - url(r'^recent_scans/$', home.recent_scans, name="recent"), + url(r'^about$', home.about, name='about'), + url(r'^api_docs$', home.api_docs, name='api_docs'), + url(r'^recent_scans/$', home.recent_scans, name='recent'), url(r'^delete_scan/$', home.delete_scan), url(r'^search$', home.search), - url(r'^error/$', home.error, name="error"), + url(r'^error/$', home.error, name='error'), url(r'^not_found/$', home.not_found), url(r'^zip_format/$', home.zip_format), url(r'^mac_only/$', home.mac_only), @@ -54,12 +40,13 @@ urlpatterns = [ # IOS url(r'^StaticAnalyzer_iOS/$', ios_sa.static_analyzer_ios), url(r'^ViewFile/$', io_view_source.run), - #Windows + # Windows url(r'^StaticAnalyzer_Windows/$', windows.staticanalyzer_windows), - #Shared + # Shared url(r'^PDF/$', shared_func.pdf), # We validate the hash sanity in the URL already - url(r'^compare/(?P[0-9a-f]{32})/(?P[0-9a-f]{32})/$', shared_func.compare_apps, ), + url(r'^compare/(?P[0-9a-f]{32})/(?P[0-9a-f]{32})/$', + shared_func.compare_apps), # Android Dynamic Analysis url(r'^DynamicAnalyzer/$', dynamic.android_dynamic_analyzer), @@ -93,4 +80,4 @@ urlpatterns = [ ] -utils.printMobSFverison() +utils.print_version() diff --git a/MobSF/utils.py b/MobSF/utils.py index 0df29770..e216e602 100755 --- a/MobSF/utils.py +++ b/MobSF/utils.py @@ -1,27 +1,27 @@ -""" -Common Utils -""" -import os -import re -import io +"""Common Utils.""" import ast -import sys -import signal +import hashlib +import io +import logging +import ntpath +import os import platform import random -import subprocess -import linecache -import ntpath -import hashlib -import unicodedata +import re import shutil +import signal +import subprocess +import sys +import unicodedata + import requests -import logging + +from django.shortcuts import render from install.windows.setup import windows_config_local -from django.shortcuts import render from . import settings + logger = logging.getLogger(__name__) @@ -34,18 +34,23 @@ class Color(object): def upstream_proxy(flaw_type): - """Set upstream Proxy if needed""" + """Set upstream Proxy if needed.""" if settings.UPSTREAM_PROXY_ENABLED: if not settings.UPSTREAM_PROXY_USERNAME: proxy_port = str(settings.UPSTREAM_PROXY_PORT) - proxy_host = settings.UPSTREAM_PROXY_TYPE + '://' + \ - settings.UPSTREAM_PROXY_IP + ':' + proxy_port + proxy_host = '{}://{}:{}'.format( + settings.UPSTREAM_PROXY_TYPE, + settings.UPSTREAM_PROXY_IP, + proxy_port) proxies = {flaw_type: proxy_host} else: proxy_port = str(settings.UPSTREAM_PROXY_PORT) - proxy_host = settings.UPSTREAM_PROXY_TYPE + '://' + settings.UPSTREAM_PROXY_USERNAME + \ - ':' + settings.UPSTREAM_PROXY_PASSWORD + "@" + \ - settings.UPSTREAM_PROXY_IP + ':' + proxy_port + proxy_host = '{}://{}:{}@{}:{}'.format( + settings.UPSTREAM_PROXY_TYPE, + settings.UPSTREAM_PROXY_USERNAME, + settings.UPSTREAM_PROXY_PASSWORD, + settings.UPSTREAM_PROXY_IP, + proxy_port) proxies = {flaw_type: proxy_host} else: proxies = {flaw_type: None} @@ -54,37 +59,36 @@ def upstream_proxy(flaw_type): def api_key(): - """Print REST API Key""" - + """Print REST API Key.""" if os.environ.get('MOBSF_API_KEY'): - logger.info("\nAPI Key read from environment variable") + logger.info('\nAPI Key read from environment variable') return os.environ['MOBSF_API_KEY'] - secret_file = os.path.join(settings.MobSF_HOME, "secret") - if isFileExists(secret_file): + secret_file = os.path.join(settings.MobSF_HOME, 'secret') + if is_file_exists(secret_file): try: _api_key = open(secret_file).read().strip() return gen_sha256_hash(_api_key) except Exception: - PrintException("Cannot Read API Key") + log_exception('Cannot Read API Key') -def printMobSFverison(): - """Print MobSF Version""" +def print_version(): + """Print MobSF Version.""" logger.info(settings.BANNER) - if platform.system() == "Windows": - logger.info('Mobile Security Framework ' + settings.MOBSF_VER) - print("REST API Key: " + api_key()) + ver = settings.MOBSF_VER + if platform.system() == 'Windows': + logger.info('Mobile Security Framework %s', ver) + print('REST API Key: ' + api_key()) else: - logger.info('\033[1m\033[34mMobile Security Framework ' + - settings.MOBSF_VER + '\033[0m') - print("REST API Key: " + Color.BOLD + api_key() + Color.END) - logger.info("OS: " + platform.system()) - logger.info("Platform: " + platform.platform()) + logger.info('\033[1m\033[34mMobile Security Framework %s\033[0m', ver) + print('REST API Key: ' + Color.BOLD + api_key() + Color.END) + logger.info('OS: %s', platform.system()) + logger.info('Platform: %s', platform.platform()) if platform.dist()[0]: - logger.info("Dist: " + str(platform.dist())) - FindJava(True) - FindVbox(True) + logger.info('Dist: %s', str(platform.dist())) + find_java_binary(True) + find_vboxmange_binary(True) check_basic_env() adb_binary_or32bit_support() check_update() @@ -92,163 +96,161 @@ def printMobSFverison(): def check_update(): try: - logger.info("Checking for Update.") - github_url = "https://raw.githubusercontent.com/MobSF/Mobile-Security-Framework-MobSF/master/MobSF/settings.py" + logger.info('Checking for Update.') + github_url = ('https://raw.githubusercontent.com/' + 'MobSF/Mobile-Security-Framework-MobSF/' + 'master/MobSF/settings.py') try: proxies, verify = upstream_proxy('https') except Exception: - PrintException("Setting upstream proxy") + log_exception('Setting upstream proxy') response = requests.get(github_url, timeout=5, proxies=proxies, verify=verify) - html = str(response.text).split("\n") + html = str(response.text).split('\n') for line in html: - if line.startswith("MOBSF_VER"): - line = line.replace("MOBSF_VER", "").replace('"', '') - line = line.replace("=", "").strip() + if line.startswith('MOBSF_VER'): + line = line.replace('MOBSF_VER', '').replace('"', '') + line = line.replace('=', '').strip() if line != settings.MOBSF_VER: - logger.warning("A new version of MobSF is available, Please update from master branch or check " - "for new releases.") + logger.warning('A new version of MobSF is available, ' + 'Please update from master branch or check ' + 'for new releases.') else: - logger.info("No updates available.") - except requests.exceptions.HTTPError as err: - logger.warning( - "\nCannot check for updates.. No Internet Connection Found.") + logger.info('No updates available.') + except requests.exceptions.HTTPError: + logger.warning('\nCannot check for updates..' + ' No Internet Connection Found.') return - except: - PrintException("Cannot Check for updates.") + except Exception: + log_exception('Cannot Check for updates.') -def createUserConfig(MobSF_HOME): +def create_user_conf(mobsf_home): try: - CONFIG_PATH = os.path.join(MobSF_HOME, 'config.py') - if isFileExists(CONFIG_PATH) == False: - SAMPLE_CONF = os.path.join(settings.BASE_DIR, "MobSF/settings.py") - with io.open(SAMPLE_CONF, mode='r', encoding="utf8", errors="ignore") as f: + config_path = os.path.join(mobsf_home, 'config.py') + if not is_file_exists(config_path): + sample_conf = os.path.join(settings.BASE_DIR, 'MobSF/settings.py') + with open(sample_conf, 'r') as f: dat = f.readlines() - CONFIG = list() + config = [] add = False for line in dat: - if "^CONFIG-START^" in line: + if '^CONFIG-START^' in line: add = True - if "^CONFIG-END^" in line: + if '^CONFIG-END^' in line: break if add: - CONFIG.append(line.lstrip()) - CONFIG.pop(0) - COMFIG_STR = ''.join(CONFIG) - with io.open(CONFIG_PATH, mode='w', encoding="utf8", errors="ignore") as f: - f.write(COMFIG_STR) - except: - PrintException("Cannot create config file") + config.append(line.lstrip()) + config.pop(0) + conf_str = ''.join(config) + with open(config_path, 'w') as f: + f.write(conf_str) + except Exception: + log_exception('Cannot create config file') -def getMobSFHome(useHOME): +def get_mobsf_home(use_home): try: - MobSF_HOME = "" - if useHOME: - MobSF_HOME = os.path.join(os.path.expanduser('~'), ".MobSF") + mobsf_home = '' + if use_home: + mobsf_home = os.path.join(os.path.expanduser('~'), '.MobSF') # MobSF Home Directory - if not os.path.exists(MobSF_HOME): - os.makedirs(MobSF_HOME) - createUserConfig(MobSF_HOME) + if not os.path.exists(mobsf_home): + os.makedirs(mobsf_home) + create_user_conf(mobsf_home) else: - MobSF_HOME = settings.BASE_DIR + mobsf_home = settings.BASE_DIR # Logs Directory - LOG_DIR = os.path.join(MobSF_HOME, 'logs/') - if not os.path.exists(LOG_DIR): - os.makedirs(LOG_DIR) + log_dir = os.path.join(mobsf_home, 'logs/') + if not os.path.exists(log_dir): + os.makedirs(log_dir) # Certs Directory - CERT_DIR = os.path.join(LOG_DIR, 'certs/') - if not os.path.exists(CERT_DIR): - os.makedirs(CERT_DIR) + cert_dir = os.path.join(log_dir, 'certs/') + if not os.path.exists(cert_dir): + os.makedirs(cert_dir) # Download Directory - DWD_DIR = os.path.join(MobSF_HOME, 'downloads/') - if not os.path.exists(DWD_DIR): - os.makedirs(DWD_DIR) + dwd_dir = os.path.join(mobsf_home, 'downloads/') + if not os.path.exists(dwd_dir): + os.makedirs(dwd_dir) # Screenshot Directory - SCREEN_DIR = os.path.join(DWD_DIR, 'screen/') - if not os.path.exists(SCREEN_DIR): - os.makedirs(SCREEN_DIR) + screen_dir = os.path.join(dwd_dir, 'screen/') + if not os.path.exists(screen_dir): + os.makedirs(screen_dir) # Upload Directory - UPLD_DIR = os.path.join(MobSF_HOME, 'uploads/') - if not os.path.exists(UPLD_DIR): - os.makedirs(UPLD_DIR) - return MobSF_HOME - except: - PrintException("Creating MobSF Home Directory") - - -def get_python(): - """Get Python Executable""" - return sys.executable + upload_dir = os.path.join(mobsf_home, 'uploads/') + if not os.path.exists(upload_dir): + os.makedirs(upload_dir) + return mobsf_home + except Exception: + log_exception('Creating MobSF Home Directory') def make_migrations(base_dir): - """Create Database Migrations""" + """Create Database Migrations.""" try: - python = get_python() - manage = os.path.join(base_dir, "manage.py") - args = [python, manage, "makemigrations"] + manage = os.path.join(base_dir, 'manage.py') + args = [sys.executable, manage, 'makemigrations'] subprocess.call(args) - args = [python, manage, "makemigrations", "StaticAnalyzer"] + args = [sys.executable, manage, 'makemigrations', 'StaticAnalyzer'] subprocess.call(args) - except: - PrintException("Cannot Make Migrations") + except Exception: + log_exception('Cannot Make Migrations') -def migrate(BASE_DIR): - """Migrate Database""" +def migrate(base_dir): + """Migrate Database.""" try: - python = get_python() - manage = os.path.join(BASE_DIR, "manage.py") - args = [python, manage, "migrate"] + manage = os.path.join(base_dir, 'manage.py') + args = [sys.executable, manage, 'migrate'] subprocess.call(args) - except: - PrintException("Cannot Migrate") + args = [sys.executable, manage, 'migrate', '--run-syncdb'] + subprocess.call(args) + except Exception: + log_exception('Cannot Migrate') -def kali_fix(BASE_DIR): +def kali_fix(base_dir): try: - if platform.system() == "Linux" and platform.dist()[0] == "Kali": - fix_path = os.path.join(BASE_DIR, "scripts/kali_fix.sh") - subprocess.call(["chmod", "a+x", fix_path]) + if platform.system() == 'Linux' and platform.dist()[0] == 'Kali': + fix_path = os.path.join(base_dir, 'scripts/kali_fix.sh') + subprocess.call(['chmod', 'a+x', fix_path]) subprocess.call([fix_path], shell=True) - except: - PrintException("Cannot run Kali Fix") + except Exception: + log_exception('Cannot run Kali Fix') -def FindVbox(debug=False): +def find_vboxmange_binary(debug=False): try: - if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_VM": - if len(settings.VBOXMANAGE_BINARY) > 0 and isFileExists(settings.VBOXMANAGE_BINARY): + vpt = ['C:\\Program Files\\Oracle\\VirtualBox\\VBoxManage.exe', + 'C:\\Program Files (x86)\\Oracle\\VirtualBox\\VBoxManage.exe'] + if settings.ANDROID_DYNAMIC_ANALYZER == 'MobSF_VM': + if (len(settings.VBOXMANAGE_BINARY) > 0 + and is_file_exists(settings.VBOXMANAGE_BINARY)): return settings.VBOXMANAGE_BINARY - if platform.system() == "Windows": - # Path to VBoxManage.exe - vbox_path = ["C:\Program Files\Oracle\VirtualBox\VBoxManage.exe", - "C:\Program Files (x86)\Oracle\VirtualBox\VBoxManage.exe"] - for path in vbox_path: + if platform.system() == 'Windows': + for path in vpt: if os.path.isfile(path): return path else: # Path to VBoxManage in Linux/Mac - vbox_path = ["/usr/bin/VBoxManage", - "/usr/local/bin/VBoxManage"] - for path in vbox_path: + vpt = ['/usr/bin/VBoxManage', + '/usr/local/bin/VBoxManage'] + for path in vpt: if os.path.isfile(path): return path if debug: - logger.warning("Could not find VirtualBox path.") - except: + logger.warning('Could not find VirtualBox path') + except Exception: if debug: - PrintException("Cannot find VirtualBox path.") + log_exception('Cannot find VirtualBox path.') # Maintain JDK Version JAVA_VER = '1.7|1.8|1.9|2.0|2.1|2.2|2.3' -def FindJava(debug=False): - """ Find Java """ +def find_java_binary(debug=False): + """Find Java.""" # Maintain JDK Version java_versions = '1.7|1.8|1.9|2.0|2.1|2.2|2.3|8|9|10|11' """ @@ -256,114 +258,114 @@ def FindJava(debug=False): of setting java path :-( """ win_java_paths = [ - "C:/Program Files/Java/", - "C:/Program Files (x86)/Java/", - "D:/Program Files/Java/", - "D:/Program Files (x86)/Java/", - "E:/Program Files/Java/", - "E:/Program Files (x86)/Java/", - "F:/Program Files/Java/", - "F:/Program Files (x86)/Java/", - "G:/Program Files/Java/", - "G:/Program Files (x86)/Java/", - "H:/Program Files/Java/", - "H:/Program Files (x86)/Java/", - "I:/Program Files/Java/", - "I:/Program Files (x86)/Java/", + 'C:/Program Files/Java/', + 'C:/Program Files (x86)/Java/', + 'D:/Program Files/Java/', + 'D:/Program Files (x86)/Java/', + 'E:/Program Files/Java/', + 'E:/Program Files (x86)/Java/', + 'F:/Program Files/Java/', + 'F:/Program Files (x86)/Java/', + 'G:/Program Files/Java/', + 'G:/Program Files (x86)/Java/', + 'H:/Program Files/Java/', + 'H:/Program Files (x86)/Java/', + 'I:/Program Files/Java/', + 'I:/Program Files (x86)/Java/', ] try: - err_msg1 = "Oracle JDK 1.7 or above is not found!" - if isDirExists(settings.JAVA_DIRECTORY): - if settings.JAVA_DIRECTORY.endswith("/"): + err_msg1 = 'Oracle JDK 1.7 or above is not found!' + if is_dir_exists(settings.JAVA_DIRECTORY): + if settings.JAVA_DIRECTORY.endswith('/'): return settings.JAVA_DIRECTORY - elif settings.JAVA_DIRECTORY.endswith("\\"): + elif settings.JAVA_DIRECTORY.endswith('\\'): return settings.JAVA_DIRECTORY else: - return settings.JAVA_DIRECTORY + "/" - elif platform.system() == "Windows": + return settings.JAVA_DIRECTORY + '/' + elif platform.system() == 'Windows': if debug: - logger.info("Finding JDK Location in Windows....") + logger.info('Finding JDK Location in Windows....') # JDK 7 jdk1.7.0_17/bin/ for java_path in win_java_paths: if os.path.isdir(java_path): for dirname in os.listdir(java_path): - if "jdk" in dirname: - win_java_path = java_path + dirname + "/bin/" - args = [win_java_path + "java", "-version"] - dat = RunProcess(args) - if "java" in dat: + if 'jdk' in dirname: + win_java_path = java_path + dirname + '/bin/' + args = [win_java_path + 'java', '-version'] + dat = run_process(args) + if 'java' in dat: if debug: logger.info( - "Oracle Java JDK is installed!") + 'Oracle Java JDK is installed!') return win_java_path - for env in ["JDK_HOME", "JAVA_HOME"]: + for env in ['JDK_HOME', 'JAVA_HOME']: java_home = os.environ.get(env) if java_home and os.path.isdir(java_home): - win_java_path = java_home + "/bin/" - args = [win_java_path + "java", "-version"] - dat = RunProcess(args) - if "java" in dat: + win_java_path = java_home + '/bin/' + args = [win_java_path + 'java', '-version'] + dat = run_process(args) + if 'java' in dat: if debug: - logger.info("Oracle Java is installed!") + logger.info('Oracle Java is installed!') return win_java_path if debug: logger.info(err_msg1) - return "java" + return 'java' else: if debug: - logger.info("Finding JDK Location in Linux/MAC....") + logger.info('Finding JDK Location in Linux/MAC....') # Check in Environment Variables - for env in ["JDK_HOME", "JAVA_HOME"]: + for env in ['JDK_HOME', 'JAVA_HOME']: java_home = os.environ.get(env) if java_home and os.path.isdir(java_home): - lm_java_path = java_home + "/bin/" - args = [lm_java_path + "java", "-version"] - dat = RunProcess(args) - if "oracle" in dat: + lm_java_path = java_home + '/bin/' + args = [lm_java_path + 'java', '-version'] + dat = run_process(args) + if 'oracle' in dat: if debug: - logger.info("Oracle Java is installed!") + logger.info('Oracle Java is installed!') return lm_java_path - mac_linux_java_dir = "/usr/bin/" - args = [mac_linux_java_dir + "java"] - dat = RunProcess(args) - if "oracle" in dat: - args = [mac_linux_java_dir + "java", '-version'] - dat = RunProcess(args) - f_line = dat.split("\n")[0] + mac_linux_java_dir = '/usr/bin/' + args = [mac_linux_java_dir + 'java'] + dat = run_process(args) + if 'oracle' in dat: + args = [mac_linux_java_dir + 'java', '-version'] + dat = run_process(args) + f_line = dat.split('\n')[0] if re.findall(java_versions, f_line): if debug: - logger.info("JDK 1.7 or above is available") + logger.info('JDK 1.7 or above is available') return mac_linux_java_dir else: - err_msg = "Please install Oracle JDK 1.7 or above" + err_msg = 'Please install Oracle JDK 1.7 or above' if debug: logger.error(err_msg) - return "java" + return 'java' else: - args = [mac_linux_java_dir + "java", '-version'] - dat = RunProcess(args) - f_line = dat.split("\n")[0] + args = [mac_linux_java_dir + 'java', '-version'] + dat = run_process(args) + f_line = dat.split('\n')[0] if re.findall(java_versions, f_line): if debug: - logger.info("JDK 1.7 or above is available") + logger.info('JDK 1.7 or above is available') return mac_linux_java_dir else: - err_msg = "Please install Oracle JDK 1.7 or above" + err_msg = 'Please install Oracle JDK 1.7 or above' if debug: logger.error(err_msg) - return "java" + return 'java' - except: + except Exception: if debug: - PrintException("Oracle Java (JDK >=1.7) is not found!") - return "java" + log_exception('Oracle Java (JDK >=1.7) is not found!') + return 'java' -def RunProcess(args): +def run_process(args): try: proc = subprocess.Popen( - args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,) + args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) dat = '' while True: line = proc.stdout.readline() @@ -371,41 +373,35 @@ def RunProcess(args): break dat += str(line) return dat - except: - PrintException("Finding Java path - Cannot Run Process") - return "" + except Exception: + log_exception('Finding Java path - Cannot Run Process') + return '' -def PrintException(msg, web=False): - """Print Exception verbose""" - exc_type, exc_obj, tb = sys.exc_info() - f = tb.tb_frame - lineno = tb.tb_lineno - filename = f.f_code.co_filename - linecache.checkcache(filename) - line = linecache.getline(filename, lineno, f.f_globals) - dat = '\n' + msg + \ - ' ({0}, LINE {1} "{2}"): {3}'.format( - filename, lineno, line.strip(), exc_obj) +def log_exception(msg, web=False): + """Log Exception verbose.""" if web: - logger.warning(dat) + logger.warning(msg) else: - logger.error(dat) + logger.error(msg) -def print_n_send_error_response(request, msg, api=False, exp='Error Description'): - """Print and log errors""" +def print_n_send_error_response(request, + msg, + api=False, + exp='Error Description'): + """Print and log errors.""" logger.error(msg) if api: - api_response = {"error": msg} + api_response = {'error': msg} return api_response else: context = { 'title': 'Error', 'exp': exp, - 'doc': msg + 'doc': msg, } - template = "general/error.html" + template = 'general/error.html' return render(request, template, context, status=500) @@ -414,17 +410,17 @@ def filename_from_path(path): return tail or ntpath.basename(head) -def getMD5(data): +def get_md5(data): return hashlib.md5(data).hexdigest() -def findBetween(s, first, last): +def find_between(s, first, last): try: start = s.index(first) + len(first) end = s.index(last, start) return s[start:end] except ValueError: - return "" + return '' def is_number(s): @@ -457,47 +453,47 @@ def python_dict(value): return ast.literal_eval(value) -def isBase64(str): - return re.match('^[A-Za-z0-9+/]+[=]{0,2}$', str) +def is_base64(b_str): + return re.match('^[A-Za-z0-9+/]+[=]{0,2}$', b_str) -def isInternetAvailable(): +def is_internet_available(): try: proxies, verify = upstream_proxy('https') - except: - PrintException("Setting upstream proxy") + except Exception: + log_exception('Setting upstream proxy') try: requests.get('https://www.google.com', timeout=5, proxies=proxies, verify=verify) return True - except requests.exceptions.HTTPError as err: + except requests.exceptions.HTTPError: try: requests.get('https://www.baidu.com/', timeout=5, proxies=proxies, verify=verify) return True - except requests.exceptions.HTTPError as err1: + except requests.exceptions.HTTPError: return False return False def sha256(file_path): - BLOCKSIZE = 65536 + blocksize = 65536 hasher = hashlib.sha256() with io.open(file_path, mode='rb') as afile: - buf = afile.read(BLOCKSIZE) + buf = afile.read(blocksize) while buf: hasher.update(buf) - buf = afile.read(BLOCKSIZE) + buf = afile.read(blocksize) return (hasher.hexdigest()) def gen_sha256_hash(msg): - """Generate SHA 256 Hash of the message""" + """Generate SHA 256 Hash of the message.""" hash_object = hashlib.sha256(msg.encode('utf-8')) return hash_object.hexdigest() -def isFileExists(file_path): +def is_file_exists(file_path): if os.path.isfile(file_path): return True # This fix situation where a user just typed "adb" or another executable @@ -508,101 +504,106 @@ def isFileExists(file_path): return False -def isDirExists(dir_path): +def is_dir_exists(dir_path): if os.path.isdir(dir_path): return True else: return False -def genRandom(): - return ''.join([random.SystemRandom().choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') for i in range(50)]) +def get_random(): + choice = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)' + return ''.join([random.SystemRandom().choice(choice) for i in range(50)]) def zipdir(path, zip_file): """Zip a directory.""" try: - logger.info("Zipping") + logger.info('Zipping') # pylint: disable=unused-variable # Needed by os.walk for root, _sub_dir, files in os.walk(path): for file_name in files: zip_file.write(os.path.join(root, file_name)) - except: - PrintException("Zipping") + except Exception: + log_exception('Zipping') -def getADB(): - """Get ADB binary path""" +def get_adb(): + """Get ADB binary path.""" try: - if len(settings.ADB_BINARY) > 0 and isFileExists(settings.ADB_BINARY): + if (len(settings.ADB_BINARY) > 0 + and is_file_exists(settings.ADB_BINARY)): return settings.ADB_BINARY else: adb = 'adb' - if platform.system() == "Darwin": + if platform.system() == 'Darwin': adb_dir = os.path.join(settings.TOOLS_DIR, 'adb/mac/') - subprocess.call(["chmod", "777", adb_dir]) + subprocess.call(['chmod', '777', adb_dir]) adb = os.path.join(settings.TOOLS_DIR, 'adb/mac/adb') - elif platform.system() == "Linux": + elif platform.system() == 'Linux': adb_dir = os.path.join(settings.TOOLS_DIR, 'adb/linux/') - subprocess.call(["chmod", "777", adb_dir]) + subprocess.call(['chmod', '777', adb_dir]) adb = os.path.join(settings.TOOLS_DIR, 'adb/linux/adb') - elif platform.system() == "Windows": + elif platform.system() == 'Windows': adb = os.path.join(settings.TOOLS_DIR, 'adb/windows/adb.exe') return adb - except: - PrintException("Getting ADB Location") - return "adb" + except Exception: + log_exception('Getting ADB Location') + return 'adb' def adb_binary_or32bit_support(): - """Check if 32bit is supported. Also if the binary works""" - adb_path = getADB() + """Check if 32bit is supported. Also if the binary works.""" + adb_path = get_adb() try: fnull = open(os.devnull, 'w') subprocess.call([adb_path], stdout=fnull, stderr=fnull) - except: - msg = "\nYou don't have 32 bit execution support enabled or MobSF shipped" \ - " ADB binary is not compatible with your OS."\ - "\nPlease set the 'ADB_BINARY' path in settings.py" + except Exception: + msg = ('\nYou don\'t have 32 bit execution support enabled' + ' or MobSF shipped ADB binary is not compatible with your OS.' + '\nPlease set the ADB_BINARY path in MobSF/settings.py') logger.warning(msg) def check_basic_env(): - """Check if we have basic env for MobSF to run""" - logger.info("MobSF Basic Environment Check") + """Check if we have basic env for MobSF to run.""" + logger.info('MobSF Basic Environment Check') try: - import capfuzz + import capfuzz # noqa F401 except ImportError: - PrintException("CapFuzz not installed!") + log_exception('CapFuzz not installed!') os.kill(os.getpid(), signal.SIGTERM) try: - import lxml + import lxml # noqa F401 except ImportError: - PrintException("lxml is not installed!") + log_exception('lxml is not installed!') os.kill(os.getpid(), signal.SIGTERM) - if platform.system() == "Windows": + if platform.system() == 'Windows': java = settings.JAVA_PATH + 'java.exe' else: java = settings.JAVA_PATH + 'java' - if not isFileExists(java): + if not is_file_exists(java): logger.error( - "Oracle Java is not available or `JAVA_DIRECTORY` in settings.py is configured incorrectly!") - logger.info("JAVA_DIRECTORY=%s" % settings.JAVA_DIRECTORY) - logger.info('''Example Configuration: - JAVA_DIRECTORY = "C:/Program Files/Java/jdk1.7.0_17/bin/" - JAVA_DIRECTORY = "/usr/bin/" - ''') + 'Oracle Java is not available ' + 'or JÃ¥AVA_DIRECTORY in MobSF/settings.py ' + 'is configured incorrectly!') + logger.info('JAVA_DIRECTORY=%s"', settings.JAVA_DIRECTORY) + logger.info('Example Confxiguration:' + '\nJAVA_DIRECTORY = "C:/Program Files/' + 'Java/jdk1.7.0_17/bin/"' + '\nJAVA_DIRECTORY = "/usr/bin/"') os.kill(os.getpid(), signal.SIGTERM) + def first_run(secret_file, base_dir, mobsf_home): # Based on https://gist.github.com/ndarville/3452907#file-secret-key-gen-py - + try: secret_key = open(secret_file).read().strip() except IOError: try: - secret_key = genRandom() + secret_key = get_random() secret = open(secret_file, 'w') secret.write(secret_key) secret.close() diff --git a/MobSF/views/api/rest_api.py b/MobSF/views/api/rest_api.py index 27370605..6baa3e5d 100755 --- a/MobSF/views/api/rest_api.py +++ b/MobSF/views/api/rest_api.py @@ -1,50 +1,26 @@ -""" -MobSF REST API V 1 -""" +# -*- coding: utf_8 -*- +"""MobSF REST API V 1.""" -from django.http import ( - HttpResponse, - JsonResponse -) +from django.http import HttpResponse, JsonResponse from django.views.decorators.csrf import csrf_exempt -from MobSF.views.home import ( - Upload, - delete_scan, - RecentScans -) -from MobSF.utils import ( - api_key, -) -from MobSF.views.helpers import ( - request_method, -) -from StaticAnalyzer.views.shared_func import ( - pdf -) -from StaticAnalyzer.views.android.static_analyzer import ( - static_analyzer -) -from StaticAnalyzer.views.ios.static_analyzer import ( - static_analyzer_ios, -) -from StaticAnalyzer.views.android import ( - view_source -) -from StaticAnalyzer.views.ios import ( - view_source as ios_view_source -) -from StaticAnalyzer.views.windows import ( - staticanalyzer_windows -) +from MobSF.utils import api_key +from MobSF.views.helpers import request_method +from MobSF.views.home import RecentScans, Upload, delete_scan +from StaticAnalyzer.views.android import view_source +from StaticAnalyzer.views.android.static_analyzer import static_analyzer +from StaticAnalyzer.views.ios import view_source as ios_view_source +from StaticAnalyzer.views.ios.static_analyzer import static_analyzer_ios +from StaticAnalyzer.views.shared_func import pdf +from StaticAnalyzer.views.windows import staticanalyzer_windows BAD_REQUEST = 400 OK = 200 def make_api_response(data, status=OK): - """Make API Response""" + """Make API Response.""" resp = JsonResponse(data=data, status=status) resp['Access-Control-Allow-Origin'] = '*' resp['Access-Control-Allow-Methods'] = 'POST' @@ -54,16 +30,16 @@ def make_api_response(data, status=OK): def api_auth(meta): - """Check if API Key Matches""" - if "HTTP_AUTHORIZATION" in meta: - return bool(api_key() == meta["HTTP_AUTHORIZATION"]) + """Check if API Key Matches.""" + if 'HTTP_AUTHORIZATION' in meta: + return bool(api_key() == meta['HTTP_AUTHORIZATION']) return False @request_method(['POST']) @csrf_exempt def api_upload(request): - """POST - Upload API""" + """POST - Upload API.""" upload = Upload(request) resp, code = upload.upload_api() return make_api_response(resp, code) @@ -72,10 +48,10 @@ def api_upload(request): @request_method(['GET']) @csrf_exempt def api_recent_scans(request): - """GET - get recent scans""" + """GET - get recent scans.""" scans = RecentScans(request) resp = scans.recent_scans() - if "error" in resp: + if 'error' in resp: return make_api_response(resp, 500) else: return make_api_response(resp, 200) @@ -84,130 +60,128 @@ def api_recent_scans(request): @request_method(['POST']) @csrf_exempt def api_scan(request): - """POST - Scan API""" + """POST - Scan API.""" params = ['scan_type', 'hash', 'file_name'] if set(request.POST) >= set(params): scan_type = request.POST['scan_type'] # APK, Android ZIP and iOS ZIP - if scan_type in ["apk", "zip"]: + if scan_type in ['apk', 'zip']: resp = static_analyzer(request, True) - if "type" in resp: + if 'type' in resp: # For now it's only ios_zip request.POST._mutable = True - request.POST['scan_type'] = "ios" + request.POST['scan_type'] = 'ios' resp = static_analyzer_ios(request, True) - if "error" in resp: + if 'error' in resp: response = make_api_response(resp, 500) else: response = make_api_response(resp, 200) # IPA - elif scan_type == "ipa": + elif scan_type == 'ipa': resp = static_analyzer_ios(request, True) - if "error" in resp: + if 'error' in resp: response = make_api_response(resp, 500) else: response = make_api_response(resp, 200) # APPX - elif scan_type == "appx": + elif scan_type == 'appx': resp = staticanalyzer_windows(request, True) - if "error" in resp: + if 'error' in resp: response = make_api_response(resp, 500) else: response = make_api_response(resp, 200) else: response = make_api_response( - {"error": "Missing Parameters"}, 422) + {'error': 'Missing Parameters'}, 422) return response @request_method(['POST']) @csrf_exempt def api_delete_scan(request): - """POST - Delete a Scan""" - if "hash" in request.POST: + """POST - Delete a Scan.""" + if 'hash' in request.POST: resp = delete_scan(request, True) - if "error" in resp: + if 'error' in resp: response = make_api_response(resp, 500) else: response = make_api_response(resp, 200) else: response = make_api_response( - {"error": "Missing Parameters"}, 422) + {'error': 'Missing Parameters'}, 422) return response @request_method(['POST']) @csrf_exempt def api_pdf_report(request): - """Generate and Download PDF""" + """Generate and Download PDF.""" params = ['scan_type', 'hash'] if set(request.POST) == set(params): resp = pdf(request, api=True) - if "error" in resp: - if resp.get("error") == "Invalid scan hash": + if 'error' in resp: + if resp.get('error') == 'Invalid scan hash': response = make_api_response(resp, 400) else: response = make_api_response(resp, 500) - elif "pdf_dat" in resp: + elif 'pdf_dat' in resp: response = HttpResponse( - resp["pdf_dat"], content_type='application/pdf') - response["Access-Control-Allow-Origin"] = "*" - elif resp.get("report") == "Report not Found": + resp['pdf_dat'], content_type='application/pdf') + response['Access-Control-Allow-Origin'] = '*' + elif resp.get('report') == 'Report not Found': response = make_api_response(resp, 404) - elif resp.get("scan_type") == "Type is not Allowed": + elif resp.get('scan_type') == 'Type is not Allowed': response = make_api_response(resp, 400) else: response = make_api_response( - {"error": "PDF Generation Error"}, 500) + {'error': 'PDF Generation Error'}, 500) else: response = make_api_response( - {"error": "Missing Parameters"}, 422) + {'error': 'Missing Parameters'}, 422) return response @request_method(['POST']) @csrf_exempt def api_json_report(request): - """Generate JSON Report""" + """Generate JSON Report.""" params = ['scan_type', 'hash'] if set(request.POST) == set(params): resp = pdf(request, api=True, jsonres=True) - if "error" in resp: - if resp.get("error") == "Invalid scan hash": + if 'error' in resp: + if resp.get('error') == 'Invalid scan hash': response = make_api_response(resp, 400) else: response = make_api_response(resp, 500) - elif "report_dat" in resp: - response = make_api_response(resp["report_dat"], 200) - elif resp.get("report") == "Report not Found": + elif 'report_dat' in resp: + response = make_api_response(resp['report_dat'], 200) + elif resp.get('report') == 'Report not Found': response = make_api_response(resp, 404) - elif resp.get("scan_type") == "Type is not Allowed": + elif resp.get('scan_type') == 'Type is not Allowed': response = make_api_response(resp, 400) else: response = make_api_response( - {"error": "JSON Generation Error"}, 500) + {'error': 'JSON Generation Error'}, 500) else: response = make_api_response( - {"error": "Missing Parameters"}, 422) + {'error': 'Missing Parameters'}, 422) return response @request_method(['POST']) @csrf_exempt def api_view_source(request): - """ - View Source for android & ios source file - """ + """View Source for android & ios source file.""" params = ['file', 'type', 'hash'] if set(request.POST) >= set(params): - if request.POST["type"] in ["eclipse", "studio", "apk"]: + if request.POST['type'] in ['eclipse', 'studio', 'apk']: resp = view_source.run(request, api=True) else: resp = ios_view_source.run(request, api=True) - if "error" in resp: + if 'error' in resp: response = make_api_response(resp, 500) else: response = make_api_response(resp, 200) else: - response = make_api_response({"error": "Missing Parameters"}, 422) + response = make_api_response({'error': 'Missing Parameters'}, 422) return response diff --git a/MobSF/views/api/rest_api_middleware.py b/MobSF/views/api/rest_api_middleware.py index 02f816c6..f642f4b5 100644 --- a/MobSF/views/api/rest_api_middleware.py +++ b/MobSF/views/api/rest_api_middleware.py @@ -1,26 +1,23 @@ -""" -REST API Middleware -""" +# -*- coding: utf_8 -*- +"""REST API Middleware.""" from django.utils.deprecation import MiddlewareMixin -from MobSF.views.api.rest_api import ( - api_auth, - make_api_response -) + +from MobSF.views.api.rest_api import api_auth, make_api_response class RestApiAuthMiddleware(MiddlewareMixin): """ - Middleware + Middleware. + + Middleware for REST API. """ def process_request(self, request): - """ - Middleware to handle API Auth - """ - if not request.path.startswith("/api/"): + """Middleware to handle API Auth.""" + if not request.path.startswith('/api/'): return - if request.method == "OPTIONS": + if request.method == 'OPTIONS': return make_api_response({}, 200) if not api_auth(request.META): return make_api_response( - {"error": "You are unauthorized to make this request."}, 401) + {'error': 'You are unauthorized to make this request.'}, 401) diff --git a/MobSF/views/helpers.py b/MobSF/views/helpers.py index 21983d77..f7213299 100644 --- a/MobSF/views/helpers.py +++ b/MobSF/views/helpers.py @@ -1,16 +1,11 @@ -""" -Helpers -""" +"""Helpers.""" import functools -from django.conf import settings -from django.http import ( - HttpRequest, - HttpResponseNotAllowed, -) +from django.conf import settings +from django.http import HttpRequest, HttpResponseNotAllowed ALLOW_METHODS = ['GET', 'POST', 'PUT', 'DELETE', - 'PATCH', 'OPTIONS', 'HEAD', 'TRACE', ] + 'PATCH', 'OPTIONS', 'HEAD', 'TRACE'] class FileType(object): @@ -21,6 +16,8 @@ class FileType(object): def is_allow_file(self): """ + Is File Allowed. + return bool """ if self.is_apk() or self.is_zip() or self.is_ipa() or self.is_appx(): @@ -28,20 +25,26 @@ class FileType(object): return False def is_apk(self): - return (self.file_type in settings.APK_MIME) and self.file_name_lower.endswith('.apk') + return (self.file_type in settings.APK_MIME + and self.file_name_lower.endswith('.apk')) def is_zip(self): - return (self.file_type in settings.ZIP_MIME) and self.file_name_lower.endswith('.zip') + return (self.file_type in settings.ZIP_MIME + and self.file_name_lower.endswith('.zip')) def is_ipa(self): - return (self.file_type in settings.IPA_MIME) and self.file_name_lower.endswith('.ipa') + return (self.file_type in settings.IPA_MIME + and self.file_name_lower.endswith('.ipa')) def is_appx(self): - return (self.file_type in settings.APPX_MIME) and self.file_name_lower.endswith('.appx') + return (self.file_type in settings.APPX_MIME + and self.file_name_lower.endswith('.appx')) def request_method(methods): """ + Request Method Checks. + :param methods http method need django HttpRequest """ @@ -49,7 +52,8 @@ def request_method(methods): @functools.wraps(func) def wrapper(*args, **kwargs): - if not isinstance(methods, list) and not isinstance(methods, tuple): + if (not isinstance(methods, list) + and not isinstance(methods, tuple)): raise ValueError( 'the parameter methods is not a list or tuple') diff --git a/MobSF/views/home.py b/MobSF/views/home.py index cc02242a..08057740 100755 --- a/MobSF/views/home.py +++ b/MobSF/views/home.py @@ -1,65 +1,42 @@ # -*- coding: utf_8 -*- -""" -MobSF File Upload and Home Routes -""" +"""MobSF File Upload and Home Routes.""" import json +import logging import os import platform import re import shutil from wsgiref.util import FileWrapper -import logging + from django.conf import settings from django.core.paginator import Paginator -from django.http import ( - HttpResponse, - HttpResponseRedirect, - JsonResponse -) +from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render -from MobSF.forms import ( - FormUtil, - UploadFileForm -) -from MobSF.views.scanning import ( - Scanning, -) -from MobSF.views.helpers import ( - FileType, -) -from MobSF.utils import ( - PrintException, - api_key, - isDirExists, - isFileExists, - print_n_send_error_response -) -from StaticAnalyzer.models import ( - RecentScansDB, - StaticAnalyzerAndroid, - StaticAnalyzerIOSZIP, - StaticAnalyzerIPA, - StaticAnalyzerWindows -) -LINUX_PLATFORM = ["Darwin", "Linux"] +from MobSF.forms import FormUtil, UploadFileForm +from MobSF.utils import (api_key, is_dir_exists, is_file_exists, + print_n_send_error_response) +from MobSF.views.helpers import FileType +from MobSF.views.scanning import Scanning + +from StaticAnalyzer.models import (RecentScansDB, StaticAnalyzerAndroid, + StaticAnalyzerIOSZIP, StaticAnalyzerIPA, + StaticAnalyzerWindows) + +LINUX_PLATFORM = ['Darwin', 'Linux'] HTTP_BAD_REQUEST = 400 logger = logging.getLogger(__name__) def index(request): - """ - Index Route - """ + """Index Route.""" context = {'version': settings.MOBSF_VER} - template = "general/index.html" + template = 'general/index.html' return render(request, template, context) class Upload(object): - """ - Handle File Upload based on App type - """ + """Handle File Upload based on App type.""" def __init__(self, request): self.request = request @@ -75,7 +52,7 @@ class Upload(object): def resp_json(self, data): resp = HttpResponse(json.dumps(data), - content_type="application/json; charset=utf-8") + content_type='application/json; charset=utf-8') resp['Access-Control-Allow-Origin'] = '*' return resp @@ -84,17 +61,16 @@ class Upload(object): response_data = { 'url': '', 'description': '', - 'status': '' + 'status': '', } if request.method != 'POST': - logger.error("Method not Supported!") - form = UploadFileForm() + logger.error('Method not Supported!') response_data['description'] = 'Method not Supported!' response_data['status'] = HTTP_BAD_REQUEST return self.resp_json(response_data) if not self.form.is_valid(): - logger.error("Invalid Form Data!") + logger.error('Invalid Form Data!') response_data['description'] = 'Invalid Form Data!' response_data['status'] = HTTP_BAD_REQUEST return self.resp_json(response_data) @@ -103,17 +79,17 @@ class Upload(object): self.file_name_lower = request.FILES['file'].name.lower() self.file_type = FileType(self.file_content_type, self.file_name_lower) if not self.file_type.is_allow_file(): - logger.error("File format not Supported!") + logger.error('File format not Supported!') response_data['description'] = 'File format not Supported!' response_data['status'] = HTTP_BAD_REQUEST return self.resp_json(response_data) if self.file_type.is_ipa(): if platform.system() not in LINUX_PLATFORM: - logger.error( - "Static Analysis of iOS IPA requires Mac or Linux") + msg = 'Static Analysis of iOS IPA requires Mac or Linux' + logger.error(msg) response_data[ - 'description'] = 'Static Analysis of iOS IPA requires Mac or Linux' + 'description'] = msg response_data['status'] = 'success' response_data['url'] = 'mac_only/' return self.resp_json(response_data) @@ -122,9 +98,7 @@ class Upload(object): return self.resp_json(response_data) def upload_api(self): - """ - API File Upload - """ + """API File Upload.""" api_response = {} request = self.request if not self.form.is_valid(): @@ -134,13 +108,13 @@ class Upload(object): self.file_name_lower = request.FILES['file'].name.lower() self.file_type = FileType(self.file_content_type, self.file_name_lower) if not self.file_type.is_allow_file(): - api_response["error"] = "File format not Supported!" + api_response['error'] = 'File format not Supported!' return api_response, HTTP_BAD_REQUEST data = self.upload() api_response = { 'scan_type': data['scan_type'], 'hash': data['hash'], - 'file_name': data['file_name'] + 'file_name': data['file_name'], } return api_response, 200 @@ -150,8 +124,7 @@ class Upload(object): file_type = self.file_content_type file_name_lower = self.file_name_lower - logger.info("MIME Type: {} FILE: {}".format( - file_type, file_name_lower)) + logger.info('MIME Type: %s FILE: %s', file_type, file_name_lower) if self.file_type.is_apk(): return scanning.scan_apk() elif self.file_type.is_zip(): @@ -164,73 +137,57 @@ class Upload(object): def api_docs(request): - """ - API Docs Route - """ + """Api Docs Route.""" context = {'title': 'REST API Docs', 'api_key': api_key()} - template = "general/apidocs.html" + template = 'general/apidocs.html' return render(request, template, context) def about(request): - """ - About Route - """ + """About Route.""" context = {'title': 'About'} - template = "general/about.html" + template = 'general/about.html' return render(request, template, context) def error(request): - """ - Error Route - """ + """Error Route.""" context = {'title': 'Error'} - template = "general/error.html" + template = 'general/error.html' return render(request, template, context) def zip_format(request): - """ - Zip Format Message Route - """ + """Zip Format Message Route.""" context = {'title': 'Zipped Source Instruction'} - template = "general/zip.html" + template = 'general/zip.html' return render(request, template, context) def mac_only(request): - """ - Mac Ony Message Route - """ + """Mac Ony Message Route.""" context = {'title': 'Supports OSX Only'} - template = "general/ios.html" + template = 'general/ios.html' return render(request, template, context) def not_found(request): - """ - Not Found Route - """ + """Not Found Route.""" context = {'title': 'Not Found'} - template = "general/not_found.html" + template = 'general/not_found.html' return render(request, template, context) def recent_scans(request): - """ - Show Recent Scans Route - """ + """Show Recent Scans Route.""" db_obj = RecentScansDB.objects.all().order_by('-TS') context = {'title': 'Recent Scans', 'entries': db_obj} - template = "general/recent.html" + template = 'general/recent.html' return render(request, template, context) def search(request): - """ - Search Scan by MD5 Route - """ + """Search Scan by MD5 Route.""" md5 = request.GET['md5'] if re.match('[0-9a-f]{32}', md5): db_obj = RecentScansDB.objects.filter(MD5=md5) @@ -238,25 +195,24 @@ def search(request): return HttpResponseRedirect('/' + db_obj[0].URL) else: return HttpResponseRedirect('/not_found') - return print_n_send_error_response(request, "Invalid Scan Hash") + return print_n_send_error_response(request, 'Invalid Scan Hash') def download(request): - """ - Download from MobSF Route - """ - msg = "Error Downloading File " + """Download from MobSF Route.""" + msg = 'Error Downloading File ' if request.method == 'GET': allowed_exts = settings.ALLOWED_EXTENSIONS - filename = request.path.replace("/download/", "", 1) + filename = request.path.replace('/download/', '', 1) # Security Checks - if "../" in filename: - return print_n_send_error_response(request, "Path Traversal Attack detected") + if '../' in filename: + msg = 'Path Traversal Attack Detected' + return print_n_send_error_response(request, msg) ext = os.path.splitext(filename)[1] if ext in allowed_exts: dwd_file = os.path.join(settings.DWD_DIR, filename) if os.path.isfile(dwd_file): - wrapper = FileWrapper(open(dwd_file, "rb")) + wrapper = FileWrapper(open(dwd_file, 'rb')) response = HttpResponse( wrapper, content_type=allowed_exts[ext]) response['Content-Length'] = os.path.getsize(dwd_file) @@ -266,9 +222,7 @@ def download(request): def delete_scan(request, api=False): - """ - Delete Scan from DB and remove the scan related files - """ + """Delete Scan from DB and remove the scan related files.""" try: if request.method == 'POST': if api: @@ -287,23 +241,25 @@ def delete_scan(request, api=False): StaticAnalyzerWindows.objects.filter(MD5=md5_hash).delete() # Delete Upload Dir Contents app_upload_dir = os.path.join(settings.UPLD_DIR, md5_hash) - if isDirExists(app_upload_dir): + if is_dir_exists(app_upload_dir): shutil.rmtree(app_upload_dir) # Delete Download Dir Contents dw_dir = settings.DWD_DIR for item in os.listdir(dw_dir): item_path = os.path.join(dw_dir, item) + valid_item = item.startswith(md5_hash + '-') # Delete all related files - if isFileExists(item_path) and item.startswith(md5_hash + "-"): + if is_file_exists(item_path) and valid_item: os.remove(item_path) # Delete related directories - if isDirExists(item_path) and item.startswith(md5_hash + "-"): + if is_dir_exists(item_path) and valid_item: shutil.rmtree(item_path) data = {'deleted': 'yes'} if api: return data else: - return HttpResponse(json.dumps(data), content_type='application/json; charset=utf-8') + ctype = 'application/json; charset=utf-8' + return HttpResponse(json.dumps(data), content_type=ctype) except Exception as exp: msg = str(exp) exp_doc = exp.__doc__ @@ -326,10 +282,10 @@ class RecentScans(object): paginator = Paginator(result, page_size) content = paginator.page(page) data = { - "content": list(content), - "count": paginator.count, - "num_pages": paginator.num_pages + 'content': list(content), + 'count': paginator.count, + 'num_pages': paginator.num_pages, } except Exception as exp: - data = {"error": str(exp)} + data = {'error': str(exp)} return data diff --git a/MobSF/views/scanning.py b/MobSF/views/scanning.py index e313ea08..a5d821b4 100644 --- a/MobSF/views/scanning.py +++ b/MobSF/views/scanning.py @@ -1,34 +1,32 @@ - -# from MobSF.views import handle_uploaded_file, add_to_recent_scan +# -*- coding: utf_8 -*- import hashlib -import os import logging +import os + from django.conf import settings from django.utils import timezone -from MobSF.utils import PrintException +from MobSF.utils import log_exception + from StaticAnalyzer.models import RecentScansDB + logger = logging.getLogger(__name__) def add_to_recent_scan(name, md5, url): - """ - Add Entry to Database under Recent Scan - """ + """Add Entry to Database under Recent Scan.""" try: db_obj = RecentScansDB.objects.filter(MD5=md5) if not db_obj.exists(): new_db_obj = RecentScansDB( NAME=name, MD5=md5, URL=url, TS=timezone.now()) new_db_obj.save() - except: - PrintException("Adding Scan URL to Database") + except Exception: + log_exception('Adding Scan URL to Database') def handle_uploaded_file(filecnt, typ): - """ - Write Uploaded File - """ + """Write Uploaded File.""" md5 = hashlib.md5() # modify if crash for large for chunk in filecnt.chunks(): md5.update(chunk) @@ -42,79 +40,78 @@ def handle_uploaded_file(filecnt, typ): return md5sum - class Scanning(object): def __init__(self, request): self.request = request self.file = request.FILES['file'] self.file_name = request.FILES['file'].name - + def scan_apk(self): - """ - """ - # APK + """Android APK.""" md5 = handle_uploaded_file(self.file, '.apk') + url = 'StaticAnalyzer/?name={}&type=apk&checksum={}'.format( + self.file_name, md5) data = { - 'url': 'StaticAnalyzer/?name={}&type=apk&checksum={}'.format(self.file_name, md5), + 'url': url, 'status': 'success', 'hash': md5, 'scan_type': 'apk', - 'file_name': self.file_name + 'file_name': self.file_name, } - + add_to_recent_scan(self.file_name, md5, data['url']) - logger.info("Performing Static Analysis of Android APK") + logger.info('Performing Static Analysis of Android APK') return data def scan_zip(self): - """ - """ - # Android /iOS Zipped Source + """Android /iOS Zipped Source.""" md5 = handle_uploaded_file(self.file, '.zip') - + url = 'StaticAnalyzer/?name={}&type=zip&checksum={}'.format( + self.file_name, md5) data = { - 'url': 'StaticAnalyzer/?name={}&type=zip&checksum={}'.format(self.file_name, md5), + 'url': url, 'status': 'success', 'hash': md5, 'scan_type': 'zip', - 'file_name': self.file_name + 'file_name': self.file_name, } add_to_recent_scan(self.file_name, md5, data['url']) - logger.info("Performing Static Analysis of Android/iOS Source Code") + logger.info('Performing Static Analysis of Android/iOS Source Code') return data def scan_ipa(self): - """ - iOS Binary - """ + """IOS Binary.""" md5 = handle_uploaded_file(self.file, '.ipa') + url = 'StaticAnalyzer_iOS/?name={}&type=ipa&checksum={}'.format( + self.file_name, md5) data = { 'hash': md5, 'scan_type': 'ipa', 'file_name': self.file_name, - 'url': 'StaticAnalyzer_iOS/?name={}&type=ipa&checksum={}'.format(self.file_name, md5), - 'status': 'success' + 'url': url, + 'status': 'success', } add_to_recent_scan(self.file_name, md5, data['url']) - logger.info("Performing Static Analysis of iOS IPA") + logger.info('Performing Static Analysis of iOS IPA') return data def scan_appx(self): - """ - """ + """Windows appx.""" md5 = handle_uploaded_file(self.file, '.appx') + url = 'StaticAnalyzer_Windows/?name={}&type=appx&checksum={}'.format( + self.file_name, md5) data = { 'hash': md5, 'scan_type': 'appx', 'file_name': self.file_name, - 'url': 'StaticAnalyzer_Windows/?name={}&type=appx&checksum={}'.format(self.file_name, md5), - 'status': 'success' + 'url': url, + 'status': 'success', } - + add_to_recent_scan(self.file_name, md5, data['url']) - logger.info("Performing Static Analysis of Windows APP") + logger.info('Performing Static Analysis of Windows APP') return data diff --git a/MobSF/wsgi.py b/MobSF/wsgi.py index a89e176d..a867de16 100755 --- a/MobSF/wsgi.py +++ b/MobSF/wsgi.py @@ -7,11 +7,12 @@ For more information on this file, see https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/ """ - import os -from whitenoise import WhiteNoise -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MobSF.settings") from django.core.wsgi import get_wsgi_application + +from whitenoise import WhiteNoise +os.environ.setdefault('DJANGO_SETTINGS_MODUL', 'MobSF.settings') + application = WhiteNoise(get_wsgi_application(), - root='static', prefix='static/') + root='static', prefix='static/') diff --git a/StaticAnalyzer/admin.py b/StaticAnalyzer/admin.py index ea5d68b7..e69de29b 100755 --- a/StaticAnalyzer/admin.py +++ b/StaticAnalyzer/admin.py @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/StaticAnalyzer/forms.py b/StaticAnalyzer/forms.py index 196f12fe..5612da56 100644 --- a/StaticAnalyzer/forms.py +++ b/StaticAnalyzer/forms.py @@ -7,49 +7,41 @@ class AttackDetect(forms.Form): file = forms.CharField() def clean_file(self): - """ - Check ../ from path - """ + """Check ../ from path.""" file = self.cleaned_data['file'] - if (("../" in file) or ("%2e%2e" in file) or - (".." in file) or ("%252e" in file)): - raise forms.ValidationError("Attack Detected") + if (('../' in file) or ('%2e%2e' in file) + or ('..' in file) or ('%252e' in file)): + raise forms.ValidationError('Attack Detected') return file class IOSChecks(forms.Form): file = forms.CharField() - type = forms.ChoiceField( + type = forms.ChoiceField( # noqa A003 choices=( ('ipa', 'ipa'), - ('ios', 'ios') - ) - ) + ('ios', 'ios'))) def clean_ext(self): - """ - Safe Extension - """ + """Safe Extension.""" file = self.cleaned_data['file'] ext = file.split('.')[-1] - ext_type = re.search("plist|db|sqlitedb|sqlite|txt|m", ext) + ext_type = re.search('plist|db|sqlitedb|sqlite|txt|m', ext) if not ext_type: - raise forms.ValidationError("File Extension not supported") + raise forms.ValidationError('File Extension not supported') return file class APIChecks(forms.Form): - hash = forms.CharField(min_length=32, max_length=32) + hash = forms.CharField(min_length=32, max_length=32) # noqa A003 def clean_hash(self): - """ - Hash is valid - """ + """Hash is valid.""" md5 = self.cleaned_data['hash'] md5_match = re.match('^[0-9a-f]{32}$', md5) if not md5_match: - raise forms.ValidationError("Invalid Hash") + raise forms.ValidationError('Invalid Hash') return md5 @@ -57,34 +49,28 @@ class WebChecks(forms.Form): md5 = forms.CharField(min_length=32, max_length=32) def clean_hash(self): - """ - Hash is valid - """ + """Hash is valid.""" md5 = self.cleaned_data['md5'] md5_match = re.match('^[0-9a-f]{32}$', md5) if not md5_match: - raise forms.ValidationError("Invalid Hash") + raise forms.ValidationError('Invalid Hash') return md5 class AndroidChecks(forms.Form): - type = forms.ChoiceField( + type = forms.ChoiceField( # noqa A003 choices=( ('eclipse', 'eclipse'), ('studio', 'studio'), - ('apk', 'apk') - ) - ) + ('apk', 'apk'))) def clean_ext(self): - """ - Safe Extension - """ + """Safe Extension.""" file = self.cleaned_data['file'] ext = file.split('.')[-1] - ext_type = re.search("java|smali", ext) + ext_type = re.search('java|smali', ext) if not ext_type: - raise forms.ValidationError("File Extension not supported") + raise forms.ValidationError('File Extension not supported') return file diff --git a/StaticAnalyzer/models.py b/StaticAnalyzer/models.py index b8de15e3..8467f9d6 100755 --- a/StaticAnalyzer/models.py +++ b/StaticAnalyzer/models.py @@ -90,7 +90,7 @@ class StaticAnalyzerIPA(models.Model): BUNDLE_URL_TYPES = models.TextField() BUNDLE_SUPPORTED_PLATFORMS = models.CharField(max_length=50) BUNDLE_LOCALIZATIONS = models.TextField() - BINTYPE = models.CharField(max_length=20, default="") + BINTYPE = models.CharField(max_length=20, default='') APPSTORE_DETAILS = models.TextField(default={}) diff --git a/StaticAnalyzer/tests.py b/StaticAnalyzer/tests.py index e15da98c..8247d40e 100755 --- a/StaticAnalyzer/tests.py +++ b/StaticAnalyzer/tests.py @@ -1,18 +1,15 @@ #!/usr/bin/env python +import json +import logging import os import platform -import json from django.conf import settings -from django.test import Client from django.http import HttpResponse +from django.test import Client, TestCase + +from MobSF.utils import api_key, log_exception -from MobSF.utils import ( - PrintException, - api_key, -) -import logging -from django.test import TestCase logger = logging.getLogger(__name__) RESCAN = False @@ -20,284 +17,306 @@ RESCAN = False def static_analysis_test(): - """Test Static Analyzer""" - logger.info("Running Static Analyzer Unit test") - err_msg = '%s' - if platform.system() != "Windows": - err_msg = '\033[91m \033[1m %s \033[0m' + """Test Static Analyzer.""" + logger.info('Running Static Analyzer Unit test') try: uploaded = [] - logger.info("Running Upload Test") + logger.info('Running Upload Test') http_client = Client() - apk_dir = os.path.join(settings.BASE_DIR, "StaticAnalyzer/test_files/") + apk_dir = os.path.join(settings.BASE_DIR, 'StaticAnalyzer/test_files/') for filename in os.listdir(apk_dir): fpath = os.path.join(apk_dir, filename) with open(fpath, 'rb') as filp: response = http_client.post('/upload/', {'file': filp}) - obj = json.loads(response.content.decode("utf-8")) - if response.status_code == 200 and obj["status"] == "success": - logger.info("[OK] Upload OK: " + filename) - uploaded.append(obj["url"]) + obj = json.loads(response.content.decode('utf-8')) + if response.status_code == 200 and obj['status'] == 'success': + logger.info('[OK] Upload OK: %s', filename) + uploaded.append(obj['url']) else: - logger.error(err_msg % " Performing Upload: " + filename) + logger.error('Performing Upload: %s', filename) return True break - logger.info("[OK] Completed Upload test") - logger.info("Running Static Analysis Test") + logger.info('[OK] Completed Upload test') + logger.info('Running Static Analysis Test') for upl in uploaded: if RESCAN: - upl = "/" + upl + "&rescan=1" + upl = '/' + upl + '&rescan=1' else: - upl = "/" + upl + upl = '/' + upl resp = http_client.get(upl, follow=True) if resp.status_code == 200: - logger.info("[OK] Static Analysis Complete: " + upl) + logger.info('[OK] Static Analysis Complete: %s', upl) else: - logger.error(err_msg % " Performing Static Analysis: " + upl) + logger.error('Performing Static Analysis: %s', upl) return True break - logger.info("[OK] Static Analysis test completed") - logger.info("Running PDF Generation Test") + logger.info('[OK] Static Analysis test completed') + logger.info('Running PDF Generation Test') if platform.system() in ['Darwin', 'Linux']: pdfs = [ - "/PDF/?md5=3a552566097a8de588b8184b059b0158&type=APK", - "/PDF/?md5=6c23c2970551be15f32bbab0b5db0c71&type=IPA", - "/PDF/?md5=52c50ae824e329ba8b5b7a0f523efffe&type=ANDZIP", - "/PDF/?md5=57bb5be0ea44a755ada4a93885c3825e&type=IOSZIP", - "/PDF/?md5=8179b557433835827a70510584f3143e&type=APPX", + '/PDF/?md5=3a552566097a8de588b8184b059b0158&type=APK', + '/PDF/?md5=6c23c2970551be15f32bbab0b5db0c71&type=IPA', + '/PDF/?md5=52c50ae824e329ba8b5b7a0f523efffe&type=ANDZIP', + '/PDF/?md5=57bb5be0ea44a755ada4a93885c3825e&type=IOSZIP', + '/PDF/?md5=8179b557433835827a70510584f3143e&type=APPX', ] else: pdfs = [ - "/PDF/?md5=3a552566097a8de588b8184b059b0158&type=APK", - "/PDF/?md5=52c50ae824e329ba8b5b7a0f523efffe&type=ANDZIP", - "/PDF/?md5=57bb5be0ea44a755ada4a93885c3825e&type=IOSZIP", - "/PDF/?md5=8179b557433835827a70510584f3143e&type=APPX", + '/PDF/?md5=3a552566097a8de588b8184b059b0158&type=APK', + '/PDF/?md5=52c50ae824e329ba8b5b7a0f523efffe&type=ANDZIP', + '/PDF/?md5=57bb5be0ea44a755ada4a93885c3825e&type=IOSZIP', + '/PDF/?md5=8179b557433835827a70510584f3143e&type=APPX', ] for pdf in pdfs: resp = http_client.get(pdf) - if (resp.status_code == 200 and - resp._headers['content-type'][1] == "application/pdf" - ): - logger.info("[OK] PDF Report Generated: " + pdf) + if (resp.status_code == 200 + and resp._headers['content-type'][1] == 'application/pdf'): + logger.info('[OK] PDF Report Generated: %s', pdf) else: - logger.error(err_msg % " Generating PDF: " + pdf) + logger.error('Generating PDF: %s', pdf) logger.info(resp.content) return True break - logger.info("[OK] PDF Generation test completed") + logger.info('[OK] PDF Generation test completed') # Compare apps test - logger.info("Running App Compare tests") + logger.info('Running App Compare tests') first_app = '3a552566097a8de588b8184b059b0158' second_app = '52c50ae824e329ba8b5b7a0f523efffe' url = '/compare/{}/{}/'.format(first_app, second_app) resp = http_client.get(url, follow=True) assert (resp.status_code == 200) if resp.status_code == 200: - logger.info("[OK] App compare tests passed successfully") + logger.info('[OK] App compare tests passed successfully') else: - logger.error(err_msg % " App compare tests failed") + logger.error('App compare tests failed') logger.info(resp.content) return True - logger.info("Running Delete Scan Results test") + logger.info('Running Delete Scan Results test') # Deleting Scan Results if platform.system() in ['Darwin', 'Linux']: - scan_md5s = ["3a552566097a8de588b8184b059b0158", "6c23c2970551be15f32bbab0b5db0c71", - "52c50ae824e329ba8b5b7a0f523efffe", "57bb5be0ea44a755ada4a93885c3825e", - "8179b557433835827a70510584f3143e"] + scan_md5s = ['3a552566097a8de588b8184b059b0158', + '6c23c2970551be15f32bbab0b5db0c71', + '52c50ae824e329ba8b5b7a0f523efffe', + '57bb5be0ea44a755ada4a93885c3825e', + '8179b557433835827a70510584f3143e'] else: - scan_md5s = ["3a552566097a8de588b8184b059b0158", "52c50ae824e329ba8b5b7a0f523efffe", - "57bb5be0ea44a755ada4a93885c3825e", "8179b557433835827a70510584f3143e"] + scan_md5s = ['3a552566097a8de588b8184b059b0158', + '52c50ae824e329ba8b5b7a0f523efffe', + '57bb5be0ea44a755ada4a93885c3825e', + '8179b557433835827a70510584f3143e'] for md5 in scan_md5s: resp = http_client.post('/delete_scan/', {'md5': md5}) if resp.status_code == 200: - dat = json.loads(resp.content.decode("utf-8")) - if dat["deleted"] == "yes": - logger.info("[OK] Deleted Scan: " + md5) + dat = json.loads(resp.content.decode('utf-8')) + if dat['deleted'] == 'yes': + logger.info('[OK] Deleted Scan: %s', md5) else: - logger.error(err_msg % " Deleting Scan: " + md5) + logger.error('Deleting Scan: %s', md5) return True else: - logger.error(err_msg % " Deleting Scan: " + md5) + logger.error('Deleting Scan: %s', md5) return True - logger.info("Delete Scan Results test completed") - except: - PrintException("Completing Static Analyzer Test") + logger.info('Delete Scan Results test completed') + except Exception: + log_exception('Completing Static Analyzer Test') return False def api_test(): - """View for Handling REST API Test""" - logger.info("\nRunning REST API Unit test") + """View for Handling REST API Test.""" + logger.info('\nRunning REST API Unit test') auth = api_key() - err_msg = '%s' - if platform.system() != "Windows": - err_msg = '\033[91m \033[1m %s \033[0m' try: uploaded = [] - logger.info("Running Test on Upload API") + logger.info('Running Test on Upload API') http_client = Client() - apk_dir = os.path.join(settings.BASE_DIR, "StaticAnalyzer/test_files/") + apk_dir = os.path.join(settings.BASE_DIR, 'StaticAnalyzer/test_files/') for filename in os.listdir(apk_dir): fpath = os.path.join(apk_dir, filename) - if (platform.system() not in ['Darwin', 'Linux'] and - fpath.endswith(".ipa")): + if (platform.system() not in ['Darwin', 'Linux'] + and fpath.endswith('.ipa')): continue - with open(fpath, "rb") as filp: + with open(fpath, 'rb') as filp: response = http_client.post( '/api/v1/upload', {'file': filp}, HTTP_AUTHORIZATION=auth) - obj = json.loads(response.content.decode("utf-8")) - if response.status_code == 200 and "hash" in obj: - logger.info("[OK] Upload OK: " + filename) + obj = json.loads(response.content.decode('utf-8')) + if response.status_code == 200 and 'hash' in obj: + logger.info('[OK] Upload OK: %s', filename) uploaded.append(obj) else: - logger.error(err_msg % " Performing Upload" + filename) + logger.error('Performing Upload %s', filename) return True - logger.info("[OK] Completed Upload API test") - logger.info("Running Static Analysis API Test") + logger.info('[OK] Completed Upload API test') + logger.info('Running Static Analysis API Test') for upl in uploaded: resp = http_client.post( '/api/v1/scan', upl, HTTP_AUTHORIZATION=auth) if resp.status_code == 200: - logger.info("[OK] Static Analysis Complete: " + upl["file_name"]) + logger.info('[OK] Static Analysis Complete: %s', + upl['file_name']) else: - logger.error(err_msg % " Performing Static Analysis: " + upl["file_name"]) + logger.error('Performing Static Analysis: %s', + upl['file_name']) return True - logger.info("[OK] Static Analysis API test completed") + logger.info('[OK] Static Analysis API test completed') # Scan List API test - logger.info("Running Scan List API tests") + logger.info('Running Scan List API tests') resp = http_client.get('/api/v1/scans', HTTP_AUTHORIZATION=auth) if resp.status_code == 200: - logger.info("Scan List API Test 1 success") + logger.info('Scan List API Test 1 success') else: - logger.error(err_msg % " Scan List API Test 1") + logger.error('Scan List API Test 1') return True - resp = http_client.get('/api/v1/scans?page=1&page_size=10', HTTP_AUTHORIZATION=auth) + resp = http_client.get( + '/api/v1/scans?page=1&page_size=10', HTTP_AUTHORIZATION=auth) if resp.status_code == 200: - logger.info("Scan List API Test 2 success") + logger.info('Scan List API Test 2 success') else: - logger.error(err_msg % " Scan List API Test 2") + logger.error('Scan List API Test 2') return True - logger.info("[OK] Scan List API tests completed") + logger.info('[OK] Scan List API tests completed') # PDF Tests - logger.info("Running PDF Generation API Test") + logger.info('Running PDF Generation API Test') if platform.system() in ['Darwin', 'Linux']: pdfs = [ - {"hash": "3a552566097a8de588b8184b059b0158", "scan_type": "apk"}, - {"hash": "6c23c2970551be15f32bbab0b5db0c71", "scan_type": "ipa"}, - {"hash": "52c50ae824e329ba8b5b7a0f523efffe", "scan_type": "andzip"}, - {"hash": "57bb5be0ea44a755ada4a93885c3825e", "scan_type": "ioszip"}, - {"hash": "8179b557433835827a70510584f3143e", "scan_type": "appx"}, + {'hash': '3a552566097a8de588b8184b059b0158', + 'scan_type': 'apk'}, + {'hash': '6c23c2970551be15f32bbab0b5db0c71', + 'scan_type': 'ipa'}, + {'hash': '52c50ae824e329ba8b5b7a0f523efffe', + 'scan_type': 'andzip'}, + {'hash': '57bb5be0ea44a755ada4a93885c3825e', + 'scan_type': 'ioszip'}, + {'hash': '8179b557433835827a70510584f3143e', + 'scan_type': 'appx'}, ] else: pdfs = [ - {"hash": "3a552566097a8de588b8184b059b0158", "scan_type": "apk"}, - {"hash": "52c50ae824e329ba8b5b7a0f523efffe", "scan_type": "andzip"}, - {"hash": "57bb5be0ea44a755ada4a93885c3825e", "scan_type": "ioszip"}, - {"hash": "8179b557433835827a70510584f3143e", "scan_type": "appx"}, + {'hash': '3a552566097a8de588b8184b059b0158', + 'scan_type': 'apk'}, + {'hash': '52c50ae824e329ba8b5b7a0f523efffe', + 'scan_type': 'andzip'}, + {'hash': '57bb5be0ea44a755ada4a93885c3825e', + 'scan_type': 'ioszip'}, + {'hash': '8179b557433835827a70510584f3143e', + 'scan_type': 'appx'}, ] for pdf in pdfs: resp = http_client.post( '/api/v1/download_pdf', pdf, HTTP_AUTHORIZATION=auth) - if (resp.status_code == 200 and - resp._headers['content-type'][1] == "application/pdf" - ): - logger.info("[OK] PDF Report Generated: " + pdf["hash"]) + if (resp.status_code == 200 + and resp._headers['content-type'][1] == 'application/pdf'): + logger.info('[OK] PDF Report Generated: %s', pdf['hash']) else: - logger.error(err_msg % " Generating PDF: " + pdf["hash"]) + logger.error('Generating PDF: %s', pdf['hash']) logger.info(resp.content) return True - logger.info("[OK] PDF Generation API test completed") - logger.info("Running JSON Report API test") + logger.info('[OK] PDF Generation API test completed') + logger.info('Running JSON Report API test') # JSON Report + ctype = 'application/json; charset=utf-8' for jsn in pdfs: resp = http_client.post( '/api/v1/report_json', jsn, HTTP_AUTHORIZATION=auth) - if (resp.status_code == 200) and (resp._headers['content-type'][1] == "application/json; charset=utf-8"): - logger.info("[OK] JSON Report Generated: " + jsn["hash"]) + if (resp.status_code == 200 + and resp._headers['content-type'][1] == ctype): + logger.info('[OK] JSON Report Generated: %s', jsn['hash']) else: - logger.error("{} Generating JSON Response: {}".format(err_msg, jsn["hash"])) + logger.error('Generating JSON Response: %s', jsn['hash']) return True - logger.info("[OK] JSON Report API test completed") - logger.info("Running View Source API test") + logger.info('[OK] JSON Report API test completed') + logger.info('Running View Source API test') # View Source tests - files = [{"file": "opensecurity/helloworld/MainActivity.java", "type": "apk", "hash": "3a552566097a8de588b8184b059b0158"}, - {"file": "helloworld.app/Info.plist", "type": "ipa", "hash": "6c23c2970551be15f32bbab0b5db0c71"}, - {"file": "opensecurity/webviewignoressl/MainActivity.java", "type": "studio", "hash": "52c50ae824e329ba8b5b7a0f523efffe"}, - {"file": "DamnVulnerableIOSApp/AppDelegate.m", "type": "ios", "hash": "57bb5be0ea44a755ada4a93885c3825e"}] + files = [{'file': 'opensecurity/helloworld/MainActivity.java', + 'type': 'apk', + 'hash': '3a552566097a8de588b8184b059b0158'}, + {'file': 'helloworld.app/Info.plist', + 'type': 'ipa', + 'hash': '6c23c2970551be15f32bbab0b5db0c71'}, + {'file': 'opensecurity/webviewignoressl/MainActivity.java', + 'type': 'studio', + 'hash': '52c50ae824e329ba8b5b7a0f523efffe'}, + {'file': 'DamnVulnerableIOSApp/AppDelegate.m', + 'type': 'ios', + 'hash': '57bb5be0ea44a755ada4a93885c3825e'}] for sfile in files: resp = http_client.post( '/api/v1/view_source', sfile, HTTP_AUTHORIZATION=auth) if resp.status_code == 200: - dat = json.loads(resp.content.decode("utf-8")) - if dat["title"]: - logger.info("[OK] Reading - " + sfile["file"]) + dat = json.loads(resp.content.decode('utf-8')) + if dat['title']: + logger.info('[OK] Reading - %s', sfile['file']) else: - logger.error(err_msg % " Reading - " + sfile["file"]) + logger.error('Reading - %s', sfile['file']) return True else: - logger.error(err_msg % " Reading - " + sfile["file"]) + logger.error('Reading - %s', sfile['file']) return True - logger.info("[OK] View Source API test completed") - logger.info("Running Delete Scan API Results test") + logger.info('[OK] View Source API test completed') + logger.info('Running Delete Scan API Results test') # Deleting Scan Results if platform.system() in ['Darwin', 'Linux']: - scan_md5s = ["3a552566097a8de588b8184b059b0158", "6c23c2970551be15f32bbab0b5db0c71", - "52c50ae824e329ba8b5b7a0f523efffe", "57bb5be0ea44a755ada4a93885c3825e", - "8179b557433835827a70510584f3143e" + scan_md5s = ['3a552566097a8de588b8184b059b0158', + '6c23c2970551be15f32bbab0b5db0c71', + '52c50ae824e329ba8b5b7a0f523efffe', + '57bb5be0ea44a755ada4a93885c3825e', + '8179b557433835827a70510584f3143e', ] else: - scan_md5s = ["3a552566097a8de588b8184b059b0158", "52c50ae824e329ba8b5b7a0f523efffe", - "57bb5be0ea44a755ada4a93885c3825e", "8179b557433835827a70510584f3143e" + scan_md5s = ['3a552566097a8de588b8184b059b0158', + '52c50ae824e329ba8b5b7a0f523efffe', + '57bb5be0ea44a755ada4a93885c3825e', + '8179b557433835827a70510584f3143e', ] for md5 in scan_md5s: resp = http_client.post( '/api/v1/delete_scan', {'hash': md5}, HTTP_AUTHORIZATION=auth) if resp.status_code == 200: - dat = json.loads(resp.content.decode("utf-8")) - if dat["deleted"] == "yes": - logger.info("[OK] Deleted Scan: " + md5) + dat = json.loads(resp.content.decode('utf-8')) + if dat['deleted'] == 'yes': + logger.info('[OK] Deleted Scan: %s', md5) else: - logger.error(err_msg % " Deleting Scan: " + md5) + logger.error('Deleting Scan: %s', md5) return True else: - logger.error(err_msg % " Deleting Scan: " + md5) + logger.error('Deleting Scan: %s', md5) return True - logger.info("Delete Scan Results API test completed") - except: - PrintException("Completing REST API Unit Test") + logger.info('Delete Scan Results API test completed') + except Exception: + log_exception('Completing REST API Unit Test') return False def start_test(request): - """ Static Analyzer Unit test""" + """Static Analyzer Unit test.""" item = request.GET.get('module', 'static') - if item == "static": - comp = "static_analyzer" + if item == 'static': + comp = 'static_analyzer' failed_stat = static_analysis_test() else: - comp = "static_analyzer_api" + comp = 'static_analyzer_api' failed_stat = api_test() try: if failed_stat: - message = "some tests failed" + message = 'some tests failed' resp_code = 403 else: - message = "all tests completed" + message = 'all tests completed' resp_code = 200 - except: + except Exception: resp_code = 403 - message = "error" - logger.info("\n\nALL TESTS COMPLETED!") - logger.info("Test Status: " + message) + message = 'error' + logger.info('\n\nALL TESTS COMPLETED!') + logger.info('Test Status: %s', message) return HttpResponse(json.dumps({comp: message}), - content_type="application/json; charset=utf-8", + content_type='application/json; charset=utf-8', status=resp_code) class StaticAnalyzerAndAPI(TestCase): - """Unit Tests""" + """Unit Tests.""" def setUp(self): self.http_client = Client() diff --git a/StaticAnalyzer/tools/strings.py b/StaticAnalyzer/tools/strings.py index 61619fad..554e680a 100755 --- a/StaticAnalyzer/tools/strings.py +++ b/StaticAnalyzer/tools/strings.py @@ -1,17 +1,24 @@ import io + + """ +Python Strings. + Strings-module to be undependend from operating systems Taken from: http://stackoverflow.com/a/17197027 """ -def strings_util(filename, min=6): - """Print out all connected series of readable chars longer than min.""" - with io.open(filename, mode="rb") as f: - result = "" - for c in f.read().decode("utf-8", "ignore"): - if c in '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ ': + +def strings_util(filename, minimum=6): + """Print out all connected series of readable chars longer than minimum.""" + with io.open(filename, mode='rb') as f: + result = '' + for c in f.read().decode('utf-8', 'ignore'): + if c in ('0123456789abcdefghijklmnopqrs' + 'tuvwxyzABCDEFGHIJKLMNOPQRSTUV' + 'WXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ '): result += c continue - if len(result) >= min and result[0].isalnum(): - yield "'" + result + "'" - result = "" \ No newline at end of file + if len(result) >= minimum and result[0].isalnum(): + yield '\'' + result + '\'' + result = '' diff --git a/StaticAnalyzer/views/android/android_apis.py b/StaticAnalyzer/views/android/android_apis.py index c8a56844..3c236bc4 100755 --- a/StaticAnalyzer/views/android/android_apis.py +++ b/StaticAnalyzer/views/android/android_apis.py @@ -1,5 +1,5 @@ """ -Rule Format +Rule Format. 1. desc - Description of the findings @@ -11,14 +11,19 @@ Rule Format a. single_regex - if re.findall(regex1, input) b .regex_and - if re.findall(regex1, input) and re.findall(regex2, input) c. regex_or - if re.findall(regex1, input) or re.findall(regex2, input) - d. regex_and_perm - if re.findall(regex, input) and (permission in permission_list_from_manifest) + d. regex_and_perm - if re.findall(regex, input) and (permission in + permission_list_from_manifest) e. single_string - if string1 in input f. string_and - if (string1 in input) and (string2 in input) g. string_or - if (string1 in input) or (string2 in input) - h. string_and_or - if (string1 in input) and ((string2 in input) or (string3 in input)) - i. string_or_and - if (string1 in input) or ((string2 in input) and (string3 in input)) - j. string_and_perm - if (string1 in input) and (permission in permission_list_from_manifest) - k. string_or_and_perm - if ((string1 in input) or (string2 in input)) and (permission in permission_list_from_manifest) + h. string_and_or - if (string1 in input) and ((string2 in input) + or (string3 in input)) + i. string_or_and - if (string1 in input) or ((string2 in input) + and (string3 in input)) + j. string_and_perm - if (string1 in input) and + (permission in permission_list_from_manifest) + k. string_or_and_perm - if ((string1 in input) or (string2 in input)) + and (permission in permission_list_from_manifest) 4. input_case a. upper @@ -37,77 +42,85 @@ APIS = [ 'type': 'regex', 'match': 'single_regex', 'regex1': r'System\.loadLibrary\(|System\.load\(', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Get System Service', 'type': 'regex', 'match': 'single_regex', 'regex1': r'getSystemService', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Dynamic Class and Dexloading', 'type': 'regex', 'match': 'single_regex', - 'regex1': r'dalvik\.system\.DexClassLoader|java\.security\.ClassLoader|java\.net\.URLClassLoader|java\.security\.SecureClassLoader', - 'input_case': 'exact' + 'regex1': (r'dalvik\.system\.DexClassLoader|' + r'java\.security\.ClassLoader|' + r'java\.net\.URLClassLoader|' + r'java\.security\.SecureClassLoader'), + 'input_case': 'exact', }, { 'desc': 'Java Reflection', 'type': 'regex', 'match': 'single_regex', - 'regex1': r'java\.lang\.reflect\.Method|java\.lang\.reflect\.Field|Class\.forName', - 'input_case': 'exact' + 'regex1': (r'java\.lang\.reflect\.Method|' + r'java\.lang\.reflect\.Field|Class\.forName'), + 'input_case': 'exact', }, { 'desc': 'Crypto', 'type': 'regex', 'match': 'single_regex', 'regex1': r'javax\.crypto|kalium\.crypto|bouncycastle\.crypto', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Starting Activity', 'type': 'regex', 'match': 'single_regex', 'regex1': r'startActivity\(|startActivityForResult\(', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Starting Service', 'type': 'regex', 'match': 'single_regex', 'regex1': r'startService\(|bindService\(', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Sending Broadcast', 'type': 'regex', 'match': 'single_regex', - 'regex1': r'sendBroadcast\(|sendOrderedBroadcast\(|sendStickyBroadcast\(', - 'input_case': 'exact' + 'regex1': (r'sendBroadcast\(|' + r'sendOrderedBroadcast\(|sendStickyBroadcast\('), + 'input_case': 'exact', }, { 'desc': 'Local File I/O Operations', 'type': 'regex', 'match': 'single_regex', - 'regex1': r'OpenFileOutput|getSharedPreferences|SharedPreferences\.Editor|getCacheDir|getExternalStorageState|openOrCreateDatabase', - 'input_case': 'exact' + 'regex1': (r'OpenFileOutput|getSharedPreferences|' + r'SharedPreferences\.Editor|getCacheDir|' + r'getExternalStorageState|openOrCreateDatabase'), + 'input_case': 'exact', }, { 'desc': 'Inter Process Communication', 'type': 'regex', 'match': 'single_regex', 'regex1': r'IRemoteService|IRemoteService\.Stub|IBinder|Intent', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'HTTP Requests, Connections and Sessions', 'type': 'regex', 'match': 'single_regex', - 'regex1': r'http\.client\.HttpClient|net\.http\.AndroidHttpClient|http\.impl\.client\.AbstractHttpClient', - 'input_case': 'exact' + 'regex1': (r'http\.client\.HttpClient|net\.http\.AndroidHttpClient|' + r'http\.impl\.client\.AbstractHttpClient'), + 'input_case': 'exact', }, { 'desc': 'HTTP Connection', @@ -115,22 +128,23 @@ APIS = [ 'match': 'regex_and', 'regex1': r'HttpURLConnection|org\.apache\.http', 'regex2': r'openConnection|connect|HttpRequest', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Load and Manipulate Dex Files', 'type': 'regex', 'match': 'regex_and', - 'regex1': r'dalvik\.system\.PathClassLoader|dalvik\.system\.DexFile|dalvik\.system\.DexPathList', + 'regex1': (r'dalvik\.system\.PathClassLoader|' + r'dalvik\.system\.DexFile|dalvik\.system\.DexPathList'), 'regex2': r'loadDex|loadClass|DexClassLoader|loadDexFile', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Content Provider', 'type': 'string', 'match': 'single_string', 'string1': 'android.content.ContentProvider', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Obfuscation', @@ -138,7 +152,7 @@ APIS = [ 'match': 'string_and', 'string1': 'utils.AESObfuscator', 'string2': 'getObfuscator', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Execute OS Command', @@ -146,7 +160,7 @@ APIS = [ 'match': 'string_and', 'string1': 'getRuntime().exec(', 'string2': 'getRuntime(', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Android Keystore', @@ -154,16 +168,15 @@ APIS = [ 'match': 'string_and', 'string1': 'security.KeyStore', 'string2': 'Keystore.getInstance(', - 'input_case': 'exact' + 'input_case': 'exact', }, - { 'desc': 'TCP Server Socket', 'type': 'string', 'match': 'string_and', 'string1': 'ServerSocket', 'string2': 'net.ServerSocket', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'TCP Socket', @@ -171,7 +184,7 @@ APIS = [ 'match': 'string_and', 'string1': 'Socket', 'string2': 'net.Socket', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'UDP Datagram Packet', @@ -179,7 +192,7 @@ APIS = [ 'match': 'string_and', 'string1': 'DatagramPacket', 'string2': 'net.DatagramPacket', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'UDP Datagram Socket', @@ -187,7 +200,7 @@ APIS = [ 'match': 'string_and', 'string1': 'DatagramSocket', 'string2': 'net.DatagramSocket', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'WebView JavaScript Interface', @@ -196,7 +209,7 @@ APIS = [ 'string1': 'addJavascriptInterface', 'string2': 'WebView', 'string3': 'android.webkit', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'WebView GET Request', @@ -205,7 +218,7 @@ APIS = [ 'string1': 'WebView', 'string2': 'loadData', 'string3': 'android.webkit', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'WebView POST Request', @@ -214,7 +227,7 @@ APIS = [ 'string1': 'WebView', 'string2': 'postUrl', 'string3': 'android.webkit', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Android Notifications', @@ -222,7 +235,7 @@ APIS = [ 'match': 'string_and', 'string1': 'app.NotificationManager', 'string2': 'notify', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Get Cell Information', @@ -230,7 +243,7 @@ APIS = [ 'match': 'string_and', 'string1': 'telephony.TelephonyManager', 'string2': 'getAllCellInfo', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Get Cell Location', @@ -238,7 +251,7 @@ APIS = [ 'match': 'string_and', 'string1': 'telephony.TelephonyManager', 'string2': 'getCellLocation', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Get Subscriber ID', @@ -246,7 +259,7 @@ APIS = [ 'match': 'string_and', 'string1': 'telephony.TelephonyManager', 'string2': 'getSubscriberId', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Get Device ID, IMEI,MEID/ESN etc.', @@ -254,7 +267,7 @@ APIS = [ 'match': 'string_and', 'string1': 'telephony.TelephonyManager', 'string2': 'getDeviceId', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Get Software Version, IMEI/SV etc.', @@ -262,7 +275,7 @@ APIS = [ 'match': 'string_and', 'string1': 'telephony.TelephonyManager', 'string2': 'getDeviceSoftwareVersion', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Get SIM Serial Number', @@ -270,7 +283,7 @@ APIS = [ 'match': 'string_and', 'string1': 'telephony.TelephonyManager', 'string2': 'getSimSerialNumber', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Get SIM Provider Details', @@ -278,7 +291,7 @@ APIS = [ 'match': 'string_and', 'string1': 'telephony.TelephonyManager', 'string2': 'getSimOperator', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Get SIM Operator Name', @@ -286,7 +299,7 @@ APIS = [ 'match': 'string_and', 'string1': 'telephony.TelephonyManager', 'string2': 'getSimOperatorName', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Query Database of SMS, Contacts etc.', @@ -294,7 +307,7 @@ APIS = [ 'match': 'string_and', 'string1': 'content.ContentResolver', 'string2': 'query', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Query Database of SMS, Contacts etc.', @@ -302,7 +315,7 @@ APIS = [ 'match': 'string_and', 'string1': 'content.ContentResolver', 'string2': 'query', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Base64 Decode', @@ -310,7 +323,7 @@ APIS = [ 'match': 'string_and', 'string1': 'android.util.Base64', 'string2': '.decode', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Send SMS', @@ -320,7 +333,7 @@ APIS = [ 'string_or1': 'sendMultipartTextMessage', 'string_or2': 'sendTextMessage', 'string_or3': 'vnd.android-dir/mms-sms', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'URL Connection to file/http/https/ftp/jar', @@ -330,7 +343,7 @@ APIS = [ 'string_or1': 'openConnection', 'string_or2': 'connect', 'string_or3': 'openStream', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'JAR URL Connection', @@ -339,7 +352,7 @@ APIS = [ 'string1': 'net.JarURLConnection', 'string_or1': 'JarURLConnection', 'string_or2': 'jar:', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'HTTPS Connection', @@ -348,7 +361,7 @@ APIS = [ 'string1': 'javax.net.ssl.HttpsURLConnection', 'string_or1': 'HttpsURLConnection', 'string_or2': 'connect', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'URL Connection supports file,http,https,ftp and jar', @@ -357,7 +370,7 @@ APIS = [ 'string1': 'net.URL', 'string_or1': 'openConnection', 'string_or2': 'openStream', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Set or Read Clipboard data', @@ -366,7 +379,7 @@ APIS = [ 'string1': 'content.ClipboardManager', 'string_or1': 'CLIPBOARD_SERVICE', 'string_or2': 'ClipboardManager', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Base64 Encode', @@ -375,7 +388,7 @@ APIS = [ 'string1': 'android.util.Base64', 'string_or1': '.encodeToString', 'string_or2': '.encode', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Base64 Encode', @@ -384,7 +397,7 @@ APIS = [ 'string1': 'android.util.Base64', 'string_or1': '.encodeToString', 'string_or2': '.encode', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Message Digest', @@ -393,7 +406,7 @@ APIS = [ 'string1': 'java.security.MessageDigest', 'string_or1': 'MessageDigestSpi', 'string_or2': 'MessageDigest', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'GPS Location', @@ -404,6 +417,6 @@ APIS = [ 'string_or2': 'requestLocationUpdates(', 'string_or3': 'getLatitude(', 'string_or4': 'getLongitude(', - 'input_case': 'exact' + 'input_case': 'exact', }, ] diff --git a/StaticAnalyzer/views/android/android_manifest_desc.py b/StaticAnalyzer/views/android/android_manifest_desc.py index 868d66f2..fa854cf6 100644 --- a/StaticAnalyzer/views/android/android_manifest_desc.py +++ b/StaticAnalyzer/views/android/android_manifest_desc.py @@ -1,272 +1,705 @@ MANIFEST_DESC = { - 'a_debuggable': { - 'title': 'Debug Enabled For App
[android:debuggable=true]', - 'level': 'high', - 'description': '''Debugging was enabled on the app which makes it easier for reverse engineers to hook a debugger to it. This allows dumping a stack trace and accessing debugging helper classes.''', - 'name': 'Debug Enabled For App [android:debuggable=true]' - }, - 'a_allowbackup': { - 'title': 'Application Data can be Backed up
[android:allowBackup=true]', - 'level': 'medium', - 'description': '''This flag allows anyone to backup your application data via adb. It allows users who have enabled USB debugging to copy application data off of the device.''', - 'name': 'Application Data can be Backed up [android:allowBackup=true]' - }, - 'a_allowbackup_miss': { - 'title': 'Application Data can be Backed up
[android:allowBackup] flag is missing.', - 'level': 'medium', - 'description': 'The flag [android:allowBackup] should be set to false. By default it is set to true and allows anyone to backup your application data via adb. It allows users who have enabled USB debugging to copy application data off of the device.''', - 'name': 'Application Data can be Backed up [android:allowBackup] flag is missing.' - }, - 'a_testonly': { - 'title': 'Application is in Test Mode
[android:testOnly=true]', - 'level': 'high', - 'description': ' It may expose functionality or data outside of itself that would cause a security hole.', - 'name': 'Application is in Test Mode [android:testOnly=true]', - }, - 'a_taskaffinity': { - 'title': 'TaskAffinity is set for Activity
(%s)', - 'level': 'high', - 'description': 'If taskAffinity is set, then other application could read the Intents sent to Activities belonging to another task. Always use the default setting keeping the affinity as the package name in order to prevent sensitive information inside sent or received Intents from being read by another application.', - 'name': 'TaskAffinity is set for Activity' - }, - 'a_launchmode': { - 'title': 'Launch Mode of Activity (%s) is not standard.', - 'level': 'high', - 'description': 'An Activity should not be having the launch mode attribute set to "singleTask/singleInstance" as it becomes root Activity and it is possible for other applications to read the contents of the calling Intent. So it is required to use the "standard" launch mode attribute when sensitive information is included in an Intent.', - 'name': 'Launch Mode of Activity is not standard.' - }, - 'a_prot_sign': { - 'title': '%s (%s) is Protected by a permission.
%s
[android:exported=true]', - 'level': 'info', - 'description': 'A%s %s is found to be exported, but is protected by permission.', - 'name': 'is Protected by a permission.[android:exported=true]' - }, - 'a_prot_normal': { - 'title': '%s (%s) is Protected by a permission, but the protection level of the permission should be checked.
%s
[android:exported=true]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by a permission. However, the protection level of the permission is set to normal. This means that a malicious application can request and obtain the permission and interact with the component. If it was set to signature, only applications signed with the same certificate could obtain the permission.', - 'name': 'is Protected by a permission, but the protection level of the permission should be checked.[android:exported=true]' - }, - 'a_prot_danger': { - 'title': '%s (%s) is Protected by a permission, but the protection level of the permission should be checked.
%s
[android:exported=true]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by a permission. However, the protection level of the permission is set to dangerous. This means that a malicious application can request and obtain the permission and interact with the component. If it was set to signature, only applications signed with the same certificate could obtain the permission.', - 'name': 'is Protected by a permission, but the protection level of the permission should be checked.[android:exported=true]' - }, - 'a_prot_sign_sys': { - 'title': '%s (%s) is Protected by a permission, but the protection level of the permission should be checked.
%s
[android:exported=true]', - 'level': 'info', - 'description': 'A%s %s is found to be exported, but is protected by a permission. However, the protection level of the permission is set to signatureOrSystem. It is recommended that signature level is used instead. Signature level should suffice for most purposes, and does not depend on where the applications are installed on the device.', - 'name': 'is Protected by a permission, but the protection level of the permission should be checked.[android:exported=true]' - }, - 'a_prot_unknown': { - 'title': '%s (%s) is Protected by a permission, but the protection level of the permission should be checked.
%s
[android:exported=true]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by a permission which is not defined in the analysed application. As a result, the protection level of the permission should be checked where it is defined. If it is set to normal or dangerous, a malicious application can request and obtain the permission and interact with the component. If it is set to signature, only applications signed with the same certificate can obtain the permission.', - 'name': 'is Protected by a permission, but the protection level of the permission should be checked.[android:exported=true]' - }, - 'a_prot_normal_appl': { - 'title': '%s (%s) is Protected by a permission at the application level, but the protection level of the permission should be checked.
%s
[android:exported=true]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by a permission at the application level. However, the protection level of the permission is set to normal. This means that a malicious application can request and obtain the permission and interact with the component. If it was set to signature, only applications signed with the same certificate could obtain the permission.', - 'name': 'is Protected by a permission at the application level, but the protection level of the permission should be checked.[android:exported=true]' - }, - 'a_prot_danger_appl': { - 'title': '%s (%s) is Protected by a permission at the application level, but the protection level of the permission should be checked.
%s
[android:exported=true]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by a permission at the application level. However, the protection level of the permission is set to dangerous. This means that a malicious application can request and obtain the permission and interact with the component. If it was set to signature, only applications signed with the same certificate could obtain the permission.', - 'name': 'is Protected by a permission at the application level, but the protection level of the permission should be checked.[android:exported=true]' - }, - 'a_prot_sign_appl': { - 'title': '%s (%s) Protected by a permission at the application level.
%s
[android:exported=true]', - 'level': 'info', - 'description': 'A%s %s is found to be exported, but is protected by a permission at the application level.', - 'name': ' Protected by a permission at the application level.[android:exported=true]' - }, - 'a_prot_sign_sys_appl': { - 'title': '%s (%s) is Protected by a permission at the application level, but the protection level of the permission should be checked.
%s
[android:exported=true]', - 'level': 'info', - 'description': 'A%s %s is found to be exported, but is protected by a permission at the application level. However, the protection level of the permission is set to signatureOrSystem. It is recommended that signature level is used instead. Signature level should suffice for most purposes, and does not depend on where the applications are installed on the device.', - 'name': 'is Protected by a permission at the application level, but the protection level of the permission should be checked.[android:exported=true]' - }, - 'a_prot_unknown_appl': { - 'title': '%s (%s) is Protected by a permission at the application, but the protection level of the permission should be checked.
%s
[android:exported=true]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by a permission at the application level which is not defined in the analysed application. As a result, the protection level of the permission should be checked where it is defined. If it is set to normal or dangerous, a malicious application can request and obtain the permission and interact with the component. If it is set to signature, only applications signed with the same certificate can obtain the permission.', - 'name': 'is Protected by a permission at the application, but the protection level of the permission should be checked.[android:exported=true]' - }, - 'a_not_protected': { - 'title': '%s (%s) is not Protected.
[android:exported=true]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device.', - 'name': 'is not Protected. [android:exported=true]' - }, - 'a_not_protected_filter': { - 'title': '%s (%s) is not Protected.
An intent-filter exists.', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. The presence of intent-filter indicates that the %s is explicitly exported.', - 'name': 'is not Protected.An intent-filter exists.' - }, - 'c_not_protected': { - 'title': '%s (%s) is not Protected.
[[Content Provider, targetSdkVersion < 17]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is a Content Provider that targets an API level under 17, which makes it exported by default, regardless of the API level of the system that the application runs on.', - 'name': 'is not Protected.[[Content Provider, targetSdkVersion < 17]' - }, - 'c_not_protected2': { - 'title': '%s (%s) would not be Protected if the application ran on a device where the the API level was less than 17.
[Content Provider, targetSdkVersion >= 17]', - 'level': 'high', - 'description': 'The Content Provider(%s %s) would be exported if the application ran on a device where the the API level was less than 17. In that situation, it would be shared with other apps on the device therefore leaving it accessible to any other application on the device.', - 'name': 'would not be Protected if the application ran on a device where the the API level was less than 17.[Content Provider, targetSdkVersion >= 17]' - }, - 'c_prot_normal': { - 'title': '%s (%s) is Protected by a permission, but the protection level of the permission should be checked.
%s
[Content Provider, targetSdkVersion < 17]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by a permission. However, the protection level of the permission is set to normal. This means that a malicious application can request and obtain the permission and interact with the component. If it was set to signature, only applications signed with the same certificate could obtain the permission.', - 'name': 'is Protected by a permission, but the protection level of the permission should be checked.[Content Provider, targetSdkVersion < 17]' - }, - 'c_prot_danger': { - 'title': '%s (%s) is Protected by a permission, but the protection level of the permission should be checked.
%s
[Content Provider, targetSdkVersion < 17]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by a permission. However, the protection level of the permission is set to dangerous. This means that a malicious application can request and obtain the permission and interact with the component. If it was set to signature, only applications signed with the same certificate could obtain the permission.', - 'name': 'is Protected by a permission, but the protection level of the permission should be checked.[Content Provider, targetSdkVersion < 17]' - }, - 'c_prot_sign': { - 'title': '%s (%s) is Protected by a permission.
%s
[Content Provider, targetSdkVersion < 17]', - 'level': 'info', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by permission.', - 'name': 'is Protected by a permission.[Content Provider, targetSdkVersion < 17]' - }, - 'c_prot_sign_sys': { - 'title': '%s (%s) is Protected by a permission, but the protection level of the permission should be checked.
%s
[Content Provider, targetSdkVersion < 17]', - 'level': 'info', - 'description': 'A%s %s is found to be exported, but is protected by a permission. However, the protection level of the permission is set to signatureOrSystem. It is recommended that signature level is used instead. Signature level should suffice for most purposes, and does not depend on where the applications are installed on the device.', - 'name': 'is Protected by a permission, but the protection level of the permission should be checked.[Content Provider, targetSdkVersion < 17]' - }, - 'c_prot_unknown': { - 'title': '%s (%s) is Protected by a permission, but the protection level of the permission should be checked.
%s
[Content Provider, targetSdkVersion < 17]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by a permission which is not defined in the analysed application. As a result, the protection level of the permission should be checked where it is defined. If it is set to normal or dangerous, a malicious application can request and obtain the permission and interact with the component. If it is set to signature, only applications signed with the same certificate can obtain the permission.', - 'name': 'is Protected by a permission, but the protection level of the permission should be checked.[Content Provider, targetSdkVersion < 17]' - }, - 'c_prot_normal_appl': { - 'title': '%s (%s) is Protected by a permission at the application level, but the protection level of the permission should be checked.
%s
[Content Provider, targetSdkVersion < 17]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by a permission at the application level. However, the protection level of the permission is set to normal. This means that a malicious application can request and obtain the permission and interact with the component. If it was set to signature, only applications signed with the same certificate could obtain the permission.', - 'name': 'is Protected by a permission at the application level, but the protection level of the permission should be checked.[Content Provider, targetSdkVersion < 17]' - }, - 'c_prot_danger_appl': { - 'title': '%s (%s) is Protected by a permission at the application level, but the protection level of the permission should be checked.
%s
[Content Provider, targetSdkVersion < 17]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by a permission at the application level. However, the protection level of the permission is set to dangerous. This means that a malicious application can request and obtain the permission and interact with the component. If it was set to signature, only applications signed with the same certificate could obtain the permission.', - 'name': 'is Protected by a permission at the application level, but the protection level of the permission should be checked.[Content Provider, targetSdkVersion < 17]' - }, - 'c_prot_sign_appl': { - 'title': '%s (%s) is Protected by a permission at the application level.
%s
[Content Provider, targetSdkVersion < 17]', - 'level': 'info', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by permission at the application level.', - 'name': 'is Protected by a permission at the application level.[Content Provider, targetSdkVersion < 17]' - }, - 'c_prot_sign_sys_appl': { - 'title': '%s (%s) is Protected by a permission at the application level, but the protection level of the permission should be checked.
%s
[Content Provider, targetSdkVersion < 17]', - 'level': 'info', - 'description': 'A%s %s is found to be exported, but is protected by a permission at the application level. However, the protection level of the permission is set to signatureOrSystem. It is recommended that signature level is used instead. Signature level should suffice for most purposes, and does not depend on where the applications are installed on the device.', - 'name': 'is Protected by a permission at the application level, but the protection level of the permission should be checked.[Content Provider, targetSdkVersion < 17]' - }, - 'c_prot_unknown_appl': { - 'title': '%s (%s) is Protected by a permission at application level, but the protection level of the permission should be checked.
%s
[Content Provider, targetSdkVersion < 17]', - 'level': 'high', - 'description': 'A%s %s is found to be shared with other apps on the device therefore leaving it accessible to any other application on the device. It is protected by a permission at application level which is not defined in the analysed application. As a result, the protection level of the permission should be checked where it is defined. If it is set to normal or dangerous, a malicious application can request and obtain the permission and interact with the component. If it is set to signature, only applications signed with the same certificate can obtain the permission.', - 'name': 'is Protected by a permission at application level, but the protection level of the permission should be checked.[Content Provider, targetSdkVersion < 17]' - }, - 'c_prot_normal_new': { - 'title': '%s (%s) is Protected by a permission, but the protection level of the permission should be checked if the application runs on a device where the the API level is less than 17
%s
[Content Provider, targetSdkVersion >= 17]', - 'level': 'high', - 'description': 'The Content Provider (%s) would be exported if the application ran on a device where the the API level was less than 17. In that situation, it would still be protected by a permission. However, the protection level of the permission is set to normal. This means that a malicious application could request and obtain the permission and interact with the component. If it was set to signature, only applications signed with the same certificate could obtain the permission.', - 'name': 'is Protected by a permission, but the protection level of the permission should be checked if the application runs on a device where the the API level is less than 17 [Content Provider, targetSdkVersion >= 17]' - }, - 'c_prot_danger_new': { - 'title': '%s (%s) is Protected by a permission, but the protection level of the permission should be checked if the application runs on a device where the the API level is less than 17.
%s
[Content Provider, targetSdkVersion >= 17]', - 'level': 'high', - 'description': 'The Content Provider(%s) would be exported if the application ran on a device where the the API level was less than 17. In that situation, it would still be protected by a permission. However, the protection level of the permission is set to dangerous. This means that a malicious application could request and obtain the permission and interact with the component. If it was set to signature, only applications signed with the same certificate could obtain the permission.', - 'name': 'is Protected by a permission, but the protection level of the permission should be checked if the application runs on a device where the the API level is less than 17.[Content Provider, targetSdkVersion >= 17]' - }, - 'c_prot_sign_new': { - 'title': '%s (%s) is Protected by a permission.
%s
[Content Provider, targetSdkVersion >= 17]', - 'level': 'info', - 'description': 'The Content Provider(%s) would be exported if the application ran on a device where the the API level was less than 17. Nevertheless, it is protected by a permission.', - 'name': 'is Protected by a permission.[Content Provider, targetSdkVersion >= 17]' - }, - 'c_prot_sign_sys_new': { - 'title': '%s (%s) is Protected by a permission, but the protection level of the permission should be checked.
%s
[Content Provider, targetSdkVersion >= 17]', - 'level': 'info', - 'description': 'The Content Provider(%s) would be exported if the application ran on a device where the API level was less than 17. In that situation, it would still be protected by a permission. However, the protection level of the permission is set to signatureOrSystem. It is recommended that signature level is used instead. Signature level should suffice for most purposes, and does not depend on where the applications are installed on the device.', - 'name': 'is Protected by a permission, but the protection level of the permission should be checked.[Content Provider, targetSdkVersion >= 17]' - }, - 'c_prot_unknown_new': { - 'title': '%s (%s) is Protected by a permission, but the protection level of the permission should be checked if the application runs on a device where the the API level is less than 17.
%s
[Content Provider, targetSdkVersion >= 17]', - 'level': 'high', - 'description': 'The Content Provider(%s) would be exported if the application ran on a device where the the API level was less than 17. In that situation, it would still be protected by a permission which is not defined in the analysed application. As a result, the protection level of the permission should be checked where it is defined. If it is set to normal or dangerous, a malicious application can request and obtain the permission and interact with the component. If it is set to signature, only applications signed with the same certificate can obtain the permission.', - 'name': 'is Protected by a permission, but the protection level of the permission should be checked if the application runs on a device where the the API level is less than 17.[Content Provider, targetSdkVersion >= 17]' - }, - 'c_prot_normal_new_appl': { - 'title': '%s (%s) is Protected by a permission at the application level, but the protection level of the permission should be checked if the application runs on a device where the the API level is less than 17
%s
[Content Provider, targetSdkVersion >= 17]', - 'level': 'high', - 'description': 'The Content Provider (%s) would be exported if the application ran on a device where the the API level was less than 17. In that situation, it would still be protected by a permission. However, the protection level of the permission is set to normal. This means that a malicious application could request and obtain the permission and interact with the component. If it was set to signature, only applications signed with the same certificate could obtain the permission.', - 'name': 'is Protected by a permission at the application level, but the protection level of the permission should be checked if the application runs on a device where the the API level is less than 17.[Content Provider, targetSdkVersion >= 17]' - }, - 'c_prot_danger_new_appl': { - 'title': '%s (%s) is Protected by a permission at the application level, but the protection level of the permission should be checked if the application runs on a device where the the API level is less than 17.
%s
[Content Provider, targetSdkVersion >= 17]', - 'level': 'high', - 'description': 'The Content Provider(%s) would be exported if the application ran on a device where the the API level was less than 17. In that situation, it would still be protected by a permission. However, the protection level of the permission is set to dangerous. This means that a malicious application could request and obtain the permission and interact with the component. If it was set to signature, only applications signed with the same certificate could obtain the permission.', - 'name': 'is Protected by a permission at the application level, but the protection level of the permission should be checked if the application runs on a device where the the API level is less than 17.[Content Provider, targetSdkVersion >= 17]' - }, - 'c_prot_sign_new_appl': { - 'title': '%s (%s) is Protected by a permission at the application level.
%s
[Content Provider, targetSdkVersion >= 17]', - 'level': 'info', - 'description': 'The Content Provider(%s) would be exported if the application ran on a device where the the API level was less than 17. Nevertheless, it is protected by a permission.', - 'name': 'is Protected by a permission at the application level.[Content Provider, targetSdkVersion >= 17]' - }, - 'c_prot_sign_sys_new_appl': { - 'title': '%s (%s) is Protected by a permission at the application level, but the protection level of the permission should be checked.
%s
[Content Provider, targetSdkVersion >= 17]', - 'level': 'info', - 'description': 'The Content Provider(%s) would be exported if the application ran on a device where the API level was less than 17. In that situation, it would still be protected by a permission. However, the protection level of the permission is set to signatureOrSystem. It is recommended that signature level is used instead. Signature level should suffice for most purposes, and does not depend on where the applications are installed on the device.', - 'name': 'is Protected by a permission at the application level, but the protection level of the permission should be checked.[Content Provider, targetSdkVersion >= 17]' - }, - 'c_prot_unknown_new_appl': { - 'title': '%s (%s) is Protected by a permission at the application level, but the protection level of the permission should be checked if the application runs on a device where the the API level is less than 17.
%s
[Content Provider, targetSdkVersion >= 17]', - 'level': 'high', - 'description': 'The Content Provider(%s) would be exported if the application ran on a device where the the API level was less than 17. In that situation, it would still be protected by a permission which is not defined in the analysed application. As a result, the protection level of the permission should be checked where it is defined. If it is set to normal or dangerous, a malicious application can request and obtain the permission and interact with the component. If it is set to signature, only applications signed with the same certificate can obtain the permission.', - 'name': 'is Protected by a permission at the application level, but the protection level of the permission should be checked if the application runs on a device where the the API level is less than 17.[Content Provider, targetSdkVersion >= 17]' - }, - 'a_improper_provider': { - 'title': 'Improper Content Provider Permissions
[%s]', - 'level': 'high', - 'description': 'A content provider permission was set to allows access from any other app on the device. Content providers may contain sensitive information about an app and therefore should not be shared.', - 'name': 'Improper Content Provider Permissions' - }, - 'a_dailer_code': { - 'title': 'Dailer Code: %s Found
[android:scheme="android_secret_code"]', - 'level': 'high', - 'description': 'A secret code was found in the manifest. These codes, when entered into the dialer grant access to hidden content that may contain sensitive information.', - 'name': 'Dailer Code: Found
[android:scheme="android_secret_code"]' - }, - 'a_sms_receiver_port': { - 'title': 'Data SMS Receiver Set on Port: %s Found
[android:port]', - 'level': 'high', - 'description': 'A binary SMS recevier is configured to listen on a port. Binary SMS messages sent to a device are processed by the application in whichever way the developer choses. The data in this SMS should be properly validated by the application. Furthermore, the application should assume that the SMS being received is from an untrusted source."', - 'name': 'Data SMS Receiver Set on Port: Found
[android:port]' - }, - 'a_high_intent_priority': { - 'title': 'High Intent Priority (%s)
[android:priority]', - 'level': 'medium', - 'description': 'By setting an intent priority higher than another intent, the app effectively overrides other requests.', - 'name': 'High Intent Priority [android:priority]' - }, - 'a_high_action_priority': { - 'title': 'High Action Priority (%s)
[android:priority] ', - 'level': 'medium', - 'description': 'By setting an action priority higher than another action, the app effectively overrides other requests.', - 'name': 'High Action Priority [android:priority] ' - }, - } \ No newline at end of file + 'a_debuggable': { + 'title': 'Debug Enabled For App
[android:debuggable=true]', + 'level': 'high', + 'description': ('Debugging was enabled on the app which makes it ' + 'easier for reverse engineers to hook a debugger to' + ' it. This allows dumping a stack trace and accessing' + ' debugging helper classes.'), + 'name': 'Debug Enabled For App [android:debuggable=true]', + }, + 'a_allowbackup': { + 'title': ('Application Data can be Backed up' + '
[android:allowBackup=true]'), + 'level': 'medium', + 'description': ('This flag allows anyone to backup your application' + ' data via adb. It allows users who have enabled USB' + ' debugging to copy application data off of the' + ' device.'), + 'name': 'Application Data can be Backed up [android:allowBackup=true]', + }, + 'a_allowbackup_miss': { + 'title': ('Application Data can be Backed up
[android:allowBackup]' + ' flag is missing.'), + 'level': 'medium', + 'description': ('The flag [android:allowBackup] should be set to false' + '. By default it is set to true and allows anyone to ' + 'backup your application data via adb. It allows users' + ' who have enabled USB debugging to copy application ' + 'data off of the device.'), + 'name': ('Application Data can be Backed up [android:allowBackup] flag' + ' is missing.'), + }, + 'a_testonly': { + 'title': 'Application is in Test Mode
[android:testOnly=true]', + 'level': 'high', + 'description': ('It may expose functionality or data outside of itself' + ' that would cause a security hole.'), + 'name': 'Application is in Test Mode [android:testOnly=true]', + }, + 'a_taskaffinity': { + 'title': 'TaskAffinity is set for Activity
(%s)', + 'level': 'high', + 'description': ('If taskAffinity is set, then other application' + ' could read the Intents sent to Activities ' + 'belonging to another task. Always use the default' + ' setting keeping the affinity as the package name' + ' in order to prevent sensitive information inside' + ' sent or received Intents from being read by ' + 'another application.'), + 'name': 'TaskAffinity is set for Activity', + }, + 'a_launchmode': { + 'title': 'Launch Mode of Activity (%s) is not standard.', + 'level': 'high', + 'description': ('An Activity should not be having the launch mode' + ' attribute set to "singleTask/singleInstance" as ' + 'it becomes root Activity and it is possible for' + ' other applications to read the contents of the' + ' calling Intent. So it is required to use the' + ' "standard" launch mode attribute when sensitive' + ' information is included in an Intent.'), + 'name': 'Launch Mode of Activity is not standard.', + }, + 'a_prot_sign': { + 'title': ('%s (%s) is Protected by a permission.' + '
%s
[android:exported=true]'), + 'level': 'info', + 'description': ('A%s %s is found to be exported, but' + ' is protected by permission.'), + 'name': 'is Protected by a permission.[android:exported=true]', + }, + 'a_prot_normal': { + 'title': ('%s (%s) is Protected by a permission, but' + ' the protection level of the permission should be checked.' + '
%s
[android:exported=true]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other' + ' application on the device. It is protected by a ' + 'permission. However, the protection level of the' + ' permission is set to normal. This means that a ' + 'malicious application can request and obtain' + ' the permission and interact with the component.' + ' If it was set to signature, only applications ' + 'signed with the same certificate could obtain ' + 'the permission.'), + 'name': ('is Protected by a permission, but the protection level of ' + 'the permission should be checked.[android:exported=true]'), + }, + 'a_prot_danger': { + 'title': ('%s (%s) is Protected by a permission, but' + ' the protection level of the permission should be checked.' + '
%s
[android:exported=true]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other' + ' application on the device. It is protected by a' + ' permission. However, the protection level of the' + ' permission is set to dangerous. This means that a' + ' malicious application can request and obtain the' + ' permission and interact with the component. If it' + ' was set to signature, only applications signed with' + ' the same certificate could obtain the permission.'), + 'name': ('is Protected by a permission, but the protection level of' + ' the permission should be checked.[android:exported=true]'), + }, + 'a_prot_sign_sys': { + 'title': ('%s (%s) is Protected by a permission, but' + ' the protection level of the permission should be checked.' + '
%s
[android:exported=true]'), + 'level': 'info', + 'description': ('A%s %s is found to be exported, but is protected by' + ' a permission. However, the protection level of the' + ' permission is set to signatureOrSystem. It is ' + 'recommended that signature level is used instead. ' + 'Signature level should suffice for most purposes, ' + 'and does not depend on where the applications are ' + 'installed on the device.'), + 'name': ('is Protected by a permission, but the protection level of' + ' the permission should be checked.[android:exported=true]'), + }, + 'a_prot_unknown': { + 'title': ('%s (%s) is Protected by a permission, but' + ' the protection level of the permission should be checked.' + '
%s
[android:exported=true]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other' + ' application on the device. It is protected by a ' + 'permission which is not defined in the analysed ' + 'application. As a result, the protection level of the' + ' permission should be checked where it is defined. If' + ' it is set to normal or dangerous, a malicious ' + 'application can request and obtain the permission and' + ' interact with the component. If it is set to ' + 'signature, only applications signed with the same ' + 'certificate can obtain the permission.'), + 'name': ('is Protected by a permission, but the protection level ' + 'of the permission should be ' + 'checked.[android:exported=true]'), + }, + 'a_prot_normal_appl': { + 'title': ('%s (%s) is Protected by a permission at' + ' the application level, but the protection level of the ' + 'permission should be checked.
%s
' + '[android:exported=true]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other' + ' application on the device. It is protected by a ' + 'permission at the application level. However, the' + ' protection level of the permission is set to normal.' + ' This means that a malicious application can request ' + 'and obtain the permission and interact with the ' + 'component. If it was set to signature, only ' + 'applications signed with the same certificate ' + 'could obtain the permission.'), + 'name': ('is Protected by a permission at the application level,' + ' but the protection level of the permission should be ' + 'checked.[android:exported=true]'), + }, + 'a_prot_danger_appl': { + 'title': ('%s (%s) is Protected by a permission at' + ' the application level, but the protection level of the ' + 'permission should be checked.' + '
%s
[android:exported=true]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other' + ' application on the device. It is protected by a ' + 'permission at the application level. However, the ' + 'protection level of the permission is set to ' + 'dangerous. This means that a malicious application ' + 'can request and obtain the permission and interact ' + 'with the component. If it was set to signature, ' + 'only applications signed with the same certificate' + ' could obtain the permission.'), + 'name': ('is Protected by a permission at the application level, but' + ' the protection level of the permission should be ' + 'checked.[android:exported=true]'), + }, + 'a_prot_sign_appl': { + 'title': ('%s (%s) Protected by a permission at' + ' the application level.
%s
[android:exported=true]'), + 'level': 'info', + 'description': ('A%s %s is found to be exported, but is protected by' + ' a permission at the application level.'), + 'name': ('Protected by a permission at the application level.' + '[android:exported=true]'), + }, + 'a_prot_sign_sys_appl': { + 'title': ('%s (%s) is Protected by a permission at ' + 'the application level, but the protection level of the ' + 'permission should be checked.' + '
%s
[android:exported=true]'), + 'level': 'info', + 'description': ('A%s %s is found to be exported, but is protected ' + 'by a permission at the application level. However,' + ' the protection level of the permission is set to' + ' signatureOrSystem. It is recommended that ' + 'signature level is used instead. Signature level' + ' should suffice for most purposes, and does not ' + 'depend on where the applications are installed' + ' on the device.'), + 'name': ('is Protected by a permission at the application level, but' + ' the protection level of the permission should be checked.' + '[android:exported=true]'), + }, + 'a_prot_unknown_appl': { + 'title': ('%s (%s) is Protected by a permission' + ' at the application, but the protection level of the ' + 'permission should be checked.' + '
%s
[android:exported=true]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on ' + 'the device therefore leaving it accessible to any' + ' other application on the device. It is protected' + ' by a permission at the application level which is' + ' not defined in the analysed application. As a' + ' result, the protection level of the permission' + ' should be checked where it is defined. If it is' + ' set to normal or dangerous, a malicious application' + ' can request and obtain the permission and interact' + ' with the component. If it is set to signature, only' + ' applications signed with the same certificate can' + ' obtain the permission.'), + 'name': ('is Protected by a permission at the application, but the' + ' protection level of the permission should be checked.' + '[android:exported=true]'), + }, + 'a_not_protected': { + 'title': ('%s (%s) is not Protected.' + '
[android:exported=true]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other' + ' application on the device.'), + 'name': 'is not Protected. [android:exported=true]', + }, + 'a_not_protected_filter': { + 'title': ('%s (%s) is not Protected.
' + 'An intent-filter exists.'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other ' + 'application on the device. The presence of ' + 'intent-filter indicates that the %s' + ' is explicitly exported.'), + 'name': 'is not Protected.An intent-filter exists.', + }, + 'c_not_protected': { + 'title': ('%s (%s) is not Protected.
' + '[[Content Provider, targetSdkVersion < 17]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps' + ' on the device therefore leaving it accessible ' + 'to any other application on the device. It is ' + 'a Content Provider that targets an API level ' + 'under 17, which makes it exported by default,' + ' regardless of the API level of the system ' + 'that the application runs on.'), + 'name': 'is not Protected.[[Content Provider, targetSdkVersion < 17]', + }, + 'c_not_protected2': { + 'title': ('%s (%s) would not be Protected if the' + ' application ran on a device where the the API level was' + ' less than 17.
[Content Provider, ' + 'targetSdkVersion >= 17]'), + 'level': 'high', + 'description': ('The Content Provider(%s %s) would be exported if the' + ' application ran on a device where the the API level ' + 'was less than 17. In that situation, it would be ' + 'shared with other apps on the device therefore ' + 'leaving it accessible to any other application ' + 'on the device.'), + 'name': ('would not be Protected if the application ran on a device' + ' where the the API level was less than 17.[Content Provider,' + ' targetSdkVersion >= 17]'), + }, + 'c_prot_normal': { + 'title': ('%s (%s) is Protected by a permission, but' + ' the protection level of the permission should be checked.' + '
%s
[Content Provider, targetSdkVersion < 17]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other' + ' application on the device. It is protected by a ' + 'permission. However, the protection level of the' + ' permission is set to normal. This means that a ' + 'malicious application can request and obtain ' + 'the permission and interact with the component. ' + 'If it was set to signature, only applications signed ' + 'with the same certificate could obtain ' + 'the permission.'), + 'name': ('is Protected by a permission, but the protection level' + ' of the permission should be checked.[Content Provider,' + ' targetSdkVersion < 17]'), + }, + 'c_prot_danger': { + 'title': ('%s (%s) is Protected by a permission, ' + 'but the protection level of the permission should be ' + 'checked.
%s
[Content Provider, ' + 'targetSdkVersion < 17]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other' + ' application on the device. It is protected by a ' + 'permission. However, the protection level of the ' + 'permission is set to dangerous. This means that a ' + 'malicious application can request and obtain the ' + 'permission and interact with the component. If it' + ' was set to signature, only applications signed with' + ' the same certificate could obtain ' + 'the permission.'), + 'name': ('is Protected by a permission, but the protection level of ' + 'the permission should be checked.[Content Provider, ' + 'targetSdkVersion < 17]'), + }, + 'c_prot_sign': { + 'title': ('%s (%s) is Protected by a permission.' + '
%s
[Content Provider, targetSdkVersion < 17]'), + 'level': 'info', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other' + ' application on the device. It is ' + 'protected by permission.'), + 'name': ('is Protected by a permission.[Content Provider, ' + 'targetSdkVersion < 17]'), + }, + 'c_prot_sign_sys': { + 'title': ('%s (%s) is Protected by a permission,' + ' but the protection level of the permission should be ' + 'checked.
%s
[Content Provider, ' + 'targetSdkVersion < 17]'), + 'level': 'info', + 'description': ('A%s %s is found to be exported, but is protected by' + ' a permission. However, the protection level of the' + ' permission is set to signatureOrSystem. It is' + ' recommended that signature level is used instead.' + ' Signature level should suffice for most purposes,' + ' and does not depend on where the applications are' + ' installed on the device.'), + 'name': ('is Protected by a permission, but the protection level of ' + 'the permission should be checked.[Content Provider, ' + 'targetSdkVersion < 17]'), + }, + 'c_prot_unknown': { + 'title': ('%s (%s) is Protected by a permission, but' + ' the protection level of the permission should be checked.' + '
%s
[Content Provider, targetSdkVersion < 17]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the ' + 'device therefore leaving it accessible to any other ' + 'application on the device. It is protected by a ' + 'permission which is not defined in the analysed ' + 'application. As a result, the protection level of the' + ' permission should be checked where it is defined. If' + ' it is set to normal or dangerous, a malicious ' + 'application can request and obtain the permission and' + ' interact with the component. If it is set to ' + 'signature, only applications signed with the same ' + 'certificate can obtain the permission.'), + 'name': ('is Protected by a permission, but the protection level of' + ' the permission should be checked.[Content Provider,' + ' targetSdkVersion < 17]'), + }, + 'c_prot_normal_appl': { + 'title': ('%s (%s) is Protected by a permission at' + ' the application level, but the protection level of the' + ' permission should be checked.' + '
%s
[Content Provider, targetSdkVersion < 17]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other' + ' application on the device. It is protected by a' + ' permission at the application level. However, the' + ' protection level of the permission is set to normal.' + ' This means that a malicious application can request' + ' and obtain the permission and interact with the' + ' component. If it was set to signature, only ' + 'applications signed with the same certificate could' + ' obtain the permission.'), + 'name': ('is Protected by a permission at the application level, but' + ' the protection level of the permission should be checked.' + '[Content Provider, targetSdkVersion < 17]'), + }, + 'c_prot_danger_appl': { + 'title': ('%s (%s) is Protected by a permission at ' + 'the application level, but the protection level of the ' + 'permission should be checked.' + '
%s
[Content Provider, targetSdkVersion < 17]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other' + ' application on the device. It is protected by a ' + 'permission at the application level. However, the ' + 'protection level of the permission is set to ' + 'dangerous. This means that a malicious application' + ' can request and obtain the permission and interact' + ' with the component. If it was set to signature, ' + 'only applications signed with the same certificate' + ' could obtain the permission.'), + 'name': ('is Protected by a permission at the application level, but' + ' the protection level of the permission should be checked.' + '[Content Provider, targetSdkVersion < 17]'), + }, + 'c_prot_sign_appl': { + 'title': ('%s (%s) is Protected by a permission at' + ' the application level.
%s
[Content Provider,' + ' targetSdkVersion < 17]'), + 'level': 'info', + 'description': ('A%s %s is found to be shared with other apps on' + ' the device therefore leaving it accessible to any' + ' other application on the device. It is protected ' + 'by permission at the application level.'), + 'name': ('is Protected by a permission at the application level.' + '[Content Provider, targetSdkVersion < 17]'), + }, + 'c_prot_sign_sys_appl': { + 'title': ('%s (%s) is Protected by a permission at' + ' the application level, but the protection level of the' + ' permission should be checked.' + '
%s
[Content Provider, targetSdkVersion < 17]'), + 'level': 'info', + 'description': ('A%s %s is found to be exported, but is protected by' + ' a permission at the application level. However, the' + ' protection level of the permission is set to ' + 'signatureOrSystem. It is recommended that signature ' + 'level is used instead. Signature level should suffice' + ' for most purposes, and does not depend on where the' + ' applications are installed on the device.'), + 'name': ('is Protected by a permission at the application level, ' + 'but the protection level of the permission should be ' + 'checked.[Content Provider, targetSdkVersion < 17]'), + }, + 'c_prot_unknown_appl': { + 'title': ('%s (%s) is Protected by a permission at' + ' application level, but the protection level of the ' + 'permission should be checked.
%s ' + '
[Content Provider, targetSdkVersion < 17]'), + 'level': 'high', + 'description': ('A%s %s is found to be shared with other apps on the' + ' device therefore leaving it accessible to any other' + ' application on the device. It is protected by a ' + 'permission at application level which is not defined' + ' in the analysed application. As a result, the ' + 'protection level of the permission should be checked' + ' where it is defined. If it is set to normal or ' + 'dangerous, a malicious application can request and' + ' obtain the permission and interact with the ' + 'component. If it is set to signature, only ' + 'applications signed with the same certificate ' + 'can obtain the permission.'), + 'name': ('is Protected by a permission at application level, but' + ' the protection level of the permission should be checked.' + '[Content Provider, targetSdkVersion < 17]'), + }, + 'c_prot_normal_new': { + 'title': ('%s (%s) is Protected by a permission, ' + 'but the protection level of the permission should be ' + 'checked if the application runs on a device where the ' + 'the API level is less than 17' + '
%s
[Content Provider, targetSdkVersion >= 17]'), + 'level': 'high', + 'description': ('The Content Provider (%s) would be exported if the' + ' application ran on a device where the the API level' + ' was less than 17. In that situation, it would still' + ' be protected by a permission. However, the ' + 'protection level of the permission is set to normal. ' + 'This means that a malicious application could request' + ' and obtain the permission and interact with the' + ' component. If it was set to signature, only' + ' applications signed with the same certificate ' + 'could obtain the permission.'), + 'name': ('is Protected by a permission, but the protection level of' + ' the permission should be checked if the application runs ' + 'on a device where the the API level is less than 17 ' + '[Content Provider, targetSdkVersion >= 17]'), + }, + 'c_prot_danger_new': { + 'title': ('%s (%s) is Protected by a permission,' + ' but the protection level of the permission should be ' + 'checked if the application runs on a device where ' + 'the API level is less than 17.
%s
' + '[Content Provider, targetSdkVersion >= 17]'), + 'level': 'high', + 'description': ('The Content Provider(%s) would be exported if the' + ' application ran on a device where the the API level' + ' was less than 17. In that situation, it would still' + ' be protected by a permission. However, the ' + 'protection level of the permission is set to' + ' dangerous. This means that a malicious application' + ' could request and obtain the permission and interact' + ' with the component. If it was set to signature, only' + ' applications signed with the same certificate could' + ' obtain the permission.'), + 'name': ('is Protected by a permission, but the protection level of' + ' the permission should be checked if the application runs on' + ' a device where the the API level is less than 17.' + '[Content Provider, targetSdkVersion >= 17]'), + }, + 'c_prot_sign_new': { + 'title': ('%s (%s) is Protected by a permission.' + '
%s
[Content Provider, targetSdkVersion >= 17]'), + 'level': 'info', + 'description': ('The Content Provider(%s) would be exported if the' + ' application ran on a device where the the API level' + ' was less than 17. Nevertheless, it is protected ' + 'by a permission.'), + 'name': ('is Protected by a permission.' + '[Content Provider, targetSdkVersion >= 17]'), + }, + 'c_prot_sign_sys_new': { + 'title': ('%s (%s) is Protected by a permission, but' + ' the protection level of the permission should be checked.' + '
%s
[Content Provider, targetSdkVersion >= 17]'), + 'level': 'info', + 'description': ('The Content Provider(%s) would be exported if the ' + 'application ran on a device where the API level was' + ' less than 17. In that situation, it would still ' + 'be protected by a permission. However, the protection' + ' level of the permission is set to signatureOrSystem.' + ' It is recommended that signature level is used ' + 'instead. Signature level should suffice for most' + ' purposes, and does not depend on where the' + ' applications are installed on the device.'), + 'name': ('is Protected by a permission, but the protection level of' + ' the permission should be checked.' + '[Content Provider, targetSdkVersion >= 17]'), + }, + 'c_prot_unknown_new': { + 'title': ('%s (%s) is Protected by a permission, but' + ' the protection level of the permission should be checked' + ' if the application runs on a device where the the API ' + 'level is less than 17.
%s
' + '[Content Provider, targetSdkVersion >= 17]'), + 'level': 'high', + 'description': ('The Content Provider(%s) would be exported if the' + ' application ran on a device where the the API level' + ' was less than 17. In that situation, it would still' + ' be protected by a permission which is not defined in' + ' the analysed application. As a result, the ' + 'protection level of the permission should be ' + 'checked where it is defined. If it is set to normal' + ' or dangerous, a malicious application can request' + ' and obtain the permission and interact with the ' + 'component. If it is set to signature, only ' + 'applications signed with the same certificate' + ' can obtain the permission.'), + 'name': ('is Protected by a permission, but the protection level of' + ' the permission should be checked if the application runs' + ' on a device where the the API level is less than 17.' + '[Content Provider, targetSdkVersion >= 17]'), + }, + 'c_prot_normal_new_appl': { + 'title': ('%s (%s) is Protected by a permission at' + ' the application level, but the protection level of the' + ' permission should be checked if the application runs on' + ' a device where the the API level is less than 17' + '
%s
[Content Provider, targetSdkVersion >= 17]'), + 'level': 'high', + 'description': ('The Content Provider (%s) would be exported if the' + ' application ran on a device where the the API ' + 'level was less than 17. In that situation, it' + ' would still be protected by a permission. ' + 'However, the protection level of the permission' + ' is set to normal. This means that a malicious' + ' application could request and obtain the ' + 'permission and interact with the component. ' + 'If it was set to signature, only applications ' + 'signed with the same certificate could obtain' + ' the permission.'), + 'name': ('is Protected by a permission at the application level ' + 'should be checked, but the protection level of the ' + 'permission if the application runs on a device where' + ' the the API level is less than 17.' + '[Content Provider, targetSdkVersion >= 17]'), + }, + 'c_prot_danger_new_appl': { + 'title': ('%s (%s) is Protected by a permission at' + ' the application level, but the protection level of the' + ' permission should be checked if the application runs on' + ' a device where the the API level is less than 17.' + '
%s
[Content Provider, targetSdkVersion >= 17]'), + 'level': 'high', + 'description': ('The Content Provider(%s) would be exported if the' + ' application ran on a device where the the API ' + 'level was less than 17. In that situation, it' + ' would still be protected by a permission. However,' + ' the protection level of the permission is set to' + ' dangerous. This means that a malicious application' + ' could request and obtain the permission and interact' + ' with the component. If it was set to signature, only' + ' applications signed with the same certificate could' + ' obtain the permission.'), + 'name': ('is Protected by a permission at the application level, but' + ' the protection level of the permission should be checked ' + 'if the application runs on a device where the the API level ' + 'is less than 17.[Content Provider, targetSdkVersion >= 17]'), + }, + 'c_prot_sign_new_appl': { + 'title': ('%s (%s) is Protected by a permission at' + ' the application level.
%s
' + '[Content Provider, targetSdkVersion >= 17]'), + 'level': 'info', + 'description': ('The Content Provider(%s) would be exported if the' + ' application ran on a device where the the API ' + 'level was less than 17. Nevertheless, it is ' + 'protected by a permission.'), + 'name': ('is Protected by a permission at the application level.' + '[Content Provider, targetSdkVersion >= 17]'), + }, + 'c_prot_sign_sys_new_appl': { + 'title': ('%s (%s) is Protected by a permission at' + ' the application level, but the protection level of the' + ' permission should be checked.' + '
%s
[Content Provider, targetSdkVersion >= 17]'), + 'level': 'info', + 'description': ('The Content Provider(%s) would be exported if the' + ' application ran on a device where the API level was' + ' less than 17. In that situation, it would still be' + ' protected by a permission. However, the protection' + ' level of the permission is set to signatureOrSystem.' + ' It is recommended that signature level is used' + ' instead. Signature level should suffice for most' + ' purposes, and does not depend on where the ' + 'applications are installed on the device.'), + 'name': ('is Protected by a permission at the application level, but' + ' the protection level of the permission should be checked.' + '[Content Provider, targetSdkVersion >= 17]'), + }, + 'c_prot_unknown_new_appl': { + 'title': ('%s (%s) is Protected by a permission at ' + 'the application level, but the protection level of the ' + 'permission should be checked if the application runs on' + ' a device where the the API level is less than 17.' + '
%s
[Content Provider, targetSdkVersion >= 17]'), + 'level': 'high', + 'description': ('The Content Provider(%s) would be exported if the' + ' application ran on a device where the the API level' + ' was less than 17. In that situation, it would still' + ' be protected by a permission which is not defined ' + 'in the analysed application. As a result, the' + ' protection level of the permission should be checked' + ' where it is defined. If it is set to normal or' + ' dangerous, a malicious application can request' + ' and obtain the permission and interact with the' + ' component. If it is set to signature, only ' + 'applications signed with the same certificate' + ' can obtain the permission.'), + 'name': ('is Protected by a permission at the application level,' + ' but the protection level of the permission should be' + ' checked if the application runs on a device where the' + ' the API level is less than 17.' + '[Content Provider, targetSdkVersion >= 17]'), + }, + 'a_improper_provider': { + 'title': 'Improper Content Provider Permissions
[%s]', + 'level': 'high', + 'description': ('A content provider permission was set to allows' + ' access from any other app on the device. ' + 'Content providers may contain sensitive ' + 'information about an app and therefore ' + 'should not be shared.'), + 'name': 'Improper Content Provider Permissions', + }, + 'a_dailer_code': { + 'title': ('Dailer Code: %s Found' + '
[android:scheme="android_secret_code"]'), + 'level': 'high', + 'description': ('A secret code was found in the manifest. These codes,' + ' when entered into the dialer grant access to hidden' + ' content that may contain sensitive information.'), + 'name': ('Dailer Code: Found ' + '
[android:scheme="android_secret_code"]'), + }, + 'a_sms_receiver_port': { + 'title': 'Data SMS Receiver Set on Port: %s Found
[android:port]', + 'level': 'high', + 'description': ('A binary SMS recevier is configured to listen on a' + ' port. Binary SMS messages sent to a device are ' + 'processed by the application in whichever way the' + ' developer choses. The data in this SMS should be' + ' properly validated by the application. Furthermore,' + ' the application should assume that the SMS being' + ' received is from an untrusted source.'), + 'name': 'Data SMS Receiver Set on Port: Found
[android:port]', + }, + 'a_high_intent_priority': { + 'title': 'High Intent Priority (%s)
[android:priority]', + 'level': 'medium', + 'description': ('By setting an intent priority higher than another' + ' intent, the app effectively overrides ' + 'other requests.'), + 'name': 'High Intent Priority [android:priority]', + }, + 'a_high_action_priority': { + 'title': 'High Action Priority (%s)
[android:priority] ', + 'level': 'medium', + 'description': ('By setting an action priority higher than' + ' another action, the app effectively ' + 'overrides other requests.'), + 'name': 'High Action Priority [android:priority]', + }, +} diff --git a/StaticAnalyzer/views/android/android_rules.py b/StaticAnalyzer/views/android/android_rules.py index 6771f70b..8ec0c56e 100755 --- a/StaticAnalyzer/views/android/android_rules.py +++ b/StaticAnalyzer/views/android/android_rules.py @@ -1,5 +1,5 @@ """ -Rule Format +Rule Format. 1. desc - Description of the findings @@ -11,14 +11,19 @@ Rule Format a. single_regex - if re.findall(regex1, input) b .regex_and - if re.findall(regex1, input) and re.findall(regex2, input) c. regex_or - if re.findall(regex1, input) or re.findall(regex2, input) - d. regex_and_perm - if re.findall(regex, input) and (permission in permission_list_from_manifest) + d. regex_and_perm - if re.findall(regex, input) and + (permission in permission_list_from_manifest) e. single_string - if string1 in input f. string_and - if (string1 in input) and (string2 in input) g. string_or - if (string1 in input) or (string2 in input) - h. string_and_or - if (string1 in input) and ((string_or1 in input) or (string_or2 in input)) - i. string_or_and - if (string1 in input) or ((string_and1 in input) and (string_and2 in input)) - j. string_and_perm - if (string1 in input) and (permission in permission_list_from_manifest) - k. string_or_and_perm - if ((string1 in input) or (string2 in input)) and (permission in permission_list_from_manifest) + h. string_and_or - if (string1 in input) and ((string_or1 in input) + or (string_or2 in input)) + i. string_or_and - if (string1 in input) or ((string_and1 in input) + and (string_and2 in input)) + j. string_and_perm - if (string1 in input) + and (permission in permission_list_from_manifest) + k. string_or_and_perm - if ((string1 in input) or (string2 in input)) + and (permission in permission_list_from_manifest) 4. level a. high @@ -39,14 +44,19 @@ Rule Format """ RULES = [ { - 'desc': 'Files may contain hardcoded sensitive informations like usernames, passwords, keys etc.', + 'desc': ('Files may contain hardcoded sensitive ' + 'informations like usernames, passwords, keys etc.'), 'type': 'regex', - 'regex1': r'''(password\s*=\s*['|"].+['|"]\s{0,5})|(pass\s*=\s*['|"].+['|"]\s{0,5})|(username\s*=\s*['|"].+['|"]\s{0,5})|(secret\s*=\s*['|"].+['|"]\s{0,5})|(key\s*=\s*['|"].+['|"]\s{0,5})''', + 'regex1': (r'(password\s*=\s*[\'|\"].+[\'|\"]\s{0,5})|' + r'(pass\s*=\s*[\'|\"].+[\'|\"]\s{0,5})|' + r'(username\s*=\s*[\'|\"].+[\'|\"]\s{0,5})|' + r'(secret\s*=\s*[\'|\"].+[\'|\"]\s{0,5})|' + r'(key\s*=\s*[\'|\"].+[\'|\"]\s{0,5})'), 'level': 'high', 'match': 'single_regex', 'input_case': 'lower', 'cvss': 7.4, - 'cwe': 'CWE-312' + 'cwe': 'CWE-312', }, { 'desc': 'IP Address disclosure', @@ -56,51 +66,67 @@ RULES = [ 'match': 'single_regex', 'input_case': 'exact', 'cvss': 4.3, - 'cwe': 'CWE-200' + 'cwe': 'CWE-200', }, { - 'desc': 'Hidden elements in view can be used to hide data from user. But this data can be leaked', + 'desc': ('Hidden elements in view can be used to hide' + ' data from user. But this data can be leaked'), 'type': 'regex', - 'regex1': r'setVisibility\(View\.GONE\)|setVisibility\(View\.INVISIBLE\)', + 'regex1': (r'setVisibility\(View\.GONE\)|' + r'setVisibility\(View\.INVISIBLE\)'), 'level': 'high', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 4.3, - 'cwe': 'CWE-919' + 'cwe': 'CWE-919', }, { - 'desc': 'The App uses ECB mode in Cryptographic encryption algorithm. ECB mode is known to be weak as it results in the same ciphertext for identical blocks of plaintext.', + 'desc': ('The App uses ECB mode in Cryptographic encryption algorithm.' + ' ECB mode is known to be weak as it results in the same' + ' ciphertext for identical blocks of plaintext.'), 'type': 'regex', 'regex1': r'Cipher\.getInstance\(\s*"\s*AES\/ECB', 'level': 'high', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 5.9, - 'cwe': 'CWE-327' + 'cwe': 'CWE-327', }, { - 'desc': 'This App uses RSA Crypto without OAEP padding. The purpose of the padding scheme is to prevent a number of attacks on RSA that only work when the encryption is performed without padding.', + 'desc': ('This App uses RSA Crypto without OAEP padding. The purpose' + ' of the padding scheme is to prevent a number of attacks on' + ' RSA that only work when the encryption is performed' + ' without padding.'), 'type': 'regex', 'regex1': r'cipher\.getinstance\(\s*"rsa/.+/nopadding', 'level': 'high', 'match': 'single_regex', 'input_case': 'lower', 'cvss': 5.9, - 'cwe': 'CWE-780' + 'cwe': 'CWE-780', }, { - 'desc': 'Insecure Implementation of SSL. Trusting all the certificates or accepting self signed certificates is a critical Security Hole. This application is vulnerable to MITM attacks', + 'desc': ('Insecure Implementation of SSL. Trusting all the ' + 'certificates or accepting self signed certificates' + ' is a critical Security Hole. This application is' + ' vulnerable to MITM attacks'), 'type': 'regex', 'regex1': r'javax\.net\.ssl', - 'regex2': r'TrustAllSSLSocket-Factory|AllTrustSSLSocketFactory|NonValidatingSSLSocketFactory|net\.SSLCertificateSocketFactory|ALLOW_ALL_HOSTNAME_VERIFIER|\.setDefaultHostnameVerifier\(|NullHostnameVerifier\(', + 'regex2': (r'TrustAllSSLSocket-Factory|AllTrustSSLSocketFactory|' + r'NonValidatingSSLSocketFactory|' + r'net\.SSLCertificateSocketFactory|' + r'ALLOW_ALL_HOSTNAME_VERIFIER|' + r'\.setDefaultHostnameVerifier\(|' + r'NullHostnameVerifier\('), 'level': 'high', 'match': 'regex_and', 'input_case': 'exact', 'cvss': 7.4, - 'cwe': 'CWE-295' + 'cwe': 'CWE-295', }, { - 'desc': 'WebView load files from external storage. Files in external storage can be modified by any application.', + 'desc': ('WebView load files from external storage. Files in external' + ' storage can be modified by any application.'), 'type': 'regex', 'regex1': r'\.loadUrl\(.*getExternalStorageDirectory\(', 'regex2': r'webkit\.WebView', @@ -108,7 +134,7 @@ RULES = [ 'match': 'regex_and', 'input_case': 'exact', 'cvss': 5.0, - 'cwe': 'CWE-919' + 'cwe': 'CWE-919', }, { 'desc': 'The file is World Readable. Any App can read from the file', @@ -119,7 +145,7 @@ RULES = [ 'match': 'regex_or', 'input_case': 'exact', 'cvss': 4.0, - 'cwe': 'CWE-276' + 'cwe': 'CWE-276', }, { @@ -131,57 +157,65 @@ RULES = [ 'match': 'regex_or', 'input_case': 'exact', 'cvss': 6.0, - 'cwe': 'CWE-276' + 'cwe': 'CWE-276', }, { - 'desc': 'The file is World Readable and Writable. Any App can read/write to the file', + 'desc': ('The file is World Readable and Writable. ' + 'Any App can read/write to the file'), 'type': 'regex', 'regex1': r'openFileOutput\(\s*".+"\s*,\s*3\s*\)', 'level': 'high', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 6.0, - 'cwe': 'CWE-276' + 'cwe': 'CWE-276', }, { 'desc': 'Weak Hash algorithm used', 'type': 'regex', - 'regex1': r'getInstance(\"md4\")|getInstance(\"rc2\")|getInstance(\"rc4\")|getInstance(\"RC4\")|getInstance(\"RC2\")|getInstance(\"MD4\")', + 'regex1': (r'getInstance(\"md4\")|getInstance(\"rc2\")|' + r'getInstance(\"rc4\")|getInstance(\"RC4\")|' + r'getInstance(\"RC2\")|getInstance(\"MD4\")'), 'level': 'high', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 7.4, - 'cwe': 'CWE-327' + 'cwe': 'CWE-327', }, { 'desc': 'MD5 is a weak hash known to have hash collisions.', 'type': 'regex', - 'regex1': r'MessageDigest\.getInstance\(\"*MD5\"*\)|MessageDigest\.getInstance\(\"*md5\"*\)|DigestUtils\.md5\(', + 'regex1': (r'MessageDigest\.getInstance\(\"*MD5\"*\)|' + r'MessageDigest\.getInstance\(\"*md5\"*\)|' + r'DigestUtils\.md5\('), 'level': 'high', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 7.4, - 'cwe': 'CWE-327' + 'cwe': 'CWE-327', }, { 'desc': 'SHA-1 is a weak hash known to have hash collisions.', 'type': 'regex', - 'regex1': r'MessageDigest\.getInstance\(\"*SHA-1\"*\)|MessageDigest\.getInstance\(\"*sha-1\"*\)|DigestUtils\.sha\(', + 'regex1': (r'MessageDigest\.getInstance\(\"*SHA-1\"*\)|' + r'MessageDigest\.getInstance\(\"*sha-1\"*\)|' + r'DigestUtils\.sha\('), 'level': 'high', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 5.9, - 'cwe': 'CWE-327' + 'cwe': 'CWE-327', }, { - 'desc': 'App can write to App Directory. Sensitive Information should be encrypted.', + 'desc': ('App can write to App Directory. ' + 'Sensitive Information should be encrypted.'), 'type': 'regex', 'regex1': r'MODE_PRIVATE|Context\.MODE_PRIVATE', 'level': 'info', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 3.9, - 'cwe': 'CWE-276' + 'cwe': 'CWE-276', }, { 'desc': 'The App uses an insecure Random Number Generator.', @@ -191,37 +225,41 @@ RULES = [ 'match': 'single_regex', 'input_case': 'exact', 'cvss': 7.5, - 'cwe': 'CWE-330' + 'cwe': 'CWE-330', }, { - 'desc': 'The App logs information. Sensitive information should never be logged.', + 'desc': ('The App logs information. ' + 'Sensitive information should never be logged.'), 'type': 'regex', - 'regex1': r'Log\.(v|d|i|w|e|f|s)|System\.out\.print|System\.err\.print', + 'regex1': (r'Log\.(v|d|i|w|e|f|s)|' + r'System\.out\.print|System\.err\.print'), 'level': 'info', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 7.5, - 'cwe': 'CWE-532' + 'cwe': 'CWE-532', }, { - 'desc': 'This App uses Java Hash Code. It\'s a weak hash function and should never be used in Secure Crypto Implementation.', + 'desc': ('This App uses Java Hash Code. It\'s a weak hash function and' + ' should never be used in Secure Crypto Implementation.'), 'type': 'string', 'string1': '.hashCode()', 'level': 'high', 'match': 'single_string', 'input_case': 'exact', 'cvss': 4.3, - 'cwe': 'CWE-327' + 'cwe': 'CWE-327', }, { - 'desc': 'These activities prevent screenshot when they go to background.', + 'desc': ('These activities prevent ' + 'screenshot when they go to background.'), 'type': 'string', 'string1': 'LayoutParams.FLAG_SECURE', 'level': 'good', 'match': 'single_string', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'This App uses SQL Cipher. But the secret may be hardcoded.', @@ -231,7 +269,7 @@ RULES = [ 'match': 'single_string', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'This app has capabilities to prevent tapjacking attacks.', @@ -241,10 +279,11 @@ RULES = [ 'match': 'single_string', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { - 'desc': 'App can read/write to External Storage. Any App can read data written to External Storage.', + 'desc': ('App can read/write to External Storage. ' + 'Any App can read data written to External Storage.'), 'perm': 'android.permission.WRITE_EXTERNAL_STORAGE', 'type': 'string', 'string1': '.getExternalStorage', @@ -253,10 +292,11 @@ RULES = [ 'match': 'string_or_and_perm', 'input_case': 'exact', 'cvss': 5.5, - 'cwe': 'CWE-276' + 'cwe': 'CWE-276', }, { - 'desc': 'App creates temp file. Sensitive information should never be written into a temp file.', + 'desc': ('App creates temp file. Sensitive ' + 'information should never be written into a temp file.'), 'perm': 'android.permission.WRITE_EXTERNAL_STORAGE', 'type': 'string', 'string1': '.createTempFile(', @@ -264,10 +304,11 @@ RULES = [ 'match': 'string_and_perm', 'input_case': 'exact', 'cvss': 5.5, - 'cwe': 'CWE-276' + 'cwe': 'CWE-276', }, { - 'desc': 'Insecure WebView Implementation. Execution of user controlled code in WebView is a critical Security Hole.', + 'desc': ('Insecure WebView Implementation. Execution of user' + ' controlled code in WebView is a critical Security Hole.'), 'type': 'string', 'string1': 'setJavaScriptEnabled(true)', 'string2': '.addJavascriptInterface(', @@ -275,10 +316,11 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 8.8, - 'cwe': 'CWE-749' + 'cwe': 'CWE-749', }, { - 'desc': 'This App uses SQL Cipher. SQLCipher provides 256-bit AES encryption to sqlite database files.', + 'desc': ('This App uses SQL Cipher. SQLCipher ' + 'provides 256-bit AES encryption to sqlite database files.'), 'type': 'string', 'string1': 'SQLiteDatabase.loadLibs(', 'string2': 'net.sqlcipher.', @@ -286,7 +328,7 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'This App download files using Android Download Manager', @@ -297,7 +339,7 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'This App use Realm Database with encryption.', @@ -308,10 +350,15 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { - 'desc': 'The App may use weak IVs like "0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00" or "0x01,0x02,0x03,0x04,0x05,0x06,0x07". Not using a random IV makes the resulting ciphertext much more predictable and susceptible to a dictionary attack.', + 'desc': ('The App may use weak IVs like ' + '"0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00" or ' + '"0x01,0x02,0x03,0x04,0x05,0x06,0x07". ' + 'Not using a random IV makes the resulting ' + 'ciphertext much more predictable and ' + 'susceptible to a dictionary attack.'), 'type': 'string', 'string1': '0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00', 'string2': '0x01,0x02,0x03,0x04,0x05,0x06,0x07', @@ -319,7 +366,7 @@ RULES = [ 'match': 'string_or', 'input_case': 'exact', 'cvss': 9.8, - 'cwe': 'CWE-329' + 'cwe': 'CWE-329', }, { 'desc': 'Remote WebView debugging is enabled.', @@ -330,10 +377,11 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 5.4, - 'cwe': 'CWE-919' + 'cwe': 'CWE-919', }, { - 'desc': 'This app listens to Clipboard changes. Some malwares also listen to Clipboard changes.', + 'desc': ('This app listens to Clipboard changes.' + ' Some malwares also listen to Clipboard changes.'), 'type': 'string', 'string1': 'content.ClipboardManager', 'string2': 'OnPrimaryClipChangedListener', @@ -341,10 +389,12 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { - 'desc': 'This App copies data to clipboard. Sensitive data should not be copied to clipboard as other applications can access it.', + 'desc': ('This App copies data to clipboard. Sensitive data should' + ' not be copied to clipboard as other' + ' applications can access it.'), 'type': 'string', 'string1': 'content.ClipboardManager', 'string2': 'setPrimaryClip(', @@ -352,10 +402,12 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { - 'desc': 'Insecure WebView Implementation. WebView ignores SSL Certificate errors and accept any SSL Certificate. This application is vulnerable to MITM attacks', + 'desc': ('Insecure WebView Implementation. WebView ignores SSL' + ' Certificate errors and accept any SSL Certificate.' + ' This application is vulnerable to MITM attacks'), 'type': 'string', 'string1': 'onReceivedSslError(WebView', 'string2': '.proceed();', @@ -363,10 +415,13 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 7.4, - 'cwe': 'CWE-295' + 'cwe': 'CWE-295', }, { - 'desc': 'App uses SQLite Database and execute raw SQL query. Untrusted user input in raw SQL queries can cause SQL Injection. Also sensitive information should be encrypted and written to the database.', + 'desc': ('App uses SQLite Database and execute raw SQL query. ' + 'Untrusted user input in raw SQL queries can cause' + ' SQL Injection. Also sensitive information should' + ' be encrypted and written to the database.'), 'type': 'string', 'string1': 'android.database.sqlite', 'string_or1': 'rawQuery(', @@ -375,7 +430,7 @@ RULES = [ 'match': 'string_and_or', 'input_case': 'exact', 'cvss': 5.9, - 'cwe': 'CWE-89' + 'cwe': 'CWE-89', }, { 'desc': 'This App detects frida server.', @@ -388,10 +443,13 @@ RULES = [ 'match': 'string_and_or', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { - 'desc': 'This App uses an SSL Pinning Library (org.thoughtcrime.ssl.pinning) to prevent MITM attacks in secure communication channel.', + 'desc': ('This App uses an SSL Pinning Library ' + '(org.thoughtcrime.ssl.pinning) to ' + 'prevent MITM attacks in secure' + ' communication channel.'), 'type': 'string', 'string1': 'org.thoughtcrime.ssl.pinning', 'string_or1': 'PinningHelper.getPinnedHttpsURLConnection', @@ -401,10 +459,11 @@ RULES = [ 'match': 'string_and_or', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { - 'desc': 'This App has capabilities to prevent against Screenshots from Recent Task History/ Now On Tap etc.', + 'desc': ('This App has capabilities to prevent against' + ' Screenshots from Recent Task History/ Now On Tap etc.'), 'type': 'string', 'string1': '.FLAG_SECURE', 'string_or1': 'getWindow().setFlags(', @@ -413,10 +472,11 @@ RULES = [ 'match': 'string_and_or', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { - 'desc': 'DexGuard Debug Detection code to detect wheather an App is debuggable or not is identified.', + 'desc': ('DexGuard Debug Detection code to detect' + ' wheather an App is debuggable or not is identified.'), 'type': 'string', 'string1': 'import dexguard.util', 'string2': 'DebugDetector.isDebuggable', @@ -424,7 +484,7 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'DexGuard Debugger Detection code is identified.', @@ -435,7 +495,7 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'DexGuard Emulator Detection code is identified.', @@ -446,10 +506,11 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { - 'desc': 'DecGuard code to detect wheather the App is signed with a debug key or not is identified.', + 'desc': ('DexGuard code to detect wheather the App' + ' is signed with a debug key or not is identified.'), 'type': 'string', 'string1': 'import dexguard.util', 'string2': 'DebugDetector.isSignedWithDebugKey', @@ -457,7 +518,7 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'DexGuard Root Detection code is identified.', @@ -468,7 +529,7 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'DexGuard App Tamper Detection code is identified.', @@ -479,10 +540,11 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { - 'desc': 'DexGuard Signer Certificate Tamper Detection code is identified.', + 'desc': ('DexGuard Signer Certificate' + ' Tamper Detection code is identified.'), 'type': 'string', 'string1': 'import dexguard.util', 'string2': 'TCertificateChecker.checkCertificate', @@ -490,7 +552,7 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'The App may use package signature for tamper detection.', @@ -501,7 +563,7 @@ RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'This App uses SafetyNet API.', @@ -511,7 +573,7 @@ RULES = [ 'match': 'single_string', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'This App may request root (Super User) privileges.', @@ -525,7 +587,7 @@ RULES = [ 'match': 'string_or', 'input_case': 'exact', 'cvss': 0, - 'cwe': 'CWE-250' + 'cwe': 'CWE-250', }, { 'desc': 'This App may have root detection capabilities.', @@ -536,10 +598,10 @@ RULES = [ 'string4': '/system/bin/failsafe/su', 'string5': '/system/sd/xbin/su', 'string6': '"/system/xbin/which", "su"', - "string7": 'RootTools.isAccessGiven()', + 'string7': 'RootTools.isAccessGiven()', 'level': 'good', 'match': 'string_or', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }] diff --git a/StaticAnalyzer/views/android/binary_analysis.py b/StaticAnalyzer/views/android/binary_analysis.py index 30b49146..4f5e181b 100755 --- a/StaticAnalyzer/views/android/binary_analysis.py +++ b/StaticAnalyzer/views/android/binary_analysis.py @@ -1,19 +1,17 @@ # !/usr/bin/python # coding=utf-8 -import os import io -import struct import logging -from MobSF.utils import ( - PrintException -) +import os +import struct + +from MobSF.utils import log_exception + logger = logging.getLogger(__name__) -class tinyELFFile(object): - ''' - from pyelftools - ''' +class TinyELFFile(object): + """from pyelftools.""" def __init__(self, stream): self.stream = stream @@ -33,7 +31,7 @@ class tinyELFFile(object): self.little_endian = False else: raise Exception('Invalid EI_DATA %s' % repr(ei_data)) - self.unpack_endian = "<" if self.little_endian else ">" + self.unpack_endian = '<' if self.little_endian else '>' self.stream.seek(0) self.header = { 'e_ident': { @@ -60,7 +58,9 @@ class tinyELFFile(object): 'e_shstrndx': self.unpack_half(), } xxx = self.decode_shdr( - self.header['e_shoff'] + self.header['e_shstrndx'] * self.header['e_shentsize']) + self.header['e_shoff'] + + self.header['e_shstrndx'] + * self.header['e_shentsize']) self._file_stringtable_section = xxx['sh_offset'] def decode_shdr(self, off): @@ -92,7 +92,6 @@ class tinyELFFile(object): st_info_bind = st_info_struct >> 4 & 0x0F st_info_type = st_info_struct & 0x0F st_other_struct = self.unpack_byte() - st_other_padding = st_info_struct >> 3 & 63 st_other_visibility = st_other_struct & 0x07 elf_sym['st_info'] = { 'bind': st_info_bind, @@ -150,73 +149,86 @@ class tinyELFFile(object): return strn.decode('ascii') def unpack_byte(self): - return struct.unpack(self.unpack_endian + "B", self.stream.read(1))[0] + return struct.unpack(self.unpack_endian + 'B', self.stream.read(1))[0] def unpack_half(self): - return struct.unpack(self.unpack_endian + "H", self.stream.read(2))[0] + return struct.unpack(self.unpack_endian + 'H', self.stream.read(2))[0] def unpack_word(self): - return struct.unpack(self.unpack_endian + "L", self.stream.read(4))[0] + return struct.unpack(self.unpack_endian + 'L', self.stream.read(4))[0] def unpack_word64(self): - return struct.unpack(self.unpack_endian + "Q", self.stream.read(8))[0] + return struct.unpack(self.unpack_endian + 'Q', self.stream.read(8))[0] def unpack_addr(self): if self.elfclass == 32: - return struct.unpack(self.unpack_endian + "L", self.stream.read(4))[0] + return (struct.unpack(self.unpack_endian + + 'L', self.stream.read(4))[0]) else: - return struct.unpack(self.unpack_endian + "Q", self.stream.read(8))[0] + return (struct.unpack(self.unpack_endian + + 'Q', self.stream.read(8))[0]) def unpack_offset(self): return self.unpack_addr() def unpack_sword(self): - return struct.unpack(self.unpack_endian + "l", self.stream.read(4))[0] + return struct.unpack(self.unpack_endian + 'l', self.stream.read(4))[0] def unpack_xword(self): if self.elfclass == 32: - return struct.unpack(self.unpack_endian + "L", self.stream.read(4))[0] + return (struct.unpack(self.unpack_endian + + 'L', self.stream.read(4))[0]) else: - return struct.unpack(self.unpack_endian + "Q", self.stream.read(8))[0] + return (struct.unpack(self.unpack_endian + + 'Q', self.stream.read(8))[0]) def unpack_sxword(self): if self.elfclass == 32: - return struct.unpack(self.unpack_endian + "l", self.stream.read(4))[0] + return (struct.unpack(self.unpack_endian + + 'l', self.stream.read(4))[0]) else: - return struct.unpack(self.unpack_endian + "q", self.stream.read(8))[0] + return (struct.unpack(self.unpack_endian + + 'q', self.stream.read(8))[0]) def check_elf_built(f): has_pi = False has_sp = False - has_pi_flag = { - 3: [8, ], # EM_386=3, R_386_RELATIVE=8, - 62: [8, ], # EM_X86_64=62, R_X86_64_RELATIVE=8, + has_pi_fg = { + 3: [8], # EM_386=3, R_386_RELATIVE=8, + 62: [8], # EM_X86_64=62, R_X86_64_RELATIVE=8, 40: [23, 3], # EM_ARM=40, R_ARM_RELATIVE=23,R_ARM_REL32=3, - 183: [1027, 3], # EM_AARCH64=183, R_AARCH64_RELATIVE=1027,R_ARM_REL32=3, - 8: [3, ], # EM_MIPS=8, R_MIPS_REL32=3, + 183: [1027, 3], # EM_AARCH64=183, + # R_AARCH64_RELATIVE=1027,R_ARM_REL32=3, + 8: [3], # EM_MIPS=8, R_MIPS_REL32=3, } - elffile = tinyELFFile(f) + elffile = TinyELFFile(f) for i in range(elffile.header['e_shnum']): section_header = elffile.decode_shdr( elffile.header['e_shoff'] + i * elffile.header['e_shentsize']) - name = elffile.decode_string( - elffile._file_stringtable_section + section_header['sh_name']) sectype = section_header['sh_type'] if sectype in (4, 9): # SHT_RELA=4,SHT_REL=9, if section_header['sh_entsize'] > 0: - for i in range(section_header['sh_size'] // section_header['sh_entsize']): + siz = section_header['sh_size'] // section_header['sh_entsize'] + for i in range(siz): elffile.stream.seek( - section_header['sh_offset'] + i * section_header['sh_entsize']) + section_header['sh_offset'] + + i + * section_header['sh_entsize']) if section_header['sh_type'] == 9: entry = elffile.decode_rel( - section_header['sh_offset'] + i * section_header['sh_entsize']) + section_header['sh_offset'] + + i + * section_header['sh_entsize']) elif section_header['sh_type'] == 4: entry = elffile.decode_rela( - section_header['sh_offset'] + i * section_header['sh_entsize']) + section_header['sh_offset'] + + i + * section_header['sh_entsize']) else: continue - if entry['r_info_type'] in has_pi_flag.get(elffile.header['e_machine'], []): + if (entry['r_info_type'] + in has_pi_fg.get(elffile.header['e_machine'], [])): if entry['r_info_sym'] == 0: has_pi = True break @@ -226,35 +238,35 @@ def check_elf_built(f): def res_analysis(app_dir): """Perform the elf analysis.""" try: - logger.info("Static Android Resource Analysis Started") + logger.info('Static Android Resource Analysis Started') elf_desc = { 'html_infected': ( 'Found html files infected by malware.', 'high', - 'The built environment was probably infected by malware, The html file ' - 'used in this APK is infected.' - ), - } + 'The built environment was probably' + ' infected by malware, The html file ' + 'used in this APK is infected.')} html_an_dic = {} for k in list(elf_desc.keys()): html_an_dic[k] = [] - resraw = os.path.join(app_dir, "res", "raw") - assets = os.path.join(app_dir, "assets") + resraw = os.path.join(app_dir, 'res', 'raw') + assets = os.path.join(app_dir, 'assets') for resdir in (resraw, assets): if os.path.exists(resdir) and os.path.isdir(resdir): - for pdir, dirl, filel in os.walk(resdir): + for pdir, _dirl, filel in os.walk(resdir): for filename in filel: - if filename.endswith(".htm") or filename.endswith(".html"): + if (filename.endswith('.htm') + or filename.endswith('.html')): try: filepath = os.path.join(pdir, filename) - buf = "" + buf = '' with io.open(filepath, mode='rb') as filp: buf = filp.read() - if "svchost.exe" in buf: + if 'svchost.exe' in buf: html_an_dic['html_infected'].append( - filepath.replace(app_dir, "")) - except Exception as e: + filepath.replace(app_dir, '')) + except Exception: pass res = [] for k, filelist in list(html_an_dic.items()): @@ -263,48 +275,52 @@ def res_analysis(app_dir): res.append({'title': descs[0], 'stat': descs[1], 'desc': descs[2], - 'file': " ".join(filelist), + 'file': ' '.join(filelist), }) return res - except: - PrintException("Performing Resourse Analysis") + except Exception: + log_exception('Performing Resourse Analysis') def elf_analysis(app_dir: str) -> list: """Perform the elf analysis.""" try: - logger.info("Static Android Binary Analysis Started") + logger.info('Static Android Binary Analysis Started') + fgs = ['nopie', 'nonpie', 'no-pie'] elf_desc = { 'elf_no_pi': ( - 'Found elf built without Position Independent Executable (PIE) flag', + 'Found elf built without Position Independent Executable' + ' (PIE) flag', 'high', - 'In order to prevent an attacker from reliably jumping to, for example, a particular' - ' exploited function in memory, Address space layout randomization (ASLR) randomly ' - 'arranges the address space positions of key data areas of a process, including the ' - 'base of the executable and the positions of the stack, heap and libraries. Built with' - ' option -pie.' - ) - } + 'In order to prevent an attacker from reliably jumping' + ' to, for example, a particular' + ' exploited function in memory, Address space layout' + ' randomization (ASLR) randomly ' + 'arranges the address space positions of key data areas' + ' of a process, including the ' + 'base of the executable and the positions of the stack,' + ' heap and libraries. Built with' + ' option -pie.')} elf_an_dic = {} for k in list(elf_desc.keys()): elf_an_dic[k] = [] - libdir = os.path.join(app_dir, "lib") + libdir = os.path.join(app_dir, 'lib') if os.path.exists(libdir): - for pdir, dirl, filel in os.walk(libdir): - for filename in filel: - if filename.endswith(".so"): + for pdir, _dirl, filel in os.walk(libdir): + for fname in filel: + if fname.endswith('.so'): try: - filepath = os.path.join(pdir, filename) + filepath = os.path.join(pdir, fname) f = io.open(filepath, mode='rb') has_pie, has_sg = check_elf_built(f) f.close() if not has_pie: - if not any(pie_str in ["nopie", "nonpie", "no-pie"] for pie_str in filename): + if not any(pie_st in fgs for pie_st in fname): elf_an_dic['elf_no_pi'].append( - filepath.replace(libdir, "lib")) - except Exception as e: + filepath.replace(libdir, 'lib')) + except Exception: pass res = [] for k, filelist in list(elf_an_dic.items()): @@ -313,9 +329,9 @@ def elf_analysis(app_dir: str) -> list: res.append({'title': descs[0], 'stat': descs[1], 'desc': descs[2], - 'file': " ".join(filelist), + 'file': ' '.join(filelist), }) return res - except: - PrintException("Performing Binary Analysis") + except Exception: + log_exception('Performing Binary Analysis') diff --git a/StaticAnalyzer/views/android/cert_analysis.py b/StaticAnalyzer/views/android/cert_analysis.py index 325e6507..358ee0ca 100755 --- a/StaticAnalyzer/views/android/cert_analysis.py +++ b/StaticAnalyzer/views/android/cert_analysis.py @@ -1,56 +1,61 @@ # -*- coding: utf_8 -*- """Module holding the functions for code analysis.""" -import subprocess -import re +import binascii +import hashlib +import logging import os +import re +import subprocess + +from androguard.core.bytecodes.apk import APK +from androguard.util import get_certificate_name_string + +from asn1crypto import keys, x509 from django.conf import settings from django.utils.html import escape -from MobSF.utils import ( - PrintException -) -from androguard.core.bytecodes.apk import APK -from androguard.util import get_certificate_name_string -import hashlib -import binascii -from asn1crypto import x509, keys +from MobSF.utils import log_exception -import logging logger = logging.getLogger(__name__) def get_hardcoded_cert_keystore(files): """Returns the hardcoded certificate keystore.""" try: - logger.info("Getting Hardcoded Certificates/Keystores") + logger.info('Getting Hardcoded Certificates/Keystores') dat = '' certz = '' key_store = '' for file_name in files: ext = file_name.split('.')[-1] - if re.search("cer|pem|cert|crt|pub|key|pfx|p12", ext): - certz += escape(file_name) + "
" - if re.search("jks|bks", ext): - key_store += escape(file_name) + "
" + if re.search('cer|pem|cert|crt|pub|key|pfx|p12', ext): + certz += escape(file_name) + '
' + if re.search('jks|bks', ext): + key_store += escape(file_name) + '
' if len(certz) > 1: dat += ( - "Certificate/Key Files Hardcoded inside the App." + - certz + - "" + 'Certificate/Key Files Hardcoded' + + ' inside the App.' + + certz + + '' ) if len(key_store) > 1: - dat += "Hardcoded Keystore Found." + key_store + "" + dat += ( + 'Hardcoded Keystore Found.' + + key_store + + '' + ) return dat - except: - PrintException("Getting Hardcoded Certificates/Keystores") + except Exception: + log_exception('Getting Hardcoded Certificates/Keystores') def cert_info(app_dir, app_file, tools_dir): """Return certificate information.""" try: - logger.info("Reading Code Signing Certificate") + logger.info('Reading Code Signing Certificate') cert = os.path.join(app_dir, 'META-INF/') cp_path = tools_dir + 'CertPrint.jar' files = [f for f in os.listdir( @@ -59,84 +64,93 @@ def cert_info(app_dir, app_file, tools_dir): dat = '' manidat = '' manifestfile = None - if "CERT.RSA" in files: - certfile = os.path.join(cert, "CERT.RSA") + if 'CERT.RSA' in files: + certfile = os.path.join(cert, 'CERT.RSA') else: for file_name in files: - if file_name.lower().endswith(".rsa"): + if file_name.lower().endswith('.rsa'): certfile = os.path.join(cert, file_name) - elif file_name.lower().endswith(".dsa"): + elif file_name.lower().endswith('.dsa'): certfile = os.path.join(cert, file_name) if certfile: args = [settings.JAVA_PATH + 'java', '-jar', cp_path, certfile] issued = 'good' try: dat = subprocess.check_output(args) - unicode_output = str(dat, encoding="utf-8", errors="replace") + unicode_output = str(dat, encoding='utf-8', errors='replace') dat = escape(unicode_output).replace('\n', '
') - except: + except Exception: dat = androguard_certinfo(app_dir, app_file) else: dat = 'No Code Signing Certificate Found!' issued = 'missing' - if re.findall(r"CN=Android Debug", dat): + if re.findall(r'CN=Android Debug', dat): issued = 'bad' - if re.findall(r"\[SHA1withRSA\]", dat): + if re.findall(r'\[SHA1withRSA\]', dat): issued = 'bad hash' - if "MANIFEST.MF" in files: - manifestfile = os.path.join(cert, "MANIFEST.MF") + if 'MANIFEST.MF' in files: + manifestfile = os.path.join(cert, 'MANIFEST.MF') if manifestfile: with open(manifestfile, 'r', encoding='utf-8') as manifile: manidat = manifile.read() - sha256Digest = bool(re.findall(r"SHA-256-Digest", manidat)) + sha256_digest = bool(re.findall(r'SHA-256-Digest', manidat)) cert_dic = { 'cert_info': dat, 'issued': issued, - 'sha256Digest': sha256Digest + 'sha256Digest': sha256_digest, } return cert_dic - except: - PrintException("Reading Code Signing Certificate") + except Exception: + log_exception('Reading Code Signing Certificate') def androguard_certinfo(app_dir, app_file): """Return certificate information.""" certlist = [] apk_file = os.path.join(app_dir, app_file) - hashfunctions = dict(md5=hashlib.md5, - sha1=hashlib.sha1, - sha256=hashlib.sha256, - sha512=hashlib.sha512, - ) + hashfunctions = { + 'md5': hashlib.md5, + 'sha1': hashlib.sha1, + 'sha256': hashlib.sha256, + 'sha512': hashlib.sha512, + } a = APK(apk_file) - certlist.append("v1: {}".format(a.is_signed_v1())) - certlist.append("v2: {}".format(a.is_signed_v2())) - certlist.append("v3: {}".format(a.is_signed_v3())) + certlist.append('v1: {}'.format(a.is_signed_v1())) + certlist.append('v2: {}'.format(a.is_signed_v2())) + certlist.append('v3: {}'.format(a.is_signed_v3())) - certs = set(a.get_certificates_der_v3() + a.get_certificates_der_v2() + [a.get_certificate_der(x) for x in a.get_signature_names()]) + certs = set(a.get_certificates_der_v3() + a.get_certificates_der_v2() + + [a.get_certificate_der(x) for x in a.get_signature_names()]) pkeys = set(a.get_public_keys_der_v3() + a.get_public_keys_der_v2()) - for cert in certs: x509_cert = x509.Certificate.load(cert) - certlist.append("Subject: {}".format(get_certificate_name_string(x509_cert.subject, short=True))) - certlist.append("Signature Algorithm: {}".format(x509_cert.signature_algo)) - certlist.append("Valid From: {}".format(x509_cert['tbs_certificate']['validity']['not_before'].native)) - certlist.append("Valid To: {}".format(x509_cert['tbs_certificate']['validity']['not_after'].native)) - certlist.append("Issuer: {}".format(get_certificate_name_string(x509_cert.issuer, short=True))) - certlist.append("Serial Number: {}".format(hex(x509_cert.serial_number))) - certlist.append("Hash Algorithm: {}".format(x509_cert.hash_algo)) + certlist.append('Subject: {}'.format( + get_certificate_name_string(x509_cert.subject, short=True))) + certlist.append('Signature Algorithm: {}'.format( + x509_cert.signature_algo)) + certlist.append('Valid From: {}'.format( + x509_cert['tbs_certificate']['validity']['not_before'].native)) + certlist.append('Valid To: {}'.format( + x509_cert['tbs_certificate']['validity']['not_after'].native)) + certlist.append('Issuer: {}'.format( + get_certificate_name_string(x509_cert.issuer, short=True))) + certlist.append('Serial Number: {}'.format( + hex(x509_cert.serial_number))) + certlist.append('Hash Algorithm: {}'.format(x509_cert.hash_algo)) for k, v in hashfunctions.items(): - certlist.append("{} {}".format(k, v(cert).hexdigest())) + certlist.append('{} {}'.format(k, v(cert).hexdigest())) for public_key in pkeys: x509_public_key = keys.PublicKeyInfo.load(public_key) - certlist.append("PublicKey Algorithm: {}".format(x509_public_key.algorithm)) - certlist.append("Bit Size: {}".format(x509_public_key.bit_size)) - certlist.append("Fingerprint: {}".format(binascii.hexlify(x509_public_key.fingerprint).decode("utf-8"))) + certlist.append('PublicKey Algorithm: {}'.format( + x509_public_key.algorithm)) + certlist.append('Bit Size: {}'.format(x509_public_key.bit_size)) + certlist.append('Fingerprint: {}'.format( + binascii.hexlify(x509_public_key.fingerprint).decode('utf-8'))) try: - certlist.append("Hash Algorithm: {}".format(x509_public_key.hash_algo)) - except ValueError as ve: - # RSA pkey does not have an hash algorithm + certlist.append('Hash Algorithm: {}'.format( + x509_public_key.hash_algo)) + except ValueError: pass return '\n'.join(certlist) diff --git a/StaticAnalyzer/views/android/code_analysis.py b/StaticAnalyzer/views/android/code_analysis.py index bcc31c35..ae61dde2 100755 --- a/StaticAnalyzer/views/android/code_analysis.py +++ b/StaticAnalyzer/views/android/code_analysis.py @@ -2,36 +2,27 @@ """Module holding the functions for code analysis.""" import io -import shutil -import re +import logging import os +import re +import shutil from django.conf import settings -from django.utils.html import escape -from MobSF.utils import ( - PrintException, - filename_from_path -) +from MobSF.utils import filename_from_path, log_exception -from StaticAnalyzer.views.shared_func import ( - url_n_email_extract, - api_rule_matcher, - code_rule_matcher, -) +from StaticAnalyzer.views.android import android_apis, android_rules +from StaticAnalyzer.views.shared_func import (api_rule_matcher, + code_rule_matcher, + url_n_email_extract) -from StaticAnalyzer.views.android import ( - android_rules, - android_apis -) -import logging logger = logging.getLogger(__name__) def code_analysis(app_dir, perms, typ): """Perform the code analysis.""" try: - logger.info("Static Android Code Analysis Started") + logger.info('Static Android Code Analysis Started') api_rules = android_apis.APIS code_rules = android_rules.RULES code_findings = {} @@ -39,54 +30,58 @@ def code_analysis(app_dir, perms, typ): email_n_file = [] url_n_file = [] url_list = [] - domains = {} - if typ == "apk": + if typ == 'apk': java_src = os.path.join(app_dir, 'java_source/') - elif typ == "studio": + elif typ == 'studio': java_src = os.path.join(app_dir, 'app/src/main/java/') - elif typ == "eclipse": + elif typ == 'eclipse': java_src = os.path.join(app_dir, 'src/') - logger.info("Code Analysis Started on - " + filename_from_path(java_src)) + logger.info('Code Analysis Started on - %s', + filename_from_path(java_src)) # pylint: disable=unused-variable # Needed by os.walk - for dir_name, sub_dir, files in os.walk(java_src): + for dir_name, _sub_dir, files in os.walk(java_src): for jfile in files: jfile_path = os.path.join(java_src, dir_name, jfile) - if "+" in jfile: + if '+' in jfile: p_2 = os.path.join(java_src, dir_name, - jfile.replace("+", "x")) + jfile.replace('+', 'x')) shutil.move(jfile_path, p_2) jfile_path = p_2 repath = dir_name.replace(java_src, '') if ( - jfile.endswith('.java') and - any(re.search(cls, repath) - for cls in settings.SKIP_CLASSES) is False + jfile.endswith('.java') + and any(re.search(cls, repath) + for cls in settings.SKIP_CLASSES) is False ): dat = '' with io.open( jfile_path, mode='r', - encoding="utf8", - errors="ignore" + encoding='utf8', + errors='ignore', ) as file_pointer: dat = file_pointer.read() # Code Analysis - # print "[INFO] Doing Code Analysis on - " + jfile_path relative_java_path = jfile_path.replace(java_src, '') code_rule_matcher( - code_findings, list(perms.keys()), dat, relative_java_path, code_rules) + code_findings, + list(perms.keys()), + dat, + relative_java_path, + code_rules) # API Check api_rule_matcher(api_findings, list(perms.keys()), dat, relative_java_path, api_rules) - # Extract URLs and Emails - urls, urls_nf, emails_nf = url_n_email_extract(dat, relative_java_path) + # Extract URLs and Emails + urls, urls_nf, emails_nf = url_n_email_extract( + dat, relative_java_path) url_list.extend(urls) url_n_file.extend(urls_nf) email_n_file.extend(emails_nf) - logger.info("Finished Code Analysis, Email and URL Extraction") + logger.info('Finished Code Analysis, Email and URL Extraction') code_an_dic = { 'api': api_findings, 'findings': code_findings, @@ -95,5 +90,5 @@ def code_analysis(app_dir, perms, typ): 'emails': email_n_file, } return code_an_dic - except: - PrintException("Performing Code Analysis") + except Exception: + log_exception('Performing Code Analysis') diff --git a/StaticAnalyzer/views/android/converter.py b/StaticAnalyzer/views/android/converter.py index 668afd7e..e8f7bf99 100755 --- a/StaticAnalyzer/views/android/converter.py +++ b/StaticAnalyzer/views/android/converter.py @@ -2,165 +2,179 @@ """Module holding the functions for converting.""" import glob +import logging import os import platform import subprocess from django.conf import settings -from MobSF.utils import ( - PrintException, - isFileExists, - isDirExists, - get_python, - filename_from_path -) -from StaticAnalyzer.views.android.win_fixes import ( - win_fix_python3, - win_fix_java -) -import logging +from MobSF.utils import (filename_from_path, get_python, is_dir_exists, + is_file_exists, log_exception) + +from StaticAnalyzer.views.android.win_fixes import (win_fix_java, + win_fix_python3) + logger = logging.getLogger(__name__) def get_dex_files(app_dir): - """Get all Dex Files for analysis""" - glob_pattern = app_dir + "*.dex" + """Get all Dex Files for analysis.""" + glob_pattern = app_dir + '*.dex' return glob.glob(glob_pattern) def get_jar_files(app_dir): - """Get all Dex Files for analysis""" - glob_pattern = app_dir + "*.jar" + """Get all Dex Files for analysis.""" + glob_pattern = app_dir + '*.jar' return glob.glob(glob_pattern) def dex_2_jar(app_path, app_dir, tools_dir): """Run dex2jar.""" try: - logger.info("DEX -> JAR") + logger.info('DEX -> JAR') working_dir = None args = [] - if settings.JAR_CONVERTER == "d2j": - logger.info("Using JAR converter - dex2jar") + if settings.JAR_CONVERTER == 'd2j': + logger.info('Using JAR converter - dex2jar') dexes = get_dex_files(app_dir) for idx, dex in enumerate(dexes): - logger.info("Converting " + - filename_from_path(dex) + " to JAR") - if len(settings.DEX2JAR_BINARY) > 0 and isFileExists(settings.DEX2JAR_BINARY): + logger.info('Converting %s to JAR', + filename_from_path(dex)) + if (len(settings.DEX2JAR_BINARY) > 0 + and is_file_exists(settings.DEX2JAR_BINARY)): d2j = settings.DEX2JAR_BINARY else: - if platform.system() == "Windows": + if platform.system() == 'Windows': win_fix_java(tools_dir) d2j = os.path.join(tools_dir, 'd2j2/d2j-dex2jar.bat') else: inv = os.path.join(tools_dir, 'd2j2/d2j_invoke.sh') d2j = os.path.join(tools_dir, 'd2j2/d2j-dex2jar.sh') - subprocess.call(["chmod", "777", d2j]) - subprocess.call(["chmod", "777", inv]) + subprocess.call(['chmod', '777', d2j]) + subprocess.call(['chmod', '777', inv]) args = [ d2j, dex, '-f', '-o', - app_dir + 'classes' + str(idx) + '.jar' + app_dir + 'classes' + str(idx) + '.jar', ] subprocess.call(args) - elif settings.JAR_CONVERTER == "enjarify": - logger.info("Using JAR converter - Google enjarify") - if len(settings.ENJARIFY_DIRECTORY) > 0 and isDirExists(settings.ENJARIFY_DIRECTORY): + elif settings.JAR_CONVERTER == 'enjarify': + logger.info('Using JAR converter - Google enjarify') + if (len(settings.ENJARIFY_DIRECTORY) > 0 + and is_dir_exists(settings.ENJARIFY_DIRECTORY)): working_dir = settings.ENJARIFY_DIRECTORY else: working_dir = os.path.join(tools_dir, 'enjarify/') - if platform.system() == "Windows": + if platform.system() == 'Windows': win_fix_python3(tools_dir) enjarify = os.path.join(working_dir, 'enjarify.bat') - args = [enjarify, app_path, "-f", - "-o", app_dir + 'classes.jar'] + args = [enjarify, app_path, '-f', + '-o', app_dir + 'classes.jar'] else: if len(settings.PYTHON3_PATH) > 2: - python3 = os.path.join(settings.PYTHON3_PATH, "python3") + python3 = os.path.join(settings.PYTHON3_PATH, 'python3') else: python3 = get_python() args = [ python3, - "-O", - "-m", - "enjarify.main", + '-O', + '-m', + 'enjarify.main', app_path, - "-f", - "-o", - app_dir + 'classes.jar' + '-f', + '-o', + app_dir + 'classes.jar', ] subprocess.call(args, cwd=working_dir) - except: - PrintException("Converting Dex to JAR") + except Exception: + log_exception('Converting Dex to JAR') def dex_2_smali(app_dir, tools_dir): - """Run dex2smali""" + """Run dex2smali.""" try: - logger.info("DEX -> SMALI") + logger.info('DEX -> SMALI') dexes = get_dex_files(app_dir) for dex_path in dexes: - logger.info("Converting " + - filename_from_path(dex_path) + " to Smali Code") - if len(settings.BACKSMALI_BINARY) > 0 and isFileExists(settings.BACKSMALI_BINARY): + logger.info('Converting %s to Smali Code', + filename_from_path(dex_path)) + if (len(settings.BACKSMALI_BINARY) > 0 + and is_file_exists(settings.BACKSMALI_BINARY)): bs_path = settings.BACKSMALI_BINARY else: bs_path = os.path.join(tools_dir, 'baksmali-2.2.7.jar') output = os.path.join(app_dir, 'smali_source/') args = [ settings.JAVA_PATH + 'java', - '-jar', bs_path, 'd', dex_path, '-o', output + '-jar', + bs_path, + 'd', + dex_path, + '-o', + output, ] subprocess.call(args) - except: - PrintException("Converting DEX to SMALI") + except Exception: + log_exception('Converting DEX to SMALI') def jar_2_java(app_dir, tools_dir): """Conver jar to java.""" try: - logger.info("JAR -> JAVA") + logger.info('JAR -> JAVA') jar_files = get_jar_files(app_dir) output = os.path.join(app_dir, 'java_source/') for jar_path in jar_files: - logger.info("Decompiling {} to Java Code".format( - filename_from_path(jar_path))) + logger.info( + 'Decompiling %s to Java Code', + filename_from_path(jar_path)) if settings.DECOMPILER == 'jd-core': - if ( - len(settings.JD_CORE_DECOMPILER_BINARY) > 0 and - isFileExists(settings.JD_CORE_DECOMPILER_BINARY) - ): - jd_path = settings.JD_CORE_DECOMPILER_BINARY + ext_jdcore = settings.JD_CORE_DECOMPILER_BINARY + if (len(ext_jdcore) > 0 + and is_file_exists(ext_jdcore)): + jd_path = ext_jdcore else: jd_path = os.path.join(tools_dir, 'jd-core.jar') args = [settings.JAVA_PATH + 'java', - '-jar', jd_path, jar_path, output] + '-jar', + jd_path, + jar_path, + output] elif settings.DECOMPILER == 'cfr': - if ( - len(settings.CFR_DECOMPILER_BINARY) > 0 and - isFileExists(settings.CFR_DECOMPILER_BINARY) - ): - jd_path = settings.CFR_DECOMPILER_BINARY + ext_cfr = settings.CFR_DECOMPILER_BINARY + if (len(ext_cfr) > 0 + and is_file_exists(ext_cfr)): + jd_path = ext_cfr else: jd_path = os.path.join(tools_dir, 'cfr-0.144.jar') - args = [settings.JAVA_PATH + 'java', '-jar', - jd_path, jar_path, '--outputdir', output, '--silent', 'true'] - elif settings.DECOMPILER == "procyon": - if ( - len(settings.PROCYON_DECOMPILER_BINARY) > 0 and - isFileExists(settings.PROCYON_DECOMPILER_BINARY) - ): - pd_path = settings.PROCYON_DECOMPILER_BINARY + args = [settings.JAVA_PATH + 'java', + '-jar', + jd_path, + jar_path, + '--outputdir', + output, + '--silent', + 'true'] + elif settings.DECOMPILER == 'procyon': + ext_proc = settings.PROCYON_DECOMPILER_BINARY + if (len(ext_proc) > 0 + and is_file_exists(ext_proc)): + pd_path = ext_proc else: pd_path = os.path.join( tools_dir, 'procyon-decompiler-0.5.34.jar') args = [settings.JAVA_PATH + 'java', - '-jar', pd_path, jar_path, '-o', output] + '-jar', + pd_path, + jar_path, + '-o', + output] subprocess.call(args) - except: - PrintException("Converting JAR to JAVA") + except Exception: + log_exception('Converting JAR to JAVA') diff --git a/StaticAnalyzer/views/android/db_interaction.py b/StaticAnalyzer/views/android/db_interaction.py index 658c0084..009d99ec 100755 --- a/StaticAnalyzer/views/android/db_interaction.py +++ b/StaticAnalyzer/views/android/db_interaction.py @@ -1,22 +1,22 @@ # -*- coding: utf_8 -*- -from django.db.models import QuerySet -"""Module holding the functions for the db.""" +import logging -from MobSF.utils import ( - PrintException, - python_list, - python_dict -) +from django.db.models import QuerySet + +from MobSF.utils import log_exception, python_dict, python_list from StaticAnalyzer.models import StaticAnalyzerAndroid -import logging + +"""Module holding the functions for the db.""" + + logger = logging.getLogger(__name__) def get_context_from_db_entry(db_entry: QuerySet) -> dict: - """Return the context for APK/ZIP from DB""" + """Return the context for APK/ZIP from DB.""" try: - logger.info("Analysis is already Done. Fetching data from the DB...") + logger.info('Analysis is already Done. Fetching data from the DB...') context = { 'title': db_entry[0].TITLE, @@ -70,12 +70,19 @@ def get_context_from_db_entry(db_entry: QuerySet) -> dict: 'trackers': python_dict(db_entry[0].TRACKERS), } return context - except: - PrintException("Fetching from DB") + except Exception: + log_exception('Fetching from DB') -def get_context_from_analysis(app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_anal, apk_id, trackers) -> dict: - """Get the context for APK/ZIP from analysis results""" +def get_context_from_analysis(app_dic, + man_data_dic, + man_an_dic, + code_an_dic, + cert_dic, + bin_anal, + apk_id, + trackers) -> dict: + """Get the context for APK/ZIP from analysis results.""" try: context = { 'title': 'Static Analysis', @@ -119,22 +126,29 @@ def get_context_from_analysis(app_dic, man_data_dic, man_an_dic, code_an_dic, ce 'strings': app_dic['strings'], 'zipped': app_dic['zipped'], 'mani': app_dic['mani'], - 'e_act': man_an_dic['exported_cnt']["act"], - 'e_ser': man_an_dic['exported_cnt']["ser"], - 'e_bro': man_an_dic['exported_cnt']["bro"], - 'e_cnt': man_an_dic['exported_cnt']["cnt"], + 'e_act': man_an_dic['exported_cnt']['act'], + 'e_ser': man_an_dic['exported_cnt']['ser'], + 'e_bro': man_an_dic['exported_cnt']['bro'], + 'e_cnt': man_an_dic['exported_cnt']['cnt'], 'apkid': apk_id, 'play_details': app_dic['playstore'], 'firebase': code_an_dic['firebase'], 'trackers': trackers, } return context - except: - PrintException("Rendering to Template") + except Exception: + log_exception('Rendering to Template') -def update_db_entry(app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_anal, apk_id, trackers) -> None: - """Update an APK/ZIP DB entry""" +def update_db_entry(app_dic, + man_data_dic, + man_an_dic, + code_an_dic, + cert_dic, + bin_anal, + apk_id, + trackers) -> None: + """Update an APK/ZIP DB entry.""" try: # pylint: disable=E1101 StaticAnalyzerAndroid.objects.filter(MD5=app_dic['md5']).update( @@ -180,21 +194,28 @@ def update_db_entry(app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bi ZIPPED=app_dic['zipped'], MANI=app_dic['mani'], EXPORTED_ACT=man_an_dic['exported_act'], - E_ACT=man_an_dic['exported_cnt']["act"], - E_SER=man_an_dic['exported_cnt']["ser"], - E_BRO=man_an_dic['exported_cnt']["bro"], - E_CNT=man_an_dic['exported_cnt']["cnt"], + E_ACT=man_an_dic['exported_cnt']['act'], + E_SER=man_an_dic['exported_cnt']['ser'], + E_BRO=man_an_dic['exported_cnt']['bro'], + E_CNT=man_an_dic['exported_cnt']['cnt'], APK_ID=apk_id, PLAY_DETAILS=app_dic['playstore'], FIREBASE=code_an_dic['firebase'], TRACKERS=trackers, ) - except: - PrintException("Updating DB") + except Exception: + log_exception('Updating DB') -def create_db_entry(app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_anal, apk_id, trackers) -> None: - """Create a new DB-Entry for APK/ZIP""" +def create_db_entry(app_dic, + man_data_dic, + man_an_dic, + code_an_dic, + cert_dic, + bin_anal, + apk_id, + trackers) -> None: + """Create a new DB-Entry for APK/ZIP.""" try: static_db = StaticAnalyzerAndroid( TITLE='Static Analysis', @@ -239,15 +260,15 @@ def create_db_entry(app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bi ZIPPED=app_dic['zipped'], MANI=app_dic['mani'], EXPORTED_ACT=man_an_dic['exported_act'], - E_ACT=man_an_dic['exported_cnt']["act"], - E_SER=man_an_dic['exported_cnt']["ser"], - E_BRO=man_an_dic['exported_cnt']["bro"], - E_CNT=man_an_dic['exported_cnt']["cnt"], + E_ACT=man_an_dic['exported_cnt']['act'], + E_SER=man_an_dic['exported_cnt']['ser'], + E_BRO=man_an_dic['exported_cnt']['bro'], + E_CNT=man_an_dic['exported_cnt']['cnt'], APK_ID=apk_id, PLAY_DETAILS=app_dic['playstore'], FIREBASE=code_an_dic['firebase'], TRACKERS=trackers, ) static_db.save() - except: - PrintException("Saving to DB") + except Exception: + log_exception('Saving to DB') diff --git a/StaticAnalyzer/views/android/dvm_permissions.py b/StaticAnalyzer/views/android/dvm_permissions.py index f6f73595..ead50b1d 100755 --- a/StaticAnalyzer/views/android/dvm_permissions.py +++ b/StaticAnalyzer/views/android/dvm_permissions.py @@ -13,226 +13,224 @@ # along with Androguard. If not, see . # frameworks/base/core/res/AndroidManifest.xml -########################################## PERMISSIONS ################### +# ######################################### PERMISSIONS ################### +# flake8: noqa DVM_PERMISSIONS = { - "MANIFEST_PERMISSION": { - "SEND_SMS": ["dangerous", "send SMS messages", "Allows application to send SMS messages. Malicious applications may cost you money by sending messages without your confirmation."], - "SEND_SMS_NO_CONFIRMATION": ["dangerous", "send SMS messages", "send SMS messages via the Messaging app with no user input or confirmation"], - "CALL_PHONE": ["dangerous", "directly call phone numbers", "Allows the application to call phone numbers without your intervention. Malicious applications may cause unexpected calls on your phone bill. Note that this does not allow the application to call emergency numbers."], - "RECEIVE_SMS": ["dangerous", "receive SMS", "Allows application to receive and process SMS messages. Malicious applications may monitor your messages or delete them without showing them to you."], - "RECEIVE_MMS": ["dangerous", "receive MMS", "Allows application to receive and process MMS messages. Malicious applications may monitor your messages or delete them without showing them to you."], - "READ_SMS": ["dangerous", "read SMS or MMS", "Allows application to read SMS messages stored on your phone or SIM card. Malicious applications may read your confidential messages."], - "WRITE_SMS": ["dangerous", "edit SMS or MMS", "Allows application to write to SMS messages stored on your phone or SIM card. Malicious applications may delete your messages."], - "RECEIVE_WAP_PUSH": ["dangerous", "receive WAP", "Allows application to receive and process WAP messages. Malicious applications may monitor your messages or delete them without showing them to you."], - "READ_CONTACTS": ["dangerous", "read contact data", "Allows an application to read all of the contact (address) data stored on your phone. Malicious applications can use this to send your data to other people."], - "WRITE_CONTACTS": ["dangerous", "write contact data", "Allows an application to modify the contact (address) data stored on your phone. Malicious applications can use this to erase or modify your contact data."], - "READ_PROFILE": ["dangerous", "read the user's personal profile data", "Allows an application to read the user's personal profile data."], - "WRITE_PROFILE": ["dangerous", "write the user's personal profile data", "Allows an application to write (but not read) the user's personal profile data."], - "READ_SOCIAL_STREAM": ["dangerous", "read from the user's social stream", "Allows an application to read from the user's social stream."], - "WRITE_SOCIAL_STREAM": ["dangerous", "write the user's social stream", "Allows an application to write (but not read) the user's social stream data."], - "READ_CALENDAR": ["dangerous", "read calendar events", "Allows an application to read all of the calendar events stored on your phone. Malicious applications can use this to send your calendar events to other people."], - - "WRITE_CALENDAR": ["dangerous", "add or modify calendar events and send emails to guests", "Allows an application to add or change the events on your calendar, which may send emails to guests. Malicious applications can use this to erase or modify your calendar events or to send emails to guests."], - "READ_USER_DICTIONARY": ["dangerous", "read user-defined dictionary", "Allows an application to read any private words, names and phrases that the user may have stored in the user dictionary."], - "WRITE_USER_DICTIONARY": ["normal", "write to user-defined dictionary", "Allows an application to write new words into the user dictionary."], - "READ_HISTORY_BOOKMARKS": ["dangerous", "read Browser\'s history and bookmarks", "Allows the application to read all the URLs that the browser has visited and all of the browser\'s bookmarks."], - "WRITE_HISTORY_BOOKMARKS": ["dangerous", "write Browser\'s history and bookmarks", "Allows an application to modify the browser\'s history or bookmarks stored on your phone. Malicious applications can use this to erase or modify your browser\'s data."], - "SET_ALARM": ["normal", "set alarm in alarm clock", "Allows the application to set an alarm in an installed alarm clock application. Some alarm clock applications may not implement this feature."], - "ACCESS_FINE_LOCATION": ["dangerous", "fine (GPS) location", "Access fine location sources, such as the Global Positioning System on the phone, where available. Malicious applications can use this to determine where you are and may consume additional battery power."], - "ACCESS_COARSE_LOCATION": ["dangerous", "coarse (network-based) location", "Access coarse location sources, such as the mobile network database, to determine an approximate phone location, where available. Malicious applications can use this to determine approximately where you are."], - "ACCESS_MOCK_LOCATION": ["dangerous", "mock location sources for testing", "Create mock location sources for testing. Malicious applications can use this to override the location and/or status returned by real-location sources such as GPS or Network providers."], - "ACCESS_LOCATION_EXTRA_COMMANDS": ["normal", "access extra location provider commands", "Access extra location provider commands. Malicious applications could use this to interfere with the operation of the GPS or other location sources."], - "INSTALL_LOCATION_PROVIDER": ["signatureOrSystem", "permission to install a location provider", "Create mock location sources for testing. Malicious applications can use this to override the location and/or status returned by real-location sources such as GPS or Network providers, or monitor and report your location to an external source."], - "INTERNET": ["dangerous", "full Internet access", "Allows an application to create network sockets."], - "ACCESS_NETWORK_STATE": ["normal", "view network status", "Allows an application to view the status of all networks."], - "ACCESS_WIFI_STATE": ["normal", "view Wi-Fi status", "Allows an application to view the information about the status of Wi-Fi."], - "BLUETOOTH": ["dangerous", "create Bluetooth connections", "Allows an application to view configuration of the local Bluetooth phone and to make and accept connections with paired devices."], - "NFC": ["dangerous", "control Near-Field Communication", "Allows an application to communicate with Near-Field Communication (NFC) tags, cards and readers."], - "USE_SIP": ["dangerous", "make/receive Internet calls", "Allows an application to use the SIP service to make/receive Internet calls."], - "ACCOUNT_MANAGER": ["signature", "act as the Account Manager Service", "Allows an application to make calls to Account Authenticators"], - "GET_ACCOUNTS": ["normal", "discover known accounts", "Allows an application to access the list of accounts known by the phone."], - "AUTHENTICATE_ACCOUNTS": ["dangerous", "act as an account authenticator", "Allows an application to use the account authenticator capabilities of the Account Manager, including creating accounts as well as obtaining and setting their passwords."], - "USE_CREDENTIALS": ["dangerous", "use the authentication credentials of an account", "Allows an application to request authentication tokens."], - "MANAGE_ACCOUNTS": ["dangerous", "manage the accounts list", "Allows an application to perform operations like adding and removing accounts and deleting their password."], - "MODIFY_AUDIO_SETTINGS": ["dangerous", "change your audio settings", "Allows application to modify global audio settings, such as volume and routing."], - "RECORD_AUDIO": ["dangerous", "record audio", "Allows application to access the audio record path."], - "CAMERA": ["dangerous", "take pictures and videos", "Allows application to take pictures and videos with the camera. This allows the application to collect images that the camera is seeing at any time."], - "VIBRATE": ["normal", "control vibrator", "Allows the application to control the vibrator."], - "FLASHLIGHT": ["normal", "control flashlight", "Allows the application to control the flashlight."], - "ACCESS_USB": ["signatureOrSystem", "access USB devices", "Allows the application to access USB devices."], - "HARDWARE_TEST": ["signature", "test hardware", "Allows the application to control various peripherals for the purpose of hardware testing."], - "PROCESS_OUTGOING_CALLS": ["dangerous", "intercept outgoing calls", "Allows application to process outgoing calls and change the number to be dialled. Malicious applications may monitor, redirect or prevent outgoing calls."], - "MODIFY_PHONE_STATE": ["signatureOrSystem", "modify phone status", "Allows the application to control the phone features of the device. An application with this permission can switch networks, turn the phone radio on and off and the like, without ever notifying you."], - "READ_PHONE_STATE": ["dangerous", "read phone state and identity", "Allows the application to access the phone features of the device. An application with this permission can determine the phone number and serial number of this phone, whether a call is active, the number that call is connected to and so on."], - "WRITE_EXTERNAL_STORAGE": ["dangerous", "read/modify/delete SD card contents", "Allows an application to write to the SD card."], - "READ_EXTERNAL_STORAGE": ["dangerous", "read SD card contents", "Allows an application to read from SD Card."], - "WRITE_SETTINGS": ["dangerous", "modify global system settings", "Allows an application to modify the system\'s settings data. Malicious applications can corrupt your system\'s configuration."], - "WRITE_SECURE_SETTINGS": ["signatureOrSystem", "modify secure system settings", "Allows an application to modify the system\'s secure settings data. Not for use by common applications."], - "WRITE_GSERVICES": ["signatureOrSystem", "modify the Google services map", "Allows an application to modify the Google services map. Not for use by common applications."], - "EXPAND_STATUS_BAR": ["normal", "expand/collapse status bar", "Allows application to expand or collapse the status bar."], - "GET_TASKS": ["dangerous", "retrieve running applications", "Allows application to retrieve information about currently and recently running tasks. May allow malicious applications to discover private information about other applications."], - "REORDER_TASKS": ["dangerous", "reorder applications running", "Allows an application to move tasks to the foreground and background. Malicious applications can force themselves to the front without your control."], - "CHANGE_CONFIGURATION": ["dangerous", "change your UI settings", "Allows an application to change the current configuration, such as the locale or overall font size."], - "RESTART_PACKAGES": ["normal", "kill background processes", "Allows an application to kill background processes of other applications, even if memory is not low."], - "KILL_BACKGROUND_PROCESSES": ["normal", "kill background processes", "Allows an application to kill background processes of other applications, even if memory is not low."], - "FORCE_STOP_PACKAGES": ["signature", "force-stop other applications", "Allows an application to stop other applications forcibly."], - "DUMP": ["signatureOrSystem", "retrieve system internal status", "Allows application to retrieve internal status of the system. Malicious applications may retrieve a wide variety of private and secure information that they should never commonly need."], - "SYSTEM_ALERT_WINDOW": ["dangerous", "display system-level alerts", "Allows an application to show system-alert windows. Malicious applications can take over the entire screen of the phone."], - "SET_ANIMATION_SCALE": ["dangerous", "modify global animation speed", "Allows an application to change the global animation speed (faster or slower animations) at any time."], - "PERSISTENT_ACTIVITY": ["dangerous", "make application always run", "Allows an application to make parts of itself persistent, so that the system can\'t use it for other applications."], - "GET_PACKAGE_SIZE": ["normal", "measure application storage space", "Allows an application to retrieve its code, data and cache sizes"], - "SET_PREFERRED_APPLICATIONS": ["signature", "set preferred applications", "Allows an application to modify your preferred applications. This can allow malicious applications to silently change the applications that are run, spoofing your existing applications to collect private data from you."], - "RECEIVE_BOOT_COMPLETED": ["normal", "automatically start at boot", "Allows an application to start itself as soon as the system has finished booting. This can make it take longer to start the phone and allow the application to slow down the overall phone by always running."], - "BROADCAST_STICKY": ["normal", "send sticky broadcast", "Allows an application to send sticky broadcasts, which remain after the broadcast ends. Malicious applications can make the phone slow or unstable by causing it to use too much memory."], - "WAKE_LOCK": ["dangerous", "prevent phone from sleeping", "Allows an application to prevent the phone from going to sleep."], - "SET_WALLPAPER": ["normal", "set wallpaper", "Allows the application to set the system wallpaper."], - "SET_WALLPAPER_HINTS": ["normal", "set wallpaper size hints", "Allows the application to set the system wallpaper size hints."], - "SET_TIME": ["signatureOrSystem", "set time", "Allows an application to change the phone\'s clock time."], - "SET_TIME_ZONE": ["dangerous", "set time zone", "Allows an application to change the phone\'s time zone."], - "MOUNT_UNMOUNT_FILESYSTEMS": ["dangerous", "mount and unmount file systems", "Allows the application to mount and unmount file systems for removable storage."], - "MOUNT_FORMAT_FILESYSTEMS": ["dangerous", "format external storage", "Allows the application to format removable storage."], - "ASEC_ACCESS": ["signature", "get information on internal storage", "Allows the application to get information on internal storage."], - "ASEC_CREATE": ["signature", "create internal storage", "Allows the application to create internal storage."], - "ASEC_DESTROY": ["signature", "destroy internal storage", "Allows the application to destroy internal storage."], - "ASEC_MOUNT_UNMOUNT": ["signature", "mount/unmount internal storage", "Allows the application to mount/unmount internal storage."], - "ASEC_RENAME": ["signature", "rename internal storage", "Allows the application to rename internal storage."], - "DISABLE_KEYGUARD": ["dangerous", "disable key lock", "Allows an application to disable the key lock and any associated password security. A legitimate example of this is the phone disabling the key lock when receiving an incoming phone call, then re-enabling the key lock when the call is finished."], - "READ_SYNC_SETTINGS": ["normal", "read sync settings", "Allows an application to read the sync settings, such as whether sync is enabled for Contacts."], - "WRITE_SYNC_SETTINGS": ["dangerous", "write sync settings", "Allows an application to modify the sync settings, such as whether sync is enabled for Contacts."], - "READ_SYNC_STATS": ["normal", "read sync statistics", "Allows an application to read the sync stats; e.g. the history of syncs that have occurred."], - "WRITE_APN_SETTINGS": ["dangerous", "write Access Point Name settings", "Allows an application to modify the APN settings, such as Proxy and Port of any APN."], - "SUBSCRIBED_FEEDS_READ": ["normal", "read subscribed feeds", "Allows an application to receive details about the currently synced feeds."], - "SUBSCRIBED_FEEDS_WRITE": ["dangerous", "write subscribed feeds", "Allows an application to modify your currently synced feeds. This could allow a malicious application to change your synced feeds."], - "CHANGE_NETWORK_STATE": ["dangerous", "change network connectivity", "Allows an application to change the state of network connectivity."], - "CHANGE_WIFI_STATE": ["dangerous", "change Wi-Fi status", "Allows an application to connect to and disconnect from Wi-Fi access points and to make changes to configured Wi-Fi networks."], - "CHANGE_WIFI_MULTICAST_STATE": ["dangerous", "allow Wi-Fi Multicast reception", "Allows an application to receive packets not directly addressed to your device. This can be useful when discovering services offered nearby. It uses more power than the non-multicast mode."], - "BLUETOOTH_ADMIN": ["dangerous", "bluetooth administration", "Allows an application to configure the local Bluetooth phone and to discover and pair with remote devices."], - "CLEAR_APP_CACHE": ["dangerous", "delete all application cache data", "Allows an application to free phone storage by deleting files in application cache directory. Access is usually very restricted to system process."], - "READ_LOGS": ["dangerous", "read sensitive log data", "Allows an application to read from the system\'s various log files. This allows it to discover general information about what you are doing with the phone, potentially including personal or private information."], - "SET_DEBUG_APP": ["dangerous", "enable application debugging", "Allows an application to turn on debugging for another application. Malicious applications can use this to kill other applications."], - "SET_PROCESS_LIMIT": ["dangerous", "limit number of running processes", "Allows an application to control the maximum number of processes that will run. Never needed for common applications."], - "SET_ALWAYS_FINISH": ["dangerous", "make all background applications close", "Allows an application to control whether activities are always finished as soon as they go to the background. Never needed for common applications."], - "SIGNAL_PERSISTENT_PROCESSES": ["dangerous", "send Linux signals to applications", "Allows application to request that the supplied signal be sent to all persistent processes."], - "DIAGNOSTIC": ["signature", "read/write to resources owned by diag", "Allows an application to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."], - "STATUS_BAR": ["signatureOrSystem", "disable or modify status bar", "Allows application to disable the status bar or add and remove system icons."], - "STATUS_BAR_SERVICE": ["signature", "status bar", "Allows the application to be the status bar."], - "FORCE_BACK": ["signature", "force application to close", "Allows an application to force any activity that is in the foreground to close and go back. Should never be needed for common applications."], - "UPDATE_DEVICE_STATS": ["signatureOrSystem", "modify battery statistics", "Allows the modification of collected battery statistics. Not for use by common applications."], - "INTERNAL_SYSTEM_WINDOW": ["signature", "display unauthorised windows", "Allows the creation of windows that are intended to be used by the internal system user interface. Not for use by common applications."], - "MANAGE_APP_TOKENS": ["signature", "manage application tokens", "Allows applications to create and manage their own tokens, bypassing their common Z-ordering. Should never be needed for common applications."], - "INJECT_EVENTS": ["signature", "press keys and control buttons", "Allows an application to deliver its own input events (key presses, etc.) to other applications. Malicious applications can use this to take over the phone."], - "SET_ACTIVITY_WATCHER": ["signature", "monitor and control all application launching", "Allows an application to monitor and control how the system launches activities. Malicious applications may compromise the system completely. This permission is needed only for development, never for common phone usage."], - "SHUTDOWN": ["signature", "partial shutdown", "Puts the activity manager into a shut-down state. Does not perform a complete shut down."], - "STOP_APP_SWITCHES": ["signature", "prevent app switches", "Prevents the user from switching to another application."], - "READ_INPUT_STATE": ["signature", "record what you type and actions that you take", "Allows applications to watch the keys that you press even when interacting with another application (such as entering a password). Should never be needed for common applications."], - "BIND_INPUT_METHOD": ["signature", "bind to an input method", "Allows the holder to bind to the top-level interface of an input method. Should never be needed for common applications."], - "BIND_WALLPAPER": ["signatureOrSystem", "bind to wallpaper", "Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for common applications."], - "BIND_DEVICE_ADMIN": ["signature", "interact with device admin", "Allows the holder to send intents to a device administrator. Should never be needed for common applications."], - "SET_ORIENTATION": ["signature", "change screen orientation", "Allows an application to change the rotation of the screen at any time. Should never be needed for common applications."], - "INSTALL_PACKAGES": ["signatureOrSystem", "directly install applications", "Allows an application to install new or updated Android packages. Malicious applications can use this to add new applications with arbitrarily powerful permissions."], - "REQUEST_INSTALL_PACKAGES": ["dangerous", "Allows an application to request installing packages.", "Malicious applications can use this to try and trick users into installing additional malicious packages."], - "CLEAR_APP_USER_DATA": ["signature", "delete other applications\' data", "Allows an application to clear user data."], - "DELETE_CACHE_FILES": ["signatureOrSystem", "delete other applications\' caches", "Allows an application to delete cache files."], - "DELETE_PACKAGES": ["signatureOrSystem", "delete applications", "Allows an application to delete Android packages. Malicious applications can use this to delete important applications."], - "MOVE_PACKAGE": ["signatureOrSystem", "Move application resources", "Allows an application to move application resources from internal to external media and vice versa."], - "CHANGE_COMPONENT_ENABLED_STATE": ["signatureOrSystem", "enable or disable application components", "Allows an application to change whether or not a component of another application is enabled. Malicious applications can use this to disable important phone capabilities. It is important to be careful with permission, as it is possible to bring application components into an unusable, inconsistent or unstable state."], - "ACCESS_SURFACE_FLINGER": ["signature", "access SurfaceFlinger", "Allows application to use SurfaceFlinger low-level features."], - "READ_FRAME_BUFFER": ["signature", "read frame buffer", "Allows application to read the content of the frame buffer."], - "BRICK": ["signature", "permanently disable phone", "Allows the application to disable the entire phone permanently. This is very dangerous."], - "REBOOT": ["signatureOrSystem", "force phone reboot", "Allows the application to force the phone to reboot."], - "DEVICE_POWER": ["signature", "turn phone on or off", "Allows the application to turn the phone on or off."], - "FACTORY_TEST": ["signature", "run in factory test mode", "Run as a low-level manufacturer test, allowing complete access to the phone hardware. Only available when a phone is running in manufacturer test mode."], - "BROADCAST_PACKAGE_REMOVED": ["signature", "send package removed broadcast", "Allows an application to broadcast a notification that an application package has been removed. Malicious applications may use this to kill any other application running."], - "BROADCAST_SMS": ["signature", "send SMS-received broadcast", "Allows an application to broadcast a notification that an SMS message has been received. Malicious applications may use this to forge incoming SMS messages."], - "BROADCAST_WAP_PUSH": ["signature", "send WAP-PUSH-received broadcast", "Allows an application to broadcast a notification that a WAP-PUSH message has been received. Malicious applications may use this to forge MMS message receipt or to replace the content of any web page silently with malicious variants."], - "MASTER_CLEAR": ["signatureOrSystem", "reset system to factory defaults", "Allows an application to completely reset the system to its factory settings, erasing all data, configuration and installed applications."], - "CALL_PRIVILEGED": ["signatureOrSystem", "directly call any phone numbers", "Allows the application to call any phone number, including emergency numbers, without your intervention. Malicious applications may place unnecessary and illegal calls to emergency services."], - "PERFORM_CDMA_PROVISIONING": ["signatureOrSystem", "directly start CDMA phone setup", "Allows the application to start CDMA provisioning. Malicious applications may start CDMA provisioning unnecessarily"], - "CONTROL_LOCATION_UPDATES": ["signatureOrSystem", "control location update notifications", "Allows enabling/disabling location update notifications from the radio. Not for use by common applications."], - "ACCESS_CHECKIN_PROPERTIES": ["signatureOrSystem", "access check-in properties", "Allows read/write access to properties uploaded by the check-in service. Not for use by common applications."], - "PACKAGE_USAGE_STATS": ["signature", "update component usage statistics", "Allows the modification of collected component usage statistics. Not for use by common applications."], - "BATTERY_STATS": ["normal", "modify battery statistics", "Allows the modification of collected battery statistics. Not for use by common applications."], - "BACKUP": ["signatureOrSystem", "control system back up and restore", "Allows the application to control the system\'s back-up and restore mechanism. Not for use by common applications."], - "BIND_APPWIDGET": ["signatureOrSystem", "choose widgets", "Allows the application to tell the system which widgets can be used by which application. With this permission, applications can give access to personal data to other applications. Not for use by common applications."], - "CHANGE_BACKGROUND_DATA_SETTING": ["signature", "change background data usage setting", "Allows an application to change the background data usage setting."], - "GLOBAL_SEARCH": ["signatureOrSystem", "", ""], - "GLOBAL_SEARCH_CONTROL": ["signature", "", ""], - "SET_WALLPAPER_COMPONENT": ["signatureOrSystem", "", ""], - "ACCESS_CACHE_FILESYSTEM": ["signatureOrSystem", "access the cache file system", "Allows an application to read and write the cache file system."], - "COPY_PROTECTED_DATA": ["signature", "Allows to invoke default container service to copy content. Not for use by common applications.", "Allows to invoke default container service to copy content. Not for use by common applications."], - "C2D_MESSAGE": ["signature", "Allows cloud to device messaging", "Allows the application to receive push notifications."], - - "ADD_VOICEMAIL": ["dangerous", "add voicemails into the system", "Allows an application to add voicemails into the system."], - - "ACCEPT_HANDOVER": ["dangerous", "", "Allows a calling app to continue a call which was started in another app. An example is a video calling app that wants to continue a voice call on the user's mobile network."], - "ACCESS_NOTIFICATION_POLICY": ["normal", "", "Marker permission for applications that wish to access notification policy."], - "ANSWER_PHONE_CALLS": ["dangerous", "", "Allows the app to answer an incoming phone call."], - "BIND_ACCESSIBILITY_SERVICE": ["signature", "", "Must be required by an AccessibilityService, to ensure that only the system can bind to it."], - "BIND_AUTOFILL_SERVICE": ["signature", "", "Must be required by a AutofillService, to ensure that only the system can bind to it."], - "BIND_CARRIER_MESSAGING_SERVICE": ["normal", "", "The system process that is allowed to bind to services in carrier apps will have this permission."], - "BIND_CARRIER_SERVICES": ["signature", "", "The system process that is allowed to bind to services in carrier apps will have this permission. Carrier apps should use this permission to protect their services that only the system is allowed to bind to."], - "BIND_CHOOSER_TARGET_SERVICE": ["signature", "", "Must be required by a ChooserTargetService, to ensure that only the system can bind to it"], - "BIND_CONDITION_PROVIDER_SERVICE": ["signature", "", "Must be required by a ConditionProviderService, to ensure that only the system can bind to it"], - "BIND_DREAM_SERVICE": ["signature", "", "Must be required by an DreamService, to ensure that only the system can bind to it."], - "BIND_INCALL_SERVICE": ["signature", "", "Must be required by a InCallService, to ensure that only the system can bind to it."], - "BIND_MIDI_DEVICE_SERVICE": ["signature", "", "Must be required by an MidiDeviceService, to ensure that only the system can bind to it."], - "BIND_NFC_SERVICE": ["signature", "", "Must be required by a HostApduService or OffHostApduService to ensure that only the system can bind to it."], - "BIND_NOTIFICATION_LISTENER_SERVICE": ["signature", "", "Must be required by an NotificationListenerService, to ensure that only the system can bind to it."], - "BIND_PRINT_SERVICE": ["signature", "", "Must be required by a PrintService, to ensure that only the system can bind to it."], - "BIND_QUICK_SETTINGS_TILE": ["normal", "", "Allows an application to bind to third party quick settings tiles."], - "BIND_REMOTEVIEWS": ["normal", "", "Must be required by a RemoteViewsService, to ensure that only the system can bind to it."], - "BIND_SCREENING_SERVICE": ["signature", "", "Must be required by a CallScreeningService, to ensure that only the system can bind to it."], - "BIND_TELECOM_CONNECTION_SERVICE": ["signature", "", "Must be required by a ConnectionService, to ensure that only the system can bind to it."], - "BIND_TEXT_SERVICE": ["signature", "", "Must be required by a TextService (e.g. SpellCheckerService) to ensure that only the system can bind to it."], - "BIND_TV_INPUT": ["signature", "", "Must be required by a TvInputService to ensure that only the system can bind to it."], - "BIND_VISUAL_VOICEMAIL_SERVICE": ["signature", "", "Must be required by a link"], - "BIND_VOICE_INTERACTION": ["signature", "", "Must be required by a VoiceInteractionService, to ensure that only the system can bind to it."], - "BIND_VPN_SERVICE": ["signature", "", "Must be required by a VpnService, to ensure that only the system can bind to it."], - "BIND_VR_LISTENER_SERVICE": ["signature", "", "Must be required by an VrListenerService, to ensure that only the system can bind to it."], - "BLUETOOTH_PRIVILEGED": ["normal", "", "Allows applications to pair bluetooth devices without user interaction, and to allow or disallow phonebook access or message access. This is not available to third party applications."], - "BODY_SENSORS": ["dangerous", "", "Allows an application to access data from sensors that the user uses to measure what is happening inside his/her body, such as heart rate."], - "CAPTURE_AUDIO_OUTPUT": ["normal", "", "Allows an application to capture audio output."], - "CAPTURE_SECURE_VIDEO_OUTPUT": ["normal", "", "Allows an application to capture secure video output."], - "CAPTURE_VIDEO_OUTPUT": ["normal", "", "Allows an application to capture video output."], - "FOREGROUND_SERVICE": ["normal", "", "Allows a regular application to use"], - "GET_ACCOUNTS_PRIVILEGED": ["normal", "", "Allows access to the list of accounts in the Accounts Service."], - "INSTALL_SHORTCUT": ["normal", "", "Allows an application to install a shortcut in Launcher."], - "INSTANT_APP_FOREGROUND_SERVICE": ["normal", "", "Allows an instant app to create foreground services."], - "LOCATION_HARDWARE": ["normal", "", "Allows an application to use location features in hardware, such as the geofencing api."], - "MANAGE_DOCUMENTS": ["signature", "", "Allows an application to manage access to documents, usually as part of a document picker."], - "MANAGE_OWN_CALLS": ["normal", "", "Allows a calling application which manages it own calls through the self-managed"], - "MEDIA_CONTENT_CONTROL": ["normal", "", "Allows an application to know what content is playing and control its playback."], - "NFC_TRANSACTION_EVENT": ["normal", "", "Allows applications to receive NFC transaction events."], - "READ_CALL_LOG": ["dangerous", "", "Allows an application to read the user's call log."], - "READ_PHONE_NUMBERS": ["dangerous", "", "Allows read access to the device's phone number(s). This is a subset of the capabilities granted by"], - "READ_VOICEMAIL": ["signature", "", "Allows an application to read voicemails in the system."], - "REQUEST_COMPANION_RUN_IN_BACKGROUND": ["normal", "", "Allows a companion app to run in the background."], - "REQUEST_COMPANION_USE_DATA_IN_BACKGROUND": ["normal", "", "Allows a companion app to use data in the background."], - "REQUEST_DELETE_PACKAGES": ["normal", "", "Allows an application to request deleting packages. Apps targeting APIs"], - "REQUEST_IGNORE_BATTERY_OPTIMIZATIONS": ["normal", "", "Permission an application must hold in order to use"], - "SEND_RESPOND_VIA_MESSAGE": ["normal", "", "Allows an application (Phone) to send a request to other applications to handle the respond-via-message action during incoming calls."], - "TRANSMIT_IR": ["normal", "", "Allows using the device's IR transmitter, if available."], - "UNINSTALL_SHORTCUT": ["normal", "", "Don\'t use this permission in your app. This permission is no longer supported."], - "USE_BIOMETRIC": ["normal", "", "Allows an app to use device supported biometric modalities."], - "USE_FINGERPRINT": ["normal", "", "This constant was deprecated in API level 28. Applications should request USE_BIOMETRIC instead"], - "WRITE_CALL_LOG": ["dangerous", "", "Allows an application to write (but not read) the user's call log data."], - "WRITE_VOICEMAIL": ["signature", "", "Allows an application to modify and remove existing voicemails in the system."], + 'MANIFEST_PERMISSION': { + 'SEND_SMS': ['dangerous', 'send SMS messages', 'Allows application to send SMS messages. Malicious applications may cost you money by sending messages without your confirmation.'], + 'SEND_SMS_NO_CONFIRMATION': ['dangerous', 'send SMS messages', 'send SMS messages via the Messaging app with no user input or confirmation'], + 'CALL_PHONE': ['dangerous', 'directly call phone numbers', 'Allows the application to call phone numbers without your intervention. Malicious applications may cause unexpected calls on your phone bill. Note that this does not allow the application to call emergency numbers.'], + 'RECEIVE_SMS': ['dangerous', 'receive SMS', 'Allows application to receive and process SMS messages. Malicious applications may monitor your messages or delete them without showing them to you.'], + 'RECEIVE_MMS': ['dangerous', 'receive MMS', 'Allows application to receive and process MMS messages. Malicious applications may monitor your messages or delete them without showing them to you.'], + 'READ_SMS': ['dangerous', 'read SMS or MMS', 'Allows application to read SMS messages stored on your phone or SIM card. Malicious applications may read your confidential messages.'], + 'WRITE_SMS': ['dangerous', 'edit SMS or MMS', 'Allows application to write to SMS messages stored on your phone or SIM card. Malicious applications may delete your messages.'], + 'RECEIVE_WAP_PUSH': ['dangerous', 'receive WAP', 'Allows application to receive and process WAP messages. Malicious applications may monitor your messages or delete them without showing them to you.'], + 'READ_CONTACTS': ['dangerous', 'read contact data', 'Allows an application to read all of the contact (address) data stored on your phone. Malicious applications can use this to send your data to other people.'], + 'WRITE_CONTACTS': ['dangerous', 'write contact data', 'Allows an application to modify the contact (address) data stored on your phone. Malicious applications can use this to erase or modify your contact data.'], + 'READ_PROFILE': ['dangerous', 'read the user\'s personal profile data', 'Allows an application to read the user\'s personal profile data.'], + 'WRITE_PROFILE': ['dangerous', 'write the user\'s personal profile data', 'Allows an application to write (but not read) the user\'s personal profile data.'], + 'READ_SOCIAL_STREAM': ['dangerous', 'read from the user\'s social stream', 'Allows an application to read from the user\'s social stream.'], + 'WRITE_SOCIAL_STREAM': ['dangerous', 'write the user\'s social stream', 'Allows an application to write (but not read) the user\'s social stream data.'], + 'READ_CALENDAR': ['dangerous', 'read calendar events', 'Allows an application to read all of the calendar events stored on your phone. Malicious applications can use this to send your calendar events to other people.'], + 'WRITE_CALENDAR': ['dangerous', 'add or modify calendar events and send emails to guests', 'Allows an application to add or change the events on your calendar, which may send emails to guests. Malicious applications can use this to erase or modify your calendar events or to send emails to guests.'], + 'READ_USER_DICTIONARY': ['dangerous', 'read user-defined dictionary', 'Allows an application to read any private words, names and phrases that the user may have stored in the user dictionary.'], + 'WRITE_USER_DICTIONARY': ['normal', 'write to user-defined dictionary', 'Allows an application to write new words into the user dictionary.'], + 'READ_HISTORY_BOOKMARKS': ['dangerous', 'read Browser\'s history and bookmarks', 'Allows the application to read all the URLs that the browser has visited and all of the browser\'s bookmarks.'], + 'WRITE_HISTORY_BOOKMARKS': ['dangerous', 'write Browser\'s history and bookmarks', 'Allows an application to modify the browser\'s history or bookmarks stored on your phone. Malicious applications can use this to erase or modify your browser\'s data.'], + 'SET_ALARM': ['normal', 'set alarm in alarm clock', 'Allows the application to set an alarm in an installed alarm clock application. Some alarm clock applications may not implement this feature.'], + 'ACCESS_FINE_LOCATION': ['dangerous', 'fine (GPS) location', 'Access fine location sources, such as the Global Positioning System on the phone, where available. Malicious applications can use this to determine where you are and may consume additional battery power.'], + 'ACCESS_COARSE_LOCATION': ['dangerous', 'coarse (network-based) location', 'Access coarse location sources, such as the mobile network database, to determine an approximate phone location, where available. Malicious applications can use this to determine approximately where you are.'], + 'ACCESS_MOCK_LOCATION': ['dangerous', 'mock location sources for testing', 'Create mock location sources for testing. Malicious applications can use this to override the location and/or status returned by real-location sources such as GPS or Network providers.'], + 'ACCESS_LOCATION_EXTRA_COMMANDS': ['normal', 'access extra location provider commands', 'Access extra location provider commands. Malicious applications could use this to interfere with the operation of the GPS or other location sources.'], + 'INSTALL_LOCATION_PROVIDER': ['signatureOrSystem', 'permission to install a location provider', 'Create mock location sources for testing. Malicious applications can use this to override the location and/or status returned by real-location sources such as GPS or Network providers, or monitor and report your location to an external source.'], + 'INTERNET': ['dangerous', 'full Internet access', 'Allows an application to create network sockets.'], + 'ACCESS_NETWORK_STATE': ['normal', 'view network status', 'Allows an application to view the status of all networks.'], + 'ACCESS_WIFI_STATE': ['normal', 'view Wi-Fi status', 'Allows an application to view the information about the status of Wi-Fi.'], + 'BLUETOOTH': ['dangerous', 'create Bluetooth connections', 'Allows an application to view configuration of the local Bluetooth phone and to make and accept connections with paired devices.'], + 'NFC': ['dangerous', 'control Near-Field Communication', 'Allows an application to communicate with Near-Field Communication (NFC) tags, cards and readers.'], + 'USE_SIP': ['dangerous', 'make/receive Internet calls', 'Allows an application to use the SIP service to make/receive Internet calls.'], + 'ACCOUNT_MANAGER': ['signature', 'act as the Account Manager Service', 'Allows an application to make calls to Account Authenticators'], + 'GET_ACCOUNTS': ['normal', 'discover known accounts', 'Allows an application to access the list of accounts known by the phone.'], + 'AUTHENTICATE_ACCOUNTS': ['dangerous', 'act as an account authenticator', 'Allows an application to use the account authenticator capabilities of the Account Manager, including creating accounts as well as obtaining and setting their passwords.'], + 'USE_CREDENTIALS': ['dangerous', 'use the authentication credentials of an account', 'Allows an application to request authentication tokens.'], + 'MANAGE_ACCOUNTS': ['dangerous', 'manage the accounts list', 'Allows an application to perform operations like adding and removing accounts and deleting their password.'], + 'MODIFY_AUDIO_SETTINGS': ['dangerous', 'change your audio settings', 'Allows application to modify global audio settings, such as volume and routing.'], + 'RECORD_AUDIO': ['dangerous', 'record audio', 'Allows application to access the audio record path.'], + 'CAMERA': ['dangerous', 'take pictures and videos', 'Allows application to take pictures and videos with the camera. This allows the application to collect images that the camera is seeing at any time.'], + 'VIBRATE': ['normal', 'control vibrator', 'Allows the application to control the vibrator.'], + 'FLASHLIGHT': ['normal', 'control flashlight', 'Allows the application to control the flashlight.'], + 'ACCESS_USB': ['signatureOrSystem', 'access USB devices', 'Allows the application to access USB devices.'], + 'HARDWARE_TEST': ['signature', 'test hardware', 'Allows the application to control various peripherals for the purpose of hardware testing.'], + 'PROCESS_OUTGOING_CALLS': ['dangerous', 'intercept outgoing calls', 'Allows application to process outgoing calls and change the number to be dialled. Malicious applications may monitor, redirect or prevent outgoing calls.'], + 'MODIFY_PHONE_STATE': ['signatureOrSystem', 'modify phone status', 'Allows the application to control the phone features of the device. An application with this permission can switch networks, turn the phone radio on and off and the like, without ever notifying you.'], + 'READ_PHONE_STATE': ['dangerous', 'read phone state and identity', 'Allows the application to access the phone features of the device. An application with this permission can determine the phone number and serial number of this phone, whether a call is active, the number that call is connected to and so on.'], + 'WRITE_EXTERNAL_STORAGE': ['dangerous', 'read/modify/delete SD card contents', 'Allows an application to write to the SD card.'], + 'READ_EXTERNAL_STORAGE': ['dangerous', 'read SD card contents', 'Allows an application to read from SD Card.'], + 'WRITE_SETTINGS': ['dangerous', 'modify global system settings', 'Allows an application to modify the system\'s settings data. Malicious applications can corrupt your system\'s configuration.'], + 'WRITE_SECURE_SETTINGS': ['signatureOrSystem', 'modify secure system settings', 'Allows an application to modify the system\'s secure settings data. Not for use by common applications.'], + 'WRITE_GSERVICES': ['signatureOrSystem', 'modify the Google services map', 'Allows an application to modify the Google services map. Not for use by common applications.'], + 'EXPAND_STATUS_BAR': ['normal', 'expand/collapse status bar', 'Allows application to expand or collapse the status bar.'], + 'GET_TASKS': ['dangerous', 'retrieve running applications', 'Allows application to retrieve information about currently and recently running tasks. May allow malicious applications to discover private information about other applications.'], + 'REORDER_TASKS': ['dangerous', 'reorder applications running', 'Allows an application to move tasks to the foreground and background. Malicious applications can force themselves to the front without your control.'], + 'CHANGE_CONFIGURATION': ['dangerous', 'change your UI settings', 'Allows an application to change the current configuration, such as the locale or overall font size.'], + 'RESTART_PACKAGES': ['normal', 'kill background processes', 'Allows an application to kill background processes of other applications, even if memory is not low.'], + 'KILL_BACKGROUND_PROCESSES': ['normal', 'kill background processes', 'Allows an application to kill background processes of other applications, even if memory is not low.'], + 'FORCE_STOP_PACKAGES': ['signature', 'force-stop other applications', 'Allows an application to stop other applications forcibly.'], + 'DUMP': ['signatureOrSystem', 'retrieve system internal status', 'Allows application to retrieve internal status of the system. Malicious applications may retrieve a wide variety of private and secure information that they should never commonly need.'], + 'SYSTEM_ALERT_WINDOW': ['dangerous', 'display system-level alerts', 'Allows an application to show system-alert windows. Malicious applications can take over the entire screen of the phone.'], + 'SET_ANIMATION_SCALE': ['dangerous', 'modify global animation speed', 'Allows an application to change the global animation speed (faster or slower animations) at any time.'], + 'PERSISTENT_ACTIVITY': ['dangerous', 'make application always run', 'Allows an application to make parts of itself persistent, so that the system can\'t use it for other applications.'], + 'GET_PACKAGE_SIZE': ['normal', 'measure application storage space', 'Allows an application to retrieve its code, data and cache sizes'], + 'SET_PREFERRED_APPLICATIONS': ['signature', 'set preferred applications', 'Allows an application to modify your preferred applications. This can allow malicious applications to silently change the applications that are run, spoofing your existing applications to collect private data from you.'], + 'RECEIVE_BOOT_COMPLETED': ['normal', 'automatically start at boot', 'Allows an application to start itself as soon as the system has finished booting. This can make it take longer to start the phone and allow the application to slow down the overall phone by always running.'], + 'BROADCAST_STICKY': ['normal', 'send sticky broadcast', 'Allows an application to send sticky broadcasts, which remain after the broadcast ends. Malicious applications can make the phone slow or unstable by causing it to use too much memory.'], + 'WAKE_LOCK': ['dangerous', 'prevent phone from sleeping', 'Allows an application to prevent the phone from going to sleep.'], + 'SET_WALLPAPER': ['normal', 'set wallpaper', 'Allows the application to set the system wallpaper.'], + 'SET_WALLPAPER_HINTS': ['normal', 'set wallpaper size hints', 'Allows the application to set the system wallpaper size hints.'], + 'SET_TIME': ['signatureOrSystem', 'set time', 'Allows an application to change the phone\'s clock time.'], + 'SET_TIME_ZONE': ['dangerous', 'set time zone', 'Allows an application to change the phone\'s time zone.'], + 'MOUNT_UNMOUNT_FILESYSTEMS': ['dangerous', 'mount and unmount file systems', 'Allows the application to mount and unmount file systems for removable storage.'], + 'MOUNT_FORMAT_FILESYSTEMS': ['dangerous', 'format external storage', 'Allows the application to format removable storage.'], + 'ASEC_ACCESS': ['signature', 'get information on internal storage', 'Allows the application to get information on internal storage.'], + 'ASEC_CREATE': ['signature', 'create internal storage', 'Allows the application to create internal storage.'], + 'ASEC_DESTROY': ['signature', 'destroy internal storage', 'Allows the application to destroy internal storage.'], + 'ASEC_MOUNT_UNMOUNT': ['signature', 'mount/unmount internal storage', 'Allows the application to mount/unmount internal storage.'], + 'ASEC_RENAME': ['signature', 'rename internal storage', 'Allows the application to rename internal storage.'], + 'DISABLE_KEYGUARD': ['dangerous', 'disable key lock', 'Allows an application to disable the key lock and any associated password security. A legitimate example of this is the phone disabling the key lock when receiving an incoming phone call, then re-enabling the key lock when the call is finished.'], + 'READ_SYNC_SETTINGS': ['normal', 'read sync settings', 'Allows an application to read the sync settings, such as whether sync is enabled for Contacts.'], + 'WRITE_SYNC_SETTINGS': ['dangerous', 'write sync settings', 'Allows an application to modify the sync settings, such as whether sync is enabled for Contacts.'], + 'READ_SYNC_STATS': ['normal', 'read sync statistics', 'Allows an application to read the sync stats; e.g. the history of syncs that have occurred.'], + 'WRITE_APN_SETTINGS': ['dangerous', 'write Access Point Name settings', 'Allows an application to modify the APN settings, such as Proxy and Port of any APN.'], + 'SUBSCRIBED_FEEDS_READ': ['normal', 'read subscribed feeds', 'Allows an application to receive details about the currently synced feeds.'], + 'SUBSCRIBED_FEEDS_WRITE': ['dangerous', 'write subscribed feeds', 'Allows an application to modify your currently synced feeds. This could allow a malicious application to change your synced feeds.'], + 'CHANGE_NETWORK_STATE': ['dangerous', 'change network connectivity', 'Allows an application to change the state of network connectivity.'], + 'CHANGE_WIFI_STATE': ['dangerous', 'change Wi-Fi status', 'Allows an application to connect to and disconnect from Wi-Fi access points and to make changes to configured Wi-Fi networks.'], + 'CHANGE_WIFI_MULTICAST_STATE': ['dangerous', 'allow Wi-Fi Multicast reception', 'Allows an application to receive packets not directly addressed to your device. This can be useful when discovering services offered nearby. It uses more power than the non-multicast mode.'], + 'BLUETOOTH_ADMIN': ['dangerous', 'bluetooth administration', 'Allows an application to configure the local Bluetooth phone and to discover and pair with remote devices.'], + 'CLEAR_APP_CACHE': ['dangerous', 'delete all application cache data', 'Allows an application to free phone storage by deleting files in application cache directory. Access is usually very restricted to system process.'], + 'READ_LOGS': ['dangerous', 'read sensitive log data', 'Allows an application to read from the system\'s various log files. This allows it to discover general information about what you are doing with the phone, potentially including personal or private information.'], + 'SET_DEBUG_APP': ['dangerous', 'enable application debugging', 'Allows an application to turn on debugging for another application. Malicious applications can use this to kill other applications.'], + 'SET_PROCESS_LIMIT': ['dangerous', 'limit number of running processes', 'Allows an application to control the maximum number of processes that will run. Never needed for common applications.'], + 'SET_ALWAYS_FINISH': ['dangerous', 'make all background applications close', 'Allows an application to control whether activities are always finished as soon as they go to the background. Never needed for common applications.'], + 'SIGNAL_PERSISTENT_PROCESSES': ['dangerous', 'send Linux signals to applications', 'Allows application to request that the supplied signal be sent to all persistent processes.'], + 'DIAGNOSTIC': ['signature', 'read/write to resources owned by diag', 'Allows an application to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator.'], + 'STATUS_BAR': ['signatureOrSystem', 'disable or modify status bar', 'Allows application to disable the status bar or add and remove system icons.'], + 'STATUS_BAR_SERVICE': ['signature', 'status bar', 'Allows the application to be the status bar.'], + 'FORCE_BACK': ['signature', 'force application to close', 'Allows an application to force any activity that is in the foreground to close and go back. Should never be needed for common applications.'], + 'UPDATE_DEVICE_STATS': ['signatureOrSystem', 'modify battery statistics', 'Allows the modification of collected battery statistics. Not for use by common applications.'], + 'INTERNAL_SYSTEM_WINDOW': ['signature', 'display unauthorised windows', 'Allows the creation of windows that are intended to be used by the internal system user interface. Not for use by common applications.'], + 'MANAGE_APP_TOKENS': ['signature', 'manage application tokens', 'Allows applications to create and manage their own tokens, bypassing their common Z-ordering. Should never be needed for common applications.'], + 'INJECT_EVENTS': ['signature', 'press keys and control buttons', 'Allows an application to deliver its own input events (key presses, etc.) to other applications. Malicious applications can use this to take over the phone.'], + 'SET_ACTIVITY_WATCHER': ['signature', 'monitor and control all application launching', 'Allows an application to monitor and control how the system launches activities. Malicious applications may compromise the system completely. This permission is needed only for development, never for common phone usage.'], + 'SHUTDOWN': ['signature', 'partial shutdown', 'Puts the activity manager into a shut-down state. Does not perform a complete shut down.'], + 'STOP_APP_SWITCHES': ['signature', 'prevent app switches', 'Prevents the user from switching to another application.'], + 'READ_INPUT_STATE': ['signature', 'record what you type and actions that you take', 'Allows applications to watch the keys that you press even when interacting with another application (such as entering a password). Should never be needed for common applications.'], + 'BIND_INPUT_METHOD': ['signature', 'bind to an input method', 'Allows the holder to bind to the top-level interface of an input method. Should never be needed for common applications.'], + 'BIND_WALLPAPER': ['signatureOrSystem', 'bind to wallpaper', 'Allows the holder to bind to the top-level interface of wallpaper. Should never be needed for common applications.'], + 'BIND_DEVICE_ADMIN': ['signature', 'interact with device admin', 'Allows the holder to send intents to a device administrator. Should never be needed for common applications.'], + 'SET_ORIENTATION': ['signature', 'change screen orientation', 'Allows an application to change the rotation of the screen at any time. Should never be needed for common applications.'], + 'INSTALL_PACKAGES': ['signatureOrSystem', 'directly install applications', 'Allows an application to install new or updated Android packages. Malicious applications can use this to add new applications with arbitrarily powerful permissions.'], + 'REQUEST_INSTALL_PACKAGES': ['dangerous', 'Allows an application to request installing packages.', 'Malicious applications can use this to try and trick users into installing additional malicious packages.'], + 'CLEAR_APP_USER_DATA': ['signature', 'delete other applications\' data', 'Allows an application to clear user data.'], + 'DELETE_CACHE_FILES': ['signatureOrSystem', 'delete other applications\' caches', 'Allows an application to delete cache files.'], + 'DELETE_PACKAGES': ['signatureOrSystem', 'delete applications', 'Allows an application to delete Android packages. Malicious applications can use this to delete important applications.'], + 'MOVE_PACKAGE': ['signatureOrSystem', 'Move application resources', 'Allows an application to move application resources from internal to external media and vice versa.'], + 'CHANGE_COMPONENT_ENABLED_STATE': ['signatureOrSystem', 'enable or disable application components', 'Allows an application to change whether or not a component of another application is enabled. Malicious applications can use this to disable important phone capabilities. It is important to be careful with permission, as it is possible to bring application components into an unusable, inconsistent or unstable state.'], + 'ACCESS_SURFACE_FLINGER': ['signature', 'access SurfaceFlinger', 'Allows application to use SurfaceFlinger low-level features.'], + 'READ_FRAME_BUFFER': ['signature', 'read frame buffer', 'Allows application to read the content of the frame buffer.'], + 'BRICK': ['signature', 'permanently disable phone', 'Allows the application to disable the entire phone permanently. This is very dangerous.'], + 'REBOOT': ['signatureOrSystem', 'force phone reboot', 'Allows the application to force the phone to reboot.'], + 'DEVICE_POWER': ['signature', 'turn phone on or off', 'Allows the application to turn the phone on or off.'], + 'FACTORY_TEST': ['signature', 'run in factory test mode', 'Run as a low-level manufacturer test, allowing complete access to the phone hardware. Only available when a phone is running in manufacturer test mode.'], + 'BROADCAST_PACKAGE_REMOVED': ['signature', 'send package removed broadcast', 'Allows an application to broadcast a notification that an application package has been removed. Malicious applications may use this to kill any other application running.'], + 'BROADCAST_SMS': ['signature', 'send SMS-received broadcast', 'Allows an application to broadcast a notification that an SMS message has been received. Malicious applications may use this to forge incoming SMS messages.'], + 'BROADCAST_WAP_PUSH': ['signature', 'send WAP-PUSH-received broadcast', 'Allows an application to broadcast a notification that a WAP-PUSH message has been received. Malicious applications may use this to forge MMS message receipt or to replace the content of any web page silently with malicious variants.'], + 'MASTER_CLEAR': ['signatureOrSystem', 'reset system to factory defaults', 'Allows an application to completely reset the system to its factory settings, erasing all data, configuration and installed applications.'], + 'CALL_PRIVILEGED': ['signatureOrSystem', 'directly call any phone numbers', 'Allows the application to call any phone number, including emergency numbers, without your intervention. Malicious applications may place unnecessary and illegal calls to emergency services.'], + 'PERFORM_CDMA_PROVISIONING': ['signatureOrSystem', 'directly start CDMA phone setup', 'Allows the application to start CDMA provisioning. Malicious applications may start CDMA provisioning unnecessarily'], + 'CONTROL_LOCATION_UPDATES': ['signatureOrSystem', 'control location update notifications', 'Allows enabling/disabling location update notifications from the radio. Not for use by common applications.'], + 'ACCESS_CHECKIN_PROPERTIES': ['signatureOrSystem', 'access check-in properties', 'Allows read/write access to properties uploaded by the check-in service. Not for use by common applications.'], + 'PACKAGE_USAGE_STATS': ['signature', 'update component usage statistics', 'Allows the modification of collected component usage statistics. Not for use by common applications.'], + 'BATTERY_STATS': ['normal', 'modify battery statistics', 'Allows the modification of collected battery statistics. Not for use by common applications.'], + 'BACKUP': ['signatureOrSystem', 'control system back up and restore', 'Allows the application to control the system\'s back-up and restore mechanism. Not for use by common applications.'], + 'BIND_APPWIDGET': ['signatureOrSystem', 'choose widgets', 'Allows the application to tell the system which widgets can be used by which application. With this permission, applications can give access to personal data to other applications. Not for use by common applications.'], + 'CHANGE_BACKGROUND_DATA_SETTING': ['signature', 'change background data usage setting', 'Allows an application to change the background data usage setting.'], + 'GLOBAL_SEARCH': ['signatureOrSystem', '', ''], + 'GLOBAL_SEARCH_CONTROL': ['signature', '', ''], + 'SET_WALLPAPER_COMPONENT': ['signatureOrSystem', '', ''], + 'ACCESS_CACHE_FILESYSTEM': ['signatureOrSystem', 'access the cache file system', 'Allows an application to read and write the cache file system.'], + 'COPY_PROTECTED_DATA': ['signature', 'Allows to invoke default container service to copy content. Not for use by common applications.', 'Allows to invoke default container service to copy content. Not for use by common applications.'], + 'C2D_MESSAGE': ['signature', 'Allows cloud to device messaging', 'Allows the application to receive push notifications.'], + 'ADD_VOICEMAIL': ['dangerous', 'add voicemails into the system', 'Allows an application to add voicemails into the system.'], + 'ACCEPT_HANDOVER': ['dangerous', '', 'Allows a calling app to continue a call which was started in another app. An example is a video calling app that wants to continue a voice call on the user\'s mobile network.'], + 'ACCESS_NOTIFICATION_POLICY': ['normal', '', 'Marker permission for applications that wish to access notification policy.'], + 'ANSWER_PHONE_CALLS': ['dangerous', '', 'Allows the app to answer an incoming phone call.'], + 'BIND_ACCESSIBILITY_SERVICE': ['signature', '', 'Must be required by an AccessibilityService, to ensure that only the system can bind to it.'], + 'BIND_AUTOFILL_SERVICE': ['signature', '', 'Must be required by a AutofillService, to ensure that only the system can bind to it.'], + 'BIND_CARRIER_MESSAGING_SERVICE': ['normal', '', 'The system process that is allowed to bind to services in carrier apps will have this permission.'], + 'BIND_CARRIER_SERVICES': ['signature', '', 'The system process that is allowed to bind to services in carrier apps will have this permission. Carrier apps should use this permission to protect their services that only the system is allowed to bind to.'], + 'BIND_CHOOSER_TARGET_SERVICE': ['signature', '', 'Must be required by a ChooserTargetService, to ensure that only the system can bind to it'], + 'BIND_CONDITION_PROVIDER_SERVICE': ['signature', '', 'Must be required by a ConditionProviderService, to ensure that only the system can bind to it'], + 'BIND_DREAM_SERVICE': ['signature', '', 'Must be required by an DreamService, to ensure that only the system can bind to it.'], + 'BIND_INCALL_SERVICE': ['signature', '', 'Must be required by a InCallService, to ensure that only the system can bind to it.'], + 'BIND_MIDI_DEVICE_SERVICE': ['signature', '', 'Must be required by an MidiDeviceService, to ensure that only the system can bind to it.'], + 'BIND_NFC_SERVICE': ['signature', '', 'Must be required by a HostApduService or OffHostApduService to ensure that only the system can bind to it.'], + 'BIND_NOTIFICATION_LISTENER_SERVICE': ['signature', '', 'Must be required by an NotificationListenerService, to ensure that only the system can bind to it.'], + 'BIND_PRINT_SERVICE': ['signature', '', 'Must be required by a PrintService, to ensure that only the system can bind to it.'], + 'BIND_QUICK_SETTINGS_TILE': ['normal', '', 'Allows an application to bind to third party quick settings tiles.'], + 'BIND_REMOTEVIEWS': ['normal', '', 'Must be required by a RemoteViewsService, to ensure that only the system can bind to it.'], + 'BIND_SCREENING_SERVICE': ['signature', '', 'Must be required by a CallScreeningService, to ensure that only the system can bind to it.'], + 'BIND_TELECOM_CONNECTION_SERVICE': ['signature', '', 'Must be required by a ConnectionService, to ensure that only the system can bind to it.'], + 'BIND_TEXT_SERVICE': ['signature', '', 'Must be required by a TextService (e.g. SpellCheckerService) to ensure that only the system can bind to it.'], + 'BIND_TV_INPUT': ['signature', '', 'Must be required by a TvInputService to ensure that only the system can bind to it.'], + 'BIND_VISUAL_VOICEMAIL_SERVICE': ['signature', '', 'Must be required by a link'], + 'BIND_VOICE_INTERACTION': ['signature', '', 'Must be required by a VoiceInteractionService, to ensure that only the system can bind to it.'], + 'BIND_VPN_SERVICE': ['signature', '', 'Must be required by a VpnService, to ensure that only the system can bind to it.'], + 'BIND_VR_LISTENER_SERVICE': ['signature', '', 'Must be required by an VrListenerService, to ensure that only the system can bind to it.'], + 'BLUETOOTH_PRIVILEGED': ['normal', '', 'Allows applications to pair bluetooth devices without user interaction, and to allow or disallow phonebook access or message access. This is not available to third party applications.'], + 'BODY_SENSORS': ['dangerous', '', 'Allows an application to access data from sensors that the user uses to measure what is happening inside his/her body, such as heart rate.'], + 'CAPTURE_AUDIO_OUTPUT': ['normal', '', 'Allows an application to capture audio output.'], + 'CAPTURE_SECURE_VIDEO_OUTPUT': ['normal', '', 'Allows an application to capture secure video output.'], + 'CAPTURE_VIDEO_OUTPUT': ['normal', '', 'Allows an application to capture video output.'], + 'FOREGROUND_SERVICE': ['normal', '', 'Allows a regular application to use'], + 'GET_ACCOUNTS_PRIVILEGED': ['normal', '', 'Allows access to the list of accounts in the Accounts Service.'], + 'INSTALL_SHORTCUT': ['normal', '', 'Allows an application to install a shortcut in Launcher.'], + 'INSTANT_APP_FOREGROUND_SERVICE': ['normal', '', 'Allows an instant app to create foreground services.'], + 'LOCATION_HARDWARE': ['normal', '', 'Allows an application to use location features in hardware, such as the geofencing api.'], + 'MANAGE_DOCUMENTS': ['signature', '', 'Allows an application to manage access to documents, usually as part of a document picker.'], + 'MANAGE_OWN_CALLS': ['normal', '', 'Allows a calling application which manages it own calls through the self-managed'], + 'MEDIA_CONTENT_CONTROL': ['normal', '', 'Allows an application to know what content is playing and control its playback.'], + 'NFC_TRANSACTION_EVENT': ['normal', '', 'Allows applications to receive NFC transaction events.'], + 'READ_CALL_LOG': ['dangerous', '', 'Allows an application to read the user\'s call log.'], + 'READ_PHONE_NUMBERS': ['dangerous', '', 'Allows read access to the device\'s phone number(s). This is a subset of the capabilities granted by'], + 'READ_VOICEMAIL': ['signature', '', 'Allows an application to read voicemails in the system.'], + 'REQUEST_COMPANION_RUN_IN_BACKGROUND': ['normal', '', 'Allows a companion app to run in the background.'], + 'REQUEST_COMPANION_USE_DATA_IN_BACKGROUND': ['normal', '', 'Allows a companion app to use data in the background.'], + 'REQUEST_DELETE_PACKAGES': ['normal', '', 'Allows an application to request deleting packages. Apps targeting APIs'], + 'REQUEST_IGNORE_BATTERY_OPTIMIZATIONS': ['normal', '', 'Permission an application must hold in order to use'], + 'SEND_RESPOND_VIA_MESSAGE': ['normal', '', 'Allows an application (Phone) to send a request to other applications to handle the respond-via-message action during incoming calls.'], + 'TRANSMIT_IR': ['normal', '', 'Allows using the device\'s IR transmitter, if available.'], + 'UNINSTALL_SHORTCUT': ['normal', '', 'Don\'t use this permission in your app. This permission is no longer supported.'], + 'USE_BIOMETRIC': ['normal', '', 'Allows an app to use device supported biometric modalities.'], + 'USE_FINGERPRINT': ['normal', '', 'This constant was deprecated in API level 28. Applications should request USE_BIOMETRIC instead'], + 'WRITE_CALL_LOG': ['dangerous', '', 'Allows an application to write (but not read) the user\'s call log data.'], + 'WRITE_VOICEMAIL': ['signature', '', 'Allows an application to modify and remove existing voicemails in the system.'], }, - "MANIFEST_PERMISSION_GROUP": + 'MANIFEST_PERMISSION_GROUP': { - "ACCOUNTS": "Permissions for direct access to the accounts managed by the Account Manager.", - "COST_MONEY": "Used for permissions that can be used to make the user spend money without their direct involvement.", - "DEVELOPMENT_TOOLS": "Group of permissions that are related to development features.", - "HARDWARE_CONTROLS": "Used for permissions that provide direct access to the hardware on the device.", - "LOCATION": "Used for permissions that allow access to the user's current location.", - "MESSAGES": "Used for permissions that allow an application to send messages on behalf of the user or intercept messages being received by the user.", - "NETWORK": "Used for permissions that provide access to networking services.", - "PERSONAL_INFO": "Used for permissions that provide access to the user's private data, such as contacts, calendar events, e-mail messages, etc.", - "PHONE_CALLS": "Used for permissions that are associated with accessing and modifyign telephony state: intercepting outgoing calls, reading and modifying the phone state.", - "STORAGE": "Group of permissions that are related to SD card access.", - "SYSTEM_TOOLS": "Group of permissions that are related to system APIs.", + 'ACCOUNTS': 'Permissions for direct access to the accounts managed by the Account Manager.', + 'COST_MONEY': 'Used for permissions that can be used to make the user spend money without their direct involvement.', + 'DEVELOPMENT_TOOLS': 'Group of permissions that are related to development features.', + 'HARDWARE_CONTROLS': 'Used for permissions that provide direct access to the hardware on the device.', + 'LOCATION': 'Used for permissions that allow access to the user\'s current location.', + 'MESSAGES': 'Used for permissions that allow an application to send messages on behalf of the user or intercept messages being received by the user.', + 'NETWORK': 'Used for permissions that provide access to networking services.', + 'PERSONAL_INFO': 'Used for permissions that provide access to the user\'s private data, such as contacts, calendar events, e-mail messages, etc.', + 'PHONE_CALLS': 'Used for permissions that are associated with accessing and modifyign telephony state: intercepting outgoing calls, reading and modifying the phone state.', + 'STORAGE': 'Group of permissions that are related to SD card access.', + 'SYSTEM_TOOLS': 'Group of permissions that are related to system APIs.', }, } diff --git a/StaticAnalyzer/views/android/find.py b/StaticAnalyzer/views/android/find.py index 42904994..31b7e025 100755 --- a/StaticAnalyzer/views/android/find.py +++ b/StaticAnalyzer/views/android/find.py @@ -1,20 +1,18 @@ # -*- coding: utf_8 -*- """Find in java or smali files.""" +import io +import logging +import os import re import shutil -import io -import os -import logging -from django.shortcuts import render -from django.http import HttpResponseRedirect + from django.conf import settings +from django.shortcuts import render from django.utils.html import escape -from MobSF.utils import ( - PrintException, - print_n_send_error_response -) +from MobSF.utils import log_exception, print_n_send_error_response + logger = logging.getLogger(__name__) @@ -28,46 +26,52 @@ def run(request): code = request.POST['code'] matches = [] if code == 'java': - src = os.path.join(settings.UPLD_DIR, md5+'/java_source/') + src = os.path.join(settings.UPLD_DIR, md5 + '/java_source/') ext = '.java' elif code == 'smali': - src = os.path.join(settings.UPLD_DIR, md5+'/smali_source/') + src = os.path.join(settings.UPLD_DIR, md5 + '/smali_source/') ext = '.smali' else: - return print_n_send_error_response(request, "Only Java/Smali files are allowed") + err = 'Only Java/Smali files are allowed' + return print_n_send_error_response(request, + err) # pylint: disable=unused-variable # Needed by os.walk - for dir_name, sub_dir, files in os.walk(src): + for dir_name, _sub_dir, files in os.walk(src): for jfile in files: if jfile.endswith(ext): file_path = os.path.join(src, dir_name, jfile) - if "+" in jfile: - fp2 = os.path.join(src, dir_name, jfile.replace("+", "x")) + if '+' in jfile: + fp2 = os.path.join( + src, dir_name, jfile.replace('+', 'x')) shutil.move(file_path, fp2) file_path = fp2 fileparam = file_path.replace(src, '') with io.open( file_path, mode='r', - encoding="utf8", - errors="ignore" + encoding='utf8', + errors='ignore', ) as file_pointer: dat = file_pointer.read() if query in dat: - matches.append( - "" + escape(fileparam) + "" + matches.append(( + '{}').format( + escape(fileparam), + md5, + escape(fileparam)), ) flz = len(matches) context = { 'title': 'Search Results', 'matches': matches, 'term': query, - 'found' : str(flz) + 'found': str(flz), } - template = "general/search.html" + template = 'general/search.html' return render(request, template, context) - except: - PrintException("Searching Failed") - return print_n_send_error_response(request, "Searching Failed") + except Exception: + log_exception('Searching Failed') + return print_n_send_error_response(request, 'Searching Failed') diff --git a/StaticAnalyzer/views/android/icon_analysis.py b/StaticAnalyzer/views/android/icon_analysis.py index 930c5d96..85c3d23e 100755 --- a/StaticAnalyzer/views/android/icon_analysis.py +++ b/StaticAnalyzer/views/android/icon_analysis.py @@ -1,15 +1,14 @@ # -*- coding: utf_8 -*- """Module holding the functions for icon analysis.""" -import subprocess -import re -import os -import platform import fnmatch -import string import logging -from django.conf import settings +import os + from androguard.core.bytecodes import apk + +from MobSF.utils import log_exception + logger = logging.getLogger(__name__) @@ -21,7 +20,7 @@ KNOWN_PATHS = [ 'drawable-xhdpi', 'mipmap-mdpi', 'drawable-mdpi', - 'mipmap-hdpi-v4' + 'mipmap-hdpi-v4', ] KNOWN_MIPMAP_SIZES = [ @@ -30,13 +29,9 @@ KNOWN_MIPMAP_SIZES = [ '-xhdpi', '-xhdpi-v4', '-mdpi', - '-mdpi-v4' + '-mdpi-v4', ] -from MobSF.utils import ( - PrintException -) - def search_folder(src, file_pattern): matches = [] @@ -50,7 +45,7 @@ def guess_icon_path(res_dir): icon_folders = [ 'mipmap-hdpi', 'mipmap-hdpi-v4', - 'drawable' + 'drawable', ] for icon_path in icon_folders: guessed_icon_path = os.path.join(res_dir, icon_path, 'ic_launcher.png') @@ -67,11 +62,16 @@ def guess_icon_path(res_dir): def find_icon_path_zip(res_dir, icon_paths_from_manifest): - """Tries to find an icon, based on paths fetched from the manifest and by global search - returns an empty string on fail or a full path""" + """ + Find icon. + + Tries to find an icon, based on paths + fetched from the manifest and by global search + returns an empty string on fail or a full path + """ global KNOWN_MIPMAP_SIZES try: - logger.info("Guessing icon path") + logger.info('Guessing icon path') for icon_path in icon_paths_from_manifest: if icon_path.startswith('@'): path_array = icon_path.strip('@').split(os.sep) @@ -103,15 +103,18 @@ def find_icon_path_zip(res_dir, icon_paths_from_manifest): # If didn't find, try the default name.. returns empty if not find return guess_icon_path(res_dir) - except: - PrintException("Guessing icon path") + except Exception: + log_exception('Guessing icon path') def get_icon(apk_path, res_dir): - """Returns a dict with isHidden boolean and a relative path - path is a full path (not relative to resource folder) """ + """ + Returns a dict with isHidden boolean and a relative path. + + path is a full path (not relative to resource folder) + """ try: - logger.info("Fetching icon path") + logger.info('Fetching icon path') a = apk.APK(apk_path) icon_resolution = 0xFFFE - 1 icon_name = a.get_app_icon(max_dpi=icon_resolution) @@ -119,16 +122,16 @@ def get_icon(apk_path, res_dir): if '.xml' in icon_name: return { 'path': guess_icon_path(res_dir), - 'hidden': False + 'hidden': False, } else: return { 'path': os.path.join(os.path.dirname(apk_path), icon_name), - 'hidden': False + 'hidden': False, } return { 'path': guess_icon_path(res_dir), - 'hidden': True + 'hidden': True, } - except: - PrintException("Fetching icon function") + except Exception: + log_exception('Fetching icon function') diff --git a/StaticAnalyzer/views/android/java.py b/StaticAnalyzer/views/android/java.py index a9247469..01bcd0de 100755 --- a/StaticAnalyzer/views/android/java.py +++ b/StaticAnalyzer/views/android/java.py @@ -1,67 +1,70 @@ # -*- coding: utf_8 -*- """List all java files.""" +import logging +import os import re import shutil -import os -from django.shortcuts import render -from django.http import HttpResponseRedirect from django.conf import settings +from django.shortcuts import render from django.utils.html import escape -from MobSF.utils import ( - PrintException, - print_n_send_error_response -) -import logging +from MobSF.utils import log_exception, print_n_send_error_response + logger = logging.getLogger(__name__) def run(request): """Show the java code.""" try: - logger.debug("showing java code for request : {}".format(request)) + logger.debug('showing java code for request : %s', request) match = re.match('^[0-9a-f]{32}$', request.GET['md5']) typ = request.GET['type'] if match: + html = '' md5 = request.GET['md5'] if typ == 'eclipse': src = os.path.join(settings.UPLD_DIR, md5 + '/src/') elif typ == 'studio': - src = os.path.join(settings.UPLD_DIR, md5 + '/app/src/main/java/') + src = os.path.join(settings.UPLD_DIR, md5 + + '/app/src/main/java/') elif typ == 'apk': src = os.path.join(settings.UPLD_DIR, md5 + '/java_source/') else: - return print_n_send_error_response(request, "Invalid Directory Structure") - html = '' + return print_n_send_error_response( + request, + 'Invalid Directory Structure') # pylint: disable=unused-variable # Needed by os.walk - for dir_name, sub_dir, files in os.walk(src): + for dir_name, _sub_dir, files in os.walk(src): for jfile in files: - if jfile.endswith(".java"): + if jfile.endswith('.java'): file_path = os.path.join(src, dir_name, jfile) - if "+" in jfile: - fp2 = os.path.join(src, dir_name, jfile.replace("+", "x")) + if '+' in jfile: + fp2 = os.path.join( + src, dir_name, jfile.replace('+', 'x')) shutil.move(file_path, fp2) file_path = fp2 fileparam = file_path.replace(src, '') - if any(re.search(cls, fileparam) for cls in settings.SKIP_CLASSES) is False: - html += ( - "" + - escape(fileparam) + "" - ) - context = { - 'title': 'Java Source', - 'files': html, - 'md5': md5, - 'type': typ, - } + if (any(re.search(cls, fileparam) + for cls in settings.SKIP_CLASSES) is False): + html += ('{}' + '').format( + escape(fileparam), + md5, + typ, + escape(fileparam)) + context = { + 'title': 'Java Source', + 'files': html, + 'md5': md5, + 'type': typ, + } - template = "static_analysis/java.html" + template = 'static_analysis/java.html' return render(request, template, context) - except: - PrintException("Getting Java Files") - return print_n_send_error_response(request, "Error Getting Java Files") + except Exception: + log_exception('Getting Java Files') + return print_n_send_error_response(request, 'Error Getting Java Files') diff --git a/StaticAnalyzer/views/android/manifest_analysis.py b/StaticAnalyzer/views/android/manifest_analysis.py index 5ea636b2..f6842bc7 100755 --- a/StaticAnalyzer/views/android/manifest_analysis.py +++ b/StaticAnalyzer/views/android/manifest_analysis.py @@ -1,23 +1,23 @@ # -*- coding: utf_8 -*- +# flake8: noqa """Module for android manifest analysis.""" import io +import logging import os import subprocess import tempfile -import logging from xml.dom import minidom from django.conf import settings -from MobSF.utils import ( - PrintException, - isFileExists -) +from MobSF.utils import is_file_exists, log_exception + +from StaticAnalyzer.views.android import android_manifest_desc # pylint: disable=E0401 from .dvm_permissions import DVM_PERMISSIONS -from StaticAnalyzer.views.android import android_manifest_desc + logger = logging.getLogger(__name__) @@ -31,30 +31,29 @@ def get_manifest(app_path, app_dir, tools_dir, typ, binary): manifest = None dat = read_manifest(app_dir, app_path, tools_dir, typ, binary) try: - logger.info("Parsing AndroidManifest.xml") + logger.info('Parsing AndroidManifest.xml') manifest = minidom.parseString(dat) - except: - PrintException( - "apktool failed to extract AndroidManifest.xml or parsing failed") + except Exception: + err = ('apktool failed to extract ' + 'AndroidManifest.xml or parsing failed') + log_exception(err) manifest = minidom.parseString( - ( - r'' - ) - ) - logger.warning("Using Fake XML to continue the Analysis") + (r'')) + logger.warning('Using Fake XML to continue the Analysis') return manifest - except: - PrintException("Parsing Manifest file") + except Exception: + log_exception('Parsing Manifest file') def manifest_data(mfxml): """Extract manifest data.""" try: - logger.info("Extracting Manifest Data") + logger.info('Extracting Manifest Data') svc = [] act = [] brd = [] @@ -71,87 +70,88 @@ def manifest_data(mfxml): mainact = '' androidversioncode = '' androidversionname = '' - applications = mfxml.getElementsByTagName("application") - permissions = mfxml.getElementsByTagName("uses-permission") - manifest = mfxml.getElementsByTagName("manifest") - activities = mfxml.getElementsByTagName("activity") - services = mfxml.getElementsByTagName("service") - providers = mfxml.getElementsByTagName("provider") - receivers = mfxml.getElementsByTagName("receiver") - libs = mfxml.getElementsByTagName("uses-library") - sdk = mfxml.getElementsByTagName("uses-sdk") - categories = mfxml.getElementsByTagName("category") + applications = mfxml.getElementsByTagName('application') + permissions = mfxml.getElementsByTagName('uses-permission') + manifest = mfxml.getElementsByTagName('manifest') + activities = mfxml.getElementsByTagName('activity') + services = mfxml.getElementsByTagName('service') + providers = mfxml.getElementsByTagName('provider') + receivers = mfxml.getElementsByTagName('receiver') + libs = mfxml.getElementsByTagName('uses-library') + sdk = mfxml.getElementsByTagName('uses-sdk') + categories = mfxml.getElementsByTagName('category') for node in sdk: - minsdk = node.getAttribute("android:minSdkVersion") - maxsdk = node.getAttribute("android:maxSdkVersion") - # Esteve 08.08.2016 - begin - If android:targetSdkVersion is not set, - # the default value is the one of the android:minSdkVersion - # targetsdk=node.getAttribute("android:targetSdkVersion") - if node.getAttribute("android:targetSdkVersion"): - targetsdk = node.getAttribute("android:targetSdkVersion") + minsdk = node.getAttribute('android:minSdkVersion') + maxsdk = node.getAttribute('android:maxSdkVersion') + # Esteve 08.08.2016 - begin - If android:targetSdkVersion + # is not set, the default value is the one of the + # android:minSdkVersiontargetsdk + # =node.getAttribute('android:targetSdkVersion') + if node.getAttribute('android:targetSdkVersion'): + targetsdk = node.getAttribute('android:targetSdkVersion') else: - targetsdk = node.getAttribute("android:minSdkVersion") + targetsdk = node.getAttribute('android:minSdkVersion') # End for node in manifest: - package = node.getAttribute("package") - androidversioncode = node.getAttribute("android:versionCode") - androidversionname = node.getAttribute("android:versionName") + package = node.getAttribute('package') + androidversioncode = node.getAttribute('android:versionCode') + androidversionname = node.getAttribute('android:versionName') for activity in activities: - act_2 = activity.getAttribute("android:name") + act_2 = activity.getAttribute('android:name') act.append(act_2) if len(mainact) < 1: # ^ Fix for Shitty Manifest with more than one MAIN - for sitem in activity.getElementsByTagName("action"): - val = sitem.getAttribute("android:name") - if val == "android.intent.action.MAIN": - mainact = activity.getAttribute("android:name") + for sitem in activity.getElementsByTagName('action'): + val = sitem.getAttribute('android:name') + if val == 'android.intent.action.MAIN': + mainact = activity.getAttribute('android:name') if mainact == '': - for sitem in activity.getElementsByTagName("category"): - val = sitem.getAttribute("android:name") - if val == "android.intent.category.LAUNCHER": - mainact = activity.getAttribute("android:name") + for sitem in activity.getElementsByTagName('category'): + val = sitem.getAttribute('android:name') + if val == 'android.intent.category.LAUNCHER': + mainact = activity.getAttribute('android:name') for service in services: - service_name = service.getAttribute("android:name") + service_name = service.getAttribute('android:name') svc.append(service_name) for provider in providers: - provider_name = provider.getAttribute("android:name") + provider_name = provider.getAttribute('android:name') cnp.append(provider_name) for receiver in receivers: - rec = receiver.getAttribute("android:name") + rec = receiver.getAttribute('android:name') brd.append(rec) for _lib in libs: - libary = _lib.getAttribute("android:name") + libary = _lib.getAttribute('android:name') lib.append(libary) for category in categories: - cat.append(category.getAttribute("android:name")) + cat.append(category.getAttribute('android:name')) for application in applications: try: - icon_path = application.getAttribute("android:icon") + icon_path = application.getAttribute('android:icon') icons.append(icon_path) - except: + except Exception: continue # No icon attribute? for permission in permissions: - perm.append(permission.getAttribute("android:name")) + perm.append(permission.getAttribute('android:name')) for i in perm: prm = i - pos = i.rfind(".") + pos = i.rfind('.') if pos != -1: prm = i[pos + 1:] try: - dvm_perm[i] = DVM_PERMISSIONS["MANIFEST_PERMISSION"][prm] + dvm_perm[i] = DVM_PERMISSIONS['MANIFEST_PERMISSION'][prm] except KeyError: dvm_perm[i] = [ - "dangerous", - "Unknown permission from android reference", - "Unknown permission from android reference" + 'dangerous', + 'Unknown permission from android reference', + 'Unknown permission from android reference', ] man_data_dic = { @@ -169,16 +169,16 @@ def manifest_data(mfxml): 'target_sdk': targetsdk, 'androver': androidversioncode, 'androvername': androidversionname, - 'icons': icons + 'icons': icons, } return man_data_dic - except: - PrintException("Extracting Manifest Data") + except Exception: + log_exception('Extracting Manifest Data') def get_browsable_activities(node): - """Get Browsable Activities""" + """Get Browsable Activities.""" try: browse_dic = {} schemes = [] @@ -188,59 +188,59 @@ def get_browsable_activities(node): paths = [] path_prefixs = [] path_patterns = [] - catg = node.getElementsByTagName("category") + catg = node.getElementsByTagName('category') for cat in catg: - if cat.getAttribute("android:name") == "android.intent.category.BROWSABLE": - datas = node.getElementsByTagName("data") + if cat.getAttribute('android:name') == 'android.intent.category.BROWSABLE': + datas = node.getElementsByTagName('data') for data in datas: - scheme = data.getAttribute("android:scheme") + scheme = data.getAttribute('android:scheme') if scheme and scheme not in schemes: schemes.append(scheme) - mime = data.getAttribute("android:mimeType") + mime = data.getAttribute('android:mimeType') if mime and mime not in mime_types: mime_types.append(mime) - host = data.getAttribute("android:host") + host = data.getAttribute('android:host') if host and host not in hosts: hosts.append(host) - port = data.getAttribute("android:port") + port = data.getAttribute('android:port') if port and port not in ports: ports.append(port) - path = data.getAttribute("android:path") + path = data.getAttribute('android:path') if path and path not in paths: paths.append(path) - path_prefix = data.getAttribute("android:pathPrefix") + path_prefix = data.getAttribute('android:pathPrefix') if path_prefix and path_prefix not in path_prefixs: path_prefixs.append(path_prefix) - path_pattern = data.getAttribute("android:pathPattern") + path_pattern = data.getAttribute('android:pathPattern') if path_pattern and path_pattern not in path_patterns: path_patterns.append(path_pattern) - schemes = [scheme + "://" for scheme in schemes] - browse_dic["schemes"] = schemes - browse_dic["mime_types"] = mime_types - browse_dic["hosts"] = hosts - browse_dic["ports"] = ports - browse_dic["paths"] = paths - browse_dic["path_prefixs"] = path_prefixs - browse_dic["path_patterns"] = path_patterns - browse_dic["browsable"] = bool(browse_dic["schemes"]) + schemes = [scheme + '://' for scheme in schemes] + browse_dic['schemes'] = schemes + browse_dic['mime_types'] = mime_types + browse_dic['hosts'] = hosts + browse_dic['ports'] = ports + browse_dic['paths'] = paths + browse_dic['path_prefixs'] = path_prefixs + browse_dic['path_patterns'] = path_patterns + browse_dic['browsable'] = bool(browse_dic['schemes']) return browse_dic - except: - PrintException("Getting Browsable Activities") + except Exception: + log_exception('Getting Browsable Activities') def manifest_analysis(mfxml, man_data_dic): """Analyse manifest file.""" # pylint: disable=C0301 try: - logger.info("Manifest Analysis Started") - exp_count = dict.fromkeys(["act", "ser", "bro", "cnt"], 0) - applications = mfxml.getElementsByTagName("application") - datas = mfxml.getElementsByTagName("data") - intents = mfxml.getElementsByTagName("intent-filter") - actions = mfxml.getElementsByTagName("action") + logger.info('Manifest Analysis Started') + exp_count = dict.fromkeys(['act', 'ser', 'bro', 'cnt'], 0) + applications = mfxml.getElementsByTagName('application') + datas = mfxml.getElementsByTagName('data') + intents = mfxml.getElementsByTagName('intent-filter') + actions = mfxml.getElementsByTagName('action') granturipermissions = mfxml.getElementsByTagName( - "grant-uri-permission") - permissions = mfxml.getElementsByTagName("permission") + 'grant-uri-permission') + permissions = mfxml.getElementsByTagName('permission') ret_value = [] ret_list = [] exported = [] @@ -249,72 +249,72 @@ def manifest_analysis(mfxml, man_data_dic): icon_hidden = True # PERMISSION for permission in permissions: - if permission.getAttribute("android:protectionLevel"): + if permission.getAttribute('android:protectionLevel'): protectionlevel = permission.getAttribute( - "android:protectionLevel") - if protectionlevel == "0x00000000": - protectionlevel = "normal" - elif protectionlevel == "0x00000001": - protectionlevel = "dangerous" - elif protectionlevel == "0x00000002": - protectionlevel = "signature" - elif protectionlevel == "0x00000003": - protectionlevel = "signatureOrSystem" + 'android:protectionLevel') + if protectionlevel == '0x00000000': + protectionlevel = 'normal' + elif protectionlevel == '0x00000001': + protectionlevel = 'dangerous' + elif protectionlevel == '0x00000002': + protectionlevel = 'signature' + elif protectionlevel == '0x00000003': + protectionlevel = 'signatureOrSystem' permission_dict[permission.getAttribute( - "android:name")] = protectionlevel - elif permission.getAttribute("android:name"): + 'android:name')] = protectionlevel + elif permission.getAttribute('android:name'): permission_dict[permission.getAttribute( - "android:name")] = "normal" + 'android:name')] = 'normal' # APPLICATIONS for application in applications: # Esteve 23.07.2016 - begin - identify permission at the # application level - if application.getAttribute("android:permission"): + if application.getAttribute('android:permission'): perm_appl_level_exists = True perm_appl_level = application.getAttribute( - "android:permission") + 'android:permission') else: perm_appl_level_exists = False # End - if application.getAttribute("android:debuggable") == "true": - ret_list.append(("a_debuggable", tuple(), tuple(),)) - if application.getAttribute("android:allowBackup") == "true": - ret_list.append(("a_allowbackup", tuple(), tuple(),)) - elif application.getAttribute("android:allowBackup") == "false": + if application.getAttribute('android:debuggable') == 'true': + ret_list.append(('a_debuggable', (), ())) + if application.getAttribute('android:allowBackup') == 'true': + ret_list.append(('a_allowbackup', (), ())) + elif application.getAttribute('android:allowBackup') == 'false': pass else: - ret_list.append(("a_allowbackup_miss", tuple(), tuple(),)) - if application.getAttribute("android:testOnly") == "true": - ret_list.append(("a_testonly", tuple(), tuple(),)) + ret_list.append(('a_allowbackup_miss', (), ())) + if application.getAttribute('android:testOnly') == 'true': + ret_list.append(('a_testonly', (), ())) for node in application.childNodes: an_or_a = '' if node.nodeName == 'activity': itemname = 'Activity' - cnt_id = "act" + cnt_id = 'act' an_or_a = 'n' browse_dic = get_browsable_activities(node) - if browse_dic["browsable"]: + if browse_dic['browsable']: browsable_activities[node.getAttribute( - "android:name")] = browse_dic + 'android:name')] = browse_dic elif node.nodeName == 'activity-alias': itemname = 'Activity-Alias' - cnt_id = "act" + cnt_id = 'act' an_or_a = 'n' browse_dic = get_browsable_activities(node) - if browse_dic["browsable"]: + if browse_dic['browsable']: browsable_activities[node.getAttribute( - "android:name")] = browse_dic + 'android:name')] = browse_dic elif node.nodeName == 'provider': itemname = 'Content Provider' - cnt_id = "cnt" + cnt_id = 'cnt' elif node.nodeName == 'receiver': itemname = 'Broadcast Receiver' - cnt_id = "bro" + cnt_id = 'bro' elif node.nodeName == 'service': itemname = 'Service' - cnt_id = "ser" + cnt_id = 'ser' else: itemname = 'NIL' item = '' @@ -322,29 +322,26 @@ def manifest_analysis(mfxml, man_data_dic): # Task Affinity if ( itemname in ['Activity', 'Activity-Alias'] and - node.getAttribute("android:taskAffinity") + node.getAttribute('android:taskAffinity') ): - item = node.getAttribute("android:name") - ret_list.append(("a_taskaffinity", (item,), tuple(),)) + item = node.getAttribute('android:name') + ret_list.append(('a_taskaffinity', (item,), ())) # LaunchMode try: - affected_sdk = int(man_data_dic['min_sdk']) < ANDROID_5_0_LEVEL - except: + affected_sdk = int( + man_data_dic['min_sdk']) < ANDROID_5_0_LEVEL + except Exception: # in case min_sdk is not defined we assume vulnerability affected_sdk = True if ( affected_sdk and itemname in ['Activity', 'Activity-Alias'] and - ( - node.getAttribute("android:launchMode") == 'singleInstance' or - node.getAttribute( - "android:launchMode") == 'singleTask' - ) - ): - item = node.getAttribute("android:name") - ret_list.append(("a_launchmode", (item,), tuple(),)) + (node.getAttribute('android:launchMode') == 'singleInstance' + or node.getAttribute('android:launchMode') == 'singleTask')): + item = node.getAttribute('android:name') + ret_list.append(('a_launchmode', (item,), ())) # Exported Check item = '' is_inf = False @@ -356,25 +353,20 @@ def manifest_analysis(mfxml, man_data_dic): protlevel = '' # End if itemname != 'NIL': - if node.getAttribute("android:exported") == 'true': + if node.getAttribute('android:exported') == 'true': perm = '' - item = node.getAttribute("android:name") - if node.getAttribute("android:permission"): + item = node.getAttribute('android:name') + if node.getAttribute('android:permission'): # permission exists - perm = ( - 'Permission: ' + - node.getAttribute("android:permission") - ) + perm = ('Permission: ' + + node.getAttribute('android:permission')) is_perm_exist = True if item != man_data_dic['mainactivity']: if is_perm_exist: - prot = "" - if node.getAttribute("android:permission") in permission_dict: - prot = ( - "
protectionLevel: " + - permission_dict[ - node.getAttribute("android:permission")] - ) + prot = '' + if node.getAttribute('android:permission') in permission_dict: + prot = ('
protectionLevel: ' + + permission_dict[node.getAttribute('android:permission')]) # Esteve 23.07.2016 - begin - take into account protection level of the permission when claiming that a component is protected by it; # - the permission might not be defined in the application being analysed, if so, the protection level is not known; # - activities (or activity-alias) that are exported and have an unknown or normal or dangerous protection level are @@ -382,31 +374,31 @@ def manifest_analysis(mfxml, man_data_dic): # counted as exported. prot_level_exist = True protlevel = permission_dict[ - node.getAttribute("android:permission")] + node.getAttribute('android:permission')] if prot_level_exist: if protlevel == 'normal': ret_list.append( - ("a_prot_normal", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_normal', (itemname, item, perm + prot), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'dangerous': ret_list.append( - ("a_prot_danger", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_danger', (itemname, item, perm + prot), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'signature': ret_list.append( - ("a_prot_sign", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_sign', (itemname, item, perm + prot), (an_or_a, itemname))) elif protlevel == 'signatureOrSystem': ret_list.append( - ("a_prot_sign_sys", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_sign_sys', (itemname, item, perm + prot), (an_or_a, itemname))) else: ret_list.append( - ("a_prot_unknown", (itemname, item, perm), (an_or_a, itemname,),)) + ('a_prot_unknown', (itemname, item, perm), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[cnt_id] + 1 @@ -417,7 +409,7 @@ def manifest_analysis(mfxml, man_data_dic): # are not protected. if perm_appl_level_exists is False: ret_list.append( - ("a_not_protected", (itemname, item), (an_or_a, itemname,),)) + ('a_not_protected', (itemname, item), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[cnt_id] + 1 @@ -430,69 +422,64 @@ def manifest_analysis(mfxml, man_data_dic): # defined in the analysed application. else: perm = 'Permission: ' + perm_appl_level - prot = "" + prot = '' if perm_appl_level in permission_dict: - prot = "
protectionLevel: " + \ - permission_dict[perm_appl_level] + prot = ('
protectionLevel: ' + + permission_dict[perm_appl_level]) prot_level_exist = True protlevel = permission_dict[ perm_appl_level] if prot_level_exist: if protlevel == 'normal': ret_list.append( - ("a_prot_normal_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_normal_appl', (itemname, item, perm + prot), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'dangerous': ret_list.append( - ("a_prot_danger_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_danger_appl', (itemname, item, perm + prot), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'signature': ret_list.append( - ("a_prot_sign_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_sign_appl', (itemname, item, perm + prot), (an_or_a, itemname))) elif protlevel == 'signatureOrSystem': ret_list.append( - ("a_prot_sign_sys_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_sign_sys_appl', (itemname, item, perm + prot), (an_or_a, itemname))) else: ret_list.append( - ("a_prot_unknown_appl", (itemname, item, perm), (an_or_a, itemname,),)) + ('a_prot_unknown_appl', (itemname, item, perm), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[ cnt_id] + 1 # Esteve 24.07.2016 - end - elif node.getAttribute("android:exported") != 'false': + elif node.getAttribute('android:exported') != 'false': # Check for Implicitly Exported # Logic to support intent-filter intentfilters = node.childNodes for i in intentfilters: inf = i.nodeName - if inf == "intent-filter": + if inf == 'intent-filter': is_inf = True if is_inf: - item = node.getAttribute("android:name") - if node.getAttribute("android:permission"): + item = node.getAttribute('android:name') + if node.getAttribute('android:permission'): # permission exists - perm = ( - 'Permission: ' + - node.getAttribute("android:permission") - ) + perm = ('Permission: ' + + node.getAttribute('android:permission')) is_perm_exist = True if item != man_data_dic['mainactivity']: if is_perm_exist: - prot = "" - if node.getAttribute("android:permission") in permission_dict: - prot = ( - "
protectionLevel: " + - permission_dict[ - node.getAttribute("android:permission")] - ) + prot = '' + if node.getAttribute('android:permission') in permission_dict: + prot = ('
protectionLevel: ' + + permission_dict[node.getAttribute('android:permission')]) # Esteve 24.07.2016 - begin - take into account protection level of the permission when claiming that a component is protected by it; # - the permission might not be defined in the application being analysed, if so, the protection level is not known; # - activities (or activity-alias) that are exported and have an unknown or normal or dangerous protection level are @@ -500,31 +487,31 @@ def manifest_analysis(mfxml, man_data_dic): # counted as exported. prot_level_exist = True protlevel = permission_dict[ - node.getAttribute("android:permission")] + node.getAttribute('android:permission')] if prot_level_exist: if protlevel == 'normal': ret_list.append( - ("a_prot_normal", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_normal', (itemname, item, perm + prot), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'dangerous': ret_list.append( - ("a_prot_danger", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_danger', (itemname, item, perm + prot), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'signature': ret_list.append( - ("a_prot_sign", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_sign', (itemname, item, perm + prot), (an_or_a, itemname))) elif protlevel == 'signatureOrSystem': ret_list.append( - ("a_prot_sign_sys", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_sign_sys', (itemname, item, perm + prot), (an_or_a, itemname))) else: ret_list.append( - ("a_prot_unknown", (itemname, item, perm), (an_or_a, itemname,),)) + ('a_prot_unknown', (itemname, item, perm), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[ @@ -536,7 +523,7 @@ def manifest_analysis(mfxml, man_data_dic): # they are not protected. if perm_appl_level_exists is False: ret_list.append( - ("a_not_protected_filter", (itemname, item,), (an_or_a, itemname, itemname,),)) + ('a_not_protected_filter', (itemname, item), (an_or_a, itemname, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[ @@ -550,44 +537,43 @@ def manifest_analysis(mfxml, man_data_dic): # defined in the analysed application. else: perm = 'Permission: ' + perm_appl_level - prot = "" + prot = '' if perm_appl_level in permission_dict: - prot = "
protectionLevel: " + \ - permission_dict[ - perm_appl_level] + prot = ('
protectionLevel: ' + + permission_dict[perm_appl_level]) prot_level_exist = True protlevel = permission_dict[ perm_appl_level] if prot_level_exist: if protlevel == 'normal': ret_list.append( - ("a_prot_normal_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_normal_appl', (itemname, item, perm + prot), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'dangerous': ret_list.append( - ("a_prot_danger_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_danger_appl', (itemname, item, perm + prot), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'signature': ret_list.append( - ("a_prot_sign_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_sign_appl', (itemname, item, perm + prot), (an_or_a, itemname))) elif protlevel == 'signatureOrSystem': ret_list.append( - ("a_prot_sign_sys_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('a_prot_sign_sys_appl', (itemname, item, perm + prot), (an_or_a, itemname))) else: ret_list.append( - ("a_prot_unknown_appl", (itemname, item, perm), (an_or_a, itemname,),)) + ('a_prot_unknown_appl', (itemname, item, perm), (an_or_a, itemname))) if itemname in ['Activity', 'Activity-Alias']: exported.append(item) exp_count[cnt_id] = exp_count[ cnt_id] + 1 # Esteve 24.07.2016 - end - # Esteve 29.07.2016 - begin The component is not explicitly exported (android:exported is not "true"). It is not implicitly exported either (it does not + # Esteve 29.07.2016 - begin The component is not explicitly exported (android:exported is not 'true'). It is not implicitly exported either (it does not # make use of an intent filter). Despite that, it could still be exported by default, if it is a content provider and the android:targetSdkVersion # is older than 17 (Jelly Bean, Android versionn 4.2). This is true regardless of the system's API level. # Finally, it must also be taken into account that, if the minSdkVersion is greater or equal than 17, this check is unnecessary, because the @@ -597,80 +583,77 @@ def manifest_analysis(mfxml, man_data_dic): if man_data_dic['min_sdk'] and man_data_dic['target_sdk'] and int(man_data_dic['min_sdk']) < ANDROID_4_2_LEVEL: if itemname == 'Content Provider' and int(man_data_dic['target_sdk']) < ANDROID_4_2_LEVEL: perm = '' - item = node.getAttribute("android:name") - if node.getAttribute("android:permission"): + item = node.getAttribute('android:name') + if node.getAttribute('android:permission'): # permission exists - perm = 'Permission: ' + \ - node.getAttribute( - "android:permission") + perm = ('Permission: ' + + node.getAttribute('android:permission')) is_perm_exist = True if is_perm_exist: - prot = "" - if node.getAttribute("android:permission") in permission_dict: - prot = "
protectionLevel: " + \ - permission_dict[ - node.getAttribute("android:permission")] + prot = '' + if node.getAttribute('android:permission') in permission_dict: + prot = ('
protectionLevel: ' + + permission_dict[node.getAttribute('android:permission')]) prot_level_exist = True protlevel = permission_dict[ - node.getAttribute("android:permission")] + node.getAttribute('android:permission')] if prot_level_exist: if protlevel == 'normal': ret_list.append( - ("c_prot_normal", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_normal', (itemname, item, perm + prot), (an_or_a, itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'dangerous': ret_list.append( - ("c_prot_danger", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_danger', (itemname, item, perm + prot), (an_or_a, itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'signature': ret_list.append( - ("c_prot_sign", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_sign', (itemname, item, perm + prot), (an_or_a, itemname))) elif protlevel == 'signatureOrSystem': ret_list.append( - ("c_prot_sign_sys", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_sign_sys', (itemname, item, perm + prot), (an_or_a, itemname))) else: ret_list.append( - ("c_prot_unknown", (itemname, item, perm), (an_or_a, itemname,),)) + ('c_prot_unknown', (itemname, item, perm), (an_or_a, itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 else: if perm_appl_level_exists is False: ret_list.append( - ("c_not_protected", (itemname, item), (an_or_a, itemname,),)) + ('c_not_protected', (itemname, item), (an_or_a, itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 else: perm = 'Permission: ' + perm_appl_level - prot = "" + prot = '' if perm_appl_level in permission_dict: - prot = "
protectionLevel: " + \ - permission_dict[ - perm_appl_level] + prot = ('
protectionLevel: ' + + permission_dict[perm_appl_level]) prot_level_exist = True protlevel = permission_dict[ perm_appl_level] if prot_level_exist: if protlevel == 'normal': ret_list.append( - ("c_prot_normal_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_normal_appl', (itemname, item, perm + prot), (an_or_a, itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'dangerous': ret_list.append( - ("c_prot_danger_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_danger_appl', (itemname, item, perm + prot), (an_or_a, itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'signature': ret_list.append( - ("c_prot_sign_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_sign_appl', (itemname, item, perm + prot), (an_or_a, itemname))) elif protlevel == 'signatureOrSystem': ret_list.append( - ("c_prot_sign_sys_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_sign_sys_appl', (itemname, item, perm + prot), (an_or_a, itemname))) else: ret_list.append( - ("c_prot_unknown_appl", (itemname, item, perm), (an_or_a, itemname,),)) + ('c_prot_unknown_appl', (itemname, item, perm), (an_or_a, itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 # Esteve 29.07.2016 - end @@ -681,130 +664,126 @@ def manifest_analysis(mfxml, man_data_dic): if itemname == 'Content Provider' and int(man_data_dic['target_sdk']) >= 17: perm = '' item = node.getAttribute( - "android:name") - if node.getAttribute("android:permission"): + 'android:name') + if node.getAttribute('android:permission'): # permission exists - perm = 'Permission: ' + \ - node.getAttribute( - "android:permission") + perm = ('Permission: ' + + node.getAttribute('android:permission')) is_perm_exist = True if is_perm_exist: - prot = "" - if node.getAttribute("android:permission") in permission_dict: - prot = "
protectionLevel: " + \ - permission_dict[ - node.getAttribute("android:permission")] + prot = '' + if node.getAttribute('android:permission') in permission_dict: + prot = ('
protectionLevel: ' + + permission_dict[node.getAttribute('android:permission')]) prot_level_exist = True protlevel = permission_dict[ - node.getAttribute("android:permission")] + node.getAttribute('android:permission')] if prot_level_exist: if protlevel == 'normal': ret_list.append( - ("c_prot_normal_new", (itemname, item, perm + prot,), (itemname,),)) + ('c_prot_normal_new', (itemname, item, perm + prot), (itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 if protlevel == 'dangerous': ret_list.append( - ("c_prot_danger_new", (itemname, item, perm + prot,), (itemname,),)) + ('c_prot_danger_new', (itemname, item, perm + prot), (itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 if protlevel == 'signature': ret_list.append( - ("c_prot_sign_new", (itemname, item, perm + prot,), (itemname,),)) + ('c_prot_sign_new', (itemname, item, perm + prot), (itemname))) if protlevel == 'signatureOrSystem': ret_list.append( - ("c_prot_sign_sys_new", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_sign_sys_new', (itemname, item, perm + prot), (an_or_a, itemname))) else: ret_list.append( - ("c_prot_unknown_new", (itemname, item, perm), (itemname,),)) + ('c_prot_unknown_new', (itemname, item, perm), (itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 else: if perm_appl_level_exists is False: ret_list.append( - ("c_not_protected2", (itemname, item), (an_or_a, itemname,),)) + ('c_not_protected2', (itemname, item), (an_or_a, itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 else: perm = 'Permission: ' + perm_appl_level - prot = "" + prot = '' if perm_appl_level in permission_dict: - prot = "
protectionLevel: " + \ - permission_dict[ - perm_appl_level] + prot = ('
protectionLevel: ' + + permission_dict[perm_appl_level]) prot_level_exist = True protlevel = permission_dict[ perm_appl_level] if prot_level_exist: if protlevel == 'normal': ret_list.append( - ("c_prot_normal_new_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_normal_new_appl', (itemname, item, perm + prot), (an_or_a, itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'dangerous': ret_list.append( - ("c_prot_danger_new_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_danger_new_appl', (itemname, item, perm + prot), (an_or_a, itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 elif protlevel == 'signature': ret_list.append( - ("c_prot_sign_new_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_sign_new_appl', (itemname, item, perm + prot), (an_or_a, itemname))) elif protlevel == 'signatureOrSystem': ret_list.append( - ("c_prot_sign_sys_new_appl", (itemname, item, perm + prot,), (an_or_a, itemname,),)) + ('c_prot_sign_sys_new_appl', (itemname, item, perm + prot), (an_or_a, itemname))) else: ret_list.append( - ("c_prot_unknown_new_appl", (itemname, item, perm), (an_or_a, itemname,),)) + ('c_prot_unknown_new_appl', (itemname, item, perm), (an_or_a, itemname))) exp_count[cnt_id] = exp_count[ cnt_id] + 1 # Esteve 08.08.2016 - end # GRANT-URI-PERMISSIONS for granturi in granturipermissions: - if granturi.getAttribute("android:pathPrefix") == '/': + if granturi.getAttribute('android:pathPrefix') == '/': ret_list.append( - ("a_improper_provider", ('pathPrefix=/',), tuple(),)) - elif granturi.getAttribute("android:path") == '/': - ret_list.append(("a_improper_provider", ('path=/',), tuple(),)) - elif granturi.getAttribute("android:pathPattern") == '*': - ret_list.append(("a_improper_provider", ('path=*',), tuple(),)) + ('a_improper_provider', ('pathPrefix=/',), ())) + elif granturi.getAttribute('android:path') == '/': + ret_list.append(('a_improper_provider', ('path=/',), ())) + elif granturi.getAttribute('android:pathPattern') == '*': + ret_list.append(('a_improper_provider', ('path=*',), ())) # DATA for data in datas: - if data.getAttribute("android:scheme") == "android_secret_code": - xmlhost = data.getAttribute("android:host") - ret_list.append(("a_dailer_code", (xmlhost,), tuple(),)) + if data.getAttribute('android:scheme') == 'android_secret_code': + xmlhost = data.getAttribute('android:host') + ret_list.append(('a_dailer_code', (xmlhost,), ())) - elif data.getAttribute("android:port"): - dataport = data.getAttribute("android:port") - ret_list.append(("a_sms_receiver_port", (dataport,), tuple(),)) + elif data.getAttribute('android:port'): + dataport = data.getAttribute('android:port') + ret_list.append(('a_sms_receiver_port', (dataport,), ())) # INTENTS for intent in intents: - if intent.getAttribute("android:priority").isdigit(): - value = intent.getAttribute("android:priority") + if intent.getAttribute('android:priority').isdigit(): + value = intent.getAttribute('android:priority') if int(value) > 100: ret_list.append( - ("a_high_intent_priority", (value,), tuple(),)) + ('a_high_intent_priority', (value,), ())) # ACTIONS for action in actions: - if action.getAttribute("android:priority").isdigit(): - value = action.getAttribute("android:priority") + if action.getAttribute('android:priority').isdigit(): + value = action.getAttribute('android:priority') if int(value) > 100: ret_list.append( - ("a_high_action_priority", (value,), tuple(),)) + ('a_high_action_priority', (value,), ())) for a_key, t_name, t_desc in ret_list: a_template = android_manifest_desc.MANIFEST_DESC.get(a_key) if a_template: ret_value.append( - {"title": a_template['title'] % t_name, - "stat": a_template['level'], - "desc": a_template['description'] % t_desc, - "name": a_template['name'], - "component": t_name - } - ) + {'title': a_template['title'] % t_name, + 'stat': a_template['level'], + 'desc': a_template['description'] % t_desc, + 'name': a_template['name'], + 'component': t_name, + }) for category in man_data_dic['categories']: - if category == "android.intent.category.LAUNCHER": + if category == 'android.intent.category.LAUNCHER': icon_hidden = False break @@ -814,7 +793,7 @@ def manifest_analysis(mfxml, man_data_dic): { 'status': permisson[0], 'info': permisson[1], - 'description': permisson[2] + 'description': permisson[2], }) # Prepare return dict man_an_dic = { @@ -827,11 +806,11 @@ def manifest_analysis(mfxml, man_data_dic): 'cnt_pro': len(man_data_dic['providers']), 'cnt_ser': len(man_data_dic['services']), 'cnt_bro': len(man_data_dic['receivers']), - 'icon_hidden': icon_hidden + 'icon_hidden': icon_hidden, } return man_an_dic - except: - PrintException("Performing Manifest Analysis") + except Exception: + log_exception('Performing Manifest Analysis') def read_manifest(app_dir, app_path, tools_dir, typ, apk): @@ -841,60 +820,61 @@ def read_manifest(app_dir, app_path, tools_dir, typ, apk): manifest = '' if apk: manifest = get_manifest_file(app_path, app_dir, tools_dir) - if isFileExists(manifest): - logger.info("Reading Android Manifest") + if is_file_exists(manifest): + logger.info('Reading Android Manifest') with io.open( manifest, mode='r', - encoding="utf8", - errors="ignore" + encoding='utf8', + errors='ignore', ) as file_pointer: dat = file_pointer.read() else: - logger.info("Reading Manifest from Source") - if typ == "eclipse": - manifest = os.path.join(app_dir, "AndroidManifest.xml") - elif typ == "studio": + logger.info('Reading Manifest from Source') + if typ == 'eclipse': + manifest = os.path.join(app_dir, 'AndroidManifest.xml') + elif typ == 'studio': manifest = os.path.join( - app_dir, "app/src/main/AndroidManifest.xml" - ) + app_dir, + 'app/src/main/AndroidManifest.xml') with io.open( manifest, mode='r', - encoding="utf8", - errors="ignore" + encoding='utf8', + errors='ignore', ) as file_pointer: dat = file_pointer.read() return dat - except: - PrintException("Reading Manifest file") + except Exception: + log_exception('Reading Manifest file') def get_manifest_file(app_path, app_dir, tools_dir): - """Get readable AndroidManifest.xml""" + """Get readable AndroidManifest.xml.""" try: manifest = None - if len(settings.APKTOOL_BINARY) > 0 and isFileExists(settings.APKTOOL_BINARY): + if (len(settings.APKTOOL_BINARY) > 0 + and is_file_exists(settings.APKTOOL_BINARY)): apktool_path = settings.APKTOOL_BINARY else: apktool_path = os.path.join(tools_dir, 'apktool_2.4.0.jar') - output_dir = os.path.join(app_dir, "apktool_out") + output_dir = os.path.join(app_dir, 'apktool_out') args = [settings.JAVA_PATH + 'java', '-jar', apktool_path, - "--match-original", - "--frame-path", + '--match-original', + '--frame-path', tempfile.gettempdir(), - "-f", "-s", "d", + '-f', '-s', 'd', app_path, - "-o", + '-o', output_dir] - manifest = os.path.join(output_dir, "AndroidManifest.xml") - if isFileExists(manifest): + manifest = os.path.join(output_dir, 'AndroidManifest.xml') + if is_file_exists(manifest): # APKTool already created readable XML return manifest - logger.info("Converting AXML to XML") + logger.info('Converting AXML to XML') subprocess.check_output(args) return manifest - except: - PrintException("Getting Manifest file") + except Exception: + log_exception('Getting Manifest file') diff --git a/StaticAnalyzer/views/android/manifest_view.py b/StaticAnalyzer/views/android/manifest_view.py index 23f404b2..83353e50 100755 --- a/StaticAnalyzer/views/android/manifest_view.py +++ b/StaticAnalyzer/views/android/manifest_view.py @@ -1,20 +1,17 @@ # -*- coding: utf_8 -*- """Module for manifest_view.""" -import re +import logging import os +import re -from django.shortcuts import render -from django.http import HttpResponseRedirect from django.conf import settings +from django.shortcuts import render -from MobSF.utils import ( - PrintException, - print_n_send_error_response -) +from MobSF.utils import log_exception, print_n_send_error_response from StaticAnalyzer.views.android.manifest_analysis import read_manifest -import logging + logger = logging.getLogger(__name__) @@ -26,23 +23,28 @@ def run(request): typ = request.GET['type'] # APK or SOURCE binary = request.GET['bin'] match = re.match('^[0-9a-f]{32}$', md5) - if match and (typ in ['eclipse', 'studio', 'apk']) and (binary in ['1', '0']): + if (match + and (typ in ['eclipse', 'studio', 'apk']) + and (binary in ['1', '0'])): app_dir = os.path.join( settings.UPLD_DIR, md5 + '/') # APP DIRECTORY - tools_dir = os.path.join(directory, 'StaticAnalyzer/tools/') # TOOLS DIR + tools_dir = os.path.join( + directory, 'StaticAnalyzer/tools/') # TOOLS DIR if binary == '1': is_binary = True elif binary == '0': is_binary = False - app_path = os.path.join(app_dir, md5 + ".apk") - manifest = read_manifest(app_dir, app_path, tools_dir, typ, is_binary) + app_path = os.path.join(app_dir, md5 + '.apk') + manifest = read_manifest( + app_dir, app_path, tools_dir, typ, is_binary) context = { 'title': 'AndroidManifest.xml', 'file': 'AndroidManifest.xml', - 'dat': manifest + 'dat': manifest, } - template = "static_analysis/view_mani.html" + template = 'static_analysis/view_mani.html' return render(request, template, context) - except: - PrintException("Viewing AndroidManifest.xml") - return print_n_send_error_response(request, "Error Viewing AndroidManifest.xml") + except Exception: + log_exception('Viewing AndroidManifest.xml') + return print_n_send_error_response(request, + 'Error Viewing AndroidManifest.xml') diff --git a/StaticAnalyzer/views/android/playstore.py b/StaticAnalyzer/views/android/playstore.py index ca72b3eb..4e2e7ac8 100644 --- a/StaticAnalyzer/views/android/playstore.py +++ b/StaticAnalyzer/views/android/playstore.py @@ -2,17 +2,18 @@ import play_scraper import logging + logger = logging.getLogger(__name__) def get_app_details(package_id): - '''Get App Details form PlayStore''' + """Get App Details form PlayStore.""" try: - logger.info("Fetching Details from Play Store: %s", package_id) + logger.info('Fetching Details from Play Store: %s', package_id) det = play_scraper.details(package_id) det.pop('description_html', None) - det["error"] = False - except Exception as exp: - logger.warning("Unable to get app details. %s", exp) - det = {"error": True} + det['error'] = False + except Exception: + logger.warning('Unable to get app details.') + det = {'error': True} return det diff --git a/StaticAnalyzer/views/android/smali.py b/StaticAnalyzer/views/android/smali.py index 2e814fc9..85001ca7 100755 --- a/StaticAnalyzer/views/android/smali.py +++ b/StaticAnalyzer/views/android/smali.py @@ -1,19 +1,17 @@ # -*- coding: utf_8 -*- -"""List all smali files..""" +"""List all smali files.""" +import logging +import os import re import shutil -import os -import logging -from django.shortcuts import render -from django.http import HttpResponseRedirect + from django.conf import settings +from django.shortcuts import render from django.utils.html import escape -from MobSF.utils import ( - PrintException, - print_n_send_error_response -) +from MobSF.utils import log_exception, print_n_send_error_response + logger = logging.getLogger(__name__) @@ -23,32 +21,36 @@ def run(request): match = re.match('^[0-9a-f]{32}$', request.GET['md5']) if match: md5 = request.GET['md5'] - src = os.path.join(settings.UPLD_DIR, md5+'/smali_source/') + src = os.path.join(settings.UPLD_DIR, md5 + '/smali_source/') html = '' # pylint: disable=unused-variable # Needed by os.walk - for dir_name, sub_dir, files in os.walk(src): + for dir_name, _sub_dir, files in os.walk(src): for jfile in files: - if jfile.endswith(".smali"): + if jfile.endswith('.smali'): file_path = os.path.join(src, dir_name, jfile) - if "+" in jfile: - fp2 = os.path.join(src, dir_name, jfile.replace("+", "x")) + if '+' in jfile: + fp2 = os.path.join( + src, dir_name, jfile.replace('+', 'x')) shutil.move(file_path, fp2) file_path = fp2 fileparam = file_path.replace(src, '') - html += ( - "" + - escape(fileparam) + "" - ) + html += ('{}' + '').format( + escape(fileparam), + md5, + escape(fileparam)) context = { 'title': 'Smali Source', 'files': html, 'md5': md5, } - template = "static_analysis/smali.html" + template = 'static_analysis/smali.html' return render(request, template, context) - except: - PrintException("Getting Smali Files") - return print_n_send_error_response(request, "Error Getting Smali Files") + except Exception: + log_exception('Getting Smali Files') + return print_n_send_error_response( + request, + 'Error Getting Smali Files') diff --git a/StaticAnalyzer/views/android/static_analyzer.py b/StaticAnalyzer/views/android/static_analyzer.py index ce716fde..1a16900c 100755 --- a/StaticAnalyzer/views/android/static_analyzer.py +++ b/StaticAnalyzer/views/android/static_analyzer.py @@ -1,79 +1,53 @@ # -*- coding: utf_8 -*- -""" -Android Static Code Analysis -""" +"""Android Static Code Analysis.""" -import re -import os -import zipfile -import shutil import logging -try: - import io - StringIO = io.StringIO -except ImportError: - from io import StringIO +import os +import re +import shutil +import zipfile -from django.shortcuts import render -from django.http import HttpResponseRedirect -from django.conf import settings -from django.template.defaulttags import register - -from MobSF.utils import ( - print_n_send_error_response, - PrintException, - zipdir -) - -from StaticAnalyzer.models import StaticAnalyzerAndroid -from StaticAnalyzer.views.shared_func import ( - file_size, - firebase_analysis, - hash_gen, - unzip, - score, - update_scan_timestamp, -) - -from StaticAnalyzer.views.android.db_interaction import ( - get_context_from_db_entry, - get_context_from_analysis, - update_db_entry, - create_db_entry, -) - -from StaticAnalyzer.views.android.code_analysis import code_analysis -from StaticAnalyzer.views.android.strings import strings_jar -from StaticAnalyzer.views.android.converter import ( - dex_2_jar, - dex_2_smali, - jar_2_java -) -from StaticAnalyzer.views.android.cert_analysis import ( - get_hardcoded_cert_keystore, - cert_info, - -) -from StaticAnalyzer.views.android.manifest_analysis import ( - manifest_data, - manifest_analysis, - get_manifest -) -from StaticAnalyzer.views.android.binary_analysis import ( - elf_analysis, - res_analysis, -) -from StaticAnalyzer.views.android.icon_analysis import ( - get_icon, - find_icon_path_zip, -) -from StaticAnalyzer.views.android.playstore import ( - get_app_details, -) -from MalwareAnalyzer.views.domain_check import malware_check -from MalwareAnalyzer.views.apkid import apkid_analysis import MalwareAnalyzer.views.Trackers as Trackers import MalwareAnalyzer.views.VirusTotal as VirusTotal +from MalwareAnalyzer.views.apkid import apkid_analysis +from MalwareAnalyzer.views.domain_check import malware_check + +from django.conf import settings +from django.http import HttpResponseRedirect +from django.shortcuts import render +from django.template.defaulttags import register + +from MobSF.utils import log_exception, print_n_send_error_response, zipdir + +from StaticAnalyzer.models import StaticAnalyzerAndroid +from StaticAnalyzer.views.android.binary_analysis import (elf_analysis, + res_analysis) +from StaticAnalyzer.views.android.cert_analysis import ( + cert_info, get_hardcoded_cert_keystore) +from StaticAnalyzer.views.android.code_analysis import code_analysis +from StaticAnalyzer.views.android.converter import (dex_2_jar, dex_2_smali, + jar_2_java) +from StaticAnalyzer.views.android.db_interaction import ( + create_db_entry, get_context_from_analysis, get_context_from_db_entry, + update_db_entry) +from StaticAnalyzer.views.android.icon_analysis import (find_icon_path_zip, + get_icon) +from StaticAnalyzer.views.android.manifest_analysis import (get_manifest, + manifest_analysis, + manifest_data) +from StaticAnalyzer.views.android.playstore import get_app_details +from StaticAnalyzer.views.android.strings import strings_jar +from StaticAnalyzer.views.shared_func import (file_size, firebase_analysis, + hash_gen, score, unzip, + update_scan_timestamp) + +try: + import io + StringIO = io.StringIO # noqa F401 +except ImportError: + from io import StringIO # noqa F401 + + logger = logging.getLogger(__name__) @@ -103,8 +77,8 @@ def static_analyzer(request, api=False): ( match ) and ( - filename.lower().endswith('.apk') or - filename.lower().endswith('.zip') + filename.lower().endswith('.apk') + or filename.lower().endswith('.zip') ) and ( typ in ['zip', 'apk'] ) @@ -116,8 +90,7 @@ def static_analyzer(request, api=False): 'md5'] + '/') # APP DIRECTORY app_dic['tools_dir'] = os.path.join( app_dic['dir'], 'StaticAnalyzer/tools/') # TOOLS DIR - # DWD_DIR = settings.DWD_DIR # not needed? Var is never used. - logger.info("Starting Analysis on : " + app_dic['app_name']) + logger.info('Starting Analysis on : %s', app_dic['app_name']) if typ == 'apk': # Check if in DB @@ -129,8 +102,8 @@ def static_analyzer(request, api=False): else: app_dic['app_file'] = app_dic[ 'md5'] + '.apk' # NEW FILENAME - app_dic['app_path'] = app_dic['app_dir'] + \ - app_dic['app_file'] # APP PATH + app_dic['app_path'] = (app_dic['app_dir'] + + app_dic['app_file']) # APP PATH # ANALYSIS BEGINS app_dic['size'] = str( @@ -142,15 +115,21 @@ def static_analyzer(request, api=False): app_dic['app_path'], app_dic['app_dir']) if not app_dic['files']: # Can't Analyze APK, bail out. - msg = "APK file is invalid or corrupt" + msg = 'APK file is invalid or corrupt' if api: - return print_n_send_error_response(request, msg, True) + return print_n_send_error_response( + request, + msg, + True) else: - return print_n_send_error_response(request, msg, False) + return print_n_send_error_response( + request, + msg, + False) app_dic['certz'] = get_hardcoded_cert_keystore(app_dic[ 'files']) - logger.info("APK Extracted") + logger.info('APK Extracted') # Manifest XML app_dic['parsed_xml'] = get_manifest( @@ -158,7 +137,7 @@ def static_analyzer(request, api=False): app_dic['app_dir'], app_dic['tools_dir'], '', - True + True, ) # Get icon @@ -179,20 +158,22 @@ def static_analyzer(request, api=False): app_dic['icon_path'] = icon_dic['path'] # Set Manifest link - app_dic['mani'] = '../ManifestView/?md5=' + \ - app_dic['md5'] + '&type=apk&bin=1' + app_dic['mani'] = ('../ManifestView/?md5=' + + app_dic['md5'] + + '&type=apk&bin=1') man_data_dic = manifest_data(app_dic['parsed_xml']) app_dic['playstore'] = get_app_details( man_data_dic['packagename']) man_an_dic = manifest_analysis( app_dic['parsed_xml'], - man_data_dic - ) + man_data_dic) bin_an_buff = [] bin_an_buff += elf_analysis(app_dic['app_dir']) bin_an_buff += res_analysis(app_dic['app_dir']) cert_dic = cert_info( - app_dic['app_dir'], app_dic['app_file'], app_dic['tools_dir']) + app_dic['app_dir'], + app_dic['app_file'], + app_dic['tools_dir']) apkid_results = apkid_analysis(app_dic[ 'app_dir'], app_dic['app_path'], app_dic['app_name']) tracker = Trackers.Trackers( @@ -205,42 +186,40 @@ def static_analyzer(request, api=False): code_an_dic = code_analysis( app_dic['app_dir'], man_an_dic['permissons'], - "apk" - ) + 'apk') # Get the strings string_res = strings_jar( app_dic['app_file'], - app_dic['app_dir'] - ) + app_dic['app_dir']) if string_res: app_dic['strings'] = string_res['strings'] - code_an_dic["urls_list"].extend( + code_an_dic['urls_list'].extend( string_res['urls_list']) - code_an_dic["urls"].extend(string_res['url_nf']) - code_an_dic["emails"].extend(string_res['emails_nf']) + code_an_dic['urls'].extend(string_res['url_nf']) + code_an_dic['emails'].extend(string_res['emails_nf']) else: app_dic['strings'] = [] # Firebase DB Check code_an_dic['firebase'] = firebase_analysis( - list(set(code_an_dic["urls_list"]))) + list(set(code_an_dic['urls_list']))) # Domain Extraction and Malware Check logger.info( - "Performing Malware Check on extracted Domains") - code_an_dic["domains"] = malware_check( - list(set(code_an_dic["urls_list"]))) + 'Performing Malware Check on extracted Domains') + code_an_dic['domains'] = malware_check( + list(set(code_an_dic['urls_list']))) - logger.info("Generating Java and Smali Downloads") + logger.info('Generating Java and Smali Downloads') gen_downloads(app_dic['app_dir'], app_dic[ 'md5'], app_dic['icon_path']) app_dic['zipped'] = '&type=apk' - logger.info("Connecting to Database") + logger.info('Connecting to Database') try: # SAVE TO DB if rescan == '1': - logger.info("Updating Database...") + logger.info('Updating Database...') update_db_entry( app_dic, man_data_dic, @@ -253,7 +232,7 @@ def static_analyzer(request, api=False): ) update_scan_timestamp(app_dic['md5']) elif rescan == '0': - logger.info("Saving to Database") + logger.info('Saving to Database') create_db_entry( app_dic, man_data_dic, @@ -264,8 +243,8 @@ def static_analyzer(request, api=False): apkid_results, tracker_res, ) - except: - PrintException("Saving to Database Failed") + except Exception: + log_exception('Saving to Database Failed') context = get_context_from_analysis( app_dic, man_data_dic, @@ -276,8 +255,8 @@ def static_analyzer(request, api=False): apkid_results, tracker_res, ) - context["average_cvss"], context[ - "security_score"] = score(context["findings"]) + context['average_cvss'], context[ + 'security_score'] = score(context['findings']) context['dynamic_analysis_done'] = os.path.exists( os.path.join(app_dic['app_dir'], 'logcat.txt')) @@ -287,9 +266,8 @@ def static_analyzer(request, api=False): context['VT_RESULT'] = vt.get_result( os.path.join(app_dic['app_dir'], app_dic['md5']) + '.apk', - app_dic['md5'] - ) - template = "static_analysis/android_binary_analysis.html" + app_dic['md5']) + template = 'static_analysis/android_binary_analysis.html' if api: return context else: @@ -312,26 +290,27 @@ def static_analyzer(request, api=False): else: app_dic['app_file'] = app_dic[ 'md5'] + '.zip' # NEW FILENAME - app_dic['app_path'] = app_dic['app_dir'] + \ - app_dic['app_file'] # APP PATH - logger.info("Extracting ZIP") + app_dic['app_path'] = (app_dic['app_dir'] + + app_dic['app_file']) # APP PATH + logger.info('Extracting ZIP') app_dic['files'] = unzip( app_dic['app_path'], app_dic['app_dir']) # Check if Valid Directory Structure and get ZIP Type pro_type, valid = valid_android_zip(app_dic['app_dir']) if valid and pro_type == 'ios': - logger.info("Redirecting to iOS Source Code Analyzer") + logger.info('Redirecting to iOS Source Code Analyzer') if api: - return {"type": "ios"} + return {'type': 'ios'} else: return HttpResponseRedirect( - '/StaticAnalyzer_iOS/?name=' + app_dic['app_name'] + - '&type=ios&checksum=' + app_dic['md5'] - ) - app_dic['certz'] = get_hardcoded_cert_keystore(app_dic[ - 'files']) + '/StaticAnalyzer_iOS/?name=' + + app_dic['app_name'] + + '&type=ios&checksum=' + + app_dic['md5']) + app_dic['certz'] = get_hardcoded_cert_keystore( + app_dic['files']) app_dic['zipped'] = pro_type - logger.info("ZIP Type - " + pro_type) + logger.info('ZIP Type - %s', pro_type) if valid and (pro_type in ['eclipse', 'studio']): # ANALYSIS BEGINS app_dic['size'] = str( @@ -341,17 +320,18 @@ def static_analyzer(request, api=False): # Manifest XML app_dic['persed_xml'] = get_manifest( - "", + '', app_dic['app_dir'], app_dic['tools_dir'], pro_type, - False + False, ) # Set manifest view link app_dic['mani'] = ( - '../ManifestView/?md5=' + - app_dic['md5'] + '&type=' + pro_type + '&bin=0' + '../ManifestView/?md5=' + + app_dic['md5'] + '&type=' + + pro_type + '&bin=0' ) man_data_dic = manifest_data(app_dic['persed_xml']) @@ -359,7 +339,7 @@ def static_analyzer(request, api=False): man_data_dic['packagename']) man_an_dic = manifest_analysis( app_dic['persed_xml'], - man_data_dic + man_data_dic, ) # Get icon eclipse_res_path = os.path.join( @@ -384,27 +364,30 @@ def static_analyzer(request, api=False): if app_dic['icon_path']: if os.path.exists(app_dic['icon_path']): - shutil.copy2(app_dic['icon_path'], os.path.join( - settings.DWD_DIR, app_dic['md5'] + '-icon.png')) + shutil.copy2( + app_dic['icon_path'], + os.path.join( + settings.DWD_DIR, + app_dic['md5'] + '-icon.png')) code_an_dic = code_analysis( app_dic['app_dir'], man_an_dic['permissons'], - pro_type + pro_type, ) # Firebase DB Check code_an_dic['firebase'] = firebase_analysis( - list(set(code_an_dic["urls_list"]))) + list(set(code_an_dic['urls_list']))) # Domain Extraction and Malware Check logger.info( - "Performing Malware Check on extracted Domains") - code_an_dic["domains"] = malware_check( - list(set(code_an_dic["urls_list"]))) - logger.info("Connecting to Database") + 'Performing Malware Check on extracted Domains') + code_an_dic['domains'] = malware_check( + list(set(code_an_dic['urls_list']))) + logger.info('Connecting to Database') try: # SAVE TO DB if rescan == '1': - logger.info("Updating Database...") + logger.info('Updating Database...') update_db_entry( app_dic, man_data_dic, @@ -417,7 +400,7 @@ def static_analyzer(request, api=False): ) update_scan_timestamp(app_dic['md5']) elif rescan == '0': - logger.info("Saving to Database") + logger.info('Saving to Database') create_db_entry( app_dic, man_data_dic, @@ -428,8 +411,8 @@ def static_analyzer(request, api=False): {}, {}, ) - except: - PrintException("Saving to Database Failed") + except Exception: + log_exception('Saving to Database Failed') context = get_context_from_analysis( app_dic, man_data_dic, @@ -441,24 +424,28 @@ def static_analyzer(request, api=False): {}, ) else: - msg = "This ZIP Format is not supported" + msg = 'This ZIP Format is not supported' if api: - return print_n_send_error_response(request, msg, True) + return print_n_send_error_response( + request, + msg, + True) else: print_n_send_error_response(request, msg, False) return HttpResponseRedirect('/zip_format/') - context["average_cvss"], context[ - "security_score"] = score(context["findings"]) - template = "static_analysis/android_source_analysis.html" + context['average_cvss'], context[ + 'security_score'] = score(context['findings']) + template = 'static_analysis/android_source_analysis.html' if api: return context else: return render(request, template, context) else: - logger.error( - "Only APK,IPA and Zipped Android/iOS Source code supported now!") + err = ('Only APK,IPA and Zipped ' + 'Android/iOS Source code supported now!') + logger.error(err) else: - msg = "Hash match failed or Invalid file extension or file type" + msg = 'Hash match failed or Invalid file extension or file type' if api: return print_n_send_error_response(request, msg, True) else: @@ -476,34 +463,32 @@ def static_analyzer(request, api=False): def valid_android_zip(app_dir): """Test if this is an valid android zip.""" try: - logger.info("Checking for ZIP Validity and Mode") + logger.info('Checking for ZIP Validity and Mode') # Eclipse - man = os.path.isfile(os.path.join(app_dir, "AndroidManifest.xml")) - src = os.path.exists(os.path.join(app_dir, "src/")) + man = os.path.isfile(os.path.join(app_dir, 'AndroidManifest.xml')) + src = os.path.exists(os.path.join(app_dir, 'src/')) if man and src: return 'eclipse', True # Studio man = os.path.isfile( - os.path.join( - app_dir, "app/src/main/AndroidManifest.xml" - ) + os.path.join(app_dir, 'app/src/main/AndroidManifest.xml'), ) - src = os.path.exists(os.path.join(app_dir, "app/src/main/java/")) + src = os.path.exists(os.path.join(app_dir, 'app/src/main/java/')) if man and src: return 'studio', True # iOS Source - xcode = [f for f in os.listdir(app_dir) if f.endswith(".xcodeproj")] + xcode = [f for f in os.listdir(app_dir) if f.endswith('.xcodeproj')] if xcode: return 'ios', True return '', False - except: - PrintException("Determining Upload type") + except Exception: + log_exception('Determining Upload type') def gen_downloads(app_dir, md5, icon_path=''): """Generate downloads for java and smali.""" try: - logger.info("Generating Downloads") + logger.info('Generating Downloads') # For Java directory = os.path.join(app_dir, 'java_source/') dwd_dir = os.path.join(settings.DWD_DIR, md5 + '-java.zip') @@ -523,5 +508,5 @@ def gen_downloads(app_dir, md5, icon_path=''): shutil.copy2(icon_path, os.path.join( settings.DWD_DIR, md5 + '-icon.png')) - except: - PrintException("Generating Downloads") + except Exception: + log_exception('Generating Downloads') diff --git a/StaticAnalyzer/views/android/strings.py b/StaticAnalyzer/views/android/strings.py index ce2d72c0..d5c6f9e9 100755 --- a/StaticAnalyzer/views/android/strings.py +++ b/StaticAnalyzer/views/android/strings.py @@ -1,20 +1,13 @@ # -*- coding: utf_8 -*- """Module for strings-method for java.""" - -import io -import os import logging -import subprocess +import os + from androguard.core.bytecodes import apk -from django.conf import settings +from MobSF.utils import log_exception -from MobSF.utils import ( - PrintException -) -from StaticAnalyzer.views.shared_func import ( - url_n_email_extract, -) +from StaticAnalyzer.views.shared_func import url_n_email_extract logger = logging.getLogger(__name__) @@ -22,7 +15,7 @@ logger = logging.getLogger(__name__) def strings_jar(app_file, app_dir): """Extract the strings from an app.""" try: - logger.info("Extracting Strings from APK") + logger.info('Extracting Strings from APK') dat = [] apk_file = os.path.join(app_dir, app_file) and_a = apk.APK(apk_file) @@ -34,14 +27,14 @@ def strings_jar(app_file, app_dir): if res_string: for duo in res_string: dat.append('"' + duo[0] + '" : "' + duo[1] + '"') - data_string = "".join(dat) + data_string = ''.join(dat) urls, urls_nf, emails_nf = url_n_email_extract( - data_string, "Android String Resource") - return {"strings": dat, - "urls_list": urls, - "url_nf": urls_nf, - "emails_nf": emails_nf, + data_string, 'Android String Resource') + return {'strings': dat, + 'urls_list': urls, + 'url_nf': urls_nf, + 'emails_nf': emails_nf, } - except: - PrintException("Extracting Strings from APK") + except Exception: + log_exception('Extracting Strings from APK') return {} diff --git a/StaticAnalyzer/views/android/view_source.py b/StaticAnalyzer/views/android/view_source.py index f7b928c1..41aae990 100644 --- a/StaticAnalyzer/views/android/view_source.py +++ b/StaticAnalyzer/views/android/view_source.py @@ -2,34 +2,27 @@ """View Source of a file.""" import io -import ntpath -import re -import os import logging -from django.shortcuts import render -from django.http import HttpResponseRedirect +import ntpath +import os + from django.conf import settings +from django.shortcuts import render from django.utils.html import escape -from StaticAnalyzer.forms import ( - ViewSourceAndroidApiForm, - ViewSourceAndroidForm -) +from MobSF.forms import FormUtil +from MobSF.utils import print_n_send_error_response -from MobSF.forms import ( - FormUtil -) +from StaticAnalyzer.forms import (ViewSourceAndroidApiForm, + ViewSourceAndroidForm) -from MobSF.utils import ( - print_n_send_error_response -) logger = logging.getLogger(__name__) def run(request, api=False): """View the source of a file.""" try: - logger.info("View Android Source File") + logger.info('View Android Source File') if api: fil = request.POST['file'] md5 = request.POST['hash'] @@ -47,9 +40,9 @@ def run(request, api=False): context = { 'title': 'Error', 'exp': 'Error Description', - 'doc': err + 'doc': err, } - template = "general/error.html" + template = 'general/error.html' return render(request, template, context, status=400) if fil.endswith('.java'): if typ == 'eclipse': @@ -64,28 +57,29 @@ def run(request, api=False): src = os.path.join(settings.UPLD_DIR, md5 + '/smali_source/') else: - msg = "Not Found" - doc = "File not Found!" + msg = 'Not Found' + doc = 'File not Found!' is_api = False if api: is_api = True return print_n_send_error_response(request, msg, is_api, doc) - # Unset SRC for any other case. Otherwise it will cause Directory Traversal + # Unset SRC for any other case. + # Otherwise it will cause Directory Traversal sfile = os.path.join(src, fil) dat = '' with io.open( sfile, mode='r', - encoding="utf8", - errors="ignore" + encoding='utf8', + errors='ignore', ) as file_pointer: dat = file_pointer.read() context = { 'title': escape(ntpath.basename(fil)), 'file': escape(ntpath.basename(fil)), - 'dat': dat + 'dat': dat, } - template = "static_analysis/view_source.html" + template = 'static_analysis/view_source.html' if api: return context return render(request, template, context) diff --git a/StaticAnalyzer/views/android/win_fixes.py b/StaticAnalyzer/views/android/win_fixes.py index 58e2ab17..390e468c 100755 --- a/StaticAnalyzer/views/android/win_fixes.py +++ b/StaticAnalyzer/views/android/win_fixes.py @@ -1,52 +1,53 @@ # -*- coding: utf_8 -*- """Holds the different winfixes.""" -import os import logging +import os + from django.conf import settings -from MobSF.utils import ( - PrintException -) +from MobSF.utils import log_exception + logger = logging.getLogger(__name__) def win_fix_java(tools_dir): - """Runn JAVA path fix in Windows""" + """Run JAVA path fix in Windows.""" try: - logger.info("Running JAVA path fix in Windows") + logger.info('Running JAVA path fix in Windows') dmy = os.path.join(tools_dir, 'd2j2/d2j_invoke.tmp') org = os.path.join(tools_dir, 'd2j2/d2j_invoke.bat') dat = '' with open(dmy, 'r') as file_pointer: - dat = file_pointer.read().replace("[xxx]", settings.JAVA_PATH + "java") + dat = file_pointer.read().replace( + '[xxx]', settings.JAVA_PATH + 'java') with open(org, 'w') as file_pointer: file_pointer.write(dat) - except: - PrintException("Running JAVA path fix in Windows") + except Exception: + log_exception('Running JAVA path fix in Windows') def win_fix_python3(tools_dir): - """Runn Python 3 path fix in Windows.""" + """Run Python 3 path fix in Windows.""" try: - logger.info("Running Python 3 path fix in Windows") - python3_path = "" + logger.info('Running Python 3 path fix in Windows') + python3_path = '' if len(settings.PYTHON3_PATH) > 2: python3_path = settings.python3_path else: - pathenv = os.environ["path"] + pathenv = os.environ['path'] if pathenv: - paths = pathenv.split(";") + paths = pathenv.split(';') for path in paths: - if "python3" in path.lower(): + if 'python3' in path.lower(): python3_path = path - python3 = "\"" + os.path.join(python3_path, "python") + "\"" + python3 = '"' + os.path.join(python3_path, 'python') + '"' dmy = os.path.join(tools_dir, 'enjarify/enjarify.tmp') org = os.path.join(tools_dir, 'enjarify/enjarify.bat') dat = '' with open(dmy, 'r') as file_pointer: - dat = file_pointer.read().replace("[xxx]", python3) + dat = file_pointer.read().replace('[xxx]', python3) with open(org, 'w') as file_pointer: file_pointer.write(dat) - except: - PrintException("Running Python 3 path fix in Windows") + except Exception: + log_exception('Running Python 3 path fix in Windows') diff --git a/StaticAnalyzer/views/comparer.py b/StaticAnalyzer/views/comparer.py index 4aeed098..2addb245 100644 --- a/StaticAnalyzer/views/comparer.py +++ b/StaticAnalyzer/views/comparer.py @@ -1,22 +1,20 @@ # -*- coding: utf_8 -*- """ -Module providing the shared functions for static analysis of iOS and Android +Compare Apps. + +Module for comparing app results. """ import re -from copy import deepcopy from collections import defaultdict +from copy import deepcopy from django.shortcuts import render -from MobSF.utils import ( - print_n_send_error_response -) +from MobSF.utils import print_n_send_error_response from StaticAnalyzer.models import StaticAnalyzerAndroid - from StaticAnalyzer.views.android.db_interaction import ( - get_context_from_db_entry -) + get_context_from_db_entry) # The APKiD is pain because it really differs from the others @@ -25,22 +23,25 @@ def diff_apkid(context: dict) -> None: 'packer', 'dropper', 'manipulator', 'anti_disassembly', 'anti_debug', 'abnormal'] - context['apkid'] = dict() - context['apkid']['common'] = dict() - context['apkid']['only_first'] = dict() - context['apkid']['only_second'] = dict() + context['apkid'] = {} + context['apkid']['common'] = {} + context['apkid']['only_first'] = {} + context['apkid']['only_second'] = {} - first_apkid, second_apkid = context['first_app']['apkid'], context['second_app']['apkid'] - first_error, second_error = first_apkid.get('error', False), second_apkid.get('error', False) + first_apkid, second_apkid = (context['first_app']['apkid'], + context['second_app']['apkid']) + first_error, second_error = first_apkid.get( + 'error', False), second_apkid.get('error', False) context['apkid_error'] = (first_error or second_error) if context['apkid_error']: return - tmp_flat_results = dict() + tmp_flat_results = {} for curr_app_str in ['first_app', 'second_app']: # Flatten the results per app (join all the dex files result into one) flat_results = defaultdict(list) - for results in [dex_results for (dex_name, dex_results) in context[curr_app_str]['apkid'].items()]: + for results in [dex_results for (dex_name, dex_results) in + context[curr_app_str]['apkid'].items()]: for apkid_key, key_results in results.items(): flat_results[apkid_key] += key_results # Distinct list @@ -49,31 +50,41 @@ def diff_apkid(context: dict) -> None: for key in apkid_keys: # The keys may be different between the two lists - context['apkid']['common'][key] = [x for x in tmp_flat_results['first_app'][key] if x in - tmp_flat_results['second_app'][key]] + context['apkid']['common'][key] = [ + x for x in tmp_flat_results['first_app'][key] if x in + tmp_flat_results['second_app'][key]] - context['apkid']['only_first'][key] = [x for x in tmp_flat_results['first_app'][key] if x not in - tmp_flat_results['second_app'][key]] + context['apkid']['only_first'][key] = [ + x for x in tmp_flat_results['first_app'][key] if x not in + tmp_flat_results['second_app'][key]] - context['apkid']['only_second'][key] = [x for x in tmp_flat_results['second_app'][key] if x not in - tmp_flat_results['first_app'][key]] + context['apkid']['only_second'][key] = [ + x for x in tmp_flat_results['second_app'][key] if x not in + tmp_flat_results['first_app'][key]] -# suppose to get any 2 apps (android / ios / appx) and then figure out what to do with them -def generic_compare(request, first_hash: str, second_hash: str, api: bool = False): - # This context consists of specific lists and analysis that is done on the classic ones +# suppose to get any 2 apps (android / ios / appx) +# and then figure out what to do with them +def generic_compare(request, + first_hash: str, + second_hash: str, + api: bool = False): + # This context consists of specific lists and analysis + # that is done on the classic ones # it will be filled during the different diff analysis context = { 'title': 'Compare report', - 'first_app': dict(), - 'second_app': dict(), - 'urls': dict(), - 'api': dict(), - 'permissions': dict(), - 'apkid': dict() + 'first_app': {}, + 'second_app': {}, + 'urls': {}, + 'api': {}, + 'permissions': {}, + 'apkid': {}, } - static_fields = ['md5', 'name', 'size', 'icon_found', 'icon_hidden', 'act_count', 'e_act', 'serv_count', 'e_ser', - 'bro_count', 'e_bro', 'prov_count', 'e_cnt', 'apkid'] + static_fields = ['md5', 'name', 'size', 'icon_found', + 'icon_hidden', 'act_count', 'e_act', 'serv_count', + 'e_ser', 'bro_count', 'e_bro', 'prov_count', + 'e_cnt', 'apkid'] # For now - support only android db_entry = StaticAnalyzerAndroid.objects.filter(MD5=first_hash) @@ -81,21 +92,28 @@ def generic_compare(request, first_hash: str, second_hash: str, api: bool = Fals if not (db_entry.exists() and db_entry2.exists()): return print_n_send_error_response(request, - "One of the Hashes wasn't found in the Android-results DB, make sure " - "both of the apps finished analysis & they are both Android", False) + 'One of the Hashes wasn\'t found ' + 'in the Android - results DB, make ' + 'sure both of the apps finished ' + 'analysis & they are both Android', + False) # First fetch the already done analysis on each of the apps - # We don't want to return this whole context back to the user because its a lot of data we don't use + # We don't want to return this whole context back to the user + # because its a lot of data we don't use # it should help the performance I guess first_app = deepcopy(get_context_from_db_entry(db_entry)) second_app = deepcopy(get_context_from_db_entry(db_entry2)) - # Second, fill the common static parts that are missing in the classic analysis - for curr_app, db_context in [('first_app', first_app), ('second_app', second_app)]: + # Second, fill the common static parts that + # are missing in the classic analysis + for curr_app, db_context in [('first_app', first_app), + ('second_app', second_app)]: # format informative title - context[curr_app]['name_ver'] = "{0} - {1}".format(db_context['packagename'], - db_context['androvername']) + context[curr_app]['name_ver'] = '{0} - {1}'.format( + db_context['packagename'], + db_context['androvername']) # Fill all the static information for static_attr in static_fields: @@ -107,14 +125,15 @@ def generic_compare(request, first_hash: str, second_hash: str, api: bool = Fals if match: context[curr_app]['cert_subject'] = match.group(1) else: - context[curr_app]['cert_subject'] = "No subject" + context[curr_app]['cert_subject'] = 'No subject' # Some preparations so we have some sort of same structures # (urls are lists inside the list which mess things up...) - tmp_list = list() + tmp_list = [] for url_obj in db_context['urls']: for url in url_obj['urls']: - # urls can mess up the table because they can be really long, so let's cut them + # urls can mess up the table because they can be really long, + # so let's cut them tmp_url = url[:70] while len(url) > 70: url = url[70:] @@ -125,38 +144,46 @@ def generic_compare(request, first_hash: str, second_hash: str, api: bool = Fals db_context['urls'] = list(set(deepcopy(tmp_list))) tmp_list.clear() - # apkid check - we do it here just because its really ugly inside the template - # it has a dedicated function because the result is more complicated then the others... + # apkid check - we do it here just because + # its really ugly inside the template + # it has a dedicated function because the result + # is more complicated then the others... diff_apkid(context) # Third, calculate some diffs for section, is_tuples in [ ('permissions', True), ('api', True), - ('urls', False) + ('urls', False), ]: if is_tuples: - context[section]['common'] = [(x, y) for (x, y) in first_app[section].items() if x in - second_app[section].keys()] + context[section]['common'] = [ + (x, y) for (x, y) in first_app[section].items() if x in + second_app[section].keys()] # Only first - context[section]['only_first'] = [(x, y) for (x, y) in first_app[section].items() if x not in - second_app[section].keys()] + context[section]['only_first'] = [ + (x, y) for (x, y) in first_app[section].items() if x not in + second_app[section].keys()] # Only Second - context[section]['only_second'] = [(x, y) for (x, y) in second_app[section].items() if x not in - first_app[section].keys()] + context[section]['only_second'] = [ + (x, y) for (x, y) in second_app[section].items() if x not in + first_app[section].keys()] else: - context[section]['common'] = [x for x in first_app[section] if x in - second_app[section]] + context[section]['common'] = [ + x for x in first_app[section] if x in + second_app[section]] - context[section]['only_first'] = [x for x in first_app[section] if x not in - second_app[section]] + context[section]['only_first'] = [ + x for x in first_app[section] if x not in + second_app[section]] - context[section]['only_second'] = [x for x in second_app[section] if x not in - first_app[section]] + context[section]['only_second'] = [ + x for x in second_app[section] if x not in + first_app[section]] - template = "static_analysis/compare.html" + template = 'static_analysis/compare.html' if api: return context else: diff --git a/StaticAnalyzer/views/ios/appstore.py b/StaticAnalyzer/views/ios/appstore.py index 1fb8205d..36ad3d0f 100644 --- a/StaticAnalyzer/views/ios/appstore.py +++ b/StaticAnalyzer/views/ios/appstore.py @@ -1,23 +1,23 @@ # -*- coding: utf_8 -*- -import requests - import logging -from MobSF.utils import ( - upstream_proxy, -) +import requests + +from MobSF.utils import upstream_proxy logger = logging.getLogger(__name__) def app_search(app_id): - '''iOS Get App Details from App Store''' - logger.info("Fetching Details from App Store: %s", app_id) + """IOS Get App Details from App Store.""" + logger.info('Fetching Details from App Store: %s', app_id) lookup_url = 'https://itunes.apple.com/lookup' req_url = '{}?bundleId={}&country={}&entity=software'.format( lookup_url, app_id, 'us') headers = { - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'} + 'User-Agent': ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) ' + 'AppleWebKit/537.36 (KHTML, like Gecko) ' + 'Chrome/39.0.2171.95 Safari/537.36')} try: det = {} proxies, verify = upstream_proxy('https') @@ -28,7 +28,9 @@ def app_search(app_id): det = resp['results'][0] return { 'features': det['features'] or [], - 'icon': det['artworkUrl512'] or det['artworkUrl100'] or det['artworkUrl60'] or '', + 'icon': (det['artworkUrl512'] + or det['artworkUrl100'] + or det['artworkUrl60'] or ''), 'developer_id': det['artistId'], 'developer': det['artistName'], 'developer_url': det['artistViewUrl'], @@ -45,6 +47,6 @@ def app_search(app_id): } logger.warning('Unable to get app details.') return {'error': True} - except Exception as exp: - logger.warning('Unable to get app details. %s', exp) + except Exception: + logger.warning('Unable to get app details') return {'error': True} diff --git a/StaticAnalyzer/views/ios/binary_analysis.py b/StaticAnalyzer/views/ios/binary_analysis.py index 788f1e46..3d02b270 100755 --- a/StaticAnalyzer/views/ios/binary_analysis.py +++ b/StaticAnalyzer/views/ios/binary_analysis.py @@ -1,22 +1,24 @@ # -*- coding: utf_8 -*- -'''Module for iOS IPA Binary Analysis.''' +"""Module for iOS IPA Binary Analysis.""" -import re +import logging import os import platform +import re import subprocess from django.conf import settings -from django.utils.html import escape from django.utils.encoding import smart_text +from django.utils.html import escape +from macholib.mach_o import (CPU_TYPE_NAMES, MH_CIGAM_64, MH_MAGIC_64, + get_cpu_subtype) from macholib.MachO import MachO -from macholib.mach_o import get_cpu_subtype, CPU_TYPE_NAMES -from macholib.mach_o import MH_CIGAM_64, MH_MAGIC_64 + +from MobSF.utils import is_file_exists, log_exception from StaticAnalyzer.tools.strings import strings_util -from MobSF.utils import PrintException, isFileExists -import logging + logger = logging.getLogger(__name__) SECURE = 'Secure' IN_SECURE = 'Insecure' @@ -25,12 +27,14 @@ WARNING = 'Warning' def get_otool_out(tools_dir, cmd_type, bin_path, bin_dir): - '''Get otool args by OS and type''' - if len(settings.OTOOL_BINARY) > 0 and isFileExists(settings.OTOOL_BINARY): + """Get otool args by OS and type.""" + if (len(settings.OTOOL_BINARY) > 0 + and is_file_exists(settings.OTOOL_BINARY)): otool_bin = settings.OTOOL_BINARY else: otool_bin = 'otool' - if len(settings.JTOOL_BINARY) > 0 and isFileExists(settings.JTOOL_BINARY): + if (len(settings.JTOOL_BINARY) > 0 + and is_file_exists(settings.JTOOL_BINARY)): jtool_bin = settings.JTOOL_BINARY else: jtool_bin = os.path.join(tools_dir, 'jtool.ELF64') @@ -62,20 +66,21 @@ def get_otool_out(tools_dir, cmd_type, bin_path, bin_dir): elif plat == 'Linux': arg1 = [jtool_bin, '-arch', 'arm', '-bind', '-v', bin_path] arg2 = [jtool_bin, '-arch', 'arm', '-lazy_bind', '-v', bin_path] - return subprocess.check_output(arg1) + subprocess.check_output(arg2) + return (subprocess.check_output(arg1) + + subprocess.check_output(arg2)) else: # Platform Not Supported return None def otool_analysis(tools_dir, bin_name, bin_path, bin_dir): - '''OTOOL Analysis of Binary''' + """OTOOL Analysis of Binary.""" try: otool_dict = { 'libs': [], - 'anal': [] + 'anal': [], } - logger.info('Running Object Analysis of Binary : ' + bin_name) + logger.info('Running Object Analysis of Binary : %s', bin_name) otool_dict['libs'] = get_otool_out( tools_dir, 'libs', bin_path, bin_dir) # PIE @@ -84,9 +89,11 @@ def otool_analysis(tools_dir, bin_name, bin_path, bin_dir): pie_flag = { 'issue': 'fPIE -pie flag is Found', 'status': SECURE, - 'description': '''App is compiled with Position Independent Executable (PIE) flag. - This enables Address Space Layout Randomization (ASLR), a memory protection - mechanism for exploit mitigation.''', + 'description': ('App is compiled with Position Independent ' + 'Executable (PIE) flag. This enables Address' + ' Space Layout Randomization (ASLR), a memory' + ' protection mechanism for' + ' exploit mitigation.'), 'cvss': 0, 'cwe': '', } @@ -94,218 +101,274 @@ def otool_analysis(tools_dir, bin_name, bin_path, bin_dir): pie_flag = { 'issue': 'fPIE -pie flag is not Found', 'status': IN_SECURE, - 'description': '''with Position Independent Executable (PIE) flag. So Address Space Layout - Randomization (ASLR) is missing. ASLR is a memory protection mechanism for exploit mitigation.''', + 'description': ('with Position Independent Executable (PIE) ' + 'flag. So Address Space Layout Randomization ' + '(ASLR) is missing. ASLR is a memory ' + 'protection mechanism for ' + 'exploit mitigation.'), 'cvss': 2, 'cwe': 'CWE-119', } # Stack Smashing Protection & ARC dat = get_otool_out(tools_dir, 'symbols', bin_path, bin_dir) if b'stack_chk_guard' in dat: - ssmash = {'issue': 'fstack-protector-all flag is Found', - 'status': SECURE, - 'description': '''App is compiled with Stack Smashing Protector (SSP) flag and is having protection against Stack - Overflows/Stack Smashing Attacks.''', - 'cvss': 0, - 'cwe': '', - } + ssmash = { + 'issue': 'fstack-protector-all flag is Found', + 'status': SECURE, + 'description': ('App is compiled with Stack Smashing Protector' + ' (SSP) flag and is having protection against' + ' Stack Overflows/Stack Smashing Attacks.'), + 'cvss': 0, + 'cwe': ''} else: - ssmash = {'issue': 'fstack-protector-all flag is not Found', - 'status': IN_SECURE, - 'description': '''App is not compiled with Stack Smashing Protector (SSP) flag. It is vulnerable to - Stack Overflows/Stack Smashing Attacks.''', - 'cvss': 2, - 'cwe': 'CWE-119', - } + ssmash = { + 'issue': 'fstack-protector-all flag is not Found', + 'status': IN_SECURE, + 'description': ('App is not compiled with Stack Smashing ' + 'Protector (SSP) flag. It is vulnerable to' + 'Stack Overflows/Stack Smashing Attacks.'), + 'cvss': 2, + 'cwe': 'CWE-119'} + # ARC if b'_objc_release' in dat: - arc_flag = {'issue': 'fobjc-arc flag is Found', - 'status': SECURE, - 'description': '''App is compiled with Automatic Reference Counting (ARC) flag. ARC is a compiler feature - that provides automatic memory management of Objective-C objects and is an - exploit mitigation mechanism against memory corruption vulnerabilities.''', - 'cvss': 0, - 'cwe': '', - } + arc_flag = { + 'issue': 'fobjc-arc flag is Found', + 'status': SECURE, + 'description': ('App is compiled with Automatic Reference ' + 'Counting (ARC) flag. ARC is a compiler ' + 'feature that provides automatic memory ' + 'management of Objective-C objects and is an ' + 'exploit mitigation mechanism against memory ' + 'corruption vulnerabilities.'), + 'cvss': 0, + 'cwe': ''} else: - arc_flag = {'issue': 'fobjc-arc flag is not Found', - 'status': IN_SECURE, - 'description': '''App is not compiled with Automatic Reference Counting (ARC) flag. ARC is a compiler feature that - provides automatic memory management of Objective-C objects and protects from - memory corruption vulnerabilities.''', - 'cvss': 2, - 'cwe': 'CWE-119', - } + arc_flag = { + 'issue': 'fobjc-arc flag is not Found', + 'status': IN_SECURE, + 'description': ('App is not compiled with Automatic Reference ' + 'Counting (ARC) flag. ARC is a compiler ' + 'feature that provides automatic memory ' + 'management of Objective-C objects and ' + 'protects from memory corruption ' + 'vulnerabilities.'), + 'cvss': 2, + 'cwe': 'CWE-119'} banned_apis = {} baned = re.findall( - b'_alloca|_gets|_memcpy|_printf|_scanf|_sprintf|_sscanf|_strcat|StrCat|_strcpy|' + - b'StrCpy|_strlen|StrLen|_strncat|StrNCat|_strncpy|StrNCpy|_strtok|_swprintf|_vsnprintf|' + - b'_vsprintf|_vswprintf|_wcscat|_wcscpy|_wcslen|_wcsncat|_wcsncpy|_wcstok|_wmemcpy|' + + b'_alloca|_gets|_memcpy|_printf|_scanf|_sprintf|_sscanf|_strcat|' + b'StrCat|_strcpy|StrCpy|_strlen|StrLen|_strncat|StrNCat|_strncpy|' + b'StrNCpy|_strtok|_swprintf|_vsnprintf|_vsprintf|_vswprintf|' + b'_wcscat|_wcscpy|_wcslen|_wcsncat|_wcsncpy|_wcstok|_wmemcpy|' b'_fopen|_chmod|_chown|_stat|_mktemp', dat) baned = list(set(baned)) baned_s = b', '.join(baned) if len(baned_s) > 1: - banned_apis = {'issue': 'Binary make use of banned API(s)', - 'status': IN_SECURE, - 'description': 'The binary may contain the following banned API(s) ' + baned_s.decode('utf-8', 'ignore') + '.', - 'cvss': 6, - 'cwe': 'CWE-676', - } + banned_apis = { + 'issue': 'Binary make use of banned API(s)', + 'status': IN_SECURE, + 'description': ('The binary may contain' + ' the following banned API(s) {}.').format( + baned_s.decode('utf-8', 'ignore')), + 'cvss': 6, + 'cwe': 'CWE-676'} + weak_cryptos = {} weak_algo = re.findall( - b'kCCAlgorithmDES|kCCAlgorithm3DES||kCCAlgorithmRC2|kCCAlgorithmRC4|' + - b'kCCOptionECBMode|kCCOptionCBCMode', dat) + b'kCCAlgorithmDES|kCCAlgorithm3DES||kCCAlgorithmRC2|' + b'kCCAlgorithmRC4|kCCOptionECBMode|kCCOptionCBCMode', dat) weak_algo = list(set(weak_algo)) weak_algo_s = b', '.join(weak_algo) if len(weak_algo_s) > 1: - weak_cryptos = {'issue': 'Binary make use of some Weak Crypto API(s)', - 'status': IN_SECURE, - 'description': 'The binary may use the following weak crypto API(s) ' + weak_algo_s.decode('utf-8', 'ignore') + '.', - 'cvss': 3, - 'cwe': 'CWE-327', - } + weak_cryptos = { + 'issue': 'Binary make use of some Weak Crypto API(s)', + 'status': IN_SECURE, + 'description': ('The binary may use the' + ' following weak crypto API(s) {}.').formnat( + weak_algo_s.decode('utf-8', 'ignore')), + 'cvss': 3, + 'cwe': 'CWE-327'} + crypto = {} crypto_algo = re.findall( - b'CCKeyDerivationPBKDF|CCCryptorCreate|CCCryptorCreateFromData|' + - b'CCCryptorRelease|CCCryptorUpdate|CCCryptorFinal|CCCryptorGetOutputLength|' + - b'CCCryptorReset|CCCryptorRef|kCCEncrypt|kCCDecrypt|kCCAlgorithmAES128|' + - b'kCCKeySizeAES128|kCCKeySizeAES192|kCCKeySizeAES256|kCCAlgorithmCAST|' + - b'SecCertificateGetTypeID|SecIdentityGetTypeID|SecKeyGetTypeID|SecPolicyGetTypeID|' + - b'SecTrustGetTypeID|SecCertificateCreateWithData|SecCertificateCreateFromData|' + - b'SecCertificateCopyData|SecCertificateAddToKeychain|SecCertificateGetData|' + - b'SecCertificateCopySubjectSummary|SecIdentityCopyCertificate|' + - b'SecIdentityCopyPrivateKey|SecPKCS12Import|SecKeyGeneratePair|SecKeyEncrypt|' + - b'SecKeyDecrypt|SecKeyRawSign|SecKeyRawVerify|SecKeyGetBlockSize|' + - b'SecPolicyCopyProperties|SecPolicyCreateBasicX509|SecPolicyCreateSSL|' + - b'SecTrustCopyCustomAnchorCertificates|SecTrustCopyExceptions|' + - b'SecTrustCopyProperties|SecTrustCopyPolicies|SecTrustCopyPublicKey|' + - b'SecTrustCreateWithCertificates|SecTrustEvaluate|SecTrustEvaluateAsync|' + - b'SecTrustGetCertificateCount|SecTrustGetCertificateAtIndex|SecTrustGetTrustResult|' + - b'SecTrustGetVerifyTime|SecTrustSetAnchorCertificates|' + - b'SecTrustSetAnchorCertificatesOnly|SecTrustSetExceptions|SecTrustSetPolicies|' + - b'SecTrustSetVerifyDate|SecCertificateRef|' + + b'CCKeyDerivationPBKDF|CCCryptorCreate|CCCryptorCreateFromData|' + b'CCCryptorRelease|CCCryptorUpdate|CCCryptorFinal|' + b'CCCryptorGetOutputLength|CCCryptorReset|CCCryptorRef|kCCEncrypt|' + b'kCCDecrypt|kCCAlgorithmAES128|kCCKeySizeAES128|kCCKeySizeAES192|' + b'kCCKeySizeAES256|kCCAlgorithmCAST|SecCertificateGetTypeID|' + b'SecIdentityGetTypeID|SecKeyGetTypeID|SecPolicyGetTypeID|' + b'SecTrustGetTypeID|SecCertificateCreateWithData|' + b'SecCertificateCreateFromData|SecCertificateCopyData|' + b'SecCertificateAddToKeychain|SecCertificateGetData|' + b'SecCertificateCopySubjectSummary|SecIdentityCopyCertificate|' + b'SecIdentityCopyPrivateKey|SecPKCS12Import|SecKeyGeneratePair|' + b'SecKeyEncrypt|SecKeyDecrypt|SecKeyRawSign|SecKeyRawVerify|' + b'SecKeyGetBlockSize|SecPolicyCopyProperties|' + b'SecPolicyCreateBasicX509|SecPolicyCreateSSL|' + b'SecTrustCopyCustomAnchorCertificates|SecTrustCopyExceptions|' + b'SecTrustCopyProperties|SecTrustCopyPolicies|' + b'SecTrustCopyPublicKey|SecTrustCreateWithCertificates|' + b'SecTrustEvaluate|SecTrustEvaluateAsync|' + b'SecTrustGetCertificateCount|SecTrustGetCertificateAtIndex|' + b'SecTrustGetTrustResult|SecTrustGetVerifyTime|' + b'SecTrustSetAnchorCertificates|SecTrustSetAnchorCertificatesOnly|' + b'SecTrustSetExceptions|SecTrustSetPolicies|' + b'SecTrustSetVerifyDate|SecCertificateRef|' b'SecIdentityRef|SecKeyRef|SecPolicyRef|SecTrustRef', dat) crypto_algo = list(set(crypto_algo)) crypto_algo_s = b', '.join(crypto_algo) if len(crypto_algo_s) > 1: - crypto = {'issue': 'Binary make use of the following Crypto API(s)', - 'status': 'Info', - 'description': 'The binary may use the following crypto API(s) ' + crypto_algo_s.decode('utf-8', 'ignore') + '.', - 'cvss': 0, - 'cwe': '', - } + crypto = { + 'issue': 'Binary make use of the following Crypto API(s)', + 'status': 'Info', + 'description': ('The binary may use ' + 'the following crypto API(s) {}.').format( + crypto_algo_s.decode('utf-8', 'ignore')), + 'cvss': 0, + 'cwe': ''} + weak_hashes = {} weak_hash_algo = re.findall( - b'CC_MD2_Init|CC_MD2_Update|CC_MD2_Final|CC_MD2|MD2_Init|' + - b'MD2_Update|MD2_Final|CC_MD4_Init|CC_MD4_Update|CC_MD4_Final|CC_MD4|MD4_Init|' + - b'MD4_Update|MD4_Final|CC_MD5_Init|CC_MD5_Update|CC_MD5_Final|CC_MD5|MD5_Init|' + - b'MD5_Update|MD5_Final|MD5Init|MD5Update|MD5Final|CC_SHA1_Init|CC_SHA1_Update|' + + b'CC_MD2_Init|CC_MD2_Update|CC_MD2_Final|CC_MD2|MD2_Init|' + b'MD2_Update|MD2_Final|CC_MD4_Init|CC_MD4_Update|CC_MD4_Final|' + b'CC_MD4|MD4_Init|MD4_Update|MD4_Final|CC_MD5_Init|CC_MD5_Update' + b'|CC_MD5_Final|CC_MD5|MD5_Init|MD5_Update|MD5_Final|MD5Init|' + b'MD5Update|MD5Final|CC_SHA1_Init|CC_SHA1_Update|' b'CC_SHA1_Final|CC_SHA1|SHA1_Init|SHA1_Update|SHA1_Final', dat) weak_hash_algo = list(set(weak_hash_algo)) weak_hash_algo_s = b', '.join(weak_hash_algo) if len(weak_hash_algo_s) > 1: - weak_hashes = {'issue': 'Binary make use of the following Weak HASH API(s)', - 'status': IN_SECURE, - 'description': 'The binary may use the following weak hash API(s) ' + weak_hash_algo_s.decode('utf-8', 'ignore') + '.', - 'cvss': 3, - 'cwe': 'CWE-327', - } + weak_hashes = { + 'issue': 'Binary make use of the following Weak HASH API(s)', + 'status': IN_SECURE, + 'description': ( + 'The binary may use the ' + 'following weak hash API(s) {}.').format( + weak_hash_algo_s.decode('utf-8', 'ignore')), + 'cvss': 3, + 'cwe': 'CWE-327'} + hashes = {} hash_algo = re.findall( - b'CC_SHA224_Init|CC_SHA224_Update|CC_SHA224_Final|CC_SHA224|' + - b'SHA224_Init|SHA224_Update|SHA224_Final|CC_SHA256_Init|CC_SHA256_Update|' + - b'CC_SHA256_Final|CC_SHA256|SHA256_Init|SHA256_Update|SHA256_Final|' + - b'CC_SHA384_Init|CC_SHA384_Update|CC_SHA384_Final|CC_SHA384|SHA384_Init|' + - b'SHA384_Update|SHA384_Final|CC_SHA512_Init|CC_SHA512_Update|CC_SHA512_Final|' + + b'CC_SHA224_Init|CC_SHA224_Update|CC_SHA224_Final|CC_SHA224|' + b'SHA224_Init|SHA224_Update|SHA224_Final|CC_SHA256_Init|' + b'CC_SHA256_Update|CC_SHA256_Final|CC_SHA256|SHA256_Init|' + b'SHA256_Update|SHA256_Final|CC_SHA384_Init|CC_SHA384_Update|' + b'CC_SHA384_Final|CC_SHA384|SHA384_Init|SHA384_Update|' + b'SHA384_Final|CC_SHA512_Init|CC_SHA512_Update|CC_SHA512_Final|' b'CC_SHA512|SHA512_Init|SHA512_Update|SHA512_Final', dat) hash_algo = list(set(hash_algo)) hash_algo_s = b', '.join(hash_algo) if len(hash_algo_s) > 1: - hashes = {'issue': 'Binary make use of the following HASH API(s)', - 'status': INFO, - 'description': 'The binary may use the following hash API(s) ' + hash_algo_s.decode('utf-8', 'ignore') + '.', - 'cvss': 0, - 'cwe': '', - } + hashes = { + 'issue': 'Binary make use of the following HASH API(s)', + 'status': INFO, + 'description': ('The binary may use the' + ' following hash API(s) {}.').format( + hash_algo_s.decode('utf-8', 'ignore')), + 'cvss': 0, + 'cwe': ''} + randoms = {} rand_algo = re.findall(b'_srand|_random', dat) rand_algo = list(set(rand_algo)) rand_algo_s = b', '.join(rand_algo) if len(rand_algo_s) > 1: - randoms = {'issue': 'Binary make use of the insecure Random Function(s)', - 'status': IN_SECURE, - 'description': 'The binary may use the following insecure Random Function(s) ' + rand_algo_s.decode('utf-8', 'ignore') + '.', - 'cvss': 3, - 'cwe': 'CWE-338', - } + randoms = { + 'issue': 'Binary make use of the insecure Random Function(s)', + 'status': IN_SECURE, + 'description': ('The binary may use the following ' + 'insecure Random Function(s) {}.').format( + rand_algo_s.decode('utf-8', 'ignore')), + 'cvss': 3, + 'cwe': 'CWE-338'} + logging = {} log = re.findall(b'_NSLog', dat) log = list(set(log)) log_s = b', '.join(log) if len(log_s) > 1: - logging = {'issue': 'Binary make use of Logging Function', - 'status': INFO, - 'description': 'The binary may use NSLog function for logging.', - 'cvss': 7.5, - 'cwe': 'CWE-532', - } - malloc = {} + logging = { + 'issue': 'Binary make use of Logging Function', + 'status': INFO, + 'description': ('The binary may use NSLog' + ' function for logging.'), + 'cvss': 7.5, + 'cwe': 'CWE-532'} + malloc = {} mal = re.findall(b'_malloc', dat) mal = list(set(mal)) mal_s = b', '.join(mal) if len(mal_s) > 1: - malloc = {'issue': 'Binary make use of malloc Function', - 'status': IN_SECURE, - 'description': 'The binary may use malloc function instead of calloc.', - 'cvss': 2, - 'cwe': 'CWE-789', - } - debug = {} + malloc = { + 'issue': 'Binary make use of malloc Function', + 'status': IN_SECURE, + 'description': ('The binary may use malloc' + ' function instead of calloc.'), + 'cvss': 2, + 'cwe': 'CWE-789'} + debug = {} ptrace = re.findall(b'_ptrace', dat) ptrace = list(set(ptrace)) ptrace_s = b', '.join(ptrace) if len(ptrace_s) > 1: - debug = {'issue': 'Binary calls ptrace Function for anti-debugging.', - 'status': WARNING, - 'description': '''The binary may use ptrace function. It can be used to detect and prevent debuggers. - Ptrace is not a public API and Apps that use non-public APIs will be rejected from AppStore. ''', - 'cvss': 0, - 'cwe': '', - } - otool_dict['anal'] = [pie_flag, ssmash, arc_flag, banned_apis, weak_cryptos, - crypto, weak_hashes, hashes, randoms, logging, malloc, debug] + debug = { + 'issue': 'Binary calls ptrace Function for anti-debugging.', + 'status': WARNING, + 'description': ('The binary may use ptrace function. It can be' + ' used to detect and prevent debuggers.' + 'Ptrace is not a public API and Apps that use' + ' non-public APIs will be rejected' + ' from AppStore.'), + 'cvss': 0, + 'cwe': ''} + otool_dict['anal'] = [pie_flag, + ssmash, + arc_flag, + banned_apis, + weak_cryptos, + crypto, + weak_hashes, + hashes, + randoms, + logging, + malloc, + debug] return otool_dict - except: - PrintException('Performing Object Analysis of Binary') + except Exception: + log_exception('Performing Object Analysis of Binary') def detect_bin_type(libs): - '''Detect IPA binary type''' - if any("libswiftCore.dylib" in itm for itm in libs): - return "Swift" + """Detect IPA binary type.""" + if any('libswiftCore.dylib' in itm for itm in libs): + return 'Swift' else: - return "Objective C" + return 'Objective C' def class_dump(tools_dir, bin_path, app_dir, bin_type): - '''Running Classdumpz on binary''' + """Running Classdumpz on binary.""" try: webview = {} if platform.system() == 'Darwin': logger.info('Dumping classes') - if bin_type == "Swift": - logger.info("Running class-dump-swift aganst binary") - if len(settings.CLASSDUMP_SWIFT_BINARY) > 0 and isFileExists(settings.CLASSDUMP_SWIFT_BINARY): + if bin_type == 'Swift': + logger.info('Running class-dump-swift aganst binary') + if (len(settings.CLASSDUMP_SWIFT_BINARY) > 0 + and is_file_exists(settings.CLASSDUMP_SWIFT_BINARY)): class_dump_bin = settings.CLASSDUMP_SWIFT_BINARY else: class_dump_bin = os.path.join( tools_dir, 'class-dump-swift') else: - logger.info("Running class-dump-z aganst binary") - if len(settings.CLASSDUMPZ_BINARY) > 0 and isFileExists(settings.CLASSDUMPZ_BINARY): + logger.info('Running class-dump-z aganst binary') + if (len(settings.CLASSDUMPZ_BINARY) > 0 + and is_file_exists(settings.CLASSDUMPZ_BINARY)): class_dump_bin = settings.CLASSDUMPZ_BINARY else: class_dump_bin = os.path.join(tools_dir, 'class-dump-z') @@ -313,7 +376,8 @@ def class_dump(tools_dir, bin_path, app_dir, bin_type): args = [class_dump_bin, bin_path] elif platform.system() == 'Linux': logger.info('Running jtool against the binary for dumping classes') - if len(settings.JTOOL_BINARY) > 0 and isFileExists(settings.JTOOL_BINARY): + if (len(settings.JTOOL_BINARY) > 0 + and is_file_exists(settings.JTOOL_BINARY)): jtool_bin = settings.JTOOL_BINARY else: jtool_bin = os.path.join(tools_dir, 'jtool.ELF64') @@ -325,7 +389,7 @@ def class_dump(tools_dir, bin_path, app_dir, bin_type): return {} with open(os.devnull, 'w') as devnull: classdump = subprocess.check_output(args, stderr=devnull) - if b"Source: (null)" in classdump and platform.system() == 'Darwin': + if b'Source: (null)' in classdump and platform.system() == 'Darwin': logger.info('Running fail safe class-dump-swift') class_dump_bin = os.path.join( tools_dir, 'class-dump-swift') @@ -337,17 +401,17 @@ def class_dump(tools_dir, bin_path, app_dir, bin_type): if b'UIWebView' in classdump: webview = {'issue': 'Binary uses WebView Component.', 'status': INFO, - 'description': 'The binary may use WebView Component.', + 'description': 'The binary may use WebView Component.', 'cvss': 0, 'cwe': '', } return webview - except: + except Exception: logger.error('class-dump-z/class-dump-swift failed on this binary') def strings_on_ipa(bin_path): - '''Extract Strings from IPA''' + """Extract Strings from IPA.""" try: logger.info('Running strings against the Binary') unique_str = [] @@ -355,12 +419,12 @@ def strings_on_ipa(bin_path): unique_str = [escape(ip_str) for ip_str in unique_str] # Escape evil strings return unique_str - except: - PrintException('Running strings against the Binary') + except Exception: + log_exception('Running strings against the Binary') def get_bin_info(bin_file): - '''Get Binary Information''' + """Get Binary Information.""" logger.info('Getting Binary Information') m = MachO(bin_file) for header in m.headers: @@ -379,7 +443,7 @@ def get_bin_info(bin_file): def binary_analysis(src, tools_dir, app_dir, executable_name): - '''Binary Analysis of IPA''' + """Binary Analysis of IPA.""" try: binary_analysis_dict = {} logger.info('Starting Binary Analysis') @@ -400,13 +464,13 @@ def binary_analysis(src, tools_dir, app_dir, executable_name): binary_analysis_dict['libs'] = [] binary_analysis_dict['bin_res'] = [] binary_analysis_dict['strings'] = [] - if not isFileExists(bin_path): - logger.warning('MobSF Cannot find binary in ' + bin_path) + if not is_file_exists(bin_path): + logger.warning('MobSF Cannot find binary in %s', bin_path) logger.warning('Skipping Otool, Classdump and Strings') else: bin_info = get_bin_info(bin_path) otool_dict = otool_analysis(tools_dir, bin_name, bin_path, bin_dir) - bin_type = detect_bin_type(otool_dict["libs"]) + bin_type = detect_bin_type(otool_dict['libs']) cls_dump = class_dump(tools_dir, bin_path, app_dir, bin_type) if not cls_dump: cls_dump = {} @@ -420,5 +484,5 @@ def binary_analysis(src, tools_dir, app_dir, executable_name): binary_analysis_dict['bin_type'] = bin_type return binary_analysis_dict - except: - PrintException('iOS Binary Analysis') + except Exception: + log_exception('iOS Binary Analysis') diff --git a/StaticAnalyzer/views/ios/code_analysis.py b/StaticAnalyzer/views/ios/code_analysis.py index f52cefdf..6abdd699 100755 --- a/StaticAnalyzer/views/ios/code_analysis.py +++ b/StaticAnalyzer/views/ios/code_analysis.py @@ -1,32 +1,28 @@ -import os import io +import logging +import os import shutil -from StaticAnalyzer.views.shared_func import ( - url_n_email_extract, - api_rule_matcher, - code_rule_matcher, -) -from StaticAnalyzer.views.ios import ( - ios_rules, - ios_apis -) from MalwareAnalyzer.views.domain_check import malware_check -from MobSF.utils import ( - PrintException, -) -import logging + +from MobSF.utils import log_exception + +from StaticAnalyzer.views.ios import ios_apis, ios_rules +from StaticAnalyzer.views.shared_func import (api_rule_matcher, + code_rule_matcher, + url_n_email_extract) + logger = logging.getLogger(__name__) def ios_source_analysis(src): - """iOS Objective-C Code Analysis""" + """IOS Objective-C Code Analysis.""" try: - logger.info("Starting iOS Source Code and PLIST Analysis") + logger.info('Starting iOS Source Code and PLIST Analysis') api_rules = ios_apis.CODE_APIS code_rules = ios_rules.CODE_RULES code_findings = {} - api_findings = {} + api_findings = {} email_n_file = [] url_n_file = [] url_list = [] @@ -34,34 +30,40 @@ def ios_source_analysis(src): for dirname, _, files in os.walk(src): for jfile in files: - if jfile.endswith(".m"): + if jfile.endswith('.m'): jfile_path = os.path.join(src, dirname, jfile) - if "+" in jfile: + if '+' in jfile: new_path = os.path.join( - src, dirname, jfile.replace("+", "x")) + src, dirname, jfile.replace('+', 'x')) shutil.move(jfile_path, new_path) jfile_path = new_path dat = '' - with io.open(jfile_path, mode='r', encoding="utf8", errors="ignore") as flip: + with io.open(jfile_path, + mode='r', + encoding='utf8', + errors='ignore') as flip: dat = flip.read() # Code Analysis relative_src_path = jfile_path.replace(src, '') - code_rule_matcher(code_findings, [], dat, relative_src_path, code_rules) + code_rule_matcher(code_findings, [], dat, + relative_src_path, code_rules) # API Analysis - api_rule_matcher(api_findings, [], dat, relative_src_path, api_rules) + api_rule_matcher(api_findings, [], dat, + relative_src_path, api_rules) # Extract URLs and Emails - urls, urls_nf, emails_nf = url_n_email_extract(dat, relative_src_path) + urls, urls_nf, emails_nf = url_n_email_extract( + dat, relative_src_path) url_list.extend(urls) url_n_file.extend(urls_nf) email_n_file.extend(emails_nf) - urls_list = list(set(url_list)) + urls_list = list(set(url_list)) # Domain Extraction and Malware Check - logger.info("Performing Malware Check on extracted Domains") + logger.info('Performing Malware Check on extracted Domains') domains = malware_check(urls_list) - logger.info("Finished Code Analysis, Email and URL Extraction") + logger.info('Finished Code Analysis, Email and URL Extraction') code_analysis_dict = { 'api': api_findings, 'code_anal': code_findings, @@ -72,5 +74,5 @@ def ios_source_analysis(src): } return code_analysis_dict - except: - PrintException("iOS Source Code Analysis") + except Exception: + log_exception('iOS Source Code Analysis') diff --git a/StaticAnalyzer/views/ios/db_interaction.py b/StaticAnalyzer/views/ios/db_interaction.py index 80a05446..b6d319ae 100755 --- a/StaticAnalyzer/views/ios/db_interaction.py +++ b/StaticAnalyzer/views/ios/db_interaction.py @@ -1,61 +1,62 @@ """Module holding the functions for the db.""" -from MobSF.utils import ( - PrintException, - python_list, - python_dict -) -from StaticAnalyzer.models import ( - StaticAnalyzerIPA, - StaticAnalyzerIOSZIP -) import logging + +from MobSF.utils import log_exception, python_dict, python_list + +from StaticAnalyzer.models import StaticAnalyzerIOSZIP, StaticAnalyzerIPA + logger = logging.getLogger(__name__) # IPA DB -def get_context_from_analysis_ipa(app_dict, info_dict, bin_dict, files, sfiles): - """Get the context for IPA from analysis results""" +def get_context_from_analysis_ipa(app_dict, + info_dict, + bin_dict, + files, + sfiles): + """Get the context for IPA from analysis results.""" try: context = { 'title': 'Static Analysis', - 'file_name': app_dict["file_name"], - 'size': app_dict["size"], - 'md5': app_dict["md5_hash"], - 'sha1': app_dict["sha1"], - 'sha256': app_dict["sha256"], - 'plist': info_dict["plist_xml"], - 'bin_name': info_dict["bin_name"], - 'id': info_dict["id"], - 'build': info_dict["build"], - 'version': info_dict["bundle_version_name"], - 'sdk': info_dict["sdk"], - 'pltfm': info_dict["pltfm"], - 'min': info_dict["min"], - 'bin_anal': bin_dict["bin_res"], - 'libs': bin_dict["libs"], + 'file_name': app_dict['file_name'], + 'size': app_dict['size'], + 'md5': app_dict['md5_hash'], + 'sha1': app_dict['sha1'], + 'sha256': app_dict['sha256'], + 'plist': info_dict['plist_xml'], + 'bin_name': info_dict['bin_name'], + 'id': info_dict['id'], + 'build': info_dict['build'], + 'version': info_dict['bundle_version_name'], + 'sdk': info_dict['sdk'], + 'pltfm': info_dict['pltfm'], + 'min': info_dict['min'], + 'bin_anal': bin_dict['bin_res'], + 'libs': bin_dict['libs'], 'files': files, 'file_analysis': sfiles, - 'strings': bin_dict["strings"], - 'permissions': info_dict["permissions"], - 'insecure_connections': info_dict["inseccon"], - 'bundle_name': info_dict["bundle_name"], - 'bundle_url_types': info_dict["bundle_url_types"], - 'bundle_supported_platforms': info_dict["bundle_supported_platforms"], - 'bundle_localizations': info_dict["bundle_localizations"], - 'binary_info': bin_dict["macho"], - 'bin_type': bin_dict["bin_type"], + 'strings': bin_dict['strings'], + 'permissions': info_dict['permissions'], + 'insecure_connections': info_dict['inseccon'], + 'bundle_name': info_dict['bundle_name'], + 'bundle_url_types': info_dict['bundle_url_types'], + 'bundle_supported_platforms': + info_dict['bundle_supported_platforms'], + 'bundle_localizations': info_dict['bundle_localizations'], + 'binary_info': bin_dict['macho'], + 'bin_type': bin_dict['bin_type'], 'appstore_details': app_dict['appstore'], } return context - except: - PrintException("Rendering to Template") + except Exception: + log_exception('Rendering to Template') def get_context_from_db_entry_ipa(db_entry): - """Return the context for IPA from DB""" + """Return the context for IPA from DB.""" try: - logger.info("Analysis is already Done. Fetching data from the DB...") + logger.info('Analysis is already Done. Fetching data from the DB...') context = { 'title': db_entry[0].TITLE, 'file_name': db_entry[0].FILE_NAME, @@ -80,140 +81,155 @@ def get_context_from_db_entry_ipa(db_entry): 'insecure_connections': python_list(db_entry[0].INSECCON), 'bundle_name': db_entry[0].BUNDLE_NAME, 'bundle_url_types': python_list(db_entry[0].BUNDLE_URL_TYPES), - 'bundle_supported_platforms': python_list(db_entry[0].BUNDLE_SUPPORTED_PLATFORMS), - 'bundle_localizations': python_list(db_entry[0].BUNDLE_LOCALIZATIONS), + 'bundle_supported_platforms': + python_list(db_entry[0].BUNDLE_SUPPORTED_PLATFORMS), + 'bundle_localizations': + python_list(db_entry[0].BUNDLE_LOCALIZATIONS), 'binary_info': python_dict(db_entry[0].MACHOINFO), 'bin_type': db_entry[0].BINTYPE, 'appstore_details': python_dict(db_entry[0].APPSTORE_DETAILS), } return context - except: - PrintException("Fetching from DB") + except Exception: + log_exception('Fetching from DB') -def update_db_entry_ipa(app_dict, info_dict, bin_dict, files, sfiles): - """Update an IPA DB entry""" +def update_db_entry_ipa(app_dict, + info_dict, + bin_dict, + files, + sfiles): + """Update an IPA DB entry.""" try: # pylint: disable=E1101 - StaticAnalyzerIPA.objects.filter(MD5=app_dict["md5_hash"]).update( + StaticAnalyzerIPA.objects.filter(MD5=app_dict['md5_hash']).update( TITLE='Static Analysis', - FILE_NAME=app_dict["file_name"], - SIZE=app_dict["size"], - MD5=app_dict["md5_hash"], - SHA1=app_dict["sha1"], - SHA256=app_dict["sha256"], - INFOPLIST=info_dict["plist_xml"], - BINNAME=info_dict["bin_name"], - IDF=info_dict["id"], - BUILD=info_dict["build"], - VERSION=info_dict["bundle_version_name"], - SDK=info_dict["sdk"], - PLTFM=info_dict["pltfm"], - MINX=info_dict["min"], - BIN_ANAL=bin_dict["bin_res"], - LIBS=bin_dict["libs"], + FILE_NAME=app_dict['file_name'], + SIZE=app_dict['size'], + MD5=app_dict['md5_hash'], + SHA1=app_dict['sha1'], + SHA256=app_dict['sha256'], + INFOPLIST=info_dict['plist_xml'], + BINNAME=info_dict['bin_name'], + IDF=info_dict['id'], + BUILD=info_dict['build'], + VERSION=info_dict['bundle_version_name'], + SDK=info_dict['sdk'], + PLTFM=info_dict['pltfm'], + MINX=info_dict['min'], + BIN_ANAL=bin_dict['bin_res'], + LIBS=bin_dict['libs'], FILES=files, SFILESX=sfiles, - STRINGS=bin_dict["strings"], - PERMISSIONS=info_dict["permissions"], - INSECCON=info_dict["inseccon"], - BUNDLE_NAME=info_dict["bundle_name"], - BUNDLE_URL_TYPES=info_dict["bundle_url_types"], - BUNDLE_SUPPORTED_PLATFORMS=info_dict["bundle_supported_platforms"], - BUNDLE_LOCALIZATIONS=info_dict["bundle_localizations"], - MACHOINFO=bin_dict["macho"], - BINTYPE=bin_dict["bin_type"], - APPSTORE_DETAILS=app_dict["appstore"], + STRINGS=bin_dict['strings'], + PERMISSIONS=info_dict['permissions'], + INSECCON=info_dict['inseccon'], + BUNDLE_NAME=info_dict['bundle_name'], + BUNDLE_URL_TYPES=info_dict['bundle_url_types'], + BUNDLE_SUPPORTED_PLATFORMS=info_dict['bundle_supported_platforms'], + BUNDLE_LOCALIZATIONS=info_dict['bundle_localizations'], + MACHOINFO=bin_dict['macho'], + BINTYPE=bin_dict['bin_type'], + APPSTORE_DETAILS=app_dict['appstore'], ) - except: - PrintException("Updating DB") + except Exception: + log_exception('Updating DB') -def create_db_entry_ipa(app_dict, info_dict, bin_dict, files, sfiles): - """Save an IOS IPA DB entry""" +def create_db_entry_ipa(app_dict, + info_dict, + bin_dict, + files, + sfiles): + """Save an IOS IPA DB entry.""" try: static_db = StaticAnalyzerIPA( TITLE='Static Analysis', - FILE_NAME=app_dict["file_name"], - SIZE=app_dict["size"], - MD5=app_dict["md5_hash"], - SHA1=app_dict["sha1"], - SHA256=app_dict["sha256"], - INFOPLIST=info_dict["plist_xml"], - BINNAME=info_dict["bin_name"], - IDF=info_dict["id"], - BUILD=info_dict["build"], + FILE_NAME=app_dict['file_name'], + SIZE=app_dict['size'], + MD5=app_dict['md5_hash'], + SHA1=app_dict['sha1'], + SHA256=app_dict['sha256'], + INFOPLIST=info_dict['plist_xml'], + BINNAME=info_dict['bin_name'], + IDF=info_dict['id'], + BUILD=info_dict['build'], VERSION=info_dict['bundle_version_name'], - SDK=info_dict["sdk"], - PLTFM=info_dict["pltfm"], - MINX=info_dict["min"], - BIN_ANAL=bin_dict["bin_res"], - LIBS=bin_dict["libs"], + SDK=info_dict['sdk'], + PLTFM=info_dict['pltfm'], + MINX=info_dict['min'], + BIN_ANAL=bin_dict['bin_res'], + LIBS=bin_dict['libs'], FILES=files, SFILESX=sfiles, - STRINGS=bin_dict["strings"], - PERMISSIONS=info_dict["permissions"], - INSECCON=info_dict["inseccon"], - BUNDLE_NAME=info_dict["bundle_name"], - BUNDLE_URL_TYPES=info_dict["bundle_url_types"], - BUNDLE_SUPPORTED_PLATFORMS=info_dict["bundle_supported_platforms"], - BUNDLE_LOCALIZATIONS=info_dict["bundle_localizations"], - MACHOINFO=bin_dict["macho"], - BINTYPE=bin_dict["bin_type"], - APPSTORE_DETAILS=app_dict["appstore"], + STRINGS=bin_dict['strings'], + PERMISSIONS=info_dict['permissions'], + INSECCON=info_dict['inseccon'], + BUNDLE_NAME=info_dict['bundle_name'], + BUNDLE_URL_TYPES=info_dict['bundle_url_types'], + BUNDLE_SUPPORTED_PLATFORMS=info_dict['bundle_supported_platforms'], + BUNDLE_LOCALIZATIONS=info_dict['bundle_localizations'], + MACHOINFO=bin_dict['macho'], + BINTYPE=bin_dict['bin_type'], + APPSTORE_DETAILS=app_dict['appstore'], ) static_db.save() - except: - PrintException("Saving to DB") + except Exception: + log_exception('Saving to DB') # IOS ZIP DB ENTRY -def get_context_from_analysis_ios(app_dict, info_dict,code_dict, files, sfiles): - """Get the context for IOS ZIP from analysis results""" +def get_context_from_analysis_ios(app_dict, + info_dict, + code_dict, + files, + sfiles): + """Get the context for IOS ZIP from analysis results.""" try: context = { 'title': 'Static Analysis', - 'file_name': app_dict["file_name"], - 'size': app_dict["size"], - 'md5': app_dict["md5_hash"], - 'sha1': app_dict["sha1"], - 'sha256': app_dict["sha256"], - 'plist': info_dict["plist_xml"], - 'bin_name': info_dict["bin_name"], - 'id': info_dict["id"], - 'build': info_dict["bundle_version_name"], + 'file_name': app_dict['file_name'], + 'size': app_dict['size'], + 'md5': app_dict['md5_hash'], + 'sha1': app_dict['sha1'], + 'sha256': app_dict['sha256'], + 'plist': info_dict['plist_xml'], + 'bin_name': info_dict['bin_name'], + 'id': info_dict['id'], + 'build': info_dict['bundle_version_name'], 'version': info_dict['bundle_version_name'], - 'sdk': info_dict["sdk"], - 'pltfm': info_dict["pltfm"], - 'min': info_dict["min"], + 'sdk': info_dict['sdk'], + 'pltfm': info_dict['pltfm'], + 'min': info_dict['min'], 'files': files, 'file_analysis': sfiles, - 'api': code_dict["api"], - 'insecure': code_dict["code_anal"], - 'urls': code_dict["urlnfile"], - 'domains': code_dict["domains"], - 'emails': code_dict["emailnfile"], - 'permissions': info_dict["permissions"], - 'insecure_connections': info_dict["inseccon"], - 'bundle_name': info_dict["bundle_name"], - 'bundle_url_types': info_dict["bundle_url_types"], - 'bundle_supported_platforms': info_dict["bundle_supported_platforms"], - 'bundle_localizations': info_dict["bundle_localizations"], + 'api': code_dict['api'], + 'insecure': code_dict['code_anal'], + 'urls': code_dict['urlnfile'], + 'domains': code_dict['domains'], + 'emails': code_dict['emailnfile'], + 'permissions': info_dict['permissions'], + 'insecure_connections': info_dict['inseccon'], + 'bundle_name': info_dict['bundle_name'], + 'bundle_url_types': info_dict['bundle_url_types'], + 'bundle_supported_platforms': + info_dict['bundle_supported_platforms'], + 'bundle_localizations': info_dict['bundle_localizations'], 'appstore_details': app_dict['appstore'], - 'firebase': code_dict["firebase"], + 'firebase': code_dict['firebase'], } return context - except: - PrintException("Rendering to Template") + except Exception: + log_exception('Rendering to Template') def get_context_from_db_entry_ios(db_entry): - """Return the context for IOS ZIP from DB""" + """Return the context for IOS ZIP from DB.""" try: - logger.info("Analysis is already Done. Fetching data from the DB...") + logger.info('Analysis is already Done. Fetching data from the DB...') context = { 'title': db_entry[0].TITLE, 'file_name': db_entry[0].FILE_NAME, @@ -240,91 +256,97 @@ def get_context_from_db_entry_ios(db_entry): 'insecure_connections': python_list(db_entry[0].INSECCON), 'bundle_name': db_entry[0].BUNDLE_NAME, 'bundle_url_types': python_list(db_entry[0].BUNDLE_URL_TYPES), - 'bundle_supported_platforms': python_list(db_entry[0].BUNDLE_SUPPORTED_PLATFORMS), - 'bundle_localizations': python_list(db_entry[0].BUNDLE_LOCALIZATIONS), + 'bundle_supported_platforms': + python_list(db_entry[0].BUNDLE_SUPPORTED_PLATFORMS), + 'bundle_localizations': + python_list(db_entry[0].BUNDLE_LOCALIZATIONS), 'appstore_details': python_dict(db_entry[0].APPSTORE_DETAILS), 'firebase': python_list(db_entry[0].FIREBASE), } return context - except: - PrintException("Fetching from DB") + except Exception: + log_exception('Fetching from DB') -def update_db_entry_ios(app_dict, info_dict, code_dict, files, sfiles): - """Update an IOS ZIP DB entry""" +def update_db_entry_ios(app_dict, + info_dict, + code_dict, + files, + sfiles): + """Update an IOS ZIP DB entry.""" try: # pylint: disable=E1101 - StaticAnalyzerIOSZIP.objects.filter(MD5=app_dict["md5_hash"]).update( + StaticAnalyzerIOSZIP.objects.filter(MD5=app_dict['md5_hash']).update( TITLE='Static Analysis', - FILE_NAME=app_dict["file_name"], - SIZE=app_dict["size"], - MD5=app_dict["md5_hash"], - SHA1=app_dict["sha1"], - SHA256=app_dict["sha256"], - INFOPLIST=info_dict["plist_xml"], - BINNAME=info_dict["bin_name"], - IDF=info_dict["id"], - BUILD=info_dict["build"], - VERSION=info_dict["bundle_version_name"], - SDK=info_dict["sdk"], - PLTFM=info_dict["pltfm"], - MINX=info_dict["min"], + FILE_NAME=app_dict['file_name'], + SIZE=app_dict['size'], + MD5=app_dict['md5_hash'], + SHA1=app_dict['sha1'], + SHA256=app_dict['sha256'], + INFOPLIST=info_dict['plist_xml'], + BINNAME=info_dict['bin_name'], + IDF=info_dict['id'], + BUILD=info_dict['build'], + VERSION=info_dict['bundle_version_name'], + SDK=info_dict['sdk'], + PLTFM=info_dict['pltfm'], + MINX=info_dict['min'], FILES=files, SFILESX=sfiles, - API=code_dict["api"], - CODEANAL=code_dict["code_anal"], - URLnFile=code_dict["urlnfile"], - DOMAINS=code_dict["domains"], - EmailnFile=code_dict["emailnfile"], - PERMISSIONS=info_dict["permissions"], - INSECCON=info_dict["inseccon"], - BUNDLE_NAME=info_dict["bundle_name"], - BUNDLE_URL_TYPES=info_dict["bundle_url_types"], - BUNDLE_SUPPORTED_PLATFORMS=info_dict["bundle_supported_platforms"], - BUNDLE_LOCALIZATIONS=info_dict["bundle_localizations"], - APPSTORE_DETAILS=app_dict["appstore"], - FIREBASE=code_dict["firebase"], + API=code_dict['api'], + CODEANAL=code_dict['code_anal'], + URLnFile=code_dict['urlnfile'], + DOMAINS=code_dict['domains'], + EmailnFile=code_dict['emailnfile'], + PERMISSIONS=info_dict['permissions'], + INSECCON=info_dict['inseccon'], + BUNDLE_NAME=info_dict['bundle_name'], + BUNDLE_URL_TYPES=info_dict['bundle_url_types'], + BUNDLE_SUPPORTED_PLATFORMS=info_dict['bundle_supported_platforms'], + BUNDLE_LOCALIZATIONS=info_dict['bundle_localizations'], + APPSTORE_DETAILS=app_dict['appstore'], + FIREBASE=code_dict['firebase'], ) - except: - PrintException("Updating DB") + except Exception: + log_exception('Updating DB') def create_db_entry_ios(app_dict, info_dict, code_dict, files, sfiles): - """Save an IOS ZIP DB entry""" + """Save an IOS ZIP DB entry.""" try: # pylint: disable=E1101 static_db = StaticAnalyzerIOSZIP( TITLE='Static Analysis', - FILE_NAME=app_dict["file_name"], - SIZE=app_dict["size"], - MD5=app_dict["md5_hash"], - SHA1=app_dict["sha1"], - SHA256=app_dict["sha256"], - INFOPLIST=info_dict["plist_xml"], - BINNAME=info_dict["bin_name"], - IDF=info_dict["id"], - BUILD=info_dict["build"], - VERSION=info_dict["bundle_version_name"], - SDK=info_dict["sdk"], - PLTFM=info_dict["pltfm"], - MINX=info_dict["min"], + FILE_NAME=app_dict['file_name'], + SIZE=app_dict['size'], + MD5=app_dict['md5_hash'], + SHA1=app_dict['sha1'], + SHA256=app_dict['sha256'], + INFOPLIST=info_dict['plist_xml'], + BINNAME=info_dict['bin_name'], + IDF=info_dict['id'], + BUILD=info_dict['build'], + VERSION=info_dict['bundle_version_name'], + SDK=info_dict['sdk'], + PLTFM=info_dict['pltfm'], + MINX=info_dict['min'], FILES=files, SFILESX=sfiles, - API=code_dict["api"], - CODEANAL=code_dict["code_anal"], - URLnFile=code_dict["urlnfile"], - DOMAINS=code_dict["domains"], - EmailnFile=code_dict["emailnfile"], - PERMISSIONS=info_dict["permissions"], - INSECCON=info_dict["inseccon"], - BUNDLE_NAME=info_dict["bundle_name"], - BUNDLE_URL_TYPES=info_dict["bundle_url_types"], - BUNDLE_SUPPORTED_PLATFORMS=info_dict["bundle_supported_platforms"], - BUNDLE_LOCALIZATIONS=info_dict["bundle_localizations"], - APPSTORE_DETAILS=app_dict["appstore"], - FIREBASE=code_dict["firebase"], + API=code_dict['api'], + CODEANAL=code_dict['code_anal'], + URLnFile=code_dict['urlnfile'], + DOMAINS=code_dict['domains'], + EmailnFile=code_dict['emailnfile'], + PERMISSIONS=info_dict['permissions'], + INSECCON=info_dict['inseccon'], + BUNDLE_NAME=info_dict['bundle_name'], + BUNDLE_URL_TYPES=info_dict['bundle_url_types'], + BUNDLE_SUPPORTED_PLATFORMS=info_dict['bundle_supported_platforms'], + BUNDLE_LOCALIZATIONS=info_dict['bundle_localizations'], + APPSTORE_DETAILS=app_dict['appstore'], + FIREBASE=code_dict['firebase'], ) static_db.save() - except: - PrintException("Saving DB") + except Exception: + log_exception('Saving DB') diff --git a/StaticAnalyzer/views/ios/ios_apis.py b/StaticAnalyzer/views/ios/ios_apis.py index f43e56af..239a1e9e 100755 --- a/StaticAnalyzer/views/ios/ios_apis.py +++ b/StaticAnalyzer/views/ios/ios_apis.py @@ -1,5 +1,5 @@ """ -Rule Format +Rule Format. 1. desc - Description of the findings @@ -14,8 +14,10 @@ Rule Format d. single_string - if string1 in input e. string_and - if (string1 in input) and (string2 in input) f. string_or - if (string1 in input) or (string2 in input) - g. string_and_or - if (string1 in input) and ((string2 in input) or (string3 in input)) - h. string_or_and - if (string1 in input) or ((string2 in input) and (string3 in input)) + g. string_and_or - if (string1 in input) and ((string2 in input) + or (string3 in input)) + h. string_or_and - if (string1 in input) or ((string2 in input) + and (string3 in input)) 4. input_case a. upper @@ -33,37 +35,37 @@ CODE_APIS = [ 'type': 'regex', 'match': 'single_regex', 'regex1': r'NSURL|CFStream|NSStream', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Local File I/O Operations.', 'type': 'regex', 'match': 'single_regex', - 'regex1': r'Keychain|kSecAttrAccessibleWhenUnlocked|' + - r'kSecAttrAccessibleAfterFirstUnlock|SecItemAdd|' + - r'SecItemUpdate|NSDataWritingFileProtectionComplete', - 'input_case': 'exact' + 'regex1': (r'Keychain|kSecAttrAccessibleWhenUnlocked|' + r'kSecAttrAccessibleAfterFirstUnlock|SecItemAdd|' + r'SecItemUpdate|NSDataWritingFileProtectionComplete'), + 'input_case': 'exact', }, { 'desc': 'WebView Component', 'type': 'regex', 'match': 'single_regex', 'regex1': r'UIWebView', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Encryption API', 'type': 'regex', 'match': 'single_regex', 'regex1': r'RNEncryptor|RNDecryptor|AESCrypt', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Keychain Access', 'type': 'string', 'match': 'single_string', 'string1': 'PDKeychainBindings', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'WebView Load Request', @@ -71,7 +73,7 @@ CODE_APIS = [ 'match': 'string_and', 'string1': 'loadRequest', 'string2': 'webView', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'WebView Load HTML String', @@ -79,7 +81,7 @@ CODE_APIS = [ 'match': 'string_and', 'string1': 'loadHTMLString', 'string2': 'webView', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Cookie Storage', @@ -87,7 +89,7 @@ CODE_APIS = [ 'match': 'string_and', 'string1': 'NSHTTPCookieStorage', 'string2': 'sharedHTTPCookieStorage', - 'input_case': 'exact' + 'input_case': 'exact', }, { 'desc': 'Set or Read Clipboard', @@ -95,7 +97,6 @@ CODE_APIS = [ 'match': 'string_and', 'string1': 'UIPasteboard', 'string2': 'generalPasteboard', - 'input_case': 'exact' + 'input_case': 'exact', }, - ] diff --git a/StaticAnalyzer/views/ios/ios_rules.py b/StaticAnalyzer/views/ios/ios_rules.py index 55f05c68..65542443 100755 --- a/StaticAnalyzer/views/ios/ios_rules.py +++ b/StaticAnalyzer/views/ios/ios_rules.py @@ -1,5 +1,5 @@ """ -Rule Format +Rule Format. 1. desc - Description of the findings @@ -14,8 +14,10 @@ Rule Format d. single_string - if string1 in input e. string_and - if (string1 in input) and (string2 in input) f. string_or - if (string1 in input) or (string2 in input) - g. string_and_or - if (string1 in input) and ((string_or1 in input) or (string_or2 in input)) - h. string_or_and - if (string1 in input) or ((string_and1 in input) and (string_and2 in input)) + g. string_and_or - if (string1 in input) and ((string_or1 in input) + or (string_or2 in input)) + h. string_or_and - if (string1 in input) or ((string_and1 in input) + and (string_and2 in input)) 4. level a. high @@ -35,52 +37,61 @@ Rule Format """ CODE_RULES = [ { - 'desc': 'The App may contain banned API(s). These API(s) are insecure and must not be used.', + 'desc': ('The App may contain banned API(s). ' + 'These API(s) are insecure and must not be used.'), 'type': 'regex', - 'regex1': r'strcpy|memcpy|strcat|strncat|strncpy|sprintf|vsprintf|gets', + 'regex1': (r'strcpy|memcpy|strcat|strncat|' + r'strncpy|sprintf|vsprintf|gets'), 'level': 'high', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 2.2, - 'cwe': 'CWE-676' + 'cwe': 'CWE-676', }, { - 'desc': 'App allows self signed or invalid SSL certificates. App is vulnerable to MITM attacks.', + 'desc': ('App allows self signed or invalid ' + 'SSL certificates. App is vulnerable to MITM attacks.'), 'type': 'regex', - 'regex1': r'canAuthenticateAgainstProtectionSpace|' + - r'continueWithoutCredentialForAuthenticationChallenge|' + - r'kCFStreamSSLAllowsExpiredCertificates|' + - r'kCFStreamSSLAllowsAnyRoot|' + - r'kCFStreamSSLAllowsExpiredRoots|' + - r'validatesSecureCertificate\s*=\s*(no|NO)|' + - r'allowInvalidCertificates\s*=\s*(YES|yes)', + 'regex1': (r'canAuthenticateAgainstProtectionSpace|' + r'continueWithoutCredentialForAuthenticationChallenge|' + r'kCFStreamSSLAllowsExpiredCertificates|' + r'kCFStreamSSLAllowsAnyRoot|' + r'kCFStreamSSLAllowsExpiredRoots|' + r'validatesSecureCertificate\s*=\s*(no|NO)|' + r'allowInvalidCertificates\s*=\s*(YES|yes)'), 'level': 'high', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 7.4, - 'cwe': 'CWE-295' + 'cwe': 'CWE-295', }, { - 'desc': 'UIWebView in App ignore SSL errors and accept any SSL Certificate. App is vulnerable to MITM attacks.', + 'desc': ('UIWebView in App ignore SSL errors and accept' + ' any SSL Certificate. App is vulnerable to MITM attacks.'), 'type': 'regex', - 'regex1': r'setAllowsAnyHTTPSCertificate:\s*YES|' + - r'allowsAnyHTTPSCertificateForHost|' + - r'loadingUnvalidatedHTTPSPage\s*=\s*(YES|yes)', + 'regex1': (r'setAllowsAnyHTTPSCertificate:\s*YES|' + r'allowsAnyHTTPSCertificateForHost|' + r'loadingUnvalidatedHTTPSPage\s*=\s*(YES|yes)'), 'level': 'high', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 7.4, - 'cwe': 'CWE-295' + 'cwe': 'CWE-295', }, { - 'desc': 'Files may contain hardcoded sensitive informations like usernames, passwords, keys etc.', + 'desc': ('Files may contain hardcoded sensitive' + ' informations like usernames, passwords, keys etc.'), 'type': 'regex', - 'regex1': r'''(password\s*=\s*@*\s*['|"].+['|"]\s{0,5})|(pass\s*=\s*@*\s*['|"].+['|"]\s{0,5})|(username\s*=\s*@*\s*['|"].+['|"]\s{0,5})|(secret\s*=\s*@*\s*['|"].+['|"]\s{0,5})|(key\s*=\s*@*\s*['|"].+['|"]\s{0,5})''', + 'regex1': (r'(password\s*=\s*[\'|\"].+[\'|\"]\s{0,5})|' + r'(pass\s*=\s*[\'|\"].+[\'|\"]\s{0,5})|' + r'(username\s*=\s*[\'|\"].+[\'|\"]\s{0,5})|' + r'(secret\s*=\s*[\'|\"].+[\'|\"]\s{0,5})|' + r'(key\s*=\s*[\'|\"].+[\'|\"]\s{0,5})'), 'level': 'high', 'match': 'single_regex', 'input_case': 'lower', 'cvss': 7.4, - 'cwe': 'CWE-312' + 'cwe': 'CWE-312', }, { 'desc': 'IP Address disclosure', @@ -90,50 +101,56 @@ CODE_RULES = [ 'match': 'single_regex', 'input_case': 'exact', 'cvss': 4.3, - 'cwe': 'CWE-200' + 'cwe': 'CWE-200', }, { - 'desc': 'The App logs information. Sensitive information should never be logged.', + 'desc': ('The App logs information. ' + 'Sensitive information should never be logged.'), 'type': 'regex', 'regex1': r'NSLog|NSAssert|fprintf|fprintf|Logging', 'level': 'info', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 7.5, - 'cwe': 'CWE-532' + 'cwe': 'CWE-532', }, { - 'desc': 'This app listens to Clipboard changes. Some malwares also listen to Clipboard changes.', + 'desc': ('This app listens to Clipboard changes. ' + 'Some malwares also listen to Clipboard changes.'), 'type': 'regex', - 'regex1': r'UIPasteboardChangedNotification|generalPasteboard\]\.string', + 'regex1': (r'UIPasteboardChangedNotification|' + r'generalPasteboard\]\.string'), 'level': 'warning', 'match': 'single_regex', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { - 'desc': 'App uses SQLite Database. Sensitive Information should be encrypted.', + 'desc': ('App uses SQLite Database. ' + 'Sensitive Information should be encrypted.'), 'type': 'string', 'string1': 'sqlite3_exec', 'level': 'info', 'match': 'single_string', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { - 'desc': 'Untrusted user input to "NSTemporaryDirectory()" will result in path traversal vulnerability.', + 'desc': ('Untrusted user input to "NSTemporaryDirectory()"' + ' will result in path traversal vulnerability.'), 'type': 'string', 'string1': 'NSTemporaryDirectory(),', 'level': 'warning', 'match': 'single_string', 'input_case': 'exact', 'cvss': 7.5, - 'cwe': 'CWE-22' + 'cwe': 'CWE-22', }, { - 'desc': 'User input in "loadHTMLString" will result in JavaScript Injection.', + 'desc': ('User input in "loadHTMLString" ' + 'will result in JavaScript Injection.'), 'type': 'string', 'string1': 'loadHTMLString', 'string2': 'webView', @@ -141,7 +158,7 @@ CODE_RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 8.8, - 'cwe': 'CWE-95' + 'cwe': 'CWE-95', }, { 'desc': 'SFAntiPiracy Jailbreak checks found', @@ -153,7 +170,7 @@ CODE_RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'SFAntiPiracy Piracy checks found', @@ -165,7 +182,7 @@ CODE_RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'MD5 is a weak hash known to have hash collisions.', @@ -176,7 +193,7 @@ CODE_RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 7.4, - 'cwe': 'CWE-327' + 'cwe': 'CWE-327', }, { 'desc': 'SHA1 is a weak hash known to have hash collisions.', @@ -187,10 +204,12 @@ CODE_RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 5.9, - 'cwe': 'CWE-327' + 'cwe': 'CWE-327', }, { - 'desc': 'The App uses ECB mode in Cryptographic encryption algorithm. ECB mode is known to be weak as it results in the same ciphertext for identical blocks of plaintext.', + 'desc': ('The App uses ECB mode in Cryptographic encryption algorithm.' + ' ECB mode is known to be weak as it results in the same' + ' ciphertext for identical blocks of plaintext.'), 'type': 'string', 'string1': 'kCCOptionECBMode', 'string2': 'kCCAlgorithmAES', @@ -198,7 +217,7 @@ CODE_RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 5.9, - 'cwe': 'CWE-327' + 'cwe': 'CWE-327', }, { 'desc': 'The App has ant-debugger code using ptrace() ', @@ -209,7 +228,7 @@ CODE_RULES = [ 'match': 'string_and', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'This App has anti-debugger code using Mach Exception Ports.', @@ -221,10 +240,12 @@ CODE_RULES = [ 'match': 'string_and_or', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { - 'desc': 'This App copies data to clipboard. Sensitive data should not be copied to clipboard as other applications can access it.', + 'desc': ('This App copies data to clipboard. Sensitive data should' + ' not be copied to clipboard as other applications' + ' can access it.'), 'type': 'string', 'string1': 'UITextField', 'string_or1': '@select(cut:)', @@ -233,7 +254,7 @@ CODE_RULES = [ 'match': 'string_and_or', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' + 'cwe': '', }, { 'desc': 'This App may have Jailbreak detection capabilities.', @@ -248,9 +269,11 @@ CODE_RULES = [ 'string8': '/Applications/Icy.app', 'string9': '/Applications/IntelliScreen.app', 'string10': '/Applications/SBSettings.app', - 'string11': '/Library/MobileSubstrate/DynamicLibraries/LiveClock.plist', + 'string11': ('/Library/MobileSubstrate/DynamicLibraries/' + 'LiveClock.plist'), 'string12': '/System/Library/LaunchDaemons/com.ikey.bbot.plist', - 'string13': '/System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist', + 'string13': ('/System/Library/LaunchDaemons/' + 'com.saurik.Cydia.Startup.plist'), 'string14': '/etc/ssh/sshd_config', 'string15': '/private/var/tmp/cydia.log', 'string16': '/usr/libexec/ssh-keysign', @@ -276,6 +299,6 @@ CODE_RULES = [ 'match': 'string_or', 'input_case': 'exact', 'cvss': 0, - 'cwe': '' - } + 'cwe': '', + }, ] diff --git a/StaticAnalyzer/views/ios/plist_analysis.py b/StaticAnalyzer/views/ios/plist_analysis.py index 5e852afe..574756d9 100755 --- a/StaticAnalyzer/views/ios/plist_analysis.py +++ b/StaticAnalyzer/views/ios/plist_analysis.py @@ -1,140 +1,140 @@ # -*- coding: utf_8 -*- """Module for iOS App Plist Analysis.""" -import os import logging +import os import plistlib + import biplist -from MobSF.utils import ( - PrintException, - isFileExists -) -from biplist import ( - readPlist, - writePlistToString -) +from biplist import readPlist, writePlistToString + +from MobSF.utils import is_file_exists, log_exception + logger = logging.getLogger(__name__) def convert_bin_xml(bin_xml_file): - """Convert Binary XML to Readable XML""" + """Convert Binary XML to Readable XML.""" try: - plist_obj = readPlist(bin_xml_file) - data = writePlistToString(plist_obj) - return data + plist_obj = readPlist(bin_xml_file) + data = writePlistToString(plist_obj) + return data except biplist.InvalidPlistException: - logger.warning("Failed to convert plist") - - -def __check_permissions(p_list): + logger.warning('Failed to convert plist') + + +def check_permissions(p_list): """Check the permissions the app requests.""" # List taken from - # https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html - logger.info("Checking Permissions") + # https://developer.apple.com/library/content/ + # documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html + logger.info('Checking Permissions') permissions = [] - if "NSAppleMusicUsageDescription" in p_list: + if 'NSAppleMusicUsageDescription' in p_list: permissions.append({ - "name": "NSAppleMusicUsageDescription", - "description": "Access Apple Media Library.", - "reason": p_list["NSAppleMusicUsageDescription"] + 'name': 'NSAppleMusicUsageDescription', + 'description': 'Access Apple Media Library.', + 'reason': p_list['NSAppleMusicUsageDescription'], }) - if "NSBluetoothPeripheralUsageDescription" in p_list: + if 'NSBluetoothPeripheralUsageDescription' in p_list: permissions.append({ - "name": "NSBluetoothPeripheralUsageDescription", - "description": "Access Bluetooth Interface.", - "reason": p_list["NSBluetoothPeripheralUsageDescription"] + 'name': 'NSBluetoothPeripheralUsageDescription', + 'description': 'Access Bluetooth Interface.', + 'reason': p_list['NSBluetoothPeripheralUsageDescription'], }) - if "NSCalendarsUsageDescription" in p_list: + if 'NSCalendarsUsageDescription' in p_list: permissions.append({ - "name": "NSCalendarsUsageDescription", - "description": "Access Calendars.", - "reason": p_list["NSCalendarsUsageDescription"] + 'name': 'NSCalendarsUsageDescription', + 'description': 'Access Calendars.', + 'reason': p_list['NSCalendarsUsageDescription'], }) - if "NSCameraUsageDescription" in p_list: + if 'NSCameraUsageDescription' in p_list: permissions.append({ - "name": "NSCameraUsageDescription", - "description": "Access the Camera.", - "reason": p_list["NSCameraUsageDescription"] + 'name': 'NSCameraUsageDescription', + 'description': 'Access the Camera.', + 'reason': p_list['NSCameraUsageDescription'], }) - if "NSContactsUsageDescription" in p_list: + if 'NSContactsUsageDescription' in p_list: permissions.append({ - "name": "NSContactsUsageDescription", - "description": "Access Contacts.", - "reason": p_list["NSContactsUsageDescription"] + 'name': 'NSContactsUsageDescription', + 'description': 'Access Contacts.', + 'reason': p_list['NSContactsUsageDescription'], }) - if "NSHealthShareUsageDescription" in p_list: + if 'NSHealthShareUsageDescription' in p_list: permissions.append({ - "name": "NSHealthShareUsageDescription", - "description": "Read Health Data.", - "reason": p_list["NSHealthShareUsageDescription"] + 'name': 'NSHealthShareUsageDescription', + 'description': 'Read Health Data.', + 'reason': p_list['NSHealthShareUsageDescription'], }) - if "NSHealthUpdateUsageDescription" in p_list: + if 'NSHealthUpdateUsageDescription' in p_list: permissions.append({ - "name": "NSHealthUpdateUsageDescription", - "description": "Write Health Data.", - "reason": p_list["NSHealthUpdateUsageDescription"] + 'name': 'NSHealthUpdateUsageDescription', + 'description': 'Write Health Data.', + 'reason': p_list['NSHealthUpdateUsageDescription'], }) - if "NSHomeKitUsageDescription" in p_list: + if 'NSHomeKitUsageDescription' in p_list: permissions.append({ - "name": "NSHomeKitUsageDescription", - "description": "Access HomeKit configuration data.", - "reason": p_list["NSHomeKitUsageDescription"] + 'name': 'NSHomeKitUsageDescription', + 'description': 'Access HomeKit configuration data.', + 'reason': p_list['NSHomeKitUsageDescription'], }) - if "NSLocationAlwaysUsageDescription" in p_list: + if 'NSLocationAlwaysUsageDescription' in p_list: permissions.append({ - "name": "NSLocationAlwaysUsageDescription", - "description": "Access location information at all times.", - "reason": p_list["NSLocationAlwaysUsageDescription"] + 'name': 'NSLocationAlwaysUsageDescription', + 'description': 'Access location information at all times.', + 'reason': p_list['NSLocationAlwaysUsageDescription'], }) - if "NSLocationUsageDescription" in p_list: + if 'NSLocationUsageDescription' in p_list: permissions.append({ - "name": "NSLocationUsageDescription", - "description": "Access location information at all times (< iOS 8).", - "reason": p_list["NSLocationUsageDescription"] + 'name': 'NSLocationUsageDescription', + 'description': ('Access location information' + ' at all times (< iOS 8).'), + 'reason': p_list['NSLocationUsageDescription'], }) - if "NSLocationWhenInUseUsageDescription" in p_list: + if 'NSLocationWhenInUseUsageDescription' in p_list: permissions.append({ - "name": "NSLocationWhenInUseUsageDescription", - "description": "Access location information when app is in the foreground.", - "reason": p_list["NSLocationWhenInUseUsageDescription"] + 'name': 'NSLocationWhenInUseUsageDescription', + 'description': ('Access location information when' + ' app is in the foreground.'), + 'reason': p_list['NSLocationWhenInUseUsageDescription'], }) - if "NSMicrophoneUsageDescription" in p_list: + if 'NSMicrophoneUsageDescription' in p_list: permissions.append({ - "name": "NSMicrophoneUsageDescription", - "description": "Access microphone.", - "reason": p_list["NSMicrophoneUsageDescription"] + 'name': 'NSMicrophoneUsageDescription', + 'description': 'Access microphone.', + 'reason': p_list['NSMicrophoneUsageDescription'], }) - if "NSMotionUsageDescription" in p_list: + if 'NSMotionUsageDescription' in p_list: permissions.append({ - "name": "NSMotionUsageDescription", - "description": "Access the device’s accelerometer.", - "reason": p_list["NSMotionUsageDescription"] + 'name': 'NSMotionUsageDescription', + 'description': 'Access the device’s accelerometer.', + 'reason': p_list['NSMotionUsageDescription'], }) - if "NSPhotoLibraryUsageDescription" in p_list: + if 'NSPhotoLibraryUsageDescription' in p_list: permissions.append({ - "name": "NSPhotoLibraryUsageDescription", - "description": "Access the user’s photo library.", - "reason": p_list["NSPhotoLibraryUsageDescription"] + 'name': 'NSPhotoLibraryUsageDescription', + 'description': 'Access the user’s photo library.', + 'reason': p_list['NSPhotoLibraryUsageDescription'], }) - if "NSRemindersUsageDescription" in p_list: + if 'NSRemindersUsageDescription' in p_list: permissions.append({ - "name": "NSRemindersUsageDescription", - "description": "Access the user’s reminders.", - "reason": p_list["NSRemindersUsageDescription"] + 'name': 'NSRemindersUsageDescription', + 'description': 'Access the user’s reminders.', + 'reason': p_list['NSRemindersUsageDescription'], }) - if "NSVideoSubscriberAccountUsageDescription" in p_list: + if 'NSVideoSubscriberAccountUsageDescription' in p_list: permissions.append({ - "name": "NSVideoSubscriberAccountUsageDescription", - "description": "Access the user’s TV provider account.", - "reason": p_list["NSVideoSubscriberAccountUsageDescription"] + 'name': 'NSVideoSubscriberAccountUsageDescription', + 'description': 'Access the user’s TV provider account.', + 'reason': p_list['NSVideoSubscriberAccountUsageDescription'], }) return permissions -def __check_insecure_connections(p_list): +def check_insecure_connections(p_list): """Check info.plist for insecure connection configurations.""" - logger.info("Checking for Insecure Connections") + logger.info('Checking for Insecure Connections') insecure_connections = [] if 'NSAppTransportSecurity' in p_list: @@ -149,86 +149,88 @@ def __check_insecure_connections(p_list): def plist_analysis(src, is_source): - """Plist Analysis""" + """Plist Analysis.""" try: - logger.info("iOS Info.plist Analysis Started") + logger.info('iOS Info.plist Analysis Started') plist_info = { - "bin_name": "", - "bin": "", - "id": "", - "version": "", - "build": "", - "sdk": "", - "pltfm": "", - "min": "", - "plist_xml": "", - "permissions": [], - "inseccon": [], - "bundle_name": "", - "build_version_name": "", - "bundle_url_types": [], - "bundle_supported_platforms": [], - "bundle_localizations": [] + 'bin_name': '', + 'bin': '', + 'id': '', + 'version': '', + 'build': '', + 'sdk': '', + 'pltfm': '', + 'min': '', + 'plist_xml': '', + 'permissions': [], + 'inseccon': [], + 'bundle_name': '', + 'build_version_name': '', + 'bundle_url_types': [], + 'bundle_supported_platforms': [], + 'bundle_localizations': [], } plist_file = None if is_source: - logger.info("Finding Info.plist in iOS Source") - for ifile in os.listdir(src): - if ifile.endswith(".xcodeproj"): - app_name = ifile.replace(".xcodeproj", "") - break - app_plist_file = "Info.plist" - for dirpath, dirnames, files in os.walk(src): + logger.info('Finding Info.plist in iOS Source') + app_plist_file = 'Info.plist' + for dirpath, _dirnames, files in os.walk(src): for name in files: - if "__MACOSX" not in dirpath and name == app_plist_file: + if '__MACOSX' not in dirpath and name == app_plist_file: plist_file = os.path.join(dirpath, name) break else: - logger.info("Finding Info.plist in iOS Binary") + logger.info('Finding Info.plist in iOS Binary') dirs = os.listdir(src) - dot_app_dir = "" + dot_app_dir = '' for dir_ in dirs: - if dir_.endswith(".app"): + if dir_.endswith('.app'): dot_app_dir = dir_ break - bin_dir = os.path.join(src, dot_app_dir) # Full Dir/Payload/x.app - plist_file = os.path.join(bin_dir, "Info.plist") - if not isFileExists(plist_file): - logger.warning("Cannot find Info.plist file. Skipping Plist Analysis.") + bin_dir = os.path.join(src, dot_app_dir) # Full Dir/Payload/x.app + plist_file = os.path.join(bin_dir, 'Info.plist') + if not is_file_exists(plist_file): + logger.warning( + 'Cannot find Info.plist file. Skipping Plist Analysis.') else: - #Generic Plist Analysis + # Generic Plist Analysis plist_obj = plistlib.readPlist(plist_file) - plist_info["plist_xml"] = plistlib.writePlistToBytes(plist_obj).decode("utf-8", "ignore") - if "CFBundleDisplayName" in plist_obj: - plist_info["bin_name"] = plist_obj["CFBundleDisplayName"] + plist_info['plist_xml'] = plistlib.writePlistToBytes( + plist_obj).decode('utf-8', 'ignore') + if 'CFBundleDisplayName' in plist_obj: + plist_info['bin_name'] = plist_obj['CFBundleDisplayName'] else: if not is_source: - #For iOS IPA - plist_info["bin_name"] = dot_app_dir.replace(".app", "") - if "CFBundleExecutable" in plist_obj: - plist_info["bin"] = plist_obj["CFBundleExecutable"] - if "CFBundleIdentifier" in plist_obj: - plist_info["id"] = plist_obj["CFBundleIdentifier"] + # For iOS IPA + plist_info['bin_name'] = dot_app_dir.replace('.app', '') + if 'CFBundleExecutable' in plist_obj: + plist_info['bin'] = plist_obj['CFBundleExecutable'] + if 'CFBundleIdentifier' in plist_obj: + plist_info['id'] = plist_obj['CFBundleIdentifier'] # build - if "CFBundleVersion" in plist_obj: - plist_info["build"] = plist_obj["CFBundleVersion"] - if "DTSDKName" in plist_obj: - plist_info["sdk"] = plist_obj["DTSDKName"] - if "DTPlatformVersion" in plist_obj: - plist_info["pltfm"] = plist_obj["DTPlatformVersion"] - if "MinimumOSVersion" in plist_obj: - plist_info["min"] = plist_obj["MinimumOSVersion"] + if 'CFBundleVersion' in plist_obj: + plist_info['build'] = plist_obj['CFBundleVersion'] + if 'DTSDKName' in plist_obj: + plist_info['sdk'] = plist_obj['DTSDKName'] + if 'DTPlatformVersion' in plist_obj: + plist_info['pltfm'] = plist_obj['DTPlatformVersion'] + if 'MinimumOSVersion' in plist_obj: + plist_info['min'] = plist_obj['MinimumOSVersion'] - plist_info["bundle_name"] = plist_obj.get("CFBundleName", "") - plist_info["bundle_version_name"] = plist_obj.get("CFBundleShortVersionString", "") - plist_info["bundle_url_types"] = plist_obj.get("CFBundleURLTypes", []) - plist_info["bundle_supported_platforms"] = plist_obj.get("CFBundleSupportedPlatforms", []) - plist_info["bundle_localizations"] = plist_obj.get("CFBundleLocalizations", []) + plist_info['bundle_name'] = plist_obj.get('CFBundleName', '') + plist_info['bundle_version_name'] = plist_obj.get( + 'CFBundleShortVersionString', '') + plist_info['bundle_url_types'] = plist_obj.get( + 'CFBundleURLTypes', []) + plist_info['bundle_supported_platforms'] = plist_obj.get( + 'CFBundleSupportedPlatforms', []) + plist_info['bundle_localizations'] = plist_obj.get( + 'CFBundleLocalizations', []) # Check possible app-permissions - plist_info["permissions"] = __check_permissions(plist_obj) - plist_info["inseccon"] = __check_insecure_connections(plist_obj) + plist_info['permissions'] = check_permissions(plist_obj) + plist_info['inseccon'] = check_insecure_connections(plist_obj) return plist_info - except: - PrintException("Reading from Info.plist") + except Exception: + log_exception('Reading from Info.plist') diff --git a/StaticAnalyzer/views/ios/static_analyzer.py b/StaticAnalyzer/views/ios/static_analyzer.py index c852553d..8628940c 100755 --- a/StaticAnalyzer/views/ios/static_analyzer.py +++ b/StaticAnalyzer/views/ios/static_analyzer.py @@ -1,60 +1,33 @@ # -*- coding: utf_8 -*- -""" -iOS Static Code Analysis -""" -import re -import os -import io -import shutil +"""iOS Static Code Analysis.""" import logging -from django.shortcuts import render -from django.http import HttpResponseRedirect -from django.conf import settings -from django.utils.html import escape - -from StaticAnalyzer.views.ios.db_interaction import ( - get_context_from_analysis_ipa, - get_context_from_db_entry_ipa, - update_db_entry_ipa, - create_db_entry_ipa, - - get_context_from_analysis_ios, - get_context_from_db_entry_ios, - update_db_entry_ios, - create_db_entry_ios, -) - -from StaticAnalyzer.views.ios.binary_analysis import ( - binary_analysis, -) -from StaticAnalyzer.views.ios.code_analysis import ( - ios_source_analysis, -) - -from StaticAnalyzer.views.ios.plist_analysis import ( - plist_analysis, - convert_bin_xml -) -from StaticAnalyzer.views.ios.appstore import( - app_search, -) -from StaticAnalyzer.views.shared_func import ( - file_size, - firebase_analysis, - hash_gen, - unzip, - score, - update_scan_timestamp, -) -from StaticAnalyzer.models import StaticAnalyzerIPA, StaticAnalyzerIOSZIP - -from MobSF.utils import ( - print_n_send_error_response, - PrintException, - isFileExists -) +import os +import re +import shutil import MalwareAnalyzer.views.VirusTotal as VirusTotal + +from django.conf import settings +from django.shortcuts import render +from django.utils.html import escape + +from MobSF.utils import (log_exception, + print_n_send_error_response) + +from StaticAnalyzer.models import StaticAnalyzerIOSZIP, StaticAnalyzerIPA +from StaticAnalyzer.views.ios.appstore import app_search +from StaticAnalyzer.views.ios.binary_analysis import binary_analysis +from StaticAnalyzer.views.ios.code_analysis import ios_source_analysis +from StaticAnalyzer.views.ios.db_interaction import ( + create_db_entry_ios, create_db_entry_ipa, get_context_from_analysis_ios, + get_context_from_analysis_ipa, get_context_from_db_entry_ios, + get_context_from_db_entry_ipa, update_db_entry_ios, update_db_entry_ipa) +from StaticAnalyzer.views.ios.plist_analysis import (convert_bin_xml, + plist_analysis) +from StaticAnalyzer.views.shared_func import (file_size, firebase_analysis, + hash_gen, score, unzip, + update_scan_timestamp) + logger = logging.getLogger(__name__) ############################################################## @@ -63,9 +36,9 @@ logger = logging.getLogger(__name__) def ios_list_files(src, md5_hash, binary_form, mode): - """List iOS files""" + """List iOS files.""" try: - logger.info("Get Files, BIN Plist -> XML, and Normalize") + logger.info('Get Files, BIN Plist -> XML, and Normalize') # Multi function, Get Files, BIN Plist -> XML, normalize + to x filez = [] certz = [] @@ -74,55 +47,56 @@ def ios_list_files(src, md5_hash, binary_form, mode): plist = [] for dirname, _, files in os.walk(src): for jfile in files: - if not jfile.endswith(".DS_Store"): + if not jfile.endswith('.DS_Store'): file_path = os.path.join(src, dirname, jfile) - if "+" in jfile: + if '+' in jfile: plus2x = os.path.join( - src, dirname, jfile.replace("+", "x")) + src, dirname, jfile.replace('+', 'x')) shutil.move(file_path, plus2x) file_path = plus2x fileparam = file_path.replace(src, '') filez.append(fileparam) ext = jfile.split('.')[-1] - if re.search("cer|pem|cert|crt|pub|key|pfx|p12", ext): + if re.search('cer|pem|cert|crt|pub|key|pfx|p12', ext): certz.append({ 'file_path': escape(file_path.replace(src, '')), 'type': None, - 'hash': None + 'hash': None, }) - if re.search("db|sqlitedb|sqlite", ext): + if re.search('db|sqlitedb|sqlite', ext): database.append({ 'file_path': escape(fileparam), 'type': mode, - 'hash': md5_hash + 'hash': md5_hash, }) - if jfile.endswith(".plist"): + if jfile.endswith('.plist'): if binary_form: convert_bin_xml(file_path) plist.append({ 'file_path': escape(fileparam), 'type': mode, - 'hash': md5_hash + 'hash': md5_hash, }) if len(database) > 0: - sfiles.append({"issue": "SQLite Files", "files": database}) + sfiles.append({'issue': 'SQLite Files', 'files': database}) if len(plist) > 0: - sfiles.append({"issue": "Plist Files", "files": plist}) + sfiles.append({'issue': 'Plist Files', 'files': plist}) if len(certz) > 0: sfiles.append( - {"issue": "Certificate/Key Files Hardcoded inside the App.", "files": certz}) + {'issue': 'Certificate/Key Files Hardcoded inside the App.', + 'files': certz}) return filez, sfiles - except: - PrintException("iOS List Files") + except Exception: + log_exception('iOS List Files') def static_analyzer_ios(request, api=False): - """Module that performs iOS IPA/ZIP Static Analysis""" + """Module that performs iOS IPA/ZIP Static Analysis.""" try: - logger.info("iOS Static Analysis Started") + logger.info('iOS Static Analysis Started') if api: file_type = request.POST['scan_type'] checksum = request.POST['hash'] @@ -135,62 +109,75 @@ def static_analyzer_ios(request, api=False): filename = request.GET['name'] md5_match = re.match('^[0-9a-f]{32}$', checksum) - if ((md5_match) and - (filename.lower().endswith('.ipa') or - filename.lower().endswith('.zip') - ) and - (file_type in ['ipa', 'ios']) - ): + if ((md5_match) + and (filename.lower().endswith('.ipa') + or filename.lower().endswith('.zip')) + and (file_type in ['ipa', 'ios'])): app_dict = {} - app_dict["directory"] = settings.BASE_DIR # BASE DIR - app_dict["file_name"] = filename # APP ORGINAL NAME - app_dict["md5_hash"] = checksum # MD5 - app_dict["app_dir"] = os.path.join( - settings.UPLD_DIR, app_dict["md5_hash"] + '/') # APP DIRECTORY + app_dict['directory'] = settings.BASE_DIR # BASE DIR + app_dict['file_name'] = filename # APP ORGINAL NAME + app_dict['md5_hash'] = checksum # MD5 + app_dict['app_dir'] = os.path.join( + settings.UPLD_DIR, app_dict['md5_hash'] + '/') # APP DIRECTORY tools_dir = os.path.join( - app_dict["directory"], 'StaticAnalyzer/tools/mac/') # TOOLS DIR + app_dict['directory'], 'StaticAnalyzer/tools/mac/') if file_type == 'ipa': # DB ipa_db = StaticAnalyzerIPA.objects.filter( - MD5=app_dict["md5_hash"]) + MD5=app_dict['md5_hash']) if ipa_db.exists() and rescan == '0': context = get_context_from_db_entry_ipa(ipa_db) else: - logger.info("iOS Binary (IPA) Analysis Started") - app_dict["app_file"] = app_dict[ - "md5_hash"] + '.ipa' # NEW FILENAME - app_dict["app_path"] = app_dict["app_dir"] + \ - app_dict["app_file"] # APP PATH - app_dict["bin_dir"] = os.path.join( - app_dict["app_dir"], "Payload/") - app_dict["size"] = str( - file_size(app_dict["app_path"])) + 'MB' # FILE SIZE - app_dict["sha1"], app_dict["sha256"] = hash_gen( - app_dict["app_path"]) # SHA1 & SHA256 HASHES - logger.info("Extracting IPA") + logger.info('iOS Binary (IPA) Analysis Started') + app_dict['app_file'] = app_dict[ + 'md5_hash'] + '.ipa' # NEW FILENAME + app_dict['app_path'] = (app_dict['app_dir'] + + app_dict['app_file']) + app_dict['bin_dir'] = os.path.join( + app_dict['app_dir'], 'Payload/') + app_dict['size'] = str( + file_size(app_dict['app_path'])) + 'MB' # FILE SIZE + app_dict['sha1'], app_dict['sha256'] = hash_gen( + app_dict['app_path']) # SHA1 & SHA256 HASHES + logger.info('Extracting IPA') # EXTRACT IPA - unzip(app_dict["app_path"], app_dict["app_dir"]) + unzip(app_dict['app_path'], app_dict['app_dir']) # Get Files, normalize + to x, # and convert binary plist -> xml files, sfiles = ios_list_files( - app_dict["bin_dir"], app_dict["md5_hash"], True, 'ipa') - infoplist_dict = plist_analysis(app_dict["bin_dir"], False) - app_dict["appstore"] = app_search(infoplist_dict.get("id")) + app_dict['bin_dir'], app_dict['md5_hash'], True, 'ipa') + infoplist_dict = plist_analysis(app_dict['bin_dir'], False) + app_dict['appstore'] = app_search(infoplist_dict.get('id')) bin_analysis_dict = binary_analysis( - app_dict["bin_dir"], tools_dir, app_dict["app_dir"], infoplist_dict.get("bin")) + app_dict['bin_dir'], + tools_dir, + app_dict['app_dir'], + infoplist_dict.get('bin')) # Saving to DB - logger.info("Connecting to DB") + logger.info('Connecting to DB') if rescan == '1': - logger.info("Updating Database...") + logger.info('Updating Database...') update_db_entry_ipa( - app_dict, infoplist_dict, bin_analysis_dict, files, sfiles) - update_scan_timestamp(app_dict["md5_hash"]) + app_dict, + infoplist_dict, + bin_analysis_dict, + files, + sfiles) + update_scan_timestamp(app_dict['md5_hash']) elif rescan == '0': - logger.info("Saving to Database") + logger.info('Saving to Database') create_db_entry_ipa( - app_dict, infoplist_dict, bin_analysis_dict, files, sfiles) + app_dict, + infoplist_dict, + bin_analysis_dict, + files, + sfiles) context = get_context_from_analysis_ipa( - app_dict, infoplist_dict, bin_analysis_dict, files, sfiles) + app_dict, + infoplist_dict, + bin_analysis_dict, + files, + sfiles) context['VT_RESULT'] = None if settings.VT_ENABLED: @@ -198,69 +185,83 @@ def static_analyzer_ios(request, api=False): context['VT_RESULT'] = vt.get_result( os.path.join(app_dict['app_dir'], app_dict[ 'md5_hash']) + '.ipa', - app_dict['md5_hash'] - ) - context["average_cvss"], context[ - "security_score"] = score(context["bin_anal"]) - template = "static_analysis/ios_binary_analysis.html" + app_dict['md5_hash']) + context['average_cvss'], context[ + 'security_score'] = score(context['bin_anal']) + template = 'static_analysis/ios_binary_analysis.html' if api: return context else: return render(request, template, context) elif file_type == 'ios': ios_zip_db = StaticAnalyzerIOSZIP.objects.filter( - MD5=app_dict["md5_hash"]) + MD5=app_dict['md5_hash']) if ios_zip_db.exists() and rescan == '0': context = get_context_from_db_entry_ios(ios_zip_db) else: - logger.info("iOS Source Code Analysis Started") - app_dict["app_file"] = app_dict[ - "md5_hash"] + '.zip' # NEW FILENAME - app_dict["app_path"] = app_dict["app_dir"] + \ - app_dict["app_file"] # APP PATH + logger.info('iOS Source Code Analysis Started') + app_dict['app_file'] = app_dict[ + 'md5_hash'] + '.zip' # NEW FILENAME + app_dict['app_path'] = (app_dict['app_dir'] + + app_dict['app_file']) # ANALYSIS BEGINS - Already Unzipped - logger.info("ZIP Already Extracted") - app_dict["size"] = str( - file_size(app_dict["app_path"])) + 'MB' # FILE SIZE - app_dict["sha1"], app_dict["sha256"] = hash_gen( - app_dict["app_path"]) # SHA1 & SHA256 HASHES + logger.info('ZIP Already Extracted') + app_dict['size'] = str( + file_size(app_dict['app_path'])) + 'MB' # FILE SIZE + app_dict['sha1'], app_dict['sha256'] = hash_gen( + app_dict['app_path']) # SHA1 & SHA256 HASHES files, sfiles = ios_list_files( - app_dict["app_dir"], app_dict["md5_hash"], False, 'ios') - infoplist_dict = plist_analysis(app_dict["app_dir"], True) - app_dict["appstore"] = app_search(infoplist_dict.get("id")) + app_dict['app_dir'], + app_dict['md5_hash'], + False, + 'ios') + infoplist_dict = plist_analysis(app_dict['app_dir'], True) + app_dict['appstore'] = app_search(infoplist_dict.get('id')) code_analysis_dic = ios_source_analysis( - app_dict["app_dir"]) + app_dict['app_dir']) # Firebase DB Check code_analysis_dic['firebase'] = firebase_analysis( - list(set(code_analysis_dic["urls_list"]))) + list(set(code_analysis_dic['urls_list']))) # Saving to DB - logger.info("Connecting to DB") + logger.info('Connecting to DB') if rescan == '1': - logger.info("Updating Database...") + logger.info('Updating Database...') update_db_entry_ios( - app_dict, infoplist_dict, code_analysis_dic, files, sfiles) - update_scan_timestamp(app_dict["md5_hash"]) + app_dict, + infoplist_dict, + code_analysis_dic, + files, + sfiles) + update_scan_timestamp(app_dict['md5_hash']) elif rescan == '0': - logger.info("Saving to Database") + logger.info('Saving to Database') create_db_entry_ios( - app_dict, infoplist_dict, code_analysis_dic, files, sfiles) + app_dict, + infoplist_dict, + code_analysis_dic, + files, + sfiles) context = get_context_from_analysis_ios( - app_dict, infoplist_dict, code_analysis_dic, files, sfiles) - context["average_cvss"], context[ - "security_score"] = score(context["insecure"]) - template = "static_analysis/ios_source_analysis.html" + app_dict, + infoplist_dict, + code_analysis_dic, + files, + sfiles) + context['average_cvss'], context[ + 'security_score'] = score(context['insecure']) + template = 'static_analysis/ios_source_analysis.html' if api: return context else: return render(request, template, context) else: - msg = "File Type not supported!" + msg = 'File Type not supported!' if api: return print_n_send_error_response(request, msg, True) else: return print_n_send_error_response(request, msg, False) else: - msg = "Hash match failed or Invalid file extension or file type" + msg = 'Hash match failed or Invalid file extension or file type' if api: return print_n_send_error_response(request, msg, True) else: diff --git a/StaticAnalyzer/views/ios/view_source.py b/StaticAnalyzer/views/ios/view_source.py index 2d09a6f3..1870bd3b 100644 --- a/StaticAnalyzer/views/ios/view_source.py +++ b/StaticAnalyzer/views/ios/view_source.py @@ -1,58 +1,48 @@ # -*- coding: utf_8 -*- -""" -iOS View Source -""" -import re -import os +"""iOS View Source.""" import io import json -import ntpath -import sqlite3 import logging -from django.shortcuts import render -from django.http import HttpResponseRedirect -from django.utils.html import escape +import ntpath +import os +import sqlite3 + +import biplist + from django.conf import settings +from django.http import HttpResponseRedirect +from django.shortcuts import render +from django.utils.html import escape + +from MobSF.forms import FormUtil +from MobSF.utils import (is_file_exists, log_exception, + print_n_send_error_response) + +from StaticAnalyzer.forms import ViewSourceIOSApiForm, ViewSourceIOSForm logger = logging.getLogger(__name__) -import biplist -from MobSF.forms import ( - FormUtil -) - -from StaticAnalyzer.forms import ( - ViewSourceIOSApiForm, - ViewSourceIOSForm -) - -from MobSF.utils import ( - print_n_send_error_response, - PrintException, - isFileExists -) def set_ext_api(file_path): - """ - Smart Function to set Extenstion - """ + """Smart Function to set Extenstion.""" ext = file_path.split('.')[-1] - if ext == "plist": - return "plist" + if ext == 'plist': + return 'plist' elif ext == 'xml': return 'xml' - elif ext in ["sqlitedb", "db", "sqlite"]: - return "db" - elif ext == "m": - return "m" + elif ext in ['sqlitedb', 'db', 'sqlite']: + return 'db' + elif ext == 'm': + return 'm' else: - return "txt" + return 'txt' + def run(request, api=False): - """View iOS Files""" + """View iOS Files.""" try: - logger.info("View iOS Source File") - file_format = "cpp" + logger.info('View iOS Source File') + file_format = 'cpp' if api: fil = request.POST['file'] md5_hash = request.POST['hash'] @@ -71,9 +61,9 @@ def run(request, api=False): context = { 'title': 'Error', 'exp': 'Error Description', - 'doc': err + 'doc': err, } - template = "general/error.html" + template = 'general/error.html' return render(request, template, context, status=400) if mode == 'ipa': src = os.path.join(settings.UPLD_DIR, @@ -84,44 +74,49 @@ def run(request, api=False): dat = '' if typ == 'm': file_format = 'cpp' - with io.open(sfile, mode='r', encoding="utf8", errors="ignore") as flip: + with io.open(sfile, + mode='r', + encoding='utf8', + errors='ignore') as flip: dat = flip.read() elif typ == 'xml': file_format = 'xml' - with io.open(sfile, mode='r', encoding="utf8", errors="ignore") as flip: + with io.open(sfile, + mode='r', + encoding='utf8', + errors='ignore') as flip: dat = flip.read() elif typ == 'plist': file_format = 'json' dat = biplist.readPlist(sfile) try: dat = json.dumps(dat, indent=4, sort_keys=True) - except: + except Exception: pass elif typ == 'db': file_format = 'asciidoc' dat = read_sqlite(sfile) - elif typ == 'txt' and fil == "classdump.txt": + elif typ == 'txt' and fil == 'classdump.txt': file_format = 'cpp' app_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') - cls_dump_file = os.path.join(app_dir, "classdump.txt") - if isFileExists(cls_dump_file): + cls_dump_file = os.path.join(app_dir, 'classdump.txt') + if is_file_exists(cls_dump_file): with io.open(cls_dump_file, mode='r', - encoding="utf8", - errors="ignore" - ) as flip: + encoding='utf8', + errors='ignore') as flip: dat = flip.read() else: - dat = "Class Dump result not Found" + dat = 'Class Dump result not Found' else: if api: - return {"error": "Invalid Parameters"} + return {'error': 'Invalid Parameters'} return HttpResponseRedirect('/error/') context = {'title': escape(ntpath.basename(fil)), 'file': escape(ntpath.basename(fil)), 'type': file_format, 'dat': dat} - template = "general/view.html" + template = 'general/view.html' if api: return context return render(request, template, context) @@ -135,31 +130,32 @@ def run(request, api=False): def read_sqlite(sqlite_file): - """Read SQlite File""" + """Read SQlite File.""" try: - logger.info("Dumping SQLITE Database") + logger.info('Dumping SQLITE Database') data = '' con = sqlite3.connect(sqlite_file) cur = con.cursor() - cur.execute("SELECT name FROM sqlite_master WHERE type='table';") + cur.execute('SELECT name FROM sqlite_master WHERE type=\'table\';') tables = cur.fetchall() for table in tables: - data += "\nTABLE: " + str(table[0]).decode('utf8', 'ignore') + \ - " \n=====================================================\n" - cur.execute("PRAGMA table_info('%s')" % table) + data += ('\nTABLE: ' + str(table[0]).decode('utf8', 'ignore') + + ' \n================================' + + '=====================\n') + cur.execute('PRAGMA table_info(\'%s\')' % table) rows = cur.fetchall() head = '' for row in rows: - head += str(row[1]).decode('utf8', 'ignore') + " | " - data += head + " \n========================================" +\ - "=============================\n" - cur.execute("SELECT * FROM '%s'" % table) + head += str(row[1]).decode('utf8', 'ignore') + ' | ' + data += head + (' \n========================================' + '=============================\n') + cur.execute('SELECT * FROM \'%s\'' % table) rows = cur.fetchall() for row in rows: dat = '' for item in row: - dat += str(item).decode('utf8', 'ignore') + " | " - data += dat + "\n" + dat += str(item).decode('utf8', 'ignore') + ' | ' + data += dat + '\n' return data - except: - PrintException("Dumping SQLITE Database") + except Exception: + log_exception('Dumping SQLITE Database') diff --git a/StaticAnalyzer/views/shared_func.py b/StaticAnalyzer/views/shared_func.py index 1814586d..f50da29e 100755 --- a/StaticAnalyzer/views/shared_func.py +++ b/StaticAnalyzer/views/shared_func.py @@ -1,56 +1,49 @@ # -*- coding: utf_8 -*- """ +Shared Functions. + Module providing the shared functions for static analysis of iOS and Android """ import hashlib import io +import json +import logging import os import platform import re -import json import subprocess import zipfile -import logging -import requests from urllib.parse import urlparse -from django.http import HttpResponse -from django.template.loader import get_template -from django.utils.html import escape -from django.utils import timezone -from MobSF.utils import ( - print_n_send_error_response, - PrintException, - python_list, - upstream_proxy, -) -from MobSF import settings - -from StaticAnalyzer.models import( - RecentScansDB, - StaticAnalyzerAndroid, - StaticAnalyzerIOSZIP, - StaticAnalyzerIPA, - StaticAnalyzerWindows, -) -from StaticAnalyzer.views.android.db_interaction import ( - get_context_from_db_entry -) - -from StaticAnalyzer.views.ios.db_interaction import ( - get_context_from_db_entry_ipa, - get_context_from_db_entry_ios -) +import requests import MalwareAnalyzer.views.VirusTotal as VirusTotal +from django.http import HttpResponse +from django.template.loader import get_template +from django.utils import timezone +from django.utils.html import escape + +from MobSF import settings +from MobSF.utils import (log_exception, print_n_send_error_response, + python_list, upstream_proxy) + +from StaticAnalyzer.models import (RecentScansDB, StaticAnalyzerAndroid, + StaticAnalyzerIOSZIP, StaticAnalyzerIPA, + StaticAnalyzerWindows) +from StaticAnalyzer.views.android.db_interaction import ( + get_context_from_db_entry) from StaticAnalyzer.views.comparer import generic_compare +from StaticAnalyzer.views.ios.db_interaction import ( + get_context_from_db_entry_ios, get_context_from_db_entry_ipa) + logger = logging.getLogger(__name__) try: import pdfkit except ImportError: logger.warning( - "wkhtmltopdf is not installed/configured properly. PDF Report Generation is disabled") + 'wkhtmltopdf is not installed/configured properly.' + ' PDF Report Generation is disabled') logger = logging.getLogger(__name__) @@ -60,9 +53,9 @@ def file_size(app_path): def hash_gen(app_path) -> tuple: - """Generate and return sha1 and sha256 as a tupel.""" + """Generate and return sha1 and sha256 as a tuple.""" try: - logger.info("Generating Hashes") + logger.info('Generating Hashes') sha1 = hashlib.sha1() sha256 = hashlib.sha256() block_size = 65536 @@ -75,29 +68,29 @@ def hash_gen(app_path) -> tuple: sha1val = sha1.hexdigest() sha256val = sha256.hexdigest() return sha1val, sha256val - except: - PrintException("Generating Hashes") + except Exception: + log_exception('Generating Hashes') def unzip(app_path, ext_path): - logger.info("Unzipping") + logger.info('Unzipping') try: files = [] - with zipfile.ZipFile(app_path, "r") as zipptr: + with zipfile.ZipFile(app_path, 'r') as zipptr: for fileinfo in zipptr.infolist(): filename = fileinfo.filename if not isinstance(filename, str): filename = str( - filename, encoding="utf-8", errors="replace") + filename, encoding='utf-8', errors='replace') files.append(filename) zipptr.extract(filename, ext_path) return files - except: - PrintException("Unzipping Error") - if platform.system() == "Windows": - logger.info("Not yet Implemented.") + except Exception: + log_exception('Unzipping Error') + if platform.system() == 'Windows': + logger.info('Not yet Implemented.') else: - logger.info("Using the Default OS Unzip Utility.") + logger.info('Using the Default OS Unzip Utility.') try: subprocess.call( ['unzip', '-o', '-q', app_path, '-d', ext_path]) @@ -106,8 +99,8 @@ def unzip(app_path, ext_path): files_det = ['Length Date Time Name'] files_det = files_det + dat return files_det - except: - PrintException("Unzipping Error") + except Exception: + log_exception('Unzipping Error') def pdf(request, api=False, jsonres=False): @@ -124,64 +117,74 @@ def pdf(request, api=False, jsonres=False): static_db = StaticAnalyzerAndroid.objects.filter(MD5=checksum) if static_db.exists(): logger.info( - "Fetching data from DB for PDF Report Generation (Android)") + 'Fetching data from DB for ' + 'PDF Report Generation (Android)') context = get_context_from_db_entry(static_db) - context["average_cvss"], context[ - "security_score"] = score(context["findings"]) + context['average_cvss'], context[ + 'security_score'] = score(context['findings']) if scan_type.lower() == 'apk': template = get_template( - "pdf/android_binary_analysis.pdf.html") + 'pdf/android_binary_analysis.pdf.html') else: template = get_template( - "pdf/android_source_analysis_pdf.html") + 'pdf/android_source_analysis_pdf.html') else: if api: - return {"report": "Report not Found"} + return {'report': 'Report not Found'} else: - return HttpResponse(json.dumps({"report": "Report not Found"}), - content_type="application/json; charset=utf-8", status=500) + return HttpResponse( + json.dumps({'report': 'Report not Found'}), + content_type='application/json; charset=utf-8', + status=500) elif scan_type.lower() in ['ipa', 'ioszip']: if scan_type.lower() == 'ipa': static_db = StaticAnalyzerIPA.objects.filter(MD5=checksum) if static_db.exists(): logger.info( - "Fetching data from DB for PDF Report Generation (IOS IPA)") + 'Fetching data from DB for ' + 'PDF Report Generation (IOS IPA)') context = get_context_from_db_entry_ipa(static_db) - context["average_cvss"], context[ - "security_score"] = score(context["bin_anal"]) + context['average_cvss'], context[ + 'security_score'] = score(context['bin_anal']) template = get_template( - "pdf/ios_binary_analysis_pdf.html") + 'pdf/ios_binary_analysis_pdf.html') else: if api: - return {"report": "Report not Found"} + return {'report': 'Report not Found'} else: - return HttpResponse(json.dumps({"report": "Report not Found"}), - content_type="application/json; charset=utf-8", status=500) + return HttpResponse( + json.dumps({'report': 'Report not Found'}), + content_type='application/json; charset=utf-8', + status=500) elif scan_type.lower() == 'ioszip': static_db = StaticAnalyzerIOSZIP.objects.filter( MD5=checksum) if static_db.exists(): logger.info( - "Fetching data from DB for PDF Report Generation (IOS ZIP)") + 'Fetching data from DB for ' + 'PDF Report Generation (IOS ZIP)') context = get_context_from_db_entry_ios(static_db) - context["average_cvss"], context[ - "security_score"] = score(context["insecure"]) + context['average_cvss'], context[ + 'security_score'] = score(context['insecure']) template = get_template( - "pdf/ios_source_analysis_pdf.html") + 'pdf/ios_source_analysis_pdf.html') else: if api: - return {"report": "Report not Found"} + return {'report': 'Report not Found'} else: - return HttpResponse(json.dumps({"report": "Report not Found"}), - content_type="application/json; charset=utf-8", status=500) + return HttpResponse( + json.dumps({'report': 'Report not Found'}), + content_type='application/json; charset=utf-8', + status=500) elif 'appx' == scan_type.lower(): if scan_type.lower() == 'appx': - db_entry = StaticAnalyzerWindows.objects.filter( # pylint: disable-msg=E1101 - MD5=checksum + db_entry = StaticAnalyzerWindows.objects.filter( + MD5=checksum, ) if db_entry.exists(): logger.info( - "Fetching data from DB for PDF Report Generation (APPX)") + 'Fetching data from DB for ' + 'PDF Report Generation (APPX)') context = { 'title': db_entry[0].TITLE, @@ -192,45 +195,50 @@ def pdf(request, api=False, jsonres=False): 'sha1': db_entry[0].SHA1, 'sha256': db_entry[0].SHA256, 'bin_name': db_entry[0].BINNAME, - 'version': db_entry[0].VERSION, - 'arch': db_entry[0].ARCH, - 'compiler_version': db_entry[0].COMPILER_VERSION, - 'visual_studio_version': db_entry[0].VISUAL_STUDIO_VERSION, - 'visual_studio_edition': db_entry[0].VISUAL_STUDIO_EDITION, - 'target_os': db_entry[0].TARGET_OS, - 'appx_dll_version': db_entry[0].APPX_DLL_VERSION, - 'proj_guid': db_entry[0].PROJ_GUID, - 'opti_tool': db_entry[0].OPTI_TOOL, - 'target_run': db_entry[0].TARGET_RUN, - 'files': python_list(db_entry[0].FILES), + 'version': db_entry[0].VERSION, + 'arch': db_entry[0].ARCH, + 'compiler_version': db_entry[0].COMPILER_VERSION, + 'visual_studio_version': + db_entry[0].VISUAL_STUDIO_VERSION, + 'visual_studio_edition': + db_entry[0].VISUAL_STUDIO_EDITION, + 'target_os': db_entry[0].TARGET_OS, + 'appx_dll_version': db_entry[0].APPX_DLL_VERSION, + 'proj_guid': db_entry[0].PROJ_GUID, + 'opti_tool': db_entry[0].OPTI_TOOL, + 'target_run': db_entry[0].TARGET_RUN, + 'files': python_list(db_entry[0].FILES), 'strings': python_list(db_entry[0].STRINGS), - 'bin_an_results': python_list(db_entry[0].BIN_AN_RESULTS), - 'bin_an_warnings': python_list(db_entry[0].BIN_AN_WARNINGS) + 'bin_an_results': + python_list(db_entry[0].BIN_AN_RESULTS), + 'bin_an_warnings': + python_list(db_entry[0].BIN_AN_WARNINGS), } template = get_template( - "pdf/windows_binary_analysis_pdf.html") + 'pdf/windows_binary_analysis_pdf.html') else: if api: - return {"scan_type": "Type is not Allowed"} + return {'scan_type': 'Type is not Allowed'} else: - return HttpResponse(json.dumps({"type": "Type is not Allowed"}), - content_type="application/json; charset=utf-8", status=500) + return HttpResponse( + json.dumps({'type': 'Type is not Allowed'}), + content_type='application/json; charset=utf-8', + status=500) context['VT_RESULT'] = None if settings.VT_ENABLED: app_dir = os.path.join(settings.UPLD_DIR, checksum + '/') vt = VirusTotal.VirusTotal() - if "zip" in scan_type.lower(): + if 'zip' in scan_type.lower(): context['VT_RESULT'] = None else: context['VT_RESULT'] = vt.get_result( - os.path.join(app_dir, checksum) + - '.' + scan_type.lower(), - checksum - ) + os.path.join(app_dir, checksum) + + '.' + scan_type.lower(), + checksum) try: if api and jsonres: - return {"report_dat": context} + return {'report_dat': context} else: options = { 'page-size': 'A4', @@ -240,32 +248,38 @@ def pdf(request, api=False, jsonres=False): 'margin-right': '0.50in', 'margin-bottom': '0.50in', 'margin-left': '0.50in', - 'encoding': "UTF-8", + 'encoding': 'UTF-8', 'custom-header': [ - ('Accept-Encoding', 'gzip') + ('Accept-Encoding', 'gzip'), ], - 'no-outline': None + 'no-outline': None, } html = template.render(context) pdf_dat = pdfkit.from_string(html, False, options=options) if api: - return {"pdf_dat": pdf_dat} - return HttpResponse(pdf_dat, content_type='application/pdf') + return {'pdf_dat': pdf_dat} + return HttpResponse(pdf_dat, + content_type='application/pdf') except Exception as exp: - logger.error(exp) + logger.error('Error Generating PDF Report') if api: - return {"error": "Cannot Generate PDF/JSON", "err_details": str(exp)} + return { + 'error': 'Cannot Generate PDF/JSON', + 'err_details': str(exp)} else: - return HttpResponse(json.dumps({"pdf_error": "Cannot Generate PDF", - "err_details": str(exp)}), - content_type="application/json; charset=utf-8", status=500) + return HttpResponse( + json.dumps({'pdf_error': 'Cannot Generate PDF', + 'err_details': str(exp)}), + content_type='application/json; charset=utf-8', + status=500) else: if api: - return {"error": "Invalid scan hash"} + return {'error': 'Invalid scan hash'} else: - return HttpResponse(json.dumps({"md5": "Invalid MD5"}), - content_type="application/json; charset=utf-8", status=500) + return HttpResponse( + json.dumps({'md5': 'Invalid MD5'}), + content_type='application/json; charset=utf-8', status=500) except Exception as exp: msg = str(exp) exp = exp.__doc__ @@ -276,56 +290,56 @@ def pdf(request, api=False, jsonres=False): def get_list_match_items(ruleset): - """Get List of Match item""" + """Get List of Match item.""" match_list = [] i = 1 - identifier = ruleset["type"] - if ruleset["match"] == 'string_and_or': + identifier = ruleset['type'] + if ruleset['match'] == 'string_and_or': identifier = 'string_or' - elif ruleset["match"] == 'string_or_and': + elif ruleset['match'] == 'string_or_and': identifier = 'string_and' while identifier + str(i) in ruleset: match_list.append(ruleset[identifier + str(i)]) i = i + 1 - if identifier + str(i) in ruleset == False: + if not (identifier + str(i)) in ruleset: break return match_list def add_findings(findings, desc, file_path, rule): - """Add Code Analysis Findings""" + """Add Code Analysis Findings.""" if desc in findings: - tmp_list = findings[desc]["path"] + tmp_list = findings[desc]['path'] if escape(file_path) not in tmp_list: tmp_list.append(escape(file_path)) - findings[desc]["path"] = tmp_list + findings[desc]['path'] = tmp_list else: - findings[desc] = {"path": [escape(file_path)], - "level": rule["level"], - "cvss": rule["cvss"], - "cwe": rule["cwe"]} + findings[desc] = {'path': [escape(file_path)], + 'level': rule['level'], + 'cvss': rule['cvss'], + 'cwe': rule['cwe']} def code_rule_matcher(findings, perms, data, file_path, code_rules): - """Android Static Analysis Rule Matcher""" + """Android Static Analysis Rule Matcher.""" try: for rule in code_rules: # CASE CHECK - if rule["input_case"] == "lower": + if rule['input_case'] == 'lower': tmp_data = data.lower() - elif rule["input_case"] == "upper": + elif rule['input_case'] == 'upper': tmp_data = data.upper() - elif rule["input_case"] == "exact": + elif rule['input_case'] == 'exact': tmp_data = data # MATCH TYPE - if rule["type"] == "regex": - if rule["match"] == 'single_regex': - if re.findall(rule["regex1"], tmp_data): + if rule['type'] == 'regex': + if rule['match'] == 'single_regex': + if re.findall(rule['regex1'], tmp_data): add_findings(findings, rule[ - "desc"], file_path, rule) - elif rule["match"] == 'regex_and': + 'desc'], file_path, rule) + elif rule['match'] == 'regex_and': and_match_rgx = True match_list = get_list_match_items(rule) for match in match_list: @@ -334,27 +348,28 @@ def code_rule_matcher(findings, perms, data, file_path, code_rules): break if and_match_rgx: add_findings(findings, rule[ - "desc"], file_path, rule) - elif rule["match"] == 'regex_or': + 'desc'], file_path, rule) + elif rule['match'] == 'regex_or': match_list = get_list_match_items(rule) for match in match_list: if re.findall(match, tmp_data): add_findings(findings, rule[ - "desc"], file_path, rule) + 'desc'], file_path, rule) break - elif rule["match"] == 'regex_and_perm': - if (rule["perm"] in perms) and (re.findall(rule["regex1"], tmp_data)): + elif rule['match'] == 'regex_and_perm': + if (rule['perm'] in perms + and re.findall(rule['regex1'], tmp_data)): add_findings(findings, rule[ - "desc"], file_path, rule) + 'desc'], file_path, rule) else: - logger.error("Code Regex Rule Match Error\n" + rule) + logger.error('Code Regex Rule Match Error\n %s', rule) - elif rule["type"] == "string": - if rule["match"] == 'single_string': - if rule["string1"] in tmp_data: + elif rule['type'] == 'string': + if rule['match'] == 'single_string': + if rule['string1'] in tmp_data: add_findings(findings, rule[ - "desc"], file_path, rule) - elif rule["match"] == 'string_and': + 'desc'], file_path, rule) + elif rule['match'] == 'string_and': and_match_str = True match_list = get_list_match_items(rule) for match in match_list: @@ -363,86 +378,87 @@ def code_rule_matcher(findings, perms, data, file_path, code_rules): break if and_match_str: add_findings(findings, rule[ - "desc"], file_path, rule) - elif rule["match"] == 'string_or': + 'desc'], file_path, rule) + elif rule['match'] == 'string_or': match_list = get_list_match_items(rule) for match in match_list: if match in tmp_data: add_findings(findings, rule[ - "desc"], file_path, rule) + 'desc'], file_path, rule) break - elif rule["match"] == 'string_and_or': + elif rule['match'] == 'string_and_or': match_list = get_list_match_items(rule) string_or_stat = False for match in match_list: if match in tmp_data: string_or_stat = True break - if string_or_stat and (rule["string1"] in tmp_data): + if string_or_stat and (rule['string1'] in tmp_data): add_findings(findings, rule[ - "desc"], file_path, rule) - elif rule["match"] == 'string_or_and': + 'desc'], file_path, rule) + elif rule['match'] == 'string_or_and': match_list = get_list_match_items(rule) string_and_stat = True for match in match_list: if match in tmp_data is False: string_and_stat = False break - if string_and_stat or (rule["string1"] in tmp_data): + if string_and_stat or (rule['string1'] in tmp_data): add_findings(findings, rule[ - "desc"], file_path, rule) - elif rule["match"] == 'string_and_perm': - if (rule["perm"] in perms) and (rule["string1"] in tmp_data): + 'desc'], file_path, rule) + elif rule['match'] == 'string_and_perm': + if (rule['perm'] in perms + and rule['string1'] in tmp_data): add_findings(findings, rule[ - "desc"], file_path, rule) - elif rule["match"] == 'string_or_and_perm': + 'desc'], file_path, rule) + elif rule['match'] == 'string_or_and_perm': match_list = get_list_match_items(rule) string_or_ps = False for match in match_list: if match in tmp_data: string_or_ps = True break - if (rule["perm"] in perms) and string_or_ps: + if (rule['perm'] in perms) and string_or_ps: add_findings(findings, rule[ - "desc"], file_path, rule) + 'desc'], file_path, rule) else: - logger.error("Code String Rule Match Error\n%s", rule) + logger.error('Code String Rule Match Error\n%s', rule) else: - logger.error("Code Rule Error\n%s", rule) - except: - PrintException("Error in Code Rule Processing") + logger.error('Code Rule Error\n%s', rule) + except Exception: + log_exception('Error in Code Rule Processing') def add_apis(api_findings, desc, file_path): - """Add API Findings""" + """Add API Findings.""" if desc in api_findings: - tmp_list = api_findings[desc]["path"] + tmp_list = api_findings[desc]['path'] if escape(file_path) not in tmp_list: tmp_list.append(escape(file_path)) - api_findings[desc]["path"] = tmp_list + api_findings[desc]['path'] = tmp_list else: - api_findings[desc] = {"path": [escape(file_path)]} + api_findings[desc] = {'path': [escape(file_path)]} def api_rule_matcher(api_findings, perms, data, file_path, api_rules): - """Android API Analysis Rule Matcher""" + """Android API Analysis Rule Matcher.""" try: for api in api_rules: # CASE CHECK - if api["input_case"] == "lower": + if api['input_case'] == 'lower': tmp_data = data.lower() - elif api["input_case"] == "upper": + elif api['input_case'] == 'upper': tmp_data = data.upper() - elif api["input_case"] == "exact": + elif api['input_case'] == 'exact': tmp_data = data # MATCH TYPE - if api["type"] == "regex": - if api["match"] == 'single_regex': - if re.findall(api["regex1"], tmp_data): - add_apis(api_findings, api["desc"], file_path) - elif api["match"] == 'regex_and': + if api['type'] == 'regex': + if api['match'] == 'single_regex': + if re.findall(api['regex1'], tmp_data): + add_apis(api_findings, api['desc'], file_path) + elif api['match'] == 'regex_and': and_match_rgx = True match_list = get_list_match_items(api) for match in match_list: @@ -450,24 +466,25 @@ def api_rule_matcher(api_findings, perms, data, file_path, api_rules): and_match_rgx = False break if and_match_rgx: - add_apis(api_findings, api["desc"], file_path) - elif api["match"] == 'regex_or': + add_apis(api_findings, api['desc'], file_path) + elif api['match'] == 'regex_or': match_list = get_list_match_items(api) for match in match_list: if re.findall(match, tmp_data): - add_apis(api_findings, api["desc"], file_path) + add_apis(api_findings, api['desc'], file_path) break - elif api["match"] == 'regex_and_perm': - if (api["perm"] in perms) and (re.findall(api["regex1"], tmp_data)): - add_apis(api_findings, api["desc"], file_path) + elif api['match'] == 'regex_and_perm': + if (api['perm'] in perms + and re.findall(api['regex1'], tmp_data)): + add_apis(api_findings, api['desc'], file_path) else: - logger.error("API Regex Rule Match Error\n" + api) + logger.error('API Regex Rule Match Error\n %s', api) - elif api["type"] == "string": - if api["match"] == 'single_string': - if api["string1"] in tmp_data: - add_apis(api_findings, api["desc"], file_path) - elif api["match"] == 'string_and': + elif api['type'] == 'string': + if api['match'] == 'single_string': + if api['string1'] in tmp_data: + add_apis(api_findings, api['desc'], file_path) + elif api['match'] == 'string_and': and_match_str = True match_list = get_list_match_items(api) for match in match_list: @@ -475,53 +492,53 @@ def api_rule_matcher(api_findings, perms, data, file_path, api_rules): and_match_str = False break if and_match_str: - add_apis(api_findings, api["desc"], file_path) - elif api["match"] == 'string_or': + add_apis(api_findings, api['desc'], file_path) + elif api['match'] == 'string_or': match_list = get_list_match_items(api) for match in match_list: if match in tmp_data: - add_apis(api_findings, api["desc"], file_path) + add_apis(api_findings, api['desc'], file_path) break - elif api["match"] == 'string_and_or': + elif api['match'] == 'string_and_or': match_list = get_list_match_items(api) string_or_stat = False for match in match_list: if match in tmp_data: string_or_stat = True break - if string_or_stat and (api["string1"] in tmp_data): - add_apis(api_findings, api["desc"], file_path) - elif api["match"] == 'string_or_and': + if string_or_stat and (api['string1'] in tmp_data): + add_apis(api_findings, api['desc'], file_path) + elif api['match'] == 'string_or_and': match_list = get_list_match_items(api) string_and_stat = True for match in match_list: if match in tmp_data is False: string_and_stat = False break - if string_and_stat or (api["string1"] in tmp_data): - add_apis(api_findings, api["desc"], file_path) - elif api["match"] == 'string_and_perm': - if (api["perm"] in perms) and (api["string1"] in tmp_data): - add_apis(api_findings, api["desc"], file_path) - elif api["match"] == 'string_or_and_perm': + if string_and_stat or (api['string1'] in tmp_data): + add_apis(api_findings, api['desc'], file_path) + elif api['match'] == 'string_and_perm': + if (api['perm'] in perms) and (api['string1'] in tmp_data): + add_apis(api_findings, api['desc'], file_path) + elif api['match'] == 'string_or_and_perm': match_list = get_list_match_items(api) string_or_ps = False for match in match_list: if match in tmp_data: string_or_ps = True break - if (api["perm"] in perms) and string_or_ps: - add_apis(api_findings, api["desc"], file_path) + if (api['perm'] in perms) and string_or_ps: + add_apis(api_findings, api['desc'], file_path) else: - logger.error("API String Rule Match Error\n%s", api) + logger.error('API String Rule Match Error\n%s', api) else: - logger.error("API Rule Error\n%s", api) - except: - PrintException("Error in API Rule Processing") + logger.error('API Rule Error\n%s', api) + except Exception: + log_exception('Error in API Rule Processing') def url_n_email_extract(dat, relative_path): - """Extract URLs and Emails from Source Code""" + """Extract URLs and Emails from Source Code.""" urls = [] emails = [] urllist = [] @@ -530,11 +547,11 @@ def url_n_email_extract(dat, relative_path): # URLs Extraction My Custom regex pattern = re.compile( ( - r'((?:https?://|s?ftps?://|file://|javascript:|data:|www\d{0,3}[.])' + r'((?:https?://|s?ftps?://|' + r'file://|javascript:|data:|www\d{0,3}[.])' r'[\w().=/;,#:@?&~*+!$%\'{}-]+)' ), - re.UNICODE - ) + re.UNICODE) urllist = re.findall(pattern, dat.lower()) uflag = 0 for url in urllist: @@ -543,7 +560,7 @@ def url_n_email_extract(dat, relative_path): uflag = 1 if uflag == 1: url_n_file.append( - {"urls": urls, "path": escape(relative_path)}) + {'urls': urls, 'path': escape(relative_path)}) # Email Extraction Regex regex = re.compile(r'[\w.-]+@[\w-]+\.[\w.]+') @@ -554,18 +571,18 @@ def url_n_email_extract(dat, relative_path): eflag = 1 if eflag == 1: email_n_file.append( - {"emails": emails, "path": escape(relative_path)}) + {'emails': emails, 'path': escape(relative_path)}) return urllist, url_n_file, email_n_file # This is just the first sanity check that triggers generic_compare -def compare_apps(request, first_hash: str, second_hash: str): - if first_hash == second_hash: - error_msg = "Results with same hash cannot be compared" +def compare_apps(request, hash1: str, hash2: str): + if hash1 == hash1: + error_msg = 'Results with same hash cannot be compared' return print_n_send_error_response(request, error_msg, False) logger.info( - "Starting App compare for - {} and {}".format(first_hash, second_hash)) - return generic_compare(request, first_hash, second_hash) + 'Starting App compare for %s and %s', hash1, hash2) + return generic_compare(request, hash1, hash2) def score(findings): @@ -575,22 +592,23 @@ def score(findings): app_score = 100 if isinstance(findings, list): for finding in findings: - if "cvss" in finding: - if finding["cvss"] != 0: - cvss_scores.append(finding["cvss"]) + if 'cvss' in finding: + if finding['cvss'] != 0: + cvss_scores.append(finding['cvss']) else: for _, finding in findings.items(): - if "cvss" in finding: - if finding["cvss"] != 0: - cvss_scores.append(finding["cvss"]) + if 'cvss' in finding: + if finding['cvss'] != 0: + cvss_scores.append(finding['cvss']) if cvss_scores: avg_cvss = round(sum(cvss_scores) / len(cvss_scores), 1) app_score = int((10 - avg_cvss) * 10) return avg_cvss, app_score -def update_scan_timestamp(scan_hash, tms=timezone.now()): +def update_scan_timestamp(scan_hash): # Update the last scan time. + tms = timezone.now() RecentScansDB.objects.filter(MD5=scan_hash).update(TS=tms) @@ -598,27 +616,29 @@ def open_firebase(url): # Detect Open Firebase Database try: purl = urlparse(url) - base_url = "{}://{}/.json".format(purl.scheme, purl.netloc) + base_url = '{}://{}/.json'.format(purl.scheme, purl.netloc) proxies, verify = upstream_proxy('https') headers = { - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'} + 'User-Agent': ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1)' + ' AppleWebKit/537.36 (KHTML, like Gecko) ' + 'Chrome/39.0.2171.95 Safari/537.36')} resp = requests.get(base_url, headers=headers, proxies=proxies, verify=verify) if resp.status_code == 200: return base_url, True - except Exception as exp: - logger.warning('Open Firebase DB detection failed. %s', exp) + except Exception: + logger.warning('Open Firebase DB detection failed.') return url, False def firebase_analysis(urls): # Detect Firebase URL firebase_db = [] - logger.info("Detecting Firebase URL(s)") + logger.info('Detecting Firebase URL(s)') for url in urls: if 'firebaseio.com' in url: returl, is_open = open_firebase(url) - fbdic = {"url": returl, "open": is_open} + fbdic = {'url': returl, 'open': is_open} if fbdic not in firebase_db: firebase_db.append(fbdic) return firebase_db diff --git a/StaticAnalyzer/views/windows.py b/StaticAnalyzer/views/windows.py index 7da89a99..280b5708 100755 --- a/StaticAnalyzer/views/windows.py +++ b/StaticAnalyzer/views/windows.py @@ -1,45 +1,33 @@ # -*- coding: utf_8 -*- """Windows Analysis Module.""" -import re -import os -import io -from os.path import expanduser -import platform -import logging -# Binskim/Binscope analysis -import xmlrpc.client -import json import base64 -import rsa - # Local analysis import configparser +import json +import logging +import os +import platform +import re import subprocess +# Binskim/Binscope analysis +import xmlrpc.client +from os.path import expanduser + +import rsa -# XML-Manifest from lxml import etree -from django.shortcuts import render -from django.http import HttpResponseRedirect from django.conf import settings +from django.shortcuts import render from django.utils.html import escape -from StaticAnalyzer.views.shared_func import ( - file_size, - hash_gen, - unzip, - update_scan_timestamp, -) +from MobSF.utils import log_exception, print_n_send_error_response, python_list from StaticAnalyzer.models import StaticAnalyzerWindows - from StaticAnalyzer.tools.strings import strings_util +from StaticAnalyzer.views.shared_func import (file_size, hash_gen, unzip, + update_scan_timestamp) -from MobSF.utils import ( - print_n_send_error_response, - python_list, - PrintException, -) logger = logging.getLogger(__name__) # Only used when xmlrpc is used @@ -57,7 +45,7 @@ def staticanalyzer_windows(request, api=False): """Analyse a windows app.""" try: # Input validation - logger.info("Windows Static Analysis Started") + logger.info('Windows Static Analysis Started') app_dic = {} # Dict to store the binary attributes if api: typ = request.POST['scan_type'] @@ -79,11 +67,13 @@ def staticanalyzer_windows(request, api=False): settings.BASE_DIR, 'StaticAnalyzer/tools/windows/') if typ == 'appx': # DB - db_entry = StaticAnalyzerWindows.objects.filter( # pylint: disable-msg=E1101 - MD5=app_dic['md5'] + db_entry = StaticAnalyzerWindows.objects.filter( + MD5=app_dic['md5'], ) if db_entry.exists() and rescan == '0': - logger.info("Analysis is already Done. Fetching data from the DB...") + logger.info( + 'Analysis is already Done.' + ' Fetching data from the DB...') context = { 'title': db_entry[0].TITLE, 'name': db_entry[0].APP_NAME, @@ -93,42 +83,47 @@ def staticanalyzer_windows(request, api=False): 'sha1': db_entry[0].SHA1, 'sha256': db_entry[0].SHA256, 'bin_name': db_entry[0].BINNAME, - 'version': db_entry[0].VERSION, - 'arch': db_entry[0].ARCH, - 'compiler_version': db_entry[0].COMPILER_VERSION, - 'visual_studio_version': db_entry[0].VISUAL_STUDIO_VERSION, - 'visual_studio_edition': db_entry[0].VISUAL_STUDIO_EDITION, - 'target_os': db_entry[0].TARGET_OS, - 'appx_dll_version': db_entry[0].APPX_DLL_VERSION, - 'proj_guid': db_entry[0].PROJ_GUID, - 'opti_tool': db_entry[0].OPTI_TOOL, - 'target_run': db_entry[0].TARGET_RUN, + 'version': db_entry[0].VERSION, + 'arch': db_entry[0].ARCH, + 'compiler_version': db_entry[0].COMPILER_VERSION, + 'visual_studio_version': + db_entry[0].VISUAL_STUDIO_VERSION, + 'visual_studio_edition': + db_entry[0].VISUAL_STUDIO_EDITION, + 'target_os': db_entry[0].TARGET_OS, + 'appx_dll_version': db_entry[0].APPX_DLL_VERSION, + 'proj_guid': db_entry[0].PROJ_GUID, + 'opti_tool': db_entry[0].OPTI_TOOL, + 'target_run': db_entry[0].TARGET_RUN, 'files': python_list(db_entry[0].FILES), 'strings': python_list(db_entry[0].STRINGS), - 'bin_an_results': python_list(db_entry[0].BIN_AN_RESULTS), - 'bin_an_warnings': python_list(db_entry[0].BIN_AN_WARNINGS) + 'bin_an_results': + python_list(db_entry[0].BIN_AN_RESULTS), + 'bin_an_warnings': + python_list(db_entry[0].BIN_AN_WARNINGS), } else: - logger.info("Windows Binary Analysis Started") + logger.info('Windows Binary Analysis Started') app_dic['app_path'] = os.path.join( app_dic['app_dir'], app_dic['md5'] + '.appx') # ANALYSIS BEGINS - app_dic['size'] = str(file_size(app_dic['app_path'])) + 'MB' + app_dic['size'] = str( + file_size(app_dic['app_path'])) + 'MB' # Generate hashes app_dic['sha1'], app_dic[ 'sha256'] = hash_gen(app_dic['app_path']) # EXTRACT APPX - logger.info("Extracting APPX") + logger.info('Extracting APPX') app_dic['files'] = unzip( app_dic['app_path'], app_dic['app_dir']) xml_dic = _parse_xml(app_dic['app_dir']) bin_an_dic = _binary_analysis(app_dic) # Saving to db - logger.info("Connecting to DB") + logger.info('Connecting to DB') if rescan == '1': - logger.info("Updating Database...") - StaticAnalyzerWindows.objects.filter( # pylint: disable-msg=E1101 - MD5=app_dic['md5'] + logger.info('Updating Database...') + StaticAnalyzerWindows.objects.filter( + MD5=app_dic['md5'], ).update( TITLE='Static Analysis', APP_NAME=app_dic['app_name'], @@ -157,7 +152,7 @@ def staticanalyzer_windows(request, api=False): ) update_scan_timestamp(app_dic['md5']) elif rescan == '0': - logger.info("Saving to Database") + logger.info('Saving to Database') db_item = StaticAnalyzerWindows( TITLE='Static Analysis', APP_NAME=app_dic['app_name'], @@ -197,8 +192,10 @@ def staticanalyzer_windows(request, api=False): 'version': xml_dic['version'], 'arch': xml_dic['arch'], 'compiler_version': xml_dic['compiler_version'], - 'visual_studio_version': xml_dic['visual_studio_version'], - 'visual_studio_edition': xml_dic['visual_studio_edition'], + 'visual_studio_version': + xml_dic['visual_studio_version'], + 'visual_studio_edition': + xml_dic['visual_studio_edition'], 'target_os': xml_dic['target_os'], 'appx_dll_version': xml_dic['appx_dll_version'], 'proj_guid': xml_dic['proj_guid'], @@ -209,19 +206,19 @@ def staticanalyzer_windows(request, api=False): 'bin_an_results': bin_an_dic['results'], 'bin_an_warnings': bin_an_dic['warnings'], } - template = "static_analysis/windows_binary_analysis.html" + template = 'static_analysis/windows_binary_analysis.html' if api: return context else: return render(request, template, context) else: - msg = "File type not supported" + msg = 'File type not supported' if api: return print_n_send_error_response(request, msg, True) else: return print_n_send_error_response(request, msg, False) else: - msg = "Hash match failed or Invalid file extension" + msg = 'Hash match failed or Invalid file extension' if api: return print_n_send_error_response(request, msg, True) else: @@ -234,6 +231,7 @@ def staticanalyzer_windows(request, api=False): else: return print_n_send_error_response(request, msg, False, exp_doc) + def _get_token(): """Get the authentication token for windows vm xmlrpc client.""" challenge = proxy.get_challenge() @@ -246,7 +244,7 @@ def _get_token(): def _binary_analysis(app_dic): """Start binary analsis.""" - logger.info("Starting Binary Analysis") + logger.info('Starting Binary Analysis') bin_an_dic = {} # Init optional sections to prevent None-Pointer-Errors @@ -255,78 +253,88 @@ def _binary_analysis(app_dic): # Search for exe for file_name in app_dic['files']: - if file_name.endswith(".exe"): + if file_name.endswith('.exe'): bin_an_dic['bin'] = file_name - bin_an_dic['bin_name'] = file_name.replace(".exe", "") + bin_an_dic['bin_name'] = file_name.replace('.exe', '') break if not bin_an_dic['bin_name']: - PrintException("No executeable in appx.") + log_exception('No executeable in appx.') bin_path = os.path.join(app_dic['app_dir'], bin_an_dic['bin']) # Execute strings command - bin_an_dic['strings'] = "" - str_list = list(set(strings_util(bin_path))) # Make unique # pylint: disable-msg=R0204 + bin_an_dic['strings'] = '' + # Make unique # pylint: disable-msg=R0204 + str_list = list(set(strings_util(bin_path))) str_list = [escape(s) for s in str_list] bin_an_dic['strings'] = str_list # Search for unsave function - pattern = re.compile("(alloca|gets|memcpy|printf|scanf|sprintf|sscanf|strcat|StrCat|strcpy|StrCpy|strlen|StrLen|strncat|StrNCat|strncpy|StrNCpy|strtok|swprintf|vsnprintf|vsprintf|vswprintf|wcscat|wcscpy|wcslen|wcsncat|wcsncpy|wcstok|wmemcpy)") + pattern = re.compile('(alloca|gets|memcpy|printf|scanf|sprintf|sscanf|' + 'strcat|StrCat|strcpy|StrCpy|strlen|StrLen|strncat|' + 'StrNCat|strncpy|StrNCpy|strtok|swprintf|vsnprintf|' + 'vsprintf|vswprintf|wcscat|wcscpy|wcslen|wcsncat|' + 'wcsncpy|wcstok|wmemcpy)') for elem in str_list: if pattern.match(elem[5:-5]): result = { - "rule_id": 'Possible Insecure Function', - "status": 'Insecure', - "desc": "Possible Insecure Function detected: {}".format(elem[5:-5]) - } + 'rule_id': 'Possible Insecure Function', + 'status': 'Insecure', + 'desc': ('Possible Insecure ' + 'Function detected: {}').format(elem[5:-5])} bin_an_dic['results'].append(result) # Execute binskim analysis if vm is available if platform.system() != 'Windows': if settings.WINDOWS_VM_IP: - logger.info("Windows VM configured.") + logger.info('Windows VM configured.') global proxy proxy = xmlrpc.client.ServerProxy( # pylint: disable-msg=C0103 - "http://{}:{}".format( + 'http://{}:{}'.format( settings.WINDOWS_VM_IP, - settings.WINDOWS_VM_PORT - ) - ) + settings.WINDOWS_VM_PORT)) name = _upload_sample(bin_path) - bin_an_dic = __binskim(name, bin_an_dic) - bin_an_dic = __binscope(name, bin_an_dic) + bin_an_dic = binskim(name, bin_an_dic) + bin_an_dic = binscope(name, bin_an_dic) else: - logger.warning("Windows VM not configured in settings.py. Skipping Binskim and Binscope.") + logger.warning( + 'Windows VM not configured in settings.py.' + ' Skipping Binskim and Binscope.') warning = { - "rule_id": "VM", - "status": "Info", - "info": "", - "desc": "VM is not configured. Please read the readme.md in MobSF/install/windows." + 'rule_id': 'VM', + 'status': 'Info', + 'info': '', + 'desc': 'VM is not configured. Please read the readme.md' + ' in MobSF/install/windows.', } bin_an_dic['results'].append(warning) else: - logger.info("Running lokal analysis.") + logger.info('Running lokal analysis.') global config config = configparser.ConfigParser() # Switch to settings definded path if available - config.read(expanduser("~") + "\\MobSF\\Config\\config.txt") + config.read(expanduser('~') + '\\MobSF\\Config\\config.txt') # Run analysis functions - bin_an_dic = __binskim(bin_path, bin_an_dic, - run_local=True, app_dir=app_dic['app_dir']) - bin_an_dic = __binscope(bin_path, bin_an_dic, - run_local=True, app_dir=app_dic['app_dir']) + bin_an_dic = binskim(bin_path, + bin_an_dic, + run_local=True, + app_dir=app_dic['app_dir']) + bin_an_dic = binscope(bin_path, + bin_an_dic, + run_local=True, + app_dir=app_dic['app_dir']) return bin_an_dic def _upload_sample(bin_path): """Upload sample to windows vm.""" - logger.info("Uploading sample.") + logger.info('Uploading sample.') # Upload test - with open(bin_path,"rb") as handle: + with open(bin_path, 'rb') as handle: binary_data = xmlrpc.client.Binary(handle.read()) # Name of the sample is return by the remote machine name = proxy.upload_file(binary_data, _get_token()) @@ -334,9 +342,9 @@ def _upload_sample(bin_path): return name -def __binskim(name, bin_an_dic, run_local=False, app_dir=None): +def binskim(name, bin_an_dic, run_local=False, app_dir=None): """Run the binskim analysis.""" - logger.info("Running binskim.") + logger.info('Running binskim.') if run_local: bin_path = os.path.join(app_dir, bin_an_dic['bin']) @@ -346,13 +354,13 @@ def __binskim(name, bin_an_dic, run_local=False, app_dir=None): else: binskim_path = config['binskim']['file_x86'] - command = "analyze" + command = 'analyze' path = bin_path - output_p = "-o" - output_d = bin_path + "_binskim" - verbose = "-v" - policy_p = "--config" - policy_d = "default" # TODO(Other policies?) + output_p = '-o' + output_d = bin_path + '_binskim' + verbose = '-v' + policy_p = '--config' + policy_d = 'default' # TODO(Other policies?) # Assemble params = [ @@ -361,7 +369,7 @@ def __binskim(name, bin_an_dic, run_local=False, app_dir=None): path, output_p, output_d, verbose, - policy_p, policy_d + policy_p, policy_d, ] # Execute process @@ -378,50 +386,51 @@ def __binskim(name, bin_an_dic, run_local=False, app_dir=None): # Load output as json output = json.loads(response) - bin_an_dic = __parse_binskim(bin_an_dic, output) + bin_an_dic = parse_binskim(bin_an_dic, output) return bin_an_dic -def __parse_binskim(bin_an_dic, output): - """Parse output to results and warnings""" +def parse_binskim(bin_an_dic, output): + """Parse output to results and warnings.""" current_run = output['runs'][0] if 'results' in current_run: rules = output['runs'][0]['rules'] for res in current_run['results']: - if res['level'] != "pass": + if res['level'] != 'pass': result = { - "rule_id": res['ruleId'], - "status": "Insecure", - "desc": rules[res['ruleId']]['shortDescription'] + 'rule_id': res['ruleId'], + 'status': 'Insecure', + 'desc': rules[res['ruleId']]['shortDescription'], } - if len(res['formattedRuleMessage']["arguments"])>2: - result["info"] = res['formattedRuleMessage']["arguments"][2] + if len(res['formattedRuleMessage']['arguments']) > 2: + result['info'] = res[ + 'formattedRuleMessage']['arguments'][2] else: - result["info"] = "" + result['info'] = '' else: result = { - "rule_id": res['ruleId'], - "status": "Secure", - "desc": rules[res['ruleId']]['shortDescription'] + 'rule_id': res['ruleId'], + 'status': 'Secure', + 'desc': rules[res['ruleId']]['shortDescription'], } bin_an_dic['results'].append(result) else: - logger.warning("binskim has no results.") + logger.warning('binskim has no results.') # Create an warining for the gui warning = { - "rule_id": "No Binskim-Results", - "status": "Info", - "desc": "No results from Binskim." + 'rule_id': 'No Binskim-Results', + 'status': 'Info', + 'desc': 'No results from Binskim.', } bin_an_dic['warnings'].append(warning) if 'configurationNotifications' in current_run: for warn in current_run['configurationNotifications']: warning = { - "rule_id": warn['ruleId'], - "status": "Info", - "desc": warn['message'] + 'rule_id': warn['ruleId'], + 'status': 'Info', + 'desc': warn['message'], } bin_an_dic['warnings'].append(warning) @@ -429,9 +438,11 @@ def __parse_binskim(bin_an_dic, output): return bin_an_dic -def __binscope(name, bin_an_dic, run_local=False, app_dir=None): +def binscope(name, bin_an_dic, run_local=False, app_dir=None): """Run the binskim analysis.""" - logger.info("Running binscope. This might take a while, depending on the binary size.") + logger.info( + 'Running binscope. This might take a' + ' while, depending on the binary size.') if run_local: global config bin_path = os.path.join(app_dir, bin_an_dic['bin']) @@ -439,8 +450,8 @@ def __binscope(name, bin_an_dic, run_local=False, app_dir=None): # Set params for execution of binskim binscope_path = [config['binscope']['file']] target = [bin_path] - out_type = ["/Red", "/v"] - output = ["/l", target[0] + "_binscope"] + out_type = ['/Red', '/v'] + output = ['/l', target[0] + '_binscope'] checks = [ '/Checks', 'ATLVersionCheck', '/Checks', 'ATLVulnCheck', @@ -464,11 +475,11 @@ def __binscope(name, bin_an_dic, run_local=False, app_dir=None): # Assemble params = ( - binscope_path + - target + - out_type + - output + - checks + binscope_path + + target + + out_type + + output + + checks ) # Execute process @@ -485,37 +496,38 @@ def __binscope(name, bin_an_dic, run_local=False, app_dir=None): res = response[response.find('<'):] config = etree.XMLParser( # pylint: disable-msg=E1101 remove_blank_text=True, - resolve_entities=False + resolve_entities=False, ) - xml_file = etree.XML(bytes(res, "utf-8", "ignore"), config) # pylint: disable-msg=E1101 + xml_file = etree.XML(bytes(res, 'utf-8', 'ignore'), + config) # pylint: disable-msg=E1101 for item in xml_file.find('items').getchildren(): if item.find('issueType') is not None: res = item.find('result').text if res == 'PASS': - status = "Secure" + status = 'Secure' try: desc = item.find('Information').text except AttributeError: - desc = "No description provided by analysing tool." + desc = 'No description provided by analysing tool.' elif res == 'FAIL': - status = "Insecure" + status = 'Insecure' if item.find('Failure1') is not None: desc = item.find('Failure1').text elif item.find('Information') is not None: desc = item.find('Information').text elif item.find('diagnostic') is not None: - status = "Info" + status = 'Info' desc = item.find('diagnostic').text else: - desc = "No description provided by analysing tool." + desc = 'No description provided by analysing tool.' result = { - "rule_id": item.find('issueType').text, - "status": status, - "desc": desc + 'rule_id': item.find('issueType').text, + 'status': status, + 'desc': desc, } bin_an_dic['results'].append(result) @@ -524,8 +536,8 @@ def __binscope(name, bin_an_dic, run_local=False, app_dir=None): def _parse_xml(app_dir): """Parse the AppxManifest file to get basic informations.""" - logger.info("Starting Binary Analysis - XML") - xml_file = os.path.join(app_dir, "AppxManifest.xml") + logger.info('Starting Binary Analysis - XML') + xml_file = os.path.join(app_dir, 'AppxManifest.xml') xml_dic = { 'version': '', 'arch': '', @@ -538,53 +550,55 @@ def _parse_xml(app_dir): 'appx_dll_version': '', 'proj_guid': '', 'opti_tool': '', - 'target_run': '' + 'target_run': '', } try: - logger.info("Reading AppxManifest") + logger.info('Reading AppxManifest') config = etree.XMLParser( # pylint: disable-msg=E1101 remove_blank_text=True, - resolve_entities=False + resolve_entities=False, ) - xml = etree.XML(open(xml_file, "rb").read(), + xml = etree.XML(open(xml_file, 'rb').read(), config) # pylint: disable-msg=E1101 for child in xml.getchildren(): # } to prevent conflict with PhoneIdentity.. - if isinstance(child.tag, str) and child.tag.endswith("}Identity"): - xml_dic['version'] = child.get("Version") - xml_dic['arch'] = child.get("ProcessorArchitecture") - elif isinstance(child.tag, str) and child.tag.endswith("Properties"): + if isinstance(child.tag, str) and child.tag.endswith('}Identity'): + xml_dic['version'] = child.get('Version') + xml_dic['arch'] = child.get('ProcessorArchitecture') + elif (isinstance(child.tag, str) + and child.tag.endswith('Properties')): for sub_child in child.getchildren(): - if sub_child.tag.endswith("}DisplayName"): + if sub_child.tag.endswith('}DisplayName'): # TODO(Needed? Compare to existing app_name) xml_dic['app_name'] = sub_child.text - elif sub_child.tag.endswith("}PublisherDisplayName"): + elif sub_child.tag.endswith('}PublisherDisplayName'): xml_dic['pub_name'] = sub_child.text - elif isinstance(child.tag, str) and child.tag.endswith("}Metadata"): - xml_dic = __parse_xml_metadata(xml_dic, child) - except: - PrintException("Reading from AppxManifest.xml") + elif (isinstance(child.tag, str) + and child.tag.endswith('}Metadata')): + xml_dic = parse_xml_metadata(xml_dic, child) + except Exception: + log_exception('Reading from AppxManifest.xml') return xml_dic -def __parse_xml_metadata(xml_dic, xml_node): +def parse_xml_metadata(xml_dic, xml_node): """Return the XML Metadata.""" for child in xml_node.getchildren(): - if child.get('Name') == "cl.exe": + if child.get('Name') == 'cl.exe': xml_dic['compiler_version'] = child.get('Version') - elif child.get('Name') == "VisualStudio": + elif child.get('Name') == 'VisualStudio': xml_dic['visual_studio_version'] = child.get('Version') - elif child.get('Name') == "VisualStudioEdition": + elif child.get('Name') == 'VisualStudioEdition': xml_dic['visual_studio_edition'] = child.get('Value') - elif child.get('Name') == "OperatingSystem": + elif child.get('Name') == 'OperatingSystem': xml_dic['target_os'] = child.get('Version') - elif child.get('Name') == "Microsoft.Build.AppxPackage.dll": + elif child.get('Name') == 'Microsoft.Build.AppxPackage.dll': xml_dic['appx_dll_version'] = child.get('Version') - elif child.get('Name') == "ProjectGUID": + elif child.get('Name') == 'ProjectGUID': xml_dic['proj_guid'] = child.get('Value') - elif child.get('Name') == "OptimizingToolset": + elif child.get('Name') == 'OptimizingToolset': xml_dic['opti_tool'] = child.get('Value') - elif child.get('Name') == "TargetRuntime": + elif child.get('Name') == 'TargetRuntime': xml_dic['target_run'] = child.get('Value') return xml_dic diff --git a/install/windows/rpc_client.py b/install/windows/rpc_client.py index 19be4756..dd6e54f7 100755 --- a/install/windows/rpc_client.py +++ b/install/windows/rpc_client.py @@ -1,16 +1,15 @@ """MobSF rpc_client for static windows app analysis.""" -# pylint: disable=C0325,W0603,C0103 -import os -from os.path import expanduser -import re -import subprocess -import configparser # pylint: disable-msg=E0401 -import hashlib -import random -import string import base64 - -from xmlrpc.server import SimpleXMLRPCServer # pylint: disable-msg=E0401 +import configparser # pylint: disable-msg=E0401 +import hashlib +import os +import random +# pylint: disable=C0325,W0603,C0103 +import re +import string +import subprocess +from os.path import expanduser +from xmlrpc.server import SimpleXMLRPCServer # pylint: disable-msg=E0401 import rsa @@ -22,49 +21,53 @@ pub_key = None def _init_key(): global pub_key pub_key = rsa.PublicKey.load_pkcs1( - open(config['MobSF']['pub_key']).read() - ) + open(config['MobSF']['pub_key']).read()) def _check_challenge(signature): signature = base64.b64decode(signature.data) try: rsa.verify(challenge.encode('utf-8'), signature, pub_key) - print("[*] Challenge successfully verified.") + print('[*] Challenge successfully verified.') _revoke_challenge() except rsa.pkcs1.VerificationError: - print("[!] Received wrong signature for challenge.") - raise Exception("Access Denied.") + print('[!] Received wrong signature for challenge.') + raise Exception('Access Denied.') except (TypeError, AttributeError): - print("[!] Challenge already unset.") - raise Exception("Access Denied.") + print('[!] Challenge already unset.') + raise Exception('Access Denied.') def _revoke_challenge(): - """Revoke the challenge (to prevent replay attacks)""" + """Revoke the challenge (to prevent replay attacks).""" global challenge challenge = None def get_challenge(): - """Return an ascii challenge to validate authentication in _check_challenge.""" + """Get challenge. + + Return an ascii challenge to validate + authentication in _check_challenge. + """ global challenge # Not using os.urandom for Python 2/3 transfer errors challenge = ''.join( - random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(256) + random.SystemRandom().choice( + string.ascii_uppercase + string.digits) for _ in range(256) ) - return "{}".format(challenge) + return '{}'.format(challenge) def test_challenge(signature): """Test function to check if rsa is working.""" _check_challenge(signature) - print("Check complete") - return "OK!" + print('Check complete') + return 'OK!' + def upload_file(sample_file, signature): """Upload a file.""" - # Check challenge _check_challenge(signature) @@ -76,10 +79,7 @@ def upload_file(sample_file, signature): with open( os.path.join( config['MobSF']['samples'], - md5.hexdigest() - ), - "wb" - ) as handle: + md5.hexdigest()), 'wb') as handle: handle.write(sample_file.data) # Return md5 as reference to the sample @@ -87,24 +87,23 @@ def upload_file(sample_file, signature): def binskim(sample, signature): - """Perform an static analysis on the sample and return the json""" - + """Perform an static analysis on the sample and return the json.""" # Check challenge _check_challenge(signature) # Check if param is a md5 to prevent attacks (we only use lower-case) - if len(re.findall(r"([a-f\d]{32})", sample)) == 0: - return "Wrong Input!" + if len(re.findall(r'([a-f\d]{32})', sample)) == 0: + return 'Wrong Input!' # Set params for execution of binskim binskim_path = config['binskim']['file_x64'] - command = "analyze" + command = 'analyze' path = config['MobSF']['samples'] + sample - output_p = "-o" - output_d = config['MobSF']['samples'] + sample + "_binskim" - verbose = "-v" - policy_p = "--config" - policy_d = "default" # TODO(Other policies?) + output_p = '-o' + output_d = config['MobSF']['samples'] + sample + '_binskim' + verbose = '-v' + policy_p = '--config' + policy_d = 'default' # TODO(Other policies?) # Assemble params = [ @@ -113,7 +112,7 @@ def binskim(sample, signature): path, output_p, output_d, verbose, - policy_p, policy_d + policy_p, policy_d, ] # Execute process @@ -127,7 +126,6 @@ def binskim(sample, signature): def binscope(sample, signature): """Run binscope against an sample file.""" - # Check challenge _check_challenge(signature) @@ -135,8 +133,8 @@ def binscope(sample, signature): binscope_path = [config['binscope']['file']] target = [config['MobSF']['samples'] + sample] - out_type = ["/Red", "/v"] - output = ["/l", target[0] + "_binscope"] + out_type = ['/Red', '/v'] + output = ['/l', target[0] + '_binscope'] checks = [ '/Checks', 'ATLVersionCheck', '/Checks', 'ATLVulnCheck', @@ -159,11 +157,11 @@ def binscope(sample, signature): ] # Assemble params = ( - binscope_path + - target + - out_type + - output + - checks + binscope_path + + target + + out_type + + output + + checks ) # Execute process @@ -179,15 +177,15 @@ if __name__ == '__main__': # Init configparser config = configparser.ConfigParser() - config.read(expanduser("~") + "\\MobSF\\Config\\config.txt") + config.read(expanduser('~') + '\\MobSF\\Config\\config.txt') _init_key() - server = SimpleXMLRPCServer(("0.0.0.0", 8000)) - print("Listening on port 8000...") - server.register_function(get_challenge, "get_challenge") - server.register_function(test_challenge, "test_challenge") - server.register_function(upload_file, "upload_file") - server.register_function(binskim, "binskim") - server.register_function(binscope, "binscope") + server = SimpleXMLRPCServer(('0.0.0.0', 8000)) + print('Listening on port 8000...') + server.register_function(get_challenge, 'get_challenge') + server.register_function(test_challenge, 'test_challenge') + server.register_function(upload_file, 'upload_file') + server.register_function(binskim, 'binskim') + server.register_function(binscope, 'binscope') server.serve_forever() diff --git a/install/windows/setup.py b/install/windows/setup.py index f189b910..276b784a 100755 --- a/install/windows/setup.py +++ b/install/windows/setup.py @@ -1,12 +1,18 @@ -"""Setup script for the Windows vm for usage with MobSF for static analysis of Windows apps.""" +"""Static Analysis Setup Windows. + +Setup script for the Windows vm for usage with MobSF for +static analysis of Windows apps. +""" +import configparser +import logging import os -from os.path import expanduser import platform import re import shutil import subprocess import sys -import logging +from os.path import expanduser + from six.moves import input try: @@ -14,7 +20,6 @@ try: except ImportError: import urllib as urlrequest -import configparser logger = logging.getLogger(__name__) @@ -22,38 +27,38 @@ logger = logging.getLogger(__name__) # Only static URL, let's hope this never changes.. CONFIG_URL = ( - "https://raw.githubusercontent.com/MobSF/" - "Mobile-Security-Framework-MobSF/master/install/windows/config.txt" + 'https://raw.githubusercontent.com/MobSF/' + 'Mobile-Security-Framework-MobSF/master/install/windows/config.txt' ) # Static path to config file as a starting point -CONFIG_PATH = expanduser("~") + "\\MobSF\\Config\\" -CONFIG_FILE = "config.txt" +CONFIG_PATH = expanduser('~') + '\\MobSF\\Config\\' +CONFIG_FILE = 'config.txt' # Static path to autostart AUTOSTART = ( - "C:\\Users\\{}\\AppData\\Roaming\\Microsoft\\" - "Windows\\Start Menu\\Programs\\Startup\\".format(os.getenv('username')) + 'C:\\Users\\{}\\AppData\\Roaming\\Microsoft\\' + 'Windows\\Start Menu\\Programs\\Startup\\'.format(os.getenv('username')) ) # Global var so we don't have to pass it every time.. -CONFIG = "" +CONFIG = '' def windows_config_local(path): - """Windows Configuration""" + """Windows Configuration.""" # Configure here if you are on windows # Path to lock-file (so setup is only run once) - path_to_lock_file = os.path.join(path, "setup_done.txt") - if (os.path.isfile(path_to_lock_file) is False) and platform.system() == 'Windows': - logger.info("Running first time setup for windows.") + path_to_lock_file = os.path.join(path, 'setup_done.txt') + if (os.path.isfile(path_to_lock_file) is False + and platform.system() == 'Windows'): + logger.info('Running first time setup for windows.') # Setup is to-be-executed install_locally(path) def download_config(): """Download initial config file.""" - # Create config path if not os.path.exists(CONFIG_PATH): os.makedirs(CONFIG_PATH) @@ -64,14 +69,14 @@ def download_config(): # TODO(Give user time to modify config, but mayber after rewrite?) # Open File - conf_file_local = open(CONFIG_PATH + CONFIG_FILE, "wb") + conf_file_local = open(CONFIG_PATH + CONFIG_FILE, 'wb') # Downloading File - print("[*] Downloading config file..") + print('[*] Downloading config file..') conf_file = urlrequest.urlopen(CONFIG_URL) # pylint: disable-msg=E1101 # Save content - print(("[*] Saving to File {}".format(CONFIG_FILE))) + print(('[*] Saving to File {}'.format(CONFIG_FILE))) # Write content to file conf_file_local.write(bytes(conf_file.read())) @@ -82,8 +87,7 @@ def download_config(): def read_config(): """Read the config file and write it to the global var.""" - - print("[*] Reading config file..") + print('[*] Reading config file..') global CONFIG CONFIG = configparser.ConfigParser() @@ -92,8 +96,7 @@ def read_config(): def create_folders(): """Create MobSF dirs.""" - - print("[*] Creating other folders...") + print('[*] Creating other folders...') if not os.path.exists(CONFIG['MobSF']['downloads']): os.makedirs(CONFIG['MobSF']['downloads']) @@ -110,23 +113,22 @@ def create_folders(): def check_dependencies(): """Check dependencies and install if necessary.""" - - print("[*] Checking dependencies...") + print('[*] Checking dependencies...') missing_deps = [] try: - import rsa - print("[+] rsa is installed.") + import rsa # noqa F401 + print('[+] rsa is installed.') except ImportError: # pylint: disable-msg=C0103 - print("[!] rsa not installed!") - missing_deps.append("rsa") + print('[!] rsa not installed!') + missing_deps.append('rsa') if len(missing_deps) > 0: - print("[!] Please install these missing dependencies:") + print('[!] Please install these missing dependencies:') print(missing_deps) sys.exit() else: - print("[+] Everything good.") + print('[+] Everything good.') def tools_nuget(): @@ -138,14 +140,14 @@ def tools_nuget(): # Open File nuget_file_local = open(os.path.join( - mobsf_subdir_tools, nuget_file_path), "wb") + mobsf_subdir_tools, nuget_file_path), 'wb') # Downloading File - print("[*] Downloading nuget..") + print('[*] Downloading nuget..') nuget_file = urlrequest.urlopen(nuget_url) # pylint: disable-msg=E1101 # Save content - print(("[*] Saving to File {}".format(nuget_file_path))) + print(('[*] Saving to File {}'.format(nuget_file_path))) # Write content to file nuget_file_local.write(bytes(nuget_file.read())) @@ -161,24 +163,21 @@ def tools_binskim(): mobsf_subdir_tools = CONFIG['MobSF']['tools'] nuget = mobsf_subdir_tools + CONFIG['nuget']['file'] - print("[*] Downloading and installing Binskim...") + print('[*] Downloading and installing Binskim...') # Execute nuget to get binkim output = subprocess.check_output( [ nuget, - "install", binskim_nuget, '-Pre', - '-o', mobsf_subdir_tools - ] - ) + 'install', binskim_nuget, '-Pre', + '-o', mobsf_subdir_tools]) # Some code to determine the version on the fly so we don't have to fix the # config file on every new release of binskim.. # Search for the version number folder = re.search( - b"Microsoft\.CodeAnalysis\.BinSkim\..*('|\") ", output # pylint: disable-msg=W1401 - ) + b'Microsoft\\.CodeAnalysis\\.BinSkim\\..*(\'|\") ', output) try: # Substring-Foo for removing b'X's in python3 if sys.version_info.major == 3: @@ -186,17 +185,17 @@ def tools_binskim(): else: folder = folder.group(0)[:-2] except AttributeError: - print("[!] Unable to parse folder from binskim nuget installation.") + print('[!] Unable to parse folder from binskim nuget installation.') sys.exit() # Search for the exes binaries = _find_exe(mobsf_subdir_tools + folder, []) if len(binaries) != 2: - print("[!] Found more than 2 exes for binskim, panic!") + print('[!] Found more than 2 exes for binskim, panic!') sys.exit() # Determinde which one is for which arch - if "x86" in binaries[0]: + if 'x86' in binaries[0]: CONFIG['binskim']['file_x86'] = binaries[0] CONFIG['binskim']['file_x64'] = binaries[1] else: @@ -212,10 +211,10 @@ def _find_exe(path, exe_list): """Return a list of all exes in path, recursive.""" for filename in os.listdir(path): if os.path.isfile(os.path.join(path, filename)): - if ".exe" in filename: - exe_list.append(path + "\\" + filename) + if '.exe' in filename: + exe_list.append(path + '\\' + filename) else: - exe_list = _find_exe(path + "\\" + filename, exe_list) + exe_list = _find_exe(path + '\\' + filename, exe_list) return exe_list @@ -226,14 +225,14 @@ def tools_rpcclient(): rpc_file_path = CONFIG['rpc']['file'] # Open File - rpc_local_file = open(mobsf_subdir_tools + rpc_file_path, "wb") + rpc_local_file = open(mobsf_subdir_tools + rpc_file_path, 'wb') # Downloading File - print("[*] Downloading rpc_server..") + print('[*] Downloading rpc_server..') rpc_file = urlrequest.urlopen(rpc_url) # Save content - print(("[*] Saving to File {}".format(rpc_file_path))) + print(('[*] Saving to File {}'.format(rpc_file_path))) # Write content to file rpc_local_file.write(bytes(rpc_file.read())) @@ -243,30 +242,29 @@ def tools_rpcclient(): def tools_binscope(): - """Download and install Binscope for MobSF""" - + """Download and install Binscope for MobSF.""" mobsf_subdir_tools = CONFIG['MobSF']['tools'] binscope_path = mobsf_subdir_tools + 'BinScope' # Download the right version for os if platform.machine().endswith('64'): binscope_url = CONFIG['binscope']['url_x64'] - binscope_installer_path = binscope_path + "\\BinScope_x64.msi" + binscope_installer_path = binscope_path + '\\BinScope_x64.msi' else: binscope_url = CONFIG['binscope']['url_x86'] - binscope_installer_path = binscope_path + "\\BinScope_x86.msi" + binscope_installer_path = binscope_path + '\\BinScope_x86.msi' if not os.path.exists(binscope_path): os.makedirs(binscope_path) - binscope_installer_file = open(binscope_installer_path, "wb") + binscope_installer_file = open(binscope_installer_path, 'wb') # Downloading File - print("[*] Downloading BinScope..") + print('[*] Downloading BinScope..') binscope_installer = urlrequest.urlopen(binscope_url) # Save content - print(("[*] Saving to File {}".format(binscope_installer_path))) + print(('[*] Saving to File {}'.format(binscope_installer_path))) # Write content to file binscope_installer_file.write(bytes(binscope_installer.read())) @@ -275,15 +273,14 @@ def tools_binscope(): binscope_installer_file.close() # Execute the installer - print(("[*] Installing BinScope to {}".format(binscope_path))) + print(('[*] Installing BinScope to {}'.format(binscope_path))) os.system( 'msiexec' + ' ' - 'INSTALLLOCATION="' + binscope_path + '" ' + - '/i "' + binscope_installer_path + '" ' + - '/passive' - ) + 'INSTALLLOCATION='' + binscope_path + '' ' + + '/i '' + binscope_installer_path + '' ' + + '/passive') - CONFIG['binscope']['file'] = binscope_path + "\\Binscope.exe" + CONFIG['binscope']['file'] = binscope_path + '\\Binscope.exe' # Write to config with open(os.path.join(CONFIG_PATH, CONFIG_FILE), 'w') as configfile: @@ -293,7 +290,7 @@ def tools_binscope(): def generate_secret(): """Generate rsa keys for authentication.""" import rsa - print("[*] Generating secret, please hang on.") + print('[*] Generating secret, please hang on.') # Generate keys, taken from # https://stuvel.eu/python-rsa-doc/usage.html#generating-keys (pubkey, privkey) = rsa.newkeys(2048) @@ -307,41 +304,40 @@ def generate_secret(): pub_key_file.close() print(( - "[!] Please move the private key file\n" - "\t{}\n" - "\tto MobSF to the path specified in settings.py\n" - "\t(default: Mobile-Security-Framework-MobSF/MobSF/windows_vm_priv_key.asc)" + '[!] Please move the private key file\n' + '\t{}\n' + '\tto MobSF to the path specified in settings.py\n' + '\t(default: Mobile-Security-Framework-MobSF/' + 'MobSF/windows_vm_priv_key.asc)' .format(CONFIG['MobSF']['priv_key']) )) - input("Please press any key when done..") + input('Please press any key when done..') def autostart(): """Create the autostart binary and run it.""" - mobsf_subdir_tools = CONFIG['MobSF']['tools'] - rpc_file = CONFIG['rpc']['file'] autostart_file = CONFIG['autostart']['file'] batch_file = AUTOSTART + autostart_file - print("[*] Creating autostart binary...") + print('[*] Creating autostart binary...') # Open file - autostart_file = open(batch_file, "wb") + autostart_file = open(batch_file, 'wb') # Define bat-text text = """ @echo off python {} %* - pause""".format('"' + mobsf_subdir_tools + rpc_file + '"') + pause""".format(""" + mobsf_subdir_tools + rpc_file + """) autostart_file.write(bytes(text, 'utf8')) # Close handle autostart_file.close() - print("[*] Done. Start the server.") + print('[*] Done. Start the server.') - # Execute. Beware the " " because of windows strange paths.. - os.system('"' + batch_file + '"') + # Execute. Beware the ' ' because of windows strange paths.. + os.system(""" + batch_file + """) def _place_lockfile(mobsf_home): @@ -352,24 +348,21 @@ def _place_lockfile(mobsf_home): def local_config(): """Move local config and save paths.""" # Set the CONFIG_PATH - #global CONFIG_PATH - #CONFIG_PATH = config_path - # Create path if it doesn't exist yet if not os.path.exists(CONFIG_PATH): os.makedirs(CONFIG_PATH) # Copy predefined config to MobSF folder shutil.copy( - os.getcwd() + "\\install\\windows\\config.txt", - os.path.join(CONFIG_PATH, CONFIG_FILE) + os.getcwd() + '\\install\\windows\\config.txt', + os.path.join(CONFIG_PATH, CONFIG_FILE), ) def rewrite_local_config(mobsf_home): """For local installation some config-vars need to be rewritten.""" - CONFIG['MobSF']['subdir_tools'] = mobsf_home + \ - "\\StaticAnalyzer\\tools\\windows\\" + CONFIG['MobSF']['subdir_tools'] = (mobsf_home + + '\\StaticAnalyzer\\tools\\windows\\') CONFIG['MobSF']['dir'] = mobsf_home # Write to config @@ -379,9 +372,8 @@ def rewrite_local_config(mobsf_home): def rewrite_config(): """Rewrite the config to take the profile path as the base path.""" - # Take user path as base path - CONFIG['MobSF']['dir'] = expanduser("~") + CONFIG['MobSF']['dir'] + CONFIG['MobSF']['dir'] = expanduser('~') + CONFIG['MobSF']['dir'] # Rewrite config with new base path CONFIG['MobSF']['downloads'] = CONFIG['MobSF'][ @@ -404,18 +396,10 @@ def rewrite_config(): def install_locally(mobsf_home): """Install the MobSF-Utils on the same system as MobSF.""" - # if user_config: - # local_config(mobsf_home, user_config) - # else: - # user_config = os.path.join(mobsf_home + "\\MobSF\\") local_config() - read_config() - # rewrite_local_config(mobsf_home) rewrite_config() create_folders() - # if not os.path.exists(CONFIG['MobSF']['subdir_tools']): - # os.makedirs(CONFIG['MobSF']['subdir_tools']) tools_nuget() tools_binskim() tools_binscope() @@ -436,6 +420,7 @@ def _install_remote(): generate_secret() autostart() -if __name__ == "__main__": + +if __name__ == '__main__': # Gets directly run if setup.py is run on a remote machine _install_remote() diff --git a/manage.py b/manage.py index ac8c9b67..0aa20c21 100755 --- a/manage.py +++ b/manage.py @@ -1,9 +1,10 @@ #!/usr/bin/env python3 +"""Django Manage.""" import os import sys -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MobSF.settings") +if __name__ == '__main__': + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MobSF.settings') from django.core.management import execute_from_command_line diff --git a/scripts/check_android_permissions.py b/scripts/check_android_permissions.py index d05af787..ac29154f 100644 --- a/scripts/check_android_permissions.py +++ b/scripts/check_android_permissions.py @@ -3,34 +3,39 @@ import re import requests + from bs4 import BeautifulSoup as Soup -ANDROID_PERMISSION_DOCS_URL = "https://developer.android.com/reference/android/Manifest.permission" +ANDROID_PERMISSION_DOCS_URL = ('https://developer.android.com/' + 'reference/android/Manifest.permission') response = requests.get(ANDROID_PERMISSION_DOCS_URL) -content = Soup(response.content, "html.parser") +content = Soup(response.content, 'html.parser') online_permissions = {} # grab all the permissions from the online docs permission_divs = content.find_all( - "div", {"data-version-added": re.compile(r'\d*')}) + 'div', {'data-version-added': re.compile(r'\d*')}) for pd in permission_divs: - permission_name = pd.find("h3").contents[0] + permission_name = pd.find('h3').contents[0] if permission_name in ['Constants', 'Manifest.permission']: continue try: protection_level = re.search( r'Protection level\: (\w+)', str(pd)).groups()[0] except AttributeError: - protection_level = "normal" - description = str(pd.find("p").contents[0]).strip() + protection_level = 'normal' + description = str(pd.find('p').contents[0]).strip() online_permissions[permission_name] = [protection_level, - "TODO - fill in short description", description] + 'TODO - fill in short description', + description] # check the permissions we currently have in dvm_permissions.py DVM_PERMISSIONS = {} -eval(compile(open("StaticAnalyzer/views/android/dvm_permissions.py").read(), "", "exec")) +eval(compile(open('StaticAnalyzer/views/android/dvm_permissions.py').read(), + '', + 'exec')) MANIFEST_PERMISSIONS = DVM_PERMISSIONS['MANIFEST_PERMISSION'] for permission_name in online_permissions: diff --git a/scripts/clean.sh b/scripts/clean.sh index 4ed60ce2..6dbc6269 100755 --- a/scripts/clean.sh +++ b/scripts/clean.sh @@ -34,7 +34,7 @@ then find ./ | grep -E "(__pycache__|\.pyo$)" | xargs rm -rf echo 'Deleting temp and log files' rm -rf ./logs/* - rm -rf ./classes-error.zip + rm -rf ./classes* echo 'Deleting DB' rm -rf ./db.sqlite3 echo 'Deleting Secret File' diff --git a/scripts/cloud/cloud_server.py b/scripts/cloud/cloud_server.py index a2d10c23..427b8320 100755 --- a/scripts/cloud/cloud_server.py +++ b/scripts/cloud/cloud_server.py @@ -1,55 +1,58 @@ #!/usr/bin/env python -import tornado.ioloop -import tornado.web -import sqlite3 as lite import datetime import re +import sqlite3 as lite + +import tornado.ioloop +import tornado.web def clean_db(): - """Clean Database""" + """Clean Database.""" con = lite.connect('db.db') with con: cur = con.cursor() tms = datetime.datetime.now() - datetime.timedelta(minutes=5) - cur.execute("DELETE FROM XXE WHERE ts <=?", (tms,)) - cur.execute("DELETE FROM SSRF WHERE ts <=?", (tms,)) + cur.execute('DELETE FROM XXE WHERE ts <=?', (tms,)) + cur.execute('DELETE FROM SSRF WHERE ts <=?', (tms,)) con.commit() def create_db(): - """Create Database""" + """Create Database.""" con = lite.connect('db.db') with con: cur = con.cursor() cur.execute( - "SELECT count(*) FROM sqlite_master WHERE type = 'table' AND name = 'XXE'") + 'SELECT count(*) FROM sqlite_master' + ' WHERE type = \'table\' AND name = \'XXE\'') tbl_exists = cur.fetchone()[0] if tbl_exists == 0: - cur.execute("CREATE TABLE XXE(payload TEXT, ts timestamp)") + cur.execute('CREATE TABLE XXE(payload TEXT, ts timestamp)') con.commit() cur.execute( - "SELECT count(*) FROM sqlite_master WHERE type = 'table' AND name = 'SSRF'") + 'SELECT count(*) FROM sqlite_master' + ' WHERE type = \'table\' AND name = \'SSRF\'') tbl_exists = cur.fetchone()[0] if tbl_exists == 0: - cur.execute("CREATE TABLE SSRF(ip TEXT, ts timestamp)") + cur.execute('CREATE TABLE SSRF(ip TEXT, ts timestamp)') con.commit() class DeleteByIPHandler(tornado.web.RequestHandler): - """Delete SSRF Entry by IP""" + """Delete SSRF Entry by IP.""" def get(self, pp): ip_addr = pp if pp else '' con = lite.connect('db.db') with con: cur = con.cursor() - cur.execute("DELETE FROM SSRF WHERE ip =?", (ip_addr,)) + cur.execute('DELETE FROM SSRF WHERE ip =?', (ip_addr,)) con.commit() class XXECheckHandler(tornado.web.RequestHandler): - """XXE Check""" + """XXE Check.""" def get(self, pp): xxe = pp if pp else '' @@ -58,7 +61,7 @@ class XXECheckHandler(tornado.web.RequestHandler): con = lite.connect('db.db') with con: cur = con.cursor() - cur.execute("SELECT count(*) FROM XXE WHERE payload=?", (xxe,)) + cur.execute('SELECT count(*) FROM XXE WHERE payload=?', (xxe,)) atk_exists = cur.fetchone()[0] if atk_exists == 0: self.write('{"status": "no"}') @@ -67,7 +70,7 @@ class XXECheckHandler(tornado.web.RequestHandler): class SSRFCheckHandler(tornado.web.RequestHandler): - """SSRF Check""" + """SSRF Check.""" def get(self, pp): ip_addr = pp if pp else '' @@ -77,55 +80,59 @@ class SSRFCheckHandler(tornado.web.RequestHandler): if ip_addr == 'ts': # based on timestamp tms = datetime.datetime.now() - datetime.timedelta(seconds=30) - cur.execute("SELECT count(*) FROM SSRF WHERE ts >=?", (tms,)) + cur.execute('SELECT count(*) FROM SSRF WHERE ts >=?', (tms,)) else: # based on ip - cur.execute("SELECT count(*) FROM SSRF WHERE ip=?", (ip_addr,)) + cur.execute('SELECT count(*) FROM SSRF WHERE ip=?', (ip_addr,)) atk_exists = cur.fetchone()[0] if atk_exists == 0: - self.write('{"count": 0}') + self.write('{\'count\': 0}') else: - self.write('{"count": ' + str(atk_exists) + '}') + self.write('{\'count\': \' + str(atk_exists) + \'}') -class XXE_SSRFHandler(tornado.web.RequestHandler): - """XXE and SSRF Handler""" +class XXESSRFHandler(tornado.web.RequestHandler): + """XXE and SSRF Handler.""" def get(self): # SSRF and XXE count based - if self.request.uri == "/": + if self.request.uri == '/': self.remote_ip = self.request.headers.get( - 'X-Forwarded-For', self.request.headers.get('X-Real-Ip', self.request.remote_ip)) + 'X-Forwarded-For', + self.request.headers.get( + 'X-Real-Ip', + self.request.remote_ip)) tms = datetime.datetime.now() con0 = lite.connect('db.db') with con0: cur = con0.cursor() - cur.execute("INSERT INTO SSRF VALUES(?,?)", + cur.execute('INSERT INTO SSRF VALUES(?,?)', (self.remote_ip, tms)) - self.write("ok") + self.write('ok') # XXE and SSRF hash based url tms = datetime.datetime.now() - payload = (str(self.request.uri)[:33]).replace("/", "") + payload = (str(self.request.uri)[:33]).replace('/', '') rmatch = re.match('[0-9a-f]{32}', payload) if rmatch: con = lite.connect('db.db') with con: cur = con.cursor() - cur.execute("INSERT INTO XXE VALUES(?,?)", (payload, tms)) + cur.execute('INSERT INTO XXE VALUES(?,?)', (payload, tms)) self.write(payload) -if __name__ == "__main__": + +if __name__ == '__main__': create_db() tornado.web.Application([ - (r"/ip/(?P[^\/]+)", SSRFCheckHandler), - (r"/delete/(?P[^\/]+)", DeleteByIPHandler), - (r"/md5/(?P[^\/]+)", XXECheckHandler), - (r"/.*", XXE_SSRFHandler), + (r'/ip/(?P[^\/]+)', SSRFCheckHandler), + (r'/delete/(?P[^\/]+)', DeleteByIPHandler), + (r'/md5/(?P[^\/]+)', XXECheckHandler), + (r'/.*', XXESSRFHandler), ]).listen(8080) tornado.ioloop.PeriodicCallback( clean_db, 300000).start() # 15 mins in milliseconds tornado.ioloop.IOLoop.instance().start() - ''' + """ URI 1. XXE and SSRF - http://127.0.0.1:8080/ Check - http://127.0.0.1:8080/md5/ @@ -135,4 +142,4 @@ if __name__ == "__main__": http://127.0.0.1:8080/ip/ts by timestamp 3. Delete by IP http://127.0.0.1:8080/delete/ - ''' + """ diff --git a/scripts/mass_static_analysis.py b/scripts/mass_static_analysis.py index 514a5faa..af19fe33 100755 --- a/scripts/mass_static_analysis.py +++ b/scripts/mass_static_analysis.py @@ -1,12 +1,14 @@ #!/usr/bin/env python # Mass Static Analysis +import argparse +import logging import os -import urllib.request import urllib.error import urllib.parse -import argparse +import urllib.request + import requests -import logging + logger = logging.getLogger(__name__) @@ -20,63 +22,72 @@ def is_server_up(url): def start_scan(directory, server_url, apikey, rescan='0'): - print("\nLooking for Android/iOS/Windows binaries or source code in : " + directory) - logger.info("Uploading to MobSF Server") + print('\nLooking for Android/iOS/' + 'Windows binaries or source code in : ' + directory) + logger.info('Uploading to MobSF Server') uploaded = [] - MIME = { - ".apk": 'application/octet-stream', - ".ipa": 'application/octet-stream', - ".appx": 'application/octet-stream', - ".zip": 'application/zip' + mimes = { + '.apk': 'application/octet-stream', + '.ipa': 'application/octet-stream', + '.appx': 'application/octet-stream', + '.zip': 'application/zip', } for filename in os.listdir(directory): fpath = os.path.join(directory, filename) _, ext = os.path.splitext(fpath) - if ext in MIME: + if ext in mimes: files = {'file': (filename, open(fpath, 'rb'), - MIME[ext], {'Expires': '0'})} + mimes[ext], {'Expires': '0'})} response = requests.post( - server_url + '/api/v1/upload', files=files, headers={'AUTHORIZATION': apikey}) - if response.status_code == 200 and "hash" in response.json(): - logger.info("[OK] Upload OK: " + filename) + server_url + '/api/v1/upload', + files=files, + headers={'AUTHORIZATION': apikey}) + if response.status_code == 200 and 'hash' in response.json(): + logger.info('[OK] Upload OK: %s'. filename) uploaded.append(response.json()) else: - logger.error("Performing Upload: " + filename) + logger.error('Performing Upload: %s', filename) - logger.info("Running Static Analysis") + logger.info('Running Static Analysis') for upl in uploaded: - logger.info("Started Static Analysis on: %s", upl["file_name"]) + logger.info('Started Static Analysis on: %s', upl['file_name']) if rescan == '1': - upl["re_scan"] = 1 + upl['re_scan'] = 1 response = requests.post( - server_url + "/api/v1/scan", data=upl, headers={'AUTHORIZATION': apikey}) + server_url + '/api/v1/scan', + data=upl, + headers={'AUTHORIZATION': apikey}) if response.status_code == 200: - logger.info("[OK] Static Analysis Complete: " + upl["file_name"]) + logger.info('[OK] Static Analysis Complete: %s', upl['file_name']) else: - logger.error("Performing Static Analysis: " + upl["file_name"]) + logger.error('Performing Static Analysis: %s', upl['file_name']) -if __name__ == "__main__": +if __name__ == '__main__': parser = argparse.ArgumentParser() - parser.add_argument("-d", "--directory", - help="Path to the directory that contains mobile app binary/zipped source code") + parser.add_argument('-d', '--directory', + help='Path to the directory that contains ' + 'mobile app binary/zipped source code') parser.add_argument( - "-s", "--ipport", help="IP address and Port number of a running MobSF Server. (ex: 127.0.0.1:8000)") + '-s', '--ipport', help='IP address and Port number ' + 'of a running MobSF Server. ' + '(ex: 127.0.0.1:8000)') parser.add_argument( - "-k", "--apikey", help="MobSF REST API Key") + '-k', '--apikey', help='MobSF REST API Key') parser.add_argument( - "-r", "--rescan", help="Run a fresh scan. Value can be 1 or 0 (Default: 0)") + '-r', '--rescan', help='Run a fresh scan. ' + 'Value can be 1 or 0 (Default: 0)') args = parser.parse_args() if args.directory and args.ipport and args.apikey: server = args.ipport directory = args.directory - server_url = "http://" + server + server_url = 'http://' + server apikey = args.apikey rescan = args.rescan - if is_server_up(server_url) == False: - print("MobSF REST API Server is not running at " + server_url) - print("Exiting!") + if not is_server_up(server_url): + print('MobSF REST API Server is not running at ' + server_url) + print('Exiting!') exit(0) # MobSF is running, start scan start_scan(directory, server_url, apikey, rescan) diff --git a/scripts/mobsfy.py b/scripts/mobsfy.py index aea52b89..01b80bf7 100755 --- a/scripts/mobsfy.py +++ b/scripts/mobsfy.py @@ -1,78 +1,73 @@ #!/usr/bin/env python # -*- coding: utf_8 -*- -""" -Script to create MobSF Dynamic Analysis Environment -""" +"""Script to create MobSF Dynamic Analysis Environment.""" +import argparse +import logging import os import platform import subprocess import sys -import argparse + import capfuzz as cp -import logging + logger = logging.getLogger(__name__) BASE_DIR = os.path.dirname(os.path.realpath(__file__)) TOOLSDIR = os.path.join(BASE_DIR, '../DynamicAnalyzer/tools/') # TOOLS DIR -ROOTCA = os.path.join(os.path.dirname(cp.__file__), "ca", "mitmproxy-ca-cert.cer") -TYPE_VM = "1" -XPOSED_OLD = "1" +ROOTCA = os.path.join(os.path.dirname(cp.__file__), + 'ca', 'mitmproxy-ca-cert.cer') +TYPE_VM = '1' +XPOSED_OLD = '1' def execute_cmd(args, ret=False): - """ - Execute Commands - """ + """Execute Commands.""" try: - logger.info("Executing Command - " + ' '.join(args)) + logger.info('Executing Command - %s', ' '.join(args)) if ret: return subprocess.check_output(args) else: subprocess.call(args) - except Exception as exp: - logger.error(("Executing Command - " + str(exp))) + except Exception: + logger.error('Error Executing Command') def get_adb(): - """ - Get ADB Location - """ + """Get ADB Location.""" try: adb = 'adb' - if platform.system() == "Darwin": + if platform.system() == 'Darwin': adb_dir = os.path.join(TOOLSDIR, 'adb/mac/') - subprocess.call(["chmod", "777", adb_dir]) + subprocess.call(['chmod', '777', adb_dir]) adb = os.path.join(TOOLSDIR, 'adb/mac/adb') - elif platform.system() == "Linux": + elif platform.system() == 'Linux': adb_dir = os.path.join(TOOLSDIR, 'adb/linux/') - subprocess.call(["chmod", "777", adb_dir]) + subprocess.call(['chmod', '777', adb_dir]) adb = os.path.join(TOOLSDIR, 'adb/linux/adb') - elif platform.system() == "Windows": + elif platform.system() == 'Windows': adb = os.path.join(TOOLSDIR, 'adb/windows/adb.exe') return adb except Exception as exp: - logger.error(("Getting ADB Location - " + str(exp))) - return "adb" + logger.error(('Getting ADB Location - %s', str(exp))) + return 'adb' def main(): - """ - Main of Script - """ - print("\nMobSFy Script\n\nThis script allows you to configure any rooted " - "android Device or VM to perfrom MobSF dynamic analysis.\n" - "(Supports Android Version 4.03 to 4.4)") + """Main of Script.""" + print('\nMobSFy Script\n\nThis script allows you to configure any rooted ' + 'android Device or VM to perfrom MobSF dynamic analysis.\n' + '(Supports Android Version 4.03 to 4.4)') parser = argparse.ArgumentParser() - parser.add_argument("-i", "--identifier", - help="IP:PORT or Serial no of Device/VM." - " (ex: 192.168.1.2:5555)") + parser.add_argument('-i', '--identifier', + help='IP:PORT or Serial no of Device/VM.' + ' (ex: 192.168.1.2:5555)') parser.add_argument( - "-t", "--type", help="Specify the type. Supported types are" - " 1. VM or 2.Device. (ex: 1)") + '-t', '--type', help='Specify the type. Supported types are' + ' 1. VM or 2.Device. (ex: 1)') parser.add_argument( - "-v", "--version", help="Specify the Android Version. " - "Available options are 1. <5 or 2. >=5. (ex: 1)") + '-v', '--version', help='Specify the Android Version. ' + 'Available options are 1. <5 or 2. >=5. (ex: 1)') args = parser.parse_args() try: if args.identifier and args.type: @@ -81,27 +76,27 @@ def main(): xposed_ver = args.version else: adbconnect = input( - "Enter the IP:PORT or Serial no of the Device/VM" - " (Ex: 192.168.1.2:5555) and press enter: ") - vm_or_ip = input("Choose\n 1. VM\n 2. Device\nEnter your choice: ") + 'Enter the IP:PORT or Serial no of the Device/VM' + ' (Ex: 192.168.1.2:5555) and press enter: ') + vm_or_ip = input('Choose\n 1. VM\n 2. Device\nEnter your choice: ') xposed_ver = input( - "Android Version\n1. <5\n2. >=5\nEnter your choice: ") - execute_cmd([get_adb(), "kill-server"]) - execute_cmd([get_adb(), "start-server"]) - execute_cmd([get_adb(), "connect", adbconnect]) - execute_cmd([get_adb(), "-s", adbconnect, "wait-for-device"]) + 'Android Version\n1. <5\n2. >=5\nEnter your choice: ') + execute_cmd([get_adb(), 'kill-server']) + execute_cmd([get_adb(), 'start-server']) + execute_cmd([get_adb(), 'connect', adbconnect]) + execute_cmd([get_adb(), '-s', adbconnect, 'wait-for-device']) # Install MITM RootCA - execute_cmd([get_adb(), "-s", adbconnect, "push", - ROOTCA, "/data/local/tmp/0025aabb.0"]) - execute_cmd([get_adb(), "-s", adbconnect, "shell", "su", "-c", - "mount", "-o", "rw,remount,rw", "/system"]) - execute_cmd([get_adb(), "-s", adbconnect, "shell", "su", "-c", "cp", - "/data/local/tmp/0025aabb.0", - "/system/etc/security/cacerts/0025aabb.0"]) - execute_cmd([get_adb(), "-s", adbconnect, "shell", "su", "-c", "chmod", - "644", "/system/etc/security/cacerts/0025aabb.0"]) - execute_cmd([get_adb(), "-s", adbconnect, "shell", - "rm", "/data/local/tmp/0025aabb.0"]) + execute_cmd([get_adb(), '-s', adbconnect, 'push', + ROOTCA, '/data/local/tmp/0025aabb.0']) + execute_cmd([get_adb(), '-s', adbconnect, 'shell', 'su', '-c', + 'mount', '-o', 'rw,remount,rw', '/system']) + execute_cmd([get_adb(), '-s', adbconnect, 'shell', 'su', '-c', 'cp', + '/data/local/tmp/0025aabb.0', + '/system/etc/security/cacerts/0025aabb.0']) + execute_cmd([get_adb(), '-s', adbconnect, 'shell', 'su', '-c', 'chmod', + '644', '/system/etc/security/cacerts/0025aabb.0']) + execute_cmd([get_adb(), '-s', adbconnect, 'shell', + 'rm', '/data/local/tmp/0025aabb.0']) # Install MobSF requirements data_pusher = os.path.join(TOOLSDIR, 'onDevice/DataPusher.apk') screen_cast = os.path.join(TOOLSDIR, 'onDevice/ScreenCast.apk') @@ -123,56 +118,56 @@ def main(): fake_cpuinfo = os.path.join(TOOLSDIR, 'onDevice/antivm/fake-cpuinfo') fake_drivers = os.path.join(TOOLSDIR, 'onDevice/antivm/fake-drivers') - logger.info("Installing MobSF DataPusher") - execute_cmd([get_adb(), "-s", adbconnect, - "install", "-r", data_pusher]) - logger.info("Installing MobSF ScreenCast") - execute_cmd([get_adb(), "-s", adbconnect, - "install", "-r", screen_cast]) - logger.info("Installing MobSF Clipboard Dumper") - execute_cmd([get_adb(), "-s", adbconnect, "install", "-r", clip_dump]) - logger.info("Copying hooks.json") - execute_cmd([get_adb(), "-s", adbconnect, - "push", hooks, "/data/local/tmp/"]) - logger.info("Installing Xposed Framework") - execute_cmd([get_adb(), "-s", adbconnect, "install", "-r", xposed]) - logger.info("Installing Droidmon API Analyzer") - execute_cmd([get_adb(), "-s", adbconnect, "install", "-r", droidmon]) - logger.info("Installing JustTrustMe") - execute_cmd([get_adb(), "-s", adbconnect, "install", "-r", justrustme]) - logger.info("Installing RootCloak") - execute_cmd([get_adb(), "-s", adbconnect, "install", "-r", rootcloak]) + logger.info('Installing MobSF DataPusher') + execute_cmd([get_adb(), '-s', adbconnect, + 'install', '-r', data_pusher]) + logger.info('Installing MobSF ScreenCast') + execute_cmd([get_adb(), '-s', adbconnect, + 'install', '-r', screen_cast]) + logger.info('Installing MobSF Clipboard Dumper') + execute_cmd([get_adb(), '-s', adbconnect, 'install', '-r', clip_dump]) + logger.info('Copying hooks.json') + execute_cmd([get_adb(), '-s', adbconnect, + 'push', hooks, '/data/local/tmp/']) + logger.info('Installing Xposed Framework') + execute_cmd([get_adb(), '-s', adbconnect, 'install', '-r', xposed]) + logger.info('Installing Droidmon API Analyzer') + execute_cmd([get_adb(), '-s', adbconnect, 'install', '-r', droidmon]) + logger.info('Installing JustTrustMe') + execute_cmd([get_adb(), '-s', adbconnect, 'install', '-r', justrustme]) + logger.info('Installing RootCloak') + execute_cmd([get_adb(), '-s', adbconnect, 'install', '-r', rootcloak]) if vm_or_ip == TYPE_VM: - logger.info("Installing Android BluePill") - execute_cmd([get_adb(), "-s", adbconnect, - "install", "-r", bluepill]) - logger.info("Copying fake-build.prop") - execute_cmd([get_adb(), "-s", adbconnect, "push", - fake_build, "/data/local/tmp/"]) - logger.info("Copying fake-cpuinfo") - execute_cmd([get_adb(), "-s", adbconnect, "push", - fake_cpuinfo, "/data/local/tmp/"]) - logger.info("Copying fake-drivers") - execute_cmd([get_adb(), "-s", adbconnect, "push", - fake_drivers, "/data/local/tmp/"]) - logger.info("Launching Xposed Framework.") - xposed_installer = ("de.robv.android.xposed.installer/" - "de.robv.android.xposed.installer.WelcomeActivity") - execute_cmd([get_adb(), "-s", adbconnect, "shell", "am", "start", "-n", + logger.info('Installing Android BluePill') + execute_cmd([get_adb(), '-s', adbconnect, + 'install', '-r', bluepill]) + logger.info('Copying fake-build.prop') + execute_cmd([get_adb(), '-s', adbconnect, 'push', + fake_build, '/data/local/tmp/']) + logger.info('Copying fake-cpuinfo') + execute_cmd([get_adb(), '-s', adbconnect, 'push', + fake_cpuinfo, '/data/local/tmp/']) + logger.info('Copying fake-drivers') + execute_cmd([get_adb(), '-s', adbconnect, 'push', + fake_drivers, '/data/local/tmp/']) + logger.info('Launching Xposed Framework.') + xposed_installer = ('de.robv.android.xposed.installer/' + 'de.robv.android.xposed.installer.WelcomeActivity') + execute_cmd([get_adb(), '-s', adbconnect, 'shell', 'am', 'start', '-n', xposed_installer]) if vm_or_ip == TYPE_VM: - print("\n 1 .Install the Framework\n 2. Restart the device\n" - " 3. Enable Android BluePill, Droidmon, " - "JustTrustMe and RootCloak.") + print('\n 1 .Install the Framework\n 2. Restart the device\n' + ' 3. Enable Android BluePill, Droidmon, ' + 'JustTrustMe and RootCloak.') else: - print("\n 1 .Install the Framework\n 2. Restart the device\n " - "3. Enable Droidmon, JustTrustMe and RootCloak.") - logger.info("MobSFy Script Executed Successfully") - except Exception as exp: - logger.error("Error occurred - " + str(exp)) + print('\n 1 .Install the Framework\n 2. Restart the device\n ' + '3. Enable Droidmon, JustTrustMe and RootCloak.') + logger.info('MobSFy Script Executed Successfully') + except Exception: + logger.error('Error occurred') sys.exit(0) -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/scripts/mobsfy_AVD.py b/scripts/mobsfy_AVD.py deleted file mode 100755 index 201dde0d..00000000 --- a/scripts/mobsfy_AVD.py +++ /dev/null @@ -1,318 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf_8 -*- -import os -import platform -import subprocess -import sys -import getpass -import shutil -import io -import string -import re -import logging -logger = logging.getLogger(__name__) -BASE_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../") - - -def get_windows_drive(): - drive = os.getenv('WINDIR')[:1] + ':' - if not drive: - return 'C:' - return drive - - -def print_log(msg, log_type='INFO'): - print('\n[' + log_type + '] ' + msg + '\n') - - -def execute_cmd(args, ret=False): - try: - logger.info("Executing Command - " + ' '.join(args)) - if ret: - return subprocess.check_output(args) - else: - subprocess.call(args) - except Exception as e: - logger.error("Executing Command - " + str(e)) - - -def verify_path(help_msg): - path = input(help_msg + ': ') - path = path.strip() - while not os.path.exists(path): - print_log('Path specified does not exists \ no access', 'ERROR') - path = input(help_msg) - return path - - -def guess_android_avd_folder(): - system = platform.system() - - if system == 'Darwin': - username = getpass.getuser() - first_guess = os.path.join('/Users', username, '.android/avd') - if os.path.exists(first_guess): - return first_guess - - elif system == "Linux": - for path in [os.path.expanduser('~/.android/avd/')]: - if os.path.exists(path): - return path - - elif system == 'Windows': - username = getpass.getuser() - drive = get_windows_drive() - for path in [os.path.join(drive + '\\Documents and Settings', username, '.android\\avd'), - os.path.join(drive + '\\Users', username, '.android\\avd')]: - if os.path.exists(path): - return path - - return False - - -def guess_android_sdk_folder(): - system = platform.system() - username = getpass.getuser() - - if system == 'Darwin': - for path in [os.path.join('/Users', username, 'Library/Android/Sdk/'), - os.path.join('/Users', username, 'Library/Android/sdk/')]: - if os.path.exists(path): - return path - - elif system == "Linux": - for path in ['/usr/local/android-sdk', - '/usr/local/android', - '/usr/local/Android', - os.path.expanduser('~/Android/Sdk'), - os.path.expanduser('~/Android/sdk'), - os.path.expanduser('~/android/Sdk'), - os.path.expanduser('~/android/sdk')]: - if os.path.exists(path): - return path - - elif system == 'Windows': - drive = get_windows_drive() - for path in [os.path.join(drive + '\\Users', username, 'AppData\\Local\\Android\\sdk'), - os.path.join(drive + '\\Users', username, - 'AppData\\Local\\Android\\Sdk'), - os.path.join(drive + '\\Documents and Settings', - username, 'AppData\\Local\\Android\\sdk'), - os.path.join(drive + '\\Documents and Settings', username, 'AppData\\Local\\Android\\Sdk')]: - if os.path.exists(path): - return path - - return False - - -def find_emulator_binary(sdk): - system = platform.system() - - if system in ['Darwin', 'Linux']: - # Prefer emulator folder on tools folder - for path in [os.path.join(sdk, 'emulator', 'emulator'), - os.path.join(sdk, 'tools', 'emulator')]: - if os.path.exists(path): - return path - - elif system == 'Windows': - for path in [os.path.join(sdk, 'emulator', 'emulator.exe'), - os.path.join(sdk, 'tools', 'emulator.exe')]: - if os.path.exists(path): - return path - - return False - - -def find_adb_binary(sdk): - system = platform.system() - - if system in ['Darwin', 'Linux']: - guess = os.path.join(sdk, 'platform-tools', 'adb') - if os.path.exists(guess): - return guess - - elif system == 'Windows': - guess = os.path.join(sdk, 'platform-tools', 'adb.exe') - if os.path.exists(guess): - return guess - - return False - - -def find_skin(sdk): - # Just a basic check - system = platform.system() - - if system == 'Darwin': - guess = r'/Applications/Android Studio.app/Contents/plugins/android/lib/device-art-resources/nexus_5' - if os.path.exists(guess): - return guess - - elif system in ['Windows', 'Linux']: - guess = os.path.join(sdk, 'skins', 'nexus_5') - if os.path.exists(guess): - return guess - - return False - - -def is_file_exists(file_path): - """Check if File Exists""" - return bool(os.path.isfile(file_path)) - - -# returns an array of [str(tabs_string), str(rest_of_the_string)] -def split_tabs(inp_string): - rgx = re.compile(r"([\s]+)(.*)") - match = rgx.match(inp_string) - if match: - return [match.group(1), match.group(2)] - else: - return ['', inp_string] - - -# path to modify, replace dict = {'field_to_replace1':'value1', -# 'field_to_replace2': 'value2'} -def replace_values_by_fieldnames(path, replace_dict): - replaced_lines = [] - with io.open(path, mode='r', encoding="utf8", errors="ignore") as fild: - for line in fild.readlines(): - tmp_line = line - if path.endswith('.py'): - tabs_and_str = split_tabs(line) - for field_to_replace in list(replace_dict.keys()): - # Python files has annoying tabs that we should consider - if path.endswith('.py'): - if tabs_and_str[1].lower().startswith(field_to_replace.lower()): - tmp_line = tabs_and_str[0] + field_to_replace + " = r\"" + replace_dict[ - field_to_replace].strip(" \"'").lstrip("r\"") + "\"\n" - else: - if line.startswith(field_to_replace + '='): - tmp_line = field_to_replace + '=' + \ - replace_dict[field_to_replace].strip() + '\n' - replaced_lines.append(tmp_line) - with io.open(path, 'w') as fild: - # newlines are validated before - fild.write(string.join(replaced_lines, '')) - - -def main(): - sdk_path = '' - avd_path = '' - adb_path = '' - emulator_binary = '' - mobsf_arm_folder = '' - settings_py = '' - - print("\nMobSFy_AVD Script\n\n") - print_log('Starting MobSF - AVD interactive configuration script') - print_log('Make sure to run this script ONLY after you successfuly installed latest AndroidStudio & downloaded MobSF_ARM_Emulator.zip') - - # First gather all the paths needed to make to copy opera - - print_log('Please specify the path to MobSF_ARM_Emulator extracted folder') - mobsf_arm_folder = verify_path('MobSF_ARM_Emulator folder') - - # Give the user the ability to change the sdk and avd folder, let me guess - # the other tools - print_log('This script will overwrite any previously generated files.') - guessd_sdk_path = guess_android_sdk_folder() - if guessd_sdk_path: - user_approve = input( - "Guessing Android sdk path: " + guessd_sdk_path + '\n Press Enter/alternative path') - if user_approve.strip() == '': - sdk_path = guessd_sdk_path - elif os.path.exists(user_approve): - sdk_path = user_approve - if not sdk_path: - sdk_path = verify_path('Android SDK path') - - guessd_avd_path = guess_android_avd_folder() - if guessd_avd_path: - user_approve = input( - "Guessing Android AVD folder: " + guessd_avd_path + '\n Press Enter/alternative path') - if user_approve.strip() == '': - avd_path = guessd_avd_path - elif os.path.exists(user_approve): - avd_path = user_approve - if not avd_path: - avd_path = verify_path('Android AVD path') - - emulator_binary = find_emulator_binary(sdk_path) - if not emulator_binary: - emulator_binary = verify_path('emulator binary') - - adb_path = find_adb_binary(sdk_path) - if not adb_path: - adb_path = verify_path('adb binary') - - settings_py = os.path.join(BASE_DIR, 'MobSF', 'settings.py') - if not os.path.exists(settings_py): - settings_py = verify_path('MobSF/settings.py file') - - skin_path = find_skin(sdk_path) - if not skin_path: - skin_path = verify_path('nexus 5 skin path') - - print_log('Finished finding all the paths needed') - - ################## Copy the downloaded emulator and system image ######### - - emulator_avd = os.path.join(mobsf_arm_folder, 'Nexus5API16.avd') - emulator_ini = os.path.join(mobsf_arm_folder, 'Nexus5API16.ini') - new_emulator_avd = os.path.join(avd_path, 'Nexus5API16.avd') - new_emulator_ini = os.path.join(avd_path, 'Nexus5API16.ini') - print_log('Copying emulator files to avd folder: ' + avd_path) - if is_file_exists(new_emulator_ini): - print_log("Replacing old Emulator INI") - os.remove(new_emulator_ini) - shutil.copyfile(emulator_ini, new_emulator_ini) - if os.path.isdir(new_emulator_avd): - print_log("Replacing old Emulator AVD") - shutil.rmtree(new_emulator_avd) - shutil.copytree(emulator_avd, new_emulator_avd) - system_images = os.path.join(sdk_path, 'system-images') - xposed_image_path = os.path.join(system_images, 'Xposed-android-16') - downloaded_xposed_image = os.path.join( - mobsf_arm_folder, 'Xposed-android-16') - if os.path.isdir(xposed_image_path): - print_log("Replacing old Xposed image") - shutil.rmtree(xposed_image_path) - shutil.copytree(downloaded_xposed_image, xposed_image_path) - - ################## Modify all the config files ########################### - - print_log('Modifying config files') - - # Nexus5API16.ini - replace_values_by_fieldnames(new_emulator_ini, { - 'path': new_emulator_avd, - 'skin.path': skin_path - }) - - # Nexus5API16.avd/config.ini - replace_values_by_fieldnames(os.path.join(new_emulator_avd, 'config.ini'), { - 'skin.path': skin_path - }) - - # Nexus5API16.avd/hardware-qemu.ini - replace_values_by_fieldnames(os.path.join(new_emulator_avd, 'hardware-qemu.ini'), { - 'hw.sdCard.path': os.path.join(new_emulator_avd, 'sdcard.img'), - 'disk.cachePartition.path': os.path.join(new_emulator_avd, 'cache.img'), - 'kernel.path': os.path.join(xposed_image_path, 'kernel-qemu'), - 'disk.ramdisk.path': os.path.join(xposed_image_path, 'ramdisk.img'), - 'disk.systemPartition.initPath': os.path.join(xposed_image_path, 'system.img'), - 'disk.dataPartition.path': os.path.join(new_emulator_avd, 'userdata.img'), - }) - - replace_values_by_fieldnames(settings_py, { - 'AVD_EMULATOR': emulator_binary, - 'AVD_PATH': avd_path, - 'ADB_BINARY': 'r"' + adb_path + '"' - }) - - print("\n\nAll Done! you can now use MobSF AVD Emulator :)\n\n") - -if __name__ == '__main__': - sys.exit(main()) diff --git a/scripts/qcow2.py b/scripts/qcow2.py deleted file mode 100644 index 4f9bfa36..00000000 --- a/scripts/qcow2.py +++ /dev/null @@ -1,87 +0,0 @@ -import os -import traceback -import struct -import logging -logger = logging.getLogger(__name__) -# This is a small wraper to help manipulate the qcow2 system image inside the avd -# For more info please refer to - https://people.gnome.org/~markmc/qcow-image-format.html - - -class Qcow2(): - def __init__(self, path): - self.path = path - self.backing_file_str_offset = 0 - self.backing_file_str_size = 0 - self.BACKING_FILE_HEADER = 8 - self.SIZE_HEADER = 16 - self.tmp_backing_str = '' - - def parse_header(self): - try: - # The backing file string offset & the size of the string are part of the qcow2 header - with open(self.path, 'rb') as read_fd: - - # uint64_t - read_fd.seek(self.BACKING_FILE_HEADER) - raw_offset = read_fd.read(8) - self.backing_file_str_offset = struct.unpack('>q', raw_offset)[0] - - # uint32_t - read_fd.seek(self.SIZE_HEADER) - raw_offset = read_fd.read(4) - self.backing_file_str_size = struct.unpack('>i', raw_offset)[0] - - return True - except: - logger.error("Qcow2-parse_header: \r\n{}".format(traceback.format_exc())) - return None - - def get_backing_file_path_str(self): - try: - if not (self.backing_file_str_offset and self.backing_file_str_size): - logger.error("Qcow2-get_backing_file_path_str: offset and size not initialized, run parse_header first") - return None - - with open(self.path, 'rb') as read_fd: - read_fd.seek(self.backing_file_str_offset) - raw_str = read_fd.read(self.backing_file_str_size) - backing_str = str(raw_str.decode('ascii')).replace('\x00', '') - self.tmp_backing_str = backing_str - return backing_str - except: - logger.error("Qcow2-get_backing_file_path_str: \r\n{}".format(traceback.format_exc())) - return None - - def write_new_system_path_inside_qcow(self, new_system_path): - try: - # Get the length of the path so we could update the header too - system_image_str_len = len(new_system_path) - - # Open in override mode so we don't need to read the whole file just to replace a little string - with open(self.path, 'r+b') as write_fd: - # First let's update the str size in the header - write_fd.seek(self.SIZE_HEADER) - write_fd.write(struct.pack(">i", system_image_str_len)) - - # Write the new system.img path - # There is no termination (we just wrote the size header) - write_fd.seek(self.backing_file_str_offset) - write_fd.write(new_system_path.encode('ascii')) - - # optional - Clean up the left overs from the previous string - # We don't really care about this check so we do it only when we already called get_backing_file_ - # path_str - if self.tmp_backing_str: - if len(self.tmp_backing_str) > system_image_str_len: - zeros_to_append = len(self.tmp_backing_str) - system_image_str_len - write_fd.write(b'\x00' * zeros_to_append) - - logger.info("New system path was written to qcow file") - return True - except: - logger.error("Qcow2-write_new_system_path_inside_qcow: \r\n{}".format(traceback.format_exc())) - return False - - - - diff --git a/scripts/start_avd.py b/scripts/start_avd.py deleted file mode 100644 index 68cb4f2f..00000000 --- a/scripts/start_avd.py +++ /dev/null @@ -1,199 +0,0 @@ -import sys -import os -import platform -import subprocess -import django -from os.path import dirname, abspath -import logging -from django.conf import settings -from DynamicAnalyzer.views.android.shared import adb_command -from DynamicAnalyzer.views.android.shared import get_identifier -from MobSF.utils import PrintException - -logger = logging.getLogger(__name__) -MobSF_path = dirname(dirname(abspath(__file__))) -sys.path.append(MobSF_path) -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MobSF.settings') -django.setup() - - -def check_config(): - try: - for path in [settings.AVD_EMULATOR, - settings.ADB_BINARY]: - if not path: - logger.error("ADB binary not configured, please refer to the official documentation") - return False - if settings.ANDROID_DYNAMIC_ANALYZER != 'MobSF_AVD': - logger.error("Wrong configuration - ANDROID_DYNAMIC_ANALYZER, please refer to the official documentation") - return False - return True - except: - PrintException("check_config") - return False - - -# In some cases, the modifications to the AVD won't let it boot, this will to the trick -def help_boot_avd(): - try: - emulator = get_identifier() - - # Wait for the adb to answer - args = [settings.ADB_BINARY, - "-s", - emulator, - "wait-for-device"] - logger.info("help_boot_avd: wait-for-device") - subprocess.call(args) - - # Make sure adb running as root - logger.info("help_boot_avd: root") - adb_command(['root']) - - # Make sure adb running as root - logger.info("help_boot_avd: remount") - adb_command(['remount']) - - # Make sure the system verity feature is disabled (Obviously, modified the system partition) - logger.info("help_boot_avd: disable-verity") - adb_command(['disable-verity']) - - # Make SELinux permissive - in case SuperSu/Xposed didn't patch things right - logger.info("help_boot_avd: setenforce") - adb_command(['setenforce', '0'], shell=True) - - logger.info("help_boot_avd: finished!") - return True - except: - PrintException("help_boot_avd") - return False - - -def start_avd(): - try: - if platform.system() == 'Darwin': - # There is a strage error in mac with the dyld one in a while.. - # this should fix it.. - if 'DYLD_FALLBACK_LIBRARY_PATH' in list(os.environ.keys()): - del os.environ['DYLD_FALLBACK_LIBRARY_PATH'] - - args = [ - settings.AVD_EMULATOR, - '-avd', - settings.AVD_NAME, - "-writable-system", - "-no-snapshot-load", - "-port", - str(settings.AVD_ADB_PORT), - ] - logger.info("starting emulator: \r\n" + ' '.join(args)) - subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - return True - except: - PrintException("start_avd") - return False - - -def guess_system_image(avd_emulator_path): - potential_paths = list() - if platform.system() == 'Darwin': - # Get only /Users/username first - user_home = '/'.join(avd_emulator_path.split(os.path.sep)[:3]) - potential_paths.append(os.path.join(user_home, 'Library/Android/Sdk/system-images/android-23/google_apis/armeabi-v7a/system.img')) - elif platform.system() == 'Linux': - # TODO: TBD - pass - elif platform.system() == 'Windows': - # TODO: TBD - pass - for path in potential_paths: - if os.path.exists(path): - return path - return None - - -def get_qcow_image(avd_emulator_path): - potential_paths = list() - if platform.system() == 'Darwin': - # Get only /Users/username first - user_home = '/'.join(avd_emulator_path.split(os.path.sep)[:3]) - potential_paths.append(os.path.join(user_home, '.android/avd/{}.avd/system.img.qcow2'.format(settings.AVD_NAME))) - elif platform.system() == 'Linux': - # TODO: TBD - pass - elif platform.system() == 'Windows': - # TODO: TBD - pass - for path in potential_paths: - if os.path.exists(path): - return path - return None - - -def check_system_file(): - # ex. /Users/matandobr/Library/Android/sdk/tools/emulator - emulator_binary = settings.AVD_EMULATOR - - # Check if the system image is installed currectly - local_system_image = guess_system_image(emulator_binary) - if not local_system_image: - logger.error("Cannot find system.img file, Please verify you've installed android 6 armv7 with google apis system image") - return False - - # Check if the modified system is already been patched - qcow_image = get_qcow_image(emulator_binary) - if not qcow_image: - logger.error("system.img.qcow2 wasn't found on the system, make sure you copied the emulator to the proper folder") - return False - if not os.path.exists(qcow_image): - logger.error("system.img.qcow2 wasn't found on the system, make sure you copied the emulator to the proper folder") - return False - - qcow = Qcow2(qcow_image) - if not qcow.parse_header(): - return False - - original_system_path = qcow.get_backing_file_path_str() - if not original_system_path: - return False - - if os.path.exists(original_system_path): - logger.info("system.img.qcow path check passed successfully") - return True - - logger.info("qcow path didn't match, replacing") - if not qcow.write_new_system_path_inside_qcow(local_system_image): - logger.error("Error fixing system file") - return False - - # After we wrote a new system path, verify it - qcow.parse_header() - new_system_path = qcow.get_backing_file_path_str() - if os.path.exists(new_system_path): - logger.info("system.img.qcow path check passed successfully") - return True - else: - logger.error("system file verification failed") - return False - - -def main(): - logger.info("MobSF - start_avd.py has started") - if not check_config(): - return -1 - if not check_system_file(): - return -1 - if not start_avd(): - return -1 - if not help_boot_avd(): - return -1 - logger.info("start_avd successfully finished") - logger.info("Please wait untill the emulator will load completely, only then take a snapshot") - return 1 - - -if __name__ == '__main__': - from qcow2 import Qcow2 - sys.exit(main()) -else: - from scripts.qcow2 import Qcow2 diff --git a/templates/dynamic_analysis/start_test.html b/templates/dynamic_analysis/start_test.html index a724761e..6b6763e1 100644 --- a/templates/dynamic_analysis/start_test.html +++ b/templates/dynamic_analysis/start_test.html @@ -55,7 +55,7 @@ textarea:focus {

Create Environment - + @@ -197,12 +197,7 @@ textarea:focus { $('#start').text("Environment Created"); $('#stat').append("\nRunning HTTPS Proxy"); - {% comment %} - AVD throws error if we overwrite files - {% endcomment %} - {% if AVD == True %} - $('#stat').append("\nMobSF RootCA Installed Successfully"); - {% else %} + //Install MobSF RootCA $.ajax({ url : "../MobSFCA/", @@ -222,7 +217,7 @@ textarea:focus { document.getElementById("er").srcdoc = xhr.responseText; } }); - {% endif %} + $('#stat').append("\nConnecting to VM"); $('#stat').append("\nMounting"); diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..24d0347c --- /dev/null +++ b/tox.ini @@ -0,0 +1,82 @@ +[tox] +envlist = py36 +skipsdist = True + +[testenv] +basepython = python3.6 +install_command = {basepython} {envdir}/bin/pip install {opts} {packages} +list_dependencies_command = {basepython} {envdir}/bin/pip freeze +deps = + -r{toxinidir}/requirements.txt + +[testenv:lint] +skip_install = true +deps = + pydocstyle==3.0.0 + flake8 + flake8-broken-line + flake8-bugbear + flake8-builtins + flake8-colors + flake8-commas + flake8-comprehensions + flake8-docstrings + flake8-eradicate + flake8-import-order + flake8-logging-format + flake8-quotes + flake8-self + pep8-naming + radon +commands = + {basepython} {envdir}/bin/flake8 {posargs} + +[testenv:clean] +deps = +skip_install = true +whitelist_externals = + bash + find + rm +commands = + find . -name "*.py[co]" -delete + bash -c 'find . -name "__pycache__" -exec rm -fr \{\} \; -prune' + bash -c 'find . -depth -name "*.egg-info" -exec rm -fr \{\} \;' + rm -rf .tox + bash -c './scripts/clean.sh y' + + + +; Reference for error codes: +; http://www.pydocstyle.org/en/latest/error_codes.html +[flake8] +enable-extensions = G +exclude = + .tox + .git + __pycache__ + uploads + downloads + static + templates + logs + venv + DynamicAnalyzer/tools/adb/ + StaticAnalyzer/migrations/ + StaticAnalyzer/tools/enjarify/ +ignore = + D100 + D101 + D102 + D103 + D104 + D105 + D107 + D401 + W503 + Q003 ; Allow only ' for strings + SF01 ; Allow private member access + I100 ; Use python sort imports + R701 ; TODO fix this later too complex + ; remove # flake8: noqa from manifest_analysis.py, should be fixed with R701 +radon_max_cc = 10 \ No newline at end of file