#!/usr/bin/python2
from collections import defaultdict

from androguard.misc import AnalyzeAPK

apk_path = raw_input('Provide path to apk\n')

print('Analyzing...')
apk, dex, vm = AnalyzeAPK(apk_path)

print('\nActivities:')
for activity in apk.get_activities():
    print(activity)

print('\nMain activity:')
print(apk.get_main_activity())

print('\nSuper dangerous permissions:')
for perm, details in apk.get_details_permissions().items():
    if details[0] == 'dangerous':
        # Protection levels: https://developer.android.com/guide/topics/permissions/overview#normal-dangerous
        print(perm)

print('\nServices:')
for service in apk.get_services():
    print(service)

print('\nBroadcasts:')
for receiver in apk.get_receivers():
    print(receiver)

print('\nIntent Filters:')
for service in apk.get_services():
    print('\nFilters for {}'.format(service))
    filters = apk.get_intent_filters('service', service)
    if filters:
        print(filters)

for receiver in apk.get_receivers():
    print('\nFilters for {}'.format(receiver))
    filters = apk.get_intent_filters('receiver', receiver)
    if filters:
        print(filters)

print('\nSensitive method calls:')
SENSITIVE_API_CALLS = {
    "android.content.ContextWrapper": ["bindService", "deleteDatabase", "deleteFile", "deleteSharedPreferences", "getSystemService", "openFileInput", "startService", "stopService", "unbindService", "unregisterReceiver"],
    "android.accounts.AccountManager": ["clearPassword", "getAccounts", "getPassword", "peekAuthToken", "setAuthToken", "setPassword"],
    "android.app.Activity": ["startActivity", "setContentView", "setVisible", "takeKeyEvents"],
    "android.app.DownloadManager": ["addCompletedDownload", "enqueue", "getUriForDownloadedFile", "openDownloadedFile", "query"],
    "android.app.IntentService": ["onStartCommand"],
    "android.content.ContentResolver": ["insert", "openFileDescriptor", "query", "update"],
    "android.content.pm.PackageInstaller": ["uninstall"],
    "android.database.sqlite.SQLiteDatabase": ["execSQL", "insert", "insertOrThrow", "openDatabase", "query", "rawQuery", "replace", "update"],
    "android.hardware.Camera": ["open", "reconnect", "release", "startPreview", "stopPreview", "takePicture"],
    "android.hardware.display.DisplayManager": ["getDisplay", "getDisplays"],
    "android.location.Location": ["getLatitude", "getLongitude"],
    "android.media.AudioRecord": ["read", "startRecording", "stop"],
    "android.media.MediaRecorder": ["prepare", "setCamera", "start", "stop"],
    "android.net.Network": ["bindSocket", "openConnection"],
    "android.net.NetworkInfo": ["isAvailable", "isConnected", "isRoaming"],
    "android.net.wifi.WifiInfo": ["getMacAddress", "getSSID"],
    "android.net.wifi.WifiManager": ["disconnect", "getScanResults", "getWifiState", "reconnect", "startScan"],
    "android.os.Process": ["killProcess"],
    "android.os.PowerManager": ["isInteractive", "isScreenOn", "reboot"],
    "android.telephony.SmsManager": ["sendDataMessage", "sendTextMessage"],
    "android.widget.Toast": ["makeText"],
    "dalvik.system.DexClassLoader": ["loadClass"],
    "dalvik.system.PathClassLoader": ["loadClass"],
    "java.lang.class": ["forName", "getClassLoader", "getClasses", "getField", "getFields", "getMethods", "getMethod", "getName"],
    "java.lang.reflect.Method": ["invoke"],
    "java.net.HttpCookie": ["getName", "getPath", "getSecure", "getValue", "parse", "setPath", "setSecure", "setValue"],
    "java.net.URL.openConnection": ["openConnection", "openStream"]
}

found_sensitive_calls = defaultdict(list)
methods = vm.find_methods(classname='.*', methodname='.*', descriptor='.*', accessflags='.*', no_external=False)
for method in methods:
    m = method.get_method()
    try:
        dotted_package = m.get_information().get('params')[0][1]  # Is there a better way to get to the package?
    except Exception:
        continue
    if m.name in (SENSITIVE_API_CALLS.get(dotted_package) or []):
        print('{} {}'.format(m.name, m.get_class_name()))
        found_sensitive_calls[dotted_package + m.name].append(m.get_class_name())

print('\nSensitive API Calls:')
for call, locations in found_sensitive_calls.items():
    print('{} times {}\nLocations: {}\n'.format(
        len(locations),
        call,
        ', '.join(locations),
    ))