1
2
3
4
5
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
15 """Extract Dynamic API calls Info From Droidmon logs."""
16
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
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
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
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
90
92 self.droidmon["started_activities"].append(api_call["args"][0])
93
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
102 command = api_call["this"]["command"]
103 self.droidmon["commands"].add(' '.join(command))
104
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
119
121 self.droidmon["fingerprint"].add("getNetworkOperatorName")
122
124 self.droidmon["fingerprint"].add("getSubscriberId")
125
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
149
152
155
158
161
164
166 self.droidmon["ContentResolver_queries"].add(api_call["args"][0]["uriString"])
167
169 self.droidmon["ContentValues"].append(self.get_pair(api_call))
170
172 self.droidmon["mac_data"].append(api_call["args"][0])
173
175 self.droidmon["encoded_base64"].append(api_call["args"][0])
176
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
197
200
202 self.droidmon["data_leak"].add("getInstalledPackages")
203
206
208 self.droidmon["sms"].append({
209 "dest_number": api_call["args"][0],
210 "content": " ".join(api_call["args"][1]),
211 })
212
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
238
241
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
256
259
261 self.droidmon["events"].add("abortBroadcast")
262
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
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
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
307 self.droidmon["loadClass"].add(api_call["args"][0])
308
310
311 commands = api_call["buffer"].split('\n')
312 for command in commands:
313 self.droidmon["commands"].add(command)
314
319
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
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
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
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
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