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
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
89 self.lib_pairs(api_call, "findResource")
90
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
109 self.droidmon["handleReceiver"].append(api_call["args"][0])
110
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
118 self.droidmon["fingerprint"].add("getDeviceId")
119
121 self.droidmon["fingerprint"].add("getNetworkOperatorName")
122
124 self.droidmon["fingerprint"].add("getSubscriberId")
125
127 self.droidmon["fingerprint"].add("getLine1Number")
128
130 self.droidmon["fingerprint"].add("getNetworkOperator")
131
133 self.droidmon["fingerprint"].add("getSimOperatorName")
134
136 self.droidmon["fingerprint"].add("getSimCountryIso")
137
139 self.droidmon["fingerprint"].add("getSimSerialNumber")
140
142 self.droidmon["fingerprint"].add("getNetworkCountryIso")
143
145 self.droidmon["fingerprint"].add("getDeviceSoftwareVersion")
146
148 self.droidmon["fingerprint"].add("getMacAddress")
149
151 self.droidmon["SharedPreferences"].append(self.get_pair(api_call))
152
154 self.droidmon["SharedPreferences"].append(self.get_pair(api_call))
155
157 self.droidmon["SharedPreferences"].append(self.get_pair(api_call))
158
160 self.droidmon["SharedPreferences"].append(self.get_pair(api_call))
161
163 self.droidmon["SharedPreferences"].append(self.get_pair(api_call))
164
166 self.droidmon["ContentResolver_queries"].add(api_call["args"][0]["uriString"])
167
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
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
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
196 self.droidmon["data_leak"].add("location")
197
199 self.droidmon["data_leak"].add("location")
200
202 self.droidmon["data_leak"].add("getInstalledPackages")
203
205 self.lib_pairs(api_call, "findLibrary")
206
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
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
230 self.droidmon["registerContentObserver"].add(api_call["args"][0]["uriString"])
231
233 self.droidmon["ContentResolver_queries"].add(api_call["args"][0]["uriString"])
234
236 self.droidmon["accounts"].add(api_call["args"][0]) 237 self.droidmon["data_leak"].add("getAccounts")
238
240 self.lib_pairs(api_call, "findResource")
241
243 self.droidmon["data_leak"].add("getAccounts")
244
246 self.droidmon["sms"].append({ 247 "dest_number": api_call["args"][0], 248 "content": api_call["args"][2], 249 })
250
252 self.droidmon["ContentResolver_queries"].add(api_call["args"][0]["uriString"])
253
255 self.droidmon["events"].add("mediaRecorder")
256
258 self.droidmon["events"].add("mediaRecorder")
259
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
267 self.droidmon["DexClassLoader"].append(api_call["args"])
268
270 self.droidmon["DexFile"].append(api_call["args"])
271
273 self.droidmon["PathClassLoader"].append(api_call["args"])
274
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
282 self.droidmon["setMobileDataEnabled"].append(api_call["args"][0])
283
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