def processNewInstance(self, cls, method, prototype, stack): logger.debug("Processing new instance. DST: [%s%s%s]..." % (cls, method, prototype)) #test code # print "\n" # for stackEntry in stack: # print stackEntry # print "\n" #end of test code newInstanceDstFromClient = (cls, method, prototype) newInstancePosInStack = self._findFirstNewInstancePos(stack) throughMethod = stack[newInstancePosInStack] newInstanceSrcFromStack = stack[newInstancePosInStack + 1] if newInstancePosInStack == -1: self._addSuspiciousNewInstance(throughMethod, newInstanceDstFromClient, stack) return for newInstancePathFromSources in self._sources_newInstance: newInstanceSrcFromSources = newInstancePathFromSources[0] if newInstanceSrcFromSources != newInstanceSrcFromStack: continue self._addNewInstancePathToMCG(newInstanceSrcFromSources, throughMethod, newInstanceDstFromClient) if newInstancePathFromSources in self._uncovered_newInstance: self._uncovered_newInstance.remove(newInstancePathFromSources) return self._addSuspiciousNewInstance(throughMethod, newInstanceDstFromClient, stack)
def printMoiLists(self, toLogger=True): printStr = None if self._uncovered_invoke or self._uncovered_newInstance or self._uncovered_dexload: printStr = "Printing still uncovered methods of interest:\n\n" if self._uncovered_invoke: printStr +="REFLECTION INVOKE:\n" for (src, dst) in self._uncovered_invoke: printStr += "SRC: [%s %s %s]\n" % src printStr += "DST: [%s %s %s]\n" % dst if self._uncovered_newInstance: printStr += "REFLECTION NEW_INSTANCE:\n" for (src, dst) in self._uncovered_newInstance: printStr += "SRC: [%s %s %s]\n" % src printStr += "DST: [%s %s %s]\n" % dst if self._uncovered_dexload: printStr += "DYNAMIC LOAD:\n" for (src, dst) in self._uncovered_dexload: printStr += "SRC: [%s %s %s]\n" % src printStr += "DST: [%s %s %s]\n" % dst else: printStr = "All methods of interest are covered at least one time!!!\n" if toLogger: logger.debug("%s" % printStr) else: print printStr
def processInvoke(self, cls, method, prototype, stack): logger.debug("Processing method invoke: [%s %s %s]..."% (cls, method, prototype)) #test code # print "\n" # for stackEntry in stack: # print stackEntry # print "\n" #end of test code invokeDstFromClient = (cls, method, prototype) invokePosInStack = self._findFirstInvokePos(stack) throughMethod = stack[invokePosInStack] invokeSrcFromStack = stack[invokePosInStack + 1] if invokePosInStack == -1: logger.info("Cannot find the first occurrence of invoke method in the stack! Adding method to suspicious list!") self._addSuspiciousInvoke(throughMethod, invokeDstFromClient, stack) return for invokePathFromSources in self._sources_invoke: invokeSrcFromSources = invokePathFromSources[0] if invokeSrcFromSources != invokeSrcFromStack: continue self._addInvokePathToMCG(invokeSrcFromSources, throughMethod, invokeDstFromClient) if invokePathFromSources in self._uncovered_invoke: self._uncovered_invoke.remove(invokePathFromSources) return self._addSuspiciousInvoke(throughMethod, invokeDstFromClient, stack)
def processDexLoad(self, fileName, source, output, stack): logger.debug("Processing dex load message...") file_hash = getSha256(fileName) file_load_count = self._loaded_files_count.setdefault(file_hash, 0) + 1 newFilePath = self._rename_source_file(fileName, file_hash, str(file_load_count)) self._loaded_files_count[file_hash] = file_load_count self._codeFiles[newFilePath] = file_hash dexloadPathFromStack = self._getDexLoadPathFromStack(stack) if dexloadPathFromStack: srcFromStack = dexloadPathFromStack[0] throughMethod = dexloadPathFromStack[1] if dexloadPathFromStack in self._uncovered_dexload: self._uncovered_dexload.remove(dexloadPathFromStack) self._addDexloadPathToMCG(srcFromStack, throughMethod, newFilePath) #we do analyse files if appropriate dex load calls have found in sources of application #and if we have not analysed file yet if file_load_count > 1: logger.info("File [%s] with hash [%s] is loaded for the [%d]th time! Skipping its analysis!" % (newFilePath, file_hash, file_load_count)) else: self.makeFileAnalysis(newFilePath) return #if the stack does not contain a dexload method detected in the sources self._addSuspiciousDexload(newFilePath, stack) logger.debug("Dex load message processed!")
def _addNewInstancePathToMCG(self, src, through, dst): logger.debug("Adding newInstance method path to our graph...") tupl = (src, through, dst) if tupl not in self._covered_newInstance: self._covered_newInstance.append(tupl) self._stadynaMcg.addNewInstancePath(src, through, dst) logger.info("The path [%s] -- [%s] through [%s] for newInstance method is added to our graph!" % (str(src), str(dst), str(through))) else: logger.info("The path [%s] -- [%s] through [%s] for newInstance method is already in our graph!" % (str(src), str(dst), str(through)))
def _addDexloadPathToMCG(self, src, through, filename): logger.debug("Adding dexload method path to our graph...") tupl = (src, through, filename) if tupl not in self._covered_dexload: self._covered_dexload.append(tupl) self._stadynaMcg.addDexloadPath(src, through, filename) logger.info("The path [%s] -- [%s] through [%s] for dexload is added to our graph!" % (str(src), str(filename), str(through))) else: logger.info("The path [%s] -- [%s] through [%s] for dexload is already in our graph!" % (str(src), str(filename), str(through)))
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 performFinalInfoSave(self, where, resultsFileName, executionTime = -1): logger.debug("Saving information...") self.calculateFinalNumbers() #saving gexf finalGexfFileName = "%s%s" % (resultsFileName, "_final") self.saveGexf(where, finalGexfFileName) #saving log file logFileName = '%s%s' % (resultsFileName, '_log.txt') logSavePath = os.path.join(where, logFileName) self._save_log_file(logSavePath, executionTime) logger.debug("Final results are saved!")
def log_result_path_information(res, res_prefix, res_type) : """ @param res : a result from the detector's result list @param res_prefix : result's category name @param res_type : result's type @rtype : void - it only logs extra information about the analysis result """ res_info = res.get_info() if len(res_info) > 0: paths = res.get_paths() for path in res.get_paths() : access, idx = path[0] m_idx = path[1] logger.info("'%s' %s found '%s'" % (res_prefix, res_type, res_info ) ) logger.debug("\t=> access_flag %s, index %s, method_index %s" % (access, idx, m_idx))
def _getDexLoadPathFromStack(self, stack): logger.debug("Processing dex load stack...") #test code # print "\n" # for stackEntry in stack: # print stackEntry # print "\n" #end of test code #we iterate over stack (not over entries in sources) #because it is possible that there are several dexload entries #in the stack. Thus, we look for the most recent one. for stackEntryPos in xrange(1, len(stack)): stackEntry = stack[stackEntryPos] for dexloadPathFromSources in self._sources_dexload: dexloadSrcFromSources = dexloadPathFromSources[0] dexloadDstFromSources = dexloadPathFromSources[1] if stackEntry != dexloadSrcFromSources: continue prevStackEntry = stack[stackEntryPos - 1] if prevStackEntry == dexloadDstFromSources: logger.debug("The method, which calls dexload, is found [%s%s%s]!" % dexloadSrcFromSources) return dexloadPathFromSources logger.debug("The called dexload method was not detected in sources!") return None
def _findFirstInvokePos(self, tmpList): logger.debug("Finding the first occurrence of invoke method in the stack...") position = -1 for entry in tmpList: position += 1 if entry[0] == "Ljava/lang/reflect/Method;" and entry[1] == "invoke" and entry[2] == "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;": logger.debug("The position of the first occurrence of invoke method is [%d]!" % position) return position logger.debug("We have not found invoke method in the stack!") return position
def _findFirstNewInstancePos(self, tmpList): logger.debug("Finding the first occurrence of new instance method in the stack...") position = -1 for entry in tmpList: position += 1 #print entry cls = entry[0] if cls != "Ljava/lang/Class;" and cls != "Ljava/lang/reflect/Constructor;": continue method = entry[1] if method != "newInstance": continue logger.debug("The position of the first occurrence of new instance method is [%d]!" % position) return position logger.debug("We have not found new instance method in the stack!") return position
def set_attribute(self, name, value): if name not in self.attributes.keys(): logger.debug("There is no [%name] key in the Node attributes!" % name) self.attributes[name] = value
def init(self): # step 1:Extract logger.debug("Unzipping the APK") self.unzip() self.decompile() return {}
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