From 3685443ff5b3ccf668963b776fc0f5ae51184d60 Mon Sep 17 00:00:00 2001 From: Christopher Thompson Date: Mon, 4 Jun 2018 13:56:15 -0700 Subject: [PATCH] Parse annotations out of smali --- smalisca/core/smalisca_analysis.py | 2 +- smalisca/modules/module_smali_parser.py | 60 +++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/smalisca/core/smalisca_analysis.py b/smalisca/core/smalisca_analysis.py index 9f506aa..7e33a7a 100644 --- a/smalisca/core/smalisca_analysis.py +++ b/smalisca/core/smalisca_analysis.py @@ -35,7 +35,7 @@ import abc -class AnalysisBase(metaclass=abc.ABCMeta): +class AnalysisBase(abc.ABCMeta): """Basic analysis class Provides abstract methods how to interact with the results. diff --git a/smalisca/modules/module_smali_parser.py b/smalisca/modules/module_smali_parser.py index 90e122e..4a1b962 100644 --- a/smalisca/modules/module_smali_parser.py +++ b/smalisca/modules/module_smali_parser.py @@ -75,11 +75,41 @@ def parse_file(self, filename): with codecs.open(filename, 'r', encoding='utf8') as f: current_class = None current_method = None + current_annotation = None current_call_index = 0 # Read line by line for l in f.readlines(): - if '.class' in l: + + if '.annotation' in l: + annotation_class = self.is_annotation(l) + if annotation_class: + current_annotation = { + "class": annotation_class, + "value": "", + } + + elif '.end annotation' in l: + if current_method != None: + current_method["annotations"].append(current_annotation) + elif current_class != None: + current_class["annotations"].append(current_annotation) + else: + log.error("Annotation does not have an owner: %s" % annotation_class) + + current_annotation = None + + elif current_annotation != None: + # TODO: Proper parsing of annotations + stripped_line = l.strip() + if stripped_line == "value = {" or stripped_line == "}": + continue + + match = re.search("\"(?P.*)\"", stripped_line) + if match: + current_annotation["value"] += match.group('value') + + elif '.class' in l: match_class = self.is_class(l) if match_class: current_class = self.extract_class(match_class) @@ -229,6 +259,24 @@ def is_class_method(self, line): else: return None + def is_annotation(self, line): + """Check if line contains an annotation definition + + Args: + line (str): Text line to be checked + + Returns: + bool: True if line contains annotation information, otherwise False + + """ + match = re.search("\.annotation\s+(?P[a-z]+)\s+(?P.*)$", line) + if match: + log.debug("\t\tFound annotation: %s" % match.group('class')) + return match.group('class') + else: + log.debug("\t\tNot annotation: %s" % line) + return None + def is_method_call(self, line): """Check [MaÔif the line contains a method call (invoke-*) @@ -281,7 +329,10 @@ def extract_class(self, data): 'const-strings': [], # Methods - 'methods': [] + 'methods': [], + + # Annotations + 'annotations': [], } return c @@ -385,7 +436,10 @@ def extract_class_method(self, data): 'type': " ".join(method_info[:-1]), # Calls - 'calls': [] + 'calls': [], + + # Annotations + 'annotations': [], } return m