modules.processing.droidmon

Package modules :: Package processing :: Module droidmon |
[hide private]
[frames] | no frames]

# Source Code for Module modules.processing.droidmon

      1  # Copyright (C) 2010-2013 Claudio Guarnieri.
      2  # Copyright (C) 2014-2016 Cuckoo Foundation.
      3  # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org
      4  # See the file 'docs/LICENSE' for copying permission.
      5  # Originally contributed by Check Point Software Technologies, Ltd.
      6
      7  import json
      8  import logging
      9  import os
     10  from lib.cuckoo.common.abstracts import Processing
     11
     12  log = logging.getLogger(__name__)
     13
     14 -class Droidmon(Processing):
     15      """Extract Dynamic API calls Info From Droidmon logs."""
     16
     17 -    def __init__(self):
     18          self.key = "droidmon"
     19
     20          self.droidmon = {}
     21
     22          self.droidmon["crypto_keys"] = []
     23          self.droidmon["reflection_calls"] = set()
     24          self.droidmon["SystemProperties"] = set()
     25          self.droidmon["started_activities"] = []
     26          self.droidmon["file_accessed"] = set()
     27          self.droidmon["fingerprint"] = set()
     28          self.droidmon["registered_receivers"] = set()
     29          self.droidmon["SharedPreferences"] = []
     30          self.droidmon["ContentResolver_queries"] = set()
     31          self.droidmon["ContentValues"] = []
     32          self.droidmon["encoded_base64"] = []
     33          self.droidmon["decoded_base64"] = []
     34          self.droidmon["commands"] = set()
     35          self.droidmon["commands_output"] = set()
     36          self.droidmon["ComponentEnabledSetting"] = []
     37          self.droidmon["data_leak"] = set()
     38          self.droidmon["events"] = set()
     39          self.droidmon["crypto_data"] = []
     40          self.droidmon["mac_data"] = []
     41          self.droidmon["handleReceiver"] = []
     42          self.droidmon["sms"] = []
     43          self.droidmon["killed_process"] = []
     44          self.droidmon["findResource"] = []
     45          self.droidmon["findLibrary"] = []
     46          self.droidmon["loadDex"] = set()
     47          self.droidmon["TelephonyManager_listen"] = set()
     48          self.droidmon["registerContentObserver"] = set()
     49          self.droidmon["accounts"] = set()
     50          self.droidmon["DexClassLoader"] = []
     51          self.droidmon["DexFile"] = []
     52          self.droidmon["PathClassLoader"] = []
     53          self.droidmon["loadClass"] = set()
     54          self.droidmon["setMobileDataEnabled"] = set()
     55          self.droidmon["httpConnections"] = []
     56          self.droidmon["error"] = []
     57          self.droidmon["raw"] = []
     58
     59 -    def _handle_android_os_SystemProperties_get(self, api_call):
     60          self.droidmon["SystemProperties"].add(api_call["args"][0])
     61
     62 -    def _handle_javax_crypto_spec_SecretKeySpec_javax_crypto_spec_SecretKeySpec(self, api_call):
     63          key = api_call["args"][0]
     64          for current_key in self.droidmon["crypto_keys"]:
     65              if key in current_key["key"]:
     66                  break
     67          else:
     68              self.droidmon["crypto_keys"].append({
     69                  "key": api_call["args"][0],
     70                  "type": api_call["args"][1],
     71              })
     72
     73 -    def _handle_javax_crypto_Cipher_doFinal(self, api_call):
     74
     75          if api_call["this"]["mode"] == 1:
     76              self.droidmon["crypto_data"].append(api_call["args"][0])
     77          else:
     78              self.droidmon["crypto_data"].append(api_call["result"])
     79
     80 -    def _handle_java_lang_reflect_Method_invoke(self, api_call):
     81          reflection = ""
     82          if "hooked_class" in api_call:
     83              reflection = api_call["hooked_class"]+"->"+api_call["hooked_method"]
     84          else:
     85              reflection = api_call["hooked_method"]
     86          self.droidmon["reflection_calls"].add(reflection)
     87
     88 -    def _handle_dalvik_system_BaseDexClassLoader_findResource(self, api_call):
     89          self.lib_pairs(api_call, "findResource")
     90
     91 -    def _handle_android_app_Activity_startActivity(self, api_call):
     92          self.droidmon["started_activities"].append(api_call["args"][0])
     93
     94 -    def _handle_java_lang_Runtime_exec(self, api_call):
     95          command = api_call["args"][0]
     96          if type(command) is list:
     97              self.droidmon["commands"].add(' '.join(command))
     98          else:
     99              self.droidmon["commands"].add(command)
    100
    101 -    def _handle_java_lang_ProcessBuilder_start(self, api_call):
    102          command = api_call["this"]["command"]
    103          self.droidmon["commands"].add(' '.join(command))
    104
    105 -    def _handle_libcore_io_IoBridge_open(self, api_call):
    106          self.droidmon["file_accessed"].add(api_call["args"][0])
    107
    108 -    def _handle_android_app_ActivityThread_handleReceiver(self, api_call):
    109          self.droidmon["handleReceiver"].append(api_call["args"][0])
    110
    111 -    def _handle_android_app_ContextImpl_registerReceiver(self, api_call):
    112          for arg in api_call["args"]:
    113              if "mActions" in arg:
    114                  for action in arg["mActions"]:
    115                      self.droidmon["registered_receivers"].add(action)
    116
    117 -    def _handle_android_telephony_TelephonyManager_getDeviceId(self, api_call):
    118          self.droidmon["fingerprint"].add("getDeviceId")
    119
    120 -    def _handle_android_telephony_TelephonyManager_getNetworkOperatorName(self, api_call):
    121          self.droidmon["fingerprint"].add("getNetworkOperatorName")
    122
    123 -    def _handle_android_telephony_TelephonyManager_getSubscriberId(self, api_call):
    124          self.droidmon["fingerprint"].add("getSubscriberId")
    125
    126 -    def _handle_android_telephony_TelephonyManager_getLine1Number(self, api_call):
    127          self.droidmon["fingerprint"].add("getLine1Number")
    128
    129 -    def _handle_android_telephony_TelephonyManager_getNetworkOperator(self, api_call):
    130          self.droidmon["fingerprint"].add("getNetworkOperator")
    131
    132 -    def _handle_android_telephony_TelephonyManager_getSimOperatorName(self, api_call):
    133          self.droidmon["fingerprint"].add("getSimOperatorName")
    134
    135 -    def _handle_android_telephony_TelephonyManager_getSimCountryIso(self, api_call):
    136          self.droidmon["fingerprint"].add("getSimCountryIso")
    137
    138 -    def _handle_android_telephony_TelephonyManager_getSimSerialNumber(self, api_call):
    139          self.droidmon["fingerprint"].add("getSimSerialNumber")
    140
    141 -    def _handle_android_telephony_TelephonyManager_getNetworkCountryIso(self, api_call):
    142          self.droidmon["fingerprint"].add("getNetworkCountryIso")
    143
    144 -    def _handle_android_telephony_TelephonyManager_getDeviceSoftwareVersion(self, api_call):
    145          self.droidmon["fingerprint"].add("getDeviceSoftwareVersion")
    146
    147 -    def _handle_android_net_wifi_WifiInfo_getMacAddress(self, api_call):
    148          self.droidmon["fingerprint"].add("getMacAddress")
    149
    150 -    def _handle_android_app_SharedPreferencesImpl_EditorImpl_putInt(self, api_call):
    151          self.droidmon["SharedPreferences"].append(self.get_pair(api_call))
    152
    153 -    def _handle_android_app_SharedPreferencesImpl_EditorImpl_putString(self, api_call):
    154          self.droidmon["SharedPreferences"].append(self.get_pair(api_call))
    155
    156 -    def _handle_android_app_SharedPreferencesImpl_EditorImpl_putFloat(self, api_call):
    157          self.droidmon["SharedPreferences"].append(self.get_pair(api_call))
    158
    159 -    def _handle_android_app_SharedPreferencesImpl_EditorImpl_putBoolean(self, api_call):
    160          self.droidmon["SharedPreferences"].append(self.get_pair(api_call))
    161
    162 -    def _handle_android_app_SharedPreferencesImpl_EditorImpl_putLong(self, api_call):
    163          self.droidmon["SharedPreferences"].append(self.get_pair(api_call))
    164
    165 -    def _handle_android_content_ContentResolver_query(self, api_call):
    166          self.droidmon["ContentResolver_queries"].add(api_call["args"][0]["uriString"])
    167
    168 -    def _handle_android_content_ContentValues_put(self, api_call):
    169          self.droidmon["ContentValues"].append(self.get_pair(api_call))
    170
    171 -    def _handle_javax_crypto_Mac_doFinal(self, api_call):
    172          self.droidmon["mac_data"].append(api_call["args"][0])
    173
    174 -    def _handle_android_util_Base64_encodeToString(self, api_call):
    175          self.droidmon["encoded_base64"].append(api_call["args"][0])
    176
    177 -    def _handle_android_util_Base64_encode(self, api_call):
    178          self.droidmon["encoded_base64"].append(api_call["result"][0])
    179
    180 -    def _handle_android_app_ApplicationPackageManager_setComponentEnabledSetting(self, api_call):
    181          states = {
    182              "0": "COMPONENT_ENABLED_STATE_DEFAULT",
    183              "1": "COMPONENT_ENABLED_STATE_ENABLED",
    184              "2": "COMPONENT_ENABLED_STATE_DISABLED",
    185          }
    186
    187          component = api_call["args"][0]
    188          state = api_call["args"][1]
    189
    190          self.droidmon["ComponentEnabledSetting"].append({
    191              "component_name": component["mPackage"]+"/"+component["mClass"],
    192              "component_new_state": states.get(state, ""),
    193          })
    194
    195 -    def _handle_android_location_Location_getLatitude(self, api_call):
    196          self.droidmon["data_leak"].add("location")
    197
    198 -    def _handle_android_location_Location_getLongitude(self, api_call):
    199          self.droidmon["data_leak"].add("location")
    200
    201 -    def _handle_android_app_ApplicationPackageManager_getInstalledPackages(self, api_call):
    202          self.droidmon["data_leak"].add("getInstalledPackages")
    203
    204 -    def _handle_dalvik_system_BaseDexClassLoader_findLibrary(self, api_call):
    205          self.lib_pairs(api_call, "findLibrary")
    206
    207 -    def _handle_android_telephony_SmsManager_sendTextMessage(self, api_call):
    208          self.droidmon["sms"].append({
    209              "dest_number": api_call["args"][0],
    210              "content": " ".join(api_call["args"][1]),
    211          })
    212
    213 -    def _handle_android_util_Base64_decode(self, api_call):
    214          self.droidmon["decoded_base64"].append(api_call["result"])
    215
    216 -    def _handle_android_telephony_TelephonyManager_listen(self, api_call):
    217          description = {
    218              1: "LISTEN_SERVICE_STATE",
    219              16: "LISTEN_CELL_LOCATION",
    220              32: "LISTEN_CALL_STATE",
    221              64: "LISTEN_DATA_CONNECTION_STATE",
    222              256: "LISTEN_SIGNAL_STRENGTHS",
    223          }
    224
    225          event = api_call["args"][1]
    226          if event in description:
    227              self.droidmon["TelephonyManager_listen"].add(description[event])
    228
    229 -    def _handle_android_content_ContentResolver_registerContentObserver(self, api_call):
    230          self.droidmon["registerContentObserver"].add(api_call["args"][0]["uriString"])
    231
    232 -    def _handle_android_content_ContentResolver_insert(self, api_call):
    233          self.droidmon["ContentResolver_queries"].add(api_call["args"][0]["uriString"])
    234
    235 -    def _handle_android_accounts_AccountManager_getAccountsByType(self, api_call):
    236          self.droidmon["accounts"].add(api_call["args"][0])
    237          self.droidmon["data_leak"].add("getAccounts")
    238
    239 -    def _handle_dalvik_system_BaseDexClassLoader_findResources(self, api_call):
    240          self.lib_pairs(api_call, "findResource")
    241
    242 -    def _handle_android_accounts_AccountManager_getAccounts(self, api_call):
    243          self.droidmon["data_leak"].add("getAccounts")
    244
    245 -    def _handle_android_telephony_SmsManager_sendMultipartTextMessage(self, api_call):
    246          self.droidmon["sms"].append({
    247              "dest_number": api_call["args"][0],
    248              "content": api_call["args"][2],
    249          })
    250
    251 -    def _handle_android_content_ContentResolver_delete(self, api_call):
    252          self.droidmon["ContentResolver_queries"].add(api_call["args"][0]["uriString"])
    253
    254 -    def _handle_android_media_AudioRecord_startRecording(self, api_call):
    255          self.droidmon["events"].add("mediaRecorder")
    256
    257 -    def _handle_android_media_MediaRecorder_start(self, api_call):
    258          self.droidmon["events"].add("mediaRecorder")
    259
    260 -    def _handle_android_content_BroadcastReceiver_abortBroadcast(self, api_call):
    261          self.droidmon["events"].add("abortBroadcast")
    262
    263 -    def _handle_dalvik_system_DexFile_loadDex(self, api_call):
    264          self.droidmon["loadDex"].add(api_call["args"][0])
    265
    266 -    def _handle_dalvik_system_DexClass_dalvik_system_DexClassLoader(self, api_call):
    267          self.droidmon["DexClassLoader"].append(api_call["args"])
    268
    269 -    def _handle_dalvik_system_DexFile_dalvik_system_DexFile(self, api_call):
    270          self.droidmon["DexFile"].append(api_call["args"])
    271
    272 -    def _handle_dalvik_system_PathClassLoader_dalvik_system_PathClassLoader(self, api_call):
    273          self.droidmon["PathClassLoader"].append(api_call["args"])
    274
    275 -    def _handle_android_app_ActivityManager_killBackgroundProcesses(self, api_call):
    276          self.droidmon["killed_process"].append(api_call["args"][0])
    277
    278 -    def _handle_android_os_Process_killProcess(self, api_call):
    279          self.droidmon["killed_process"].append(api_call["args"][0])
    280
    281 -    def _handle_android_net_ConnectivityManager_setMobileDataEnabled(self, api_call):
    282          self.droidmon["setMobileDataEnabled"].append(api_call["args"][0])
    283
    284 -    def _handle_org_apache_http_impl_client_AbstractHttpClient_execute(self, api_call):
    285          json = {}
    286          if type(api_call["args"][0]) is dict:
    287              json["request"] = api_call["args"][1]
    288          else:
    289              json["request"] = api_call["args"][0]
    290          json["response"] = api_call["result"]
    291          self.droidmon["httpConnections"].append(json)
    292
    293 -    def _handle_java_net_URL_openConnection(self, api_call):
    294          if("file:" in api_call["this"] or "jar:" in api_call["this"]):
    295              return
    296
    297          json = {}
    298          if api_call["result"] != "":
    299              json["request"] = api_call["result"]["request_method"] + " " + api_call["this"] + " " + api_call["result"]["version"]
    300              json["response"] = api_call["result"]["version"] + " " + str(api_call["result"]["response_code"]) + " " + api_call["result"]["response_message"]
    301          else:
    302              json["request"] = "GET " + api_call["this"] + " HTTP/1.1"
    303              json["response"] = ""
    304          self.droidmon["httpConnections"].append(json)
    305
    306 -    def _handle_dalvik_system_DexFile_loadClass(self, api_call):
    307          self.droidmon["loadClass"].add(api_call["args"][0])
    308
    309 -    def _handle_java_io_FileOutputStream_write(self, api_call):
    310          # self.droidmon["command_objects"].append(api_call)
    311          commands = api_call["buffer"].split('\n')
    312          for command in commands:
    313              self.droidmon["commands"].add(command)
    314
    315 -    def _handle_java_io_FileInputStream_read(self, api_call):
    316          pass
    317          # self.droidmon["command_objects"].append(api_call)
    318          self.droidmon["commands_output"].add("read: "+api_call["buffer"])
    319
    320 -    def get_pair(self, api_call):
    321          value = None
    322          if len(api_call["args"]) > 1:
    323              value = api_call["args"][1]
    324
    325          return {
    326              "key": api_call["args"][0],
    327              "value": value,
    328          }
    329
    330 -    def lib_pairs(self, api_call, key):
    331          libname = api_call["args"][0]
    332          for current_key in self.droidmon[key]:
    333              if libname in current_key["libname"]:
    334                  break
    335          else:
    336              self.droidmon[key].append({
    337                  "libname": api_call["args"][0],
    338                  "result": api_call.get("result", ""),
    339              })
    340
    341 -    def keyCleaner(self, d):
    342          if type(d) is dict:
    343              for key, value in d.iteritems():
    344                  d[key] = self.keyCleaner(value)
    345                  if '.' in key:
    346                      d[key.replace('.', '_')] = value
    347                      del(d[key])
    348              return d
    349          if type(d) is list:
    350              return map(self.keyCleaner, d)
    351          if type(d) is tuple:
    352              return tuple(map(self.keyCleaner, d))
    353          return d
    354
    355 -    def run(self):
    356          """Run extract of printable strings.
    357          @return: list of printable strings.
    358          """
    359
    360          if "file" not in self.task["category"]:
    361              return self.droidmon
    362
    363          results = {}
    364          log_path = self.logs_path + "/droidmon.log"
    365          if not os.path.exists(log_path):
    366              return results
    367
    368          for line in open(log_path, "rb"):
    369              try:
    370                  api_call = json.loads(line)
    371              except Exception:
    372                  self.droidmon["error"].append("Invalid JSON line: %r" % line)
    373                  continue
    374
    375              self.droidmon["raw"].append(self.keyCleaner(api_call))
    376
    377              # Construct the function name of the handler for this event.
    378              api = "_handle_%s_%s" % (api_call["class"], api_call["method"])
    379              fn = getattr(self, api.replace(".", "_"), None)
    380              if fn:
    381                  fn(api_call)
    382              else:
    383                  self.droidmon["error"].append("Unhandled: %r" % line)
    384
    385          for key, value in self.droidmon.items():
    386              results[key] = list(value)
    387
    388          return results
    389