def post(self): app = self.get_argument('app', None) status = self.get_argument('status', None) try: row = self.db.session.query(models.StaticAnalyzer).filter_by(name=app).first() row.status = status self.db.session.commit() except: logger.error("Cannot set status!")
def makeFileAnalysis(self, file_path): logger.debug("Performing analysis of file [%s]..." % file_path) a = None d = None dx = None ret_type = androconf.is_android(file_path) if ret_type == "APK": a = apk.APK(file_path) d = dvm.DalvikVMFormat(a.get_dex()) elif ret_type == "DEX" : try : d = dvm.DalvikVMFormat(open(file_path, "rb").read()) except Exception as e : logger.error("[%s] is not valid dex file!" % file_path, e) return dx = analysis.VMAnalysis(d) invokeMethodPaths = analysis.seccon_get_invoke_method_paths(dx) newInstanceMethodPaths = analysis.seccon_get_newInstance_method_paths(dx) dynamicMethodPaths = analysis.seccon_get_dyncode_loading_paths(dx) if invokeMethodPaths: t = None for path in invokeMethodPaths: src = path.get_src(d.get_class_manager()) dst = path.get_dst(d.get_class_manager()) t = (src, dst) self._sources_invoke.append(t) self._uncovered_invoke.append(t) if newInstanceMethodPaths: t = None for path in newInstanceMethodPaths: src = path.get_src(d.get_class_manager()) dst = path.get_dst(d.get_class_manager()) t = (src, dst) self._sources_newInstance.append(t) self._uncovered_newInstance.append(t) if dynamicMethodPaths: t = None for path in dynamicMethodPaths: src = path.get_src(d.get_class_manager()) dst = path.get_dst(d.get_class_manager()) t = (src, dst) self._sources_dexload.append(t) self._uncovered_dexload.append(t) #building MFG for the file self._stadynaMcg.analyseFile(dx, a)
def addNewInstancePath(self, src, through, dst): src_class_name, src_method_name, src_descriptor = src dst_class_name, dst_method_name, dst_descriptor = dst through_class_name, through_method_name, through_descriptor = through key = "%s %s %s %s %s %s %s" % \ (src_class_name, src_method_name, src_descriptor, through_class_name, through_method_name, through_descriptor, POSTFIX_REFL_NEWINSTANCE) n1 = self._get_existed_node(key) if n1 is None: logger.error("Something wrong has happened! Could not find Node in Graph with key [%s]" % str(key)) return n2 = self._get_node(NODE_CONSTRUCTOR, (dst_class_name, dst_method_name, dst_descriptor)) n2.set_attribute(ATTR_CLASS_NAME, dst_class_name) n2.set_attribute(ATTR_METHOD_NAME, dst_method_name) n2.set_attribute(ATTR_DESCRIPTOR, dst_descriptor) self.G.add_edge(n1.id, n2.id) # we also need to add link to the class node # TODO: Think in the future what to do with this n_class = self._get_node(NODE_FAKE_CLASS, dst_class_name, None, False) n_class.set_attribute(ATTR_CLASS_NAME, dst_class_name) self.G.add_edge(n_class.id, n2.id) # checking if we need to add additional permission nodes data = "%s-%s-%s" % (dst_class_name, dst_method_name, dst_descriptor) if data in DVM_PERMISSIONS_BY_API_CALLS: logger.info("YESS!The protected method is called through reflection") perm = DVM_PERMISSIONS_BY_API_CALLS[data] key1 = "%s %s %s %s %s %s %s %s" % \ (through_class_name, through_method_name, through_descriptor, dst_class_name, dst_method_name, dst_descriptor, POSTFIX_PERM, perm) n3 = self._get_node(NODE_FAKE_PERMISSION, key1, perm, False) n3.set_attribute(ATTR_CLASS_NAME, dst_class_name) n3.set_attribute(ATTR_METHOD_NAME, dst_method_name) n3.set_attribute(ATTR_DESCRIPTOR, dst_descriptor) n3.set_attribute(ATTR_PERM_NAME, perm) n3.set_attribute(ATTR_PERM_LEVEL, MANIFEST_PERMISSIONS[perm][0]) self.G.add_edge(n2.id, n3.id)
def decompile(self): jadx = os.path.join(TOOLS_DIR, 'jadx/bin/jadx') args = [jadx, "-d", self.decompile_dir, self.apk] fire_jadx = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # set to communicate with the logger stdout, stderr = fire_jadx.communicate() if stdout: logger.info(stdout) return True if stderr: logger.error(stderr) return False
def get_constants_name_from_value(constant_dict, value) : """ @param constant_dict : constant dictionary to consider @param value : value's constant name to retrieve @rtype : a string """ try: return constant_dict[value] except KeyError: logger.error("The constant name corresponding to the value '%s' can not be found in the dictionary '%s'" % (value, constant_dict)) return ERROR_CONSTANT_NAME_NOT_FOUND
def _get_existed_node(self, key): node_key = None if isinstance(key, basestring): node_key = key elif isinstance(key, tuple): node_key = "%s %s %s" % key else: logger.error("Unknown instance type of key!!!") try: return self.nodes[node_key] except KeyError: logger.error("Could not find existed node [%s]!" % node_key) return None
def detect_SMS_interception(a, x): """ @param a : an APK instance @param x : a VMAnalysis instance @rtype : a list of formatted strings """ formatted_str = [] tree = ElementTree() try: manifest = AXMLPrinter(a.zip.read("AndroidManifest.xml")).getBuff() tree.parse(BytesIO(manifest)) root = tree.getroot() for parent, child, grandchild in get_parent_child_grandchild(root): # Criteria 1: "android.provider.Telephony.SMS_RECEIVED" + "intentfilter 'android:priority' a high number" => SMS interception if '{http://schemas.android.com/apk/res/android}name' in grandchild.attrib.keys( ): if grandchild.attrib[ '{http://schemas.android.com/apk/res/android}name'] == "android.provider.Telephony.SMS_RECEIVED": if child.tag == 'intentfilter' and '{http://schemas.android.com/apk/res/android}priority' in child.attrib.keys( ): formatted_str.append( "This application intercepts your incoming SMS") # Grab the interceptor's class name class_name = parent.attrib[ '{http://schemas.android.com/apk/res/android}name'] package_name = a.package # Convert("com.test" + "." + "interceptor") to "Lcom/test/interceptor" class_name = convert_canonical_to_dex( package_name + "." + class_name[1:]) # Criteria 2: if we can find 'abortBroadcast()' call => notification deactivation structural_analysis_results = x.tainted_packages.search_methods( class_name, "abortBroadcast", ".") if structural_analysis_results: formatted_str.append( "This application disables incoming SMS notifications" ) except Exception, e: logger.error("detect_SMS_interception(): %s" % e)
def post(self): try: apk = self.request.files['files[]'] filename = apk[0]['filename'] if apk and allowed_file(filename): # save the file in the uploads folder with open(os.path.join(UPLOADS_DIR, filename), "w") as out: out.write(apk[0]['body']) logger.info("APK uploaded!") self.redirect('/dashboard?apk='+filename) else: logger.error("Invalid file!") self.render('index.html') except: logger.error("Cannot upload!")
def _get_node(self, nType, key, label=None, real=True): node_key = None if isinstance(key, basestring): node_key = key elif isinstance(key, tuple): node_key = "%s %s %s" % key else: logger.error("Unknown instance type of key!!!") if node_key not in self.nodes.keys(): new_node = NodeS(len(self.nodes), nType, node_key, label, real) self.nodes[node_key] = new_node self.nodes_id[new_node.id] = new_node return self.nodes[node_key]
def addDexloadPath(self, src, through, filename): src_class_name, src_method_name, src_descriptor = src through_class_name, through_method_name, through_descriptor = through key = "%s %s %s %s %s %s %s" % \ (src_class_name, src_method_name, src_descriptor, through_class_name, through_method_name, through_descriptor, POSTFIX_DEXLOAD) n1 = self._get_existed_node(key) if n1 is None: logger.error("Could not find Node in Graph with key [%s]" % str(key)) return n2 = self._get_node(NODE_FAKE_DEXLOAD_FILE, filename, filename, False) n2.set_attribute(ATTR_DEXLOAD_FILENAME, filename) self.G.add_edge(n1.id, n2.id)
def relevant_registers_for_the_method(instruction) : """ @param method : a method instance @param index_to_find : index of the matching method @rtype : an ordered list of register indexes related to that method call """ relevant_registers = [] current_instruction_name = instruction.get_name() current_instruction = instruction.show_buff(0) p_invoke_name = re.compile('^invoke-(?:static|virtual|direct|super|interface|interface-range|virtual-quick|super-quick)$') p_invoke_range_name = re.compile('^invoke-(?:static|virtual|direct|super|interface|interface-range|virtual-quick|super-quick)(?:\/range)$') if p_invoke_name.match(current_instruction_name) : p_invoke_registers = re.compile('(v[0-9]+),') if p_invoke_registers.findall(current_instruction) : registers_raw_list_splitted = p_invoke_registers.findall(current_instruction) relevant_registers = extract_register_index_out_splitted_values(registers_raw_list_splitted) if p_invoke_range_name.match(current_instruction_name) : # We're facing implicit an implicit range declaration, for instance "invoke v19..v20" p_invoke_registers_range = re.compile('^v([0-9]+) ... v([0-9]+), L.*$') if p_invoke_registers_range.match(current_instruction) : register_start_number = p_invoke_registers_range.match(current_instruction).groups()[0] register_end_number = p_invoke_registers_range.match(current_instruction).groups()[1] if int(register_start_number) > int(register_end_number) : logger.error("invoke-kind/range incoherent: # of the start register is lower than the end one") else : relevant_registers = [ str(i) for i in xrange(int(register_start_number), int(register_end_number))] # +1 because range does not provide the higher boundary value return relevant_registers
def backtrace_registers_before_call(x, method, index_to_find) : """ @param x : a VMAnalysis instance @param method : a regexp for the method (the package) @param index_to_find : index of the matching method @rtype : an ordered list of dictionaries of each register content [{ 'register #': 'value' }, { 'register #': 'value' } ...] """ registers = {} code = method.get_code() #code.show() bc = code.get_bc() instruction_list = [ i for i in bc.get_instructions() ] found_index = find_call_index_in_code_list(index_to_find, instruction_list) if (found_index < 0) : logger.error("The call index in the code list can not be found") return 0 else : # Initialize the returned list of dictionaries registers_final = [] # Initialize the harvesting dictionary registers_found = {} # List the register indexes related to the method call relevant_registers = relevant_registers_for_the_method(instruction_list[found_index]) #print relevant_registers i = int(found_index) - 1 # start index while ((all_relevant_registers_filled(registers_found,relevant_registers) != True) and (i >= 0)) : #current_instruction = instruction_list[i].show_buff(0) #print current_instruction current_instruction = instruction_list[i] instruction_name, local_register_number, local_register_value, registers_found = match_current_instruction(current_instruction, registers_found) if cmp(instruction_name, APUT) == 0: try : list_index_to_be_changed = relevant_registers.index(str(local_register_value)) #print "index_to_be_changed %s" % list_index_to_be_changed del(relevant_registers[int(local_register_value)]) relevant_registers.insert(list_index_to_be_changed, local_register_number) logger.debug("New relevant_registers %s" % relevant_registers) except : logger.debug("'%s' does not exist anymore in the relevant_registers list" % local_register_value) if (cmp(instruction_name, MOVE_RESULT) == 0) and (local_register_number in relevant_registers): try: #past_instruction = instruction_list[i-1].show_buff(0) #print past_instruction past_instruction = instruction_list[i-1] p_instruction_name, p_local_register_number, p_local_register_value, registers_found = match_current_instruction(past_instruction, registers_found) if cmp(p_instruction_name, INVOKE_NO_REGISTER) == 0 : registers_found[local_register_number] = p_local_register_value else: list_index_to_be_changed = relevant_registers.index(str(local_register_number)) del(relevant_registers[int(list_index_to_be_changed)]) relevant_registers.insert(list_index_to_be_changed, p_local_register_number) logger.debug("New relevant_registers %s" % relevant_registers) except: logger.debug("'%s' does not exist anymore in the relevant_registers list" % local_register_value) i = i - 1 #log.info('Registers found during the analysis %s' % registers_found) final_answer = all_relevant_registers_filled(registers_found,relevant_registers) logger.debug("Are all relevant registers filled ? %s" % str(final_answer)) for i in relevant_registers : try: register_number = i #print register_number register_value = registers_found[i] #print register_value temp_dict = { register_number : register_value } registers_final.append(temp_dict) except KeyError: registers_final = [] logger.debug("KeyError exception : The value of the register # %s could not be found for the relevant registers %s" % (register_number, relevant_registers)) break return registers_final