Esempio n. 1
0
 def _extract_custom_signature_from(self, string: str) -> Sequence[str]:
     if not hasattr(self, "_signatures"):
         self._generic_signature = Signature()
     signature = self._generic_signature.get_matches_in_string(string)
     if signature != "":
         return [signature]
     return []
Esempio n. 2
0
    def _extract_and_set_signatures_from(self, string: str):
        """
        Extract eventual signatures from a string and set the correspondent attribute.

        :param string: The string from which extracting the eventual signatures.
        """
        if not hasattr(self, "_shell"):
            self._generic_signature = Signature()
            match = self._generic_signature.get_matches_in_string(string)
            if match != "" and match not in self._custom_signatures:
                self._custom_signatures.append(match)
Esempio n. 3
0
 def parse_signatures(signature: Signature,
                      strings: List,
                      min_string_len: Optional[bool] = None) -> List:
     signatures = []
     for string in strings:
         if min_string_len is None or len(string) > min_string_len:
             match, is_valid = signature.search(string)
             if is_valid and match is not None and match != "":
                 signatures.append(match)
     return sorted(signatures)
Esempio n. 4
0
class TestSignature(unittest.TestCase):
    """
    Test Signature parser.
    """

    sut = Signature()

    @parameterized.expand([
        ["apk", True],
        ["root", True],
        ["hack", True],
        ["esploid", True],
        ["tattoo", True],
        ["AdMob", True],
        ["http://www.domain.com", False],
        ["adbd", False],
        ["/system/bin", False],
        ["VersionConstants.java", False],
    ])
    def test_is_valid(self, raw_string, expected):
        result = self.sut.is_valid(raw_string)

        self.assertEqual(expected, result)

    @parameterized.expand([
        [
            "\"mOnRootMePleaseDialogClickListener",
            "\"mOnRootMePleaseDialogClickListener", True
        ],
        ["str_root_already_rooted", "str_root_already_rooted", True],
        ["tv_gen_exploit_msg", "tv_gen_exploit_msg", True],
        ["tattoo_hack_g6561203.ko", "tattoo_hack_g6561203.ko", True],
        ["6ixxx", "6ixxx", True],
        [
            "#preserveType: %b, type: %s, obj: %s",
            "#preserveType: %b, type: %s, obj: %s", True
        ],
        [
            "Mozilla/5.0 (Linux; U; Android %s) Version/3.0.4 Mobile Safari/523.12.2 (AdMob-ANDROID-%s)",
            "Mozilla/5.0 (Linux; U; Android %s) Version/3.0.4 Mobile Safari/523.12.2 (AdMob-ANDROID-%s)",
            True
        ],
        [
            "8Lcom/corner23/android/universalandroot/UniversalAndroot;",
            "8Lcom/corner23/android/universalandroot/UniversalAndroot;", True
        ],
        [" - no match - ", None, False],
        ["http://www.domain.com", None, False],
        ["chmod 777", None, False],
    ])
    def test_search(self, pattern, expected_match, expected_is_valid):
        match, is_valid = self.sut.search(pattern)

        self.assertEqual(match, expected_match)
        self.assertEqual(is_valid, expected_is_valid)
Esempio n. 5
0
class Dex(File, DexInterface):
    """
    Parser implementation for Android DEX file.
    """

    __DEX_FILE_REGEX = ".*\\.dex$"

    def __init__(self,
                 filepath: str,
                 filename: str,
                 string_processing: bool = True,
                 logger=logger):
        super(Dex, self).__init__(filepath, filename)

        self.logger = logger
        self.logger.debug("Init Dex on %s, filename=%s, string_processing=%s",
                          filepath, filename, string_processing)

        self._filename = filename

        self._strings = []  # type: List[str]
        self._urls = []  # type: List[str]
        self._shell_commands = []  # type: List[str]
        self._custom_signatures = []  # type: List[str]

        self._extract_and_set_strings()

        if string_processing:
            self._extract_and_set_urls()
            self._extract_and_set_shell_commands()
            # self. _extract_and_set_signatures()

    def _extract_and_set_strings(self):
        self.logger.debug("Extracting strings...")
        command = "strings " + self.get_file_path()
        process = subprocess.Popen(command,
                                   stdout=subprocess.PIPE,
                                   stderr=None,
                                   shell=True)
        strings = filter(lambda string: string != "",
                         (string.strip() for string in process.communicate()
                          [0].decode("utf-8").splitlines()))
        self._strings = sorted(strings)
        self.logger.debug("%d strings extracted", len(self._strings))

    def _extract_and_set_urls(self):
        self.logger.debug("Extracting URLs from strings...")
        urls = (url for string in self._strings
                for url in self._extract_urls_from(string))
        self._urls = sorted(urls)
        self.logger.debug("%s URLs extracted from strings", len(self._urls))

    def _extract_and_set_shell_commands(self):
        self.logger.debug("Extracting shell commands from strings...")
        shell_commands = (
            command for string in self._strings
            for command in self._extract_shell_commands_from(string))
        self._shell_commands = sorted(shell_commands)
        self.logger.debug("%s shell commands extracted from strings",
                          len(self._shell_commands))

    def _extract_and_set_signatures(self):
        self.logger.debug("Extracting signatures from strings...")
        custom_signatures = (
            signature for string in self._strings
            for signature in self._extract_custom_signature_from(string))
        self._custom_signatures = sorted(custom_signatures)
        self.logger.debug("%s signatures extracted from strings",
                          len(self._custom_signatures))

    def _extract_urls_from(self, string: str) -> Sequence[str]:
        if not hasattr(self, "_uri"):
            self._uri_signature = URISignature()
        if len(string) > 6:
            uri = self._uri_signature.get_matches_in_string(string)
            if uri != "":
                return [uri]
        return []

    def _extract_shell_commands_from(self, string: str) -> Sequence[str]:
        if not hasattr(self, "_shell"):
            self._shell_signature = ShellCommandSignature()
        command = self._shell_signature.get_matches_in_string(string)
        if command != "":
            return [command]
        return []

    def _extract_custom_signature_from(self, string: str) -> Sequence[str]:
        if not hasattr(self, "_signatures"):
            self._generic_signature = Signature()
        signature = self._generic_signature.get_matches_in_string(string)
        if signature != "":
            return [signature]
        return []

    @staticmethod
    def looks_like_a_dex(filename: str) -> bool:
        return bool(re.search(Dex.__DEX_FILE_REGEX, filename))

    def dump(self) -> Dict:
        dump = super(Dex, self).dump()
        dump["urls"] = self._urls
        dump["shell_commands"] = self._shell_commands
        # TODO: improve custom signatures parsing performance (commented in the meanwhile because far too slow)
        # dump["custom_signatures"] = self._custom_signatures
        dump["strings"] = self.get_strings()
        return dump

    def get_strings(self) -> List:
        return self._strings

    def get_urls(self) -> List:
        return self._urls

    def get_shell_commands(self) -> List:
        return self._shell_commands

    def get_custom_signatures(self) -> List:
        return self._custom_signatures
Esempio n. 6
0
class Dex(File, DexInterface):
    """
    Parser implementation for Android classes.dex file.
    """

    __FILE_NAME_CLASSES_DEX = "classes.dex"

    def __init__(self, filepath: str, string_processing: bool = True):
        super(Dex, self).__init__(filepath, "classes.dex")

        self._strings = []  # type: List[str]
        self._urls = []  # type: List[str]
        self._shell_commands = []  # type: List[str]
        self._custom_signatures = []  # type: List[str]

        self._extract_and_set_strings()

        if string_processing:
            self._extract_and_set_substring_from()

    def _extract_and_set_strings(self):
        """
        Extract the strings from the classes.dex file and set the correspondent attributes.
        Empty strings will be removed.
        """
        command = "strings " + self.get_file_path()
        process = subprocess.Popen(command,
                                   stdout=subprocess.PIPE,
                                   stderr=None,
                                   shell=True)
        self._strings = process.communicate()[0].decode("utf-8").splitlines()
        self._strings.sort()
        while "" in self._strings:
            self._strings.remove("")

    def _extract_and_set_substring_from(self):
        """
        Extract the strings from the classes.dex file and set the correspondent attributes.
        Empty strings will be removed.
        """
        for string in self._strings:
            if string == "":
                continue

            self._extract_and_set_urls_from(string)
            self._extract_and_set_shell_commands_from(string)
            #self._extract_and_set_signatures_from(string)

        self._urls.sort()
        self._shell_commands.sort()
        #self._custom_signatures.sort()

    def _extract_and_set_urls_from(self, string: str):
        """
        Extract eventual URLs from a string and set the correspondent attribute.

        :param string: The string from which extracting the eventual URLs.
        """
        if not hasattr(self, "_uri"):
            self._uri_signature = URISignature()
        if len(string) > 6:
            url = self._uri_signature.get_matches_in_string(string)
            if url != "" and url not in self._urls:
                self._urls.append(url)

    def _extract_and_set_shell_commands_from(self, string: str):
        """
        Extract eventual shell commands from a string and set the correspondent attribute.

        :param string: The string from which extracting the eventual shell commands.
        """
        if not hasattr(self, "_shell"):
            self._shell_signature = ShellCommandSignature()
        command = self._shell_signature.get_matches_in_string(string)
        if command != "" and command not in self._shell_commands:
            self._shell_commands.append(command)

    def _extract_and_set_signatures_from(self, string: str):
        """
        Extract eventual signatures from a string and set the correspondent attribute.

        :param string: The string from which extracting the eventual signatures.
        """
        if not hasattr(self, "_shell"):
            self._generic_signature = Signature()
            match = self._generic_signature.get_matches_in_string(string)
            if match != "" and match not in self._custom_signatures:
                self._custom_signatures.append(match)

    @staticmethod
    def looks_like_a_dex(filename: str) -> bool:
        return filename == Dex.__FILE_NAME_CLASSES_DEX

    def dump(self) -> Dict:
        dump = super(Dex, self).dump()
        dump["urls"] = self._urls
        dump["shell_commands"] = self._shell_commands
        #dump["custom_signatures"] = self._custom_signatures
        dump["strings"] = self._strings
        return dump

    def get_strings(self) -> List:
        return self._strings

    def get_urls(self) -> List:
        return self._urls

    def get_shell_commands(self) -> List:
        return self._shell_commands

    def get_custom_signatures(self) -> List:
        return self._custom_signatures
Esempio n. 7
0
 def setUpClass(cls):
     cls.signature = Signature()