Пример #1
0
 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!")
Пример #2
0
    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)
Пример #3
0
    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)
Пример #4
0
 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
Пример #5
0
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
Пример #6
0
    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
Пример #7
0
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)
Пример #8
0
 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!")
Пример #9
0
    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]
Пример #10
0
    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)
Пример #11
0
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
Пример #12
0
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