def add_method(self, method): """Adds property to class Args: method (dict): Method object to insert """ class_obj = self.get_class_by_name(method['class']) new_method = SmaliMethod( method_name=method['name'], method_type=method['type'], method_args=method['args'], method_ret=method['return'], method_class=method['class'] ) # Append new method to class class_obj.methods.append(new_method) # Add to DB try: self.db.merge(class_obj) except sql.exc.IntegrityError: self.db.rollback() log.error("Found NOT unique values")
def add_property(self, prop): """Adds property to class Args: prop (dict): Property object to insert """ class_obj = self.get_class_by_name(prop['class']) new_prop = SmaliProperty( property_name=prop['name'], property_type=prop['type'], property_info=prop['info'], property_class=prop['class'] ) # Append new property to class class_obj.properties.append(new_prop) # Add to DB try: self.db.merge(class_obj) except sql.exc.IntegrityError: self.db.rollback() log.error("Found NOT unique values")
def write_json(self, filename): """Write app object as JSON to file""" try: with open(filename, 'w+') as f: json.dump(self.to_json(), f, indent=JSON_SETTINGS['indent']) except IOError: log.error("Couldn't save data to %s" % filename)
def write_json(self, filename): """Write app object as JSON to file""" try: with open(filename, 'w+') as f: f.write(self.to_json()) except IOError: log.error("Couldn't save data to %s" % filename)
def search(self, args={}): """Search globally for a certain pattern Args: args (dict): Specify a dict containing the search criterias Returns: dict: Returns a dict containing found classes, properties, methods, calls: results = {} results = {'classes': found_classes, 'properties': 'found_properties', ... } """ table = None classes = [] properties = [] consts = [] methods = [] if 'pattern' not in args: log.error("No search pattern") if 'table' in args: table = args['table'] if table == 'class': # Search for classes classes = self.search_class_by_pattern(args['pattern']) elif table == 'property': # Search for properties properties = self.search_property_by_pattern(args['pattern']) elif table == 'const': # Search for const strings consts = self.search_const_string_by_pattern(args['pattern']) elif table == 'method': # Search for methods methods = self.search_method_by_pattern(args['pattern']) elif table is None: # Search for all classes = self.search_class_by_pattern(args['pattern']) properties = self.search_property_by_pattern(args['pattern']) consts = self.search_const_string_by_pattern(args['pattern']) methods = self.search_method_by_pattern(args['pattern']) else: log.error("Invalid table") # Return results return { 'classes': classes, 'properties': properties, 'consts': consts, 'methods': methods }
def search(self, args={}): """Search globally for a certain pattern Args: args (dict): Specify a dict containing the search criterias Returns: dict: Returns a dict containing found classes, properties, methods, calls: results = {} results = {'classes': found_classes, 'properties': 'found_properties', ... } """ table = None classes = [] properties = [] consts = [] methods = [] if "pattern" not in args: log.error("No search pattern") if "table" in args: table = args["table"] if table == "class": # Search for classes classes = self.search_class_by_pattern(args["pattern"]) elif table == "property": # Search for properties properties = self.search_property_by_pattern(args["pattern"]) elif table == "const": # Search for const strings consts = self.search_const_string_by_pattern(args["pattern"]) elif table == "method": # Search for methods methods = self.search_method_by_pattern(args["pattern"]) elif table is None: # Search for all classes = self.search_class_by_pattern(args["pattern"]) properties = self.search_property_by_pattern(args["pattern"]) consts = self.search_const_string_by_pattern(args["pattern"]) methods = self.search_method_by_pattern(args["pattern"]) else: log.error("Invalid table") # Return results return {"classes": classes, "properties": properties, "consts": consts, "methods": methods}
def read_json(self, filename): """Create class structure from json file""" try: with open(filename, 'r') as f: data = json.loads(json.load(f)) # Set classes if 'classes' in data: self.classes = data['classes'] except IOError: log.error("Couldn't read from %s" % filename)
def search_class(self, args={}): """Searches for classes Args: args (dict): Specify a dict containing the search criterias Examples: d = u{'type': 'class_name', 'pattern': 'test'} search_class(d) Returns: list: List of any results, None otherwise. """ result = None query = self.db.query(SmaliClass) # Search for class if ('type' in args) and ('pattern' in args): # Search for class id if args['type'] == 'id': result = query.filter( SmaliClass.id == int(args['pattern'])).all() # Search for class names elif args['type'] == 'class_name': result = query.filter( SmaliClass.class_name.contains(args['pattern'])).all() # Search for class types elif args['type'] == 'class_type': result = query.filter( SmaliClass.class_type.contains(args['pattern'])).all() # Search for class package elif args['type'] == 'class_package': result = query.filter( SmaliClass.class_package.contains(args['pattern'])).all() # Search for path location elif args['type'] == 'path': result = query.filter(SmaliClass.path.contains( args['pattern'])).all() else: log.error("Invalid search type: %s" % args['type']) else: result = query.all() return result
def search_property(self, args={}): """Searches for class properties Args: args (dict): Specify a dict containing the search criterias Examples: d = u{'type': 'property_type', 'pattern': 'private'} search_property(d) Returns: list: List of any results, None otherwise. """ result = None query = self.db.query(SmaliProperty) # Search for property if ('type' in args) and ('pattern' in args): # Search for property id if args['type'] == 'id': result = query.filter( SmaliProperty.id == int(args['pattern'])).all() # Search for property name elif args['type'] == 'property_name': result = query.filter( SmaliProperty.property_name.contains( args['pattern'])).all() # Search for property type elif args['type'] == 'property_type': result = query.filter( SmaliProperty.property_type.contains( args['pattern'])).all() # Search for property class elif args['type'] == 'property_class': result = query.filter( SmaliProperty.property_class.contains( args['pattern'])).all() else: log.error("Invalid search type: %s" % args['type']) else: result = query.all() return result
def search_class(self, args={}): """Searches for classes Args: args (dict): Specify a dict containing the search criterias Examples: d = u{'type': 'class_name', 'pattern': 'test'} search_class(d) Returns: list: List of any results, None otherwise. """ result = None query = self.db.query(SmaliClass) # Search for class if ("type" in args) and ("pattern" in args): # Search for class id if args["type"] == "id": result = query.filter(SmaliClass.id == int(args["pattern"])).all() # Search for class names elif args["type"] == "class_name": result = query.filter(SmaliClass.class_name.contains(args["pattern"])).all() # Search for class types elif args["type"] == "class_type": result = query.filter(SmaliClass.class_type.contains(args["pattern"])).all() # Search for class package elif args["type"] == "class_package": result = query.filter(SmaliClass.class_package.contains(args["pattern"])).all() # Search for path location elif args["type"] == "path": result = query.filter(SmaliClass.path.contains(args["pattern"])).all() else: log.error("Invalid search type: %s" % args["type"]) else: result = query.all() return result
def do_sm(self, params): """Search for methods. Type 'sm --help' for help.""" local_fields = self.method_fields try: results = None # Parse arguments args = self.sm_parser.parse_args(params.split()) if args.search_type: # Print available columns if args.search_type == '?': print([c['name'] for c in local_fields]) return # Search if args.search_pattern: if any(c['name'] == args.search_type for c in local_fields): p = { 'type': args.search_type, 'pattern': args.search_pattern } results = self.analysis.search_method(p) else: log.error( "No such column! Type '-c ?' for a list of available columns." ) else: log.error("No pattern (-p) specified") else: results = self.analysis.search_method() # Exclude fields if args.exclude_fields: local_fields = [ d for d in local_fields if d['name'] not in args.exclude_fields ] # Print results self.print_prettytable(args, local_fields, results) except SystemExit: pass
def search_const_string(self, args={}): """Searches for const strings Args: args (dict): Specify a dict containing the search criterias Returns: list: List of any results, None otherwise. """ result = None query = self.db.query(SmaliConstString) # Search for const strings if ('type' in args) and ('pattern' in args): # Search for id if args['type'] == 'id': result = query.filter( SmaliConstString.id == int(args['pattern'])).all() # Search for variable name elif args['type'] == 'const_string_var': result = query.filter( SmaliConstString.const_string_var.contains( args['pattern'])).all() # Search for value elif args['type'] == 'const_string_value': result = query.filter( SmaliConstString.const_string_value.contains( args['pattern'])).all() # Search for class elif args['type'] == 'const_string_class': result = query.filter( SmaliConstString.const_string_class.contains( args['pattern'])).all() else: log.error("Invalid search type: %s" % args['type']) else: result = query.all() return result
def search_method(self, args={}): """Searches for class methods Args: args (dict): Specify a dict containing the search criterias Returns: list: List of any results, None otherwise. """ result = None query = self.db.query(SmaliMethod) # Search for method if ('type' in args) and ('pattern' in args): # Search for method id if args['type'] == 'id': result = query.filter( SmaliMethod.id == int(args['pattern'])).all() # Search for method name elif args['type'] == 'method_name': result = query.filter( SmaliMethod.method_name.contains(args['pattern'])).all() # Search for method type elif args['type'] == 'method_type': result = query.filter( SmaliMethod.method_type.contains(args['pattern'])).all() # Search for method class elif args['type'] == 'method_class': result = query.filter( SmaliMethod.method_class.contains(args['pattern'])).all() else: log.error("Invalid search type: %s" % args['type']) else: result = query.all() return result
def search_property(self, args={}): """Searches for class properties Args: args (dict): Specify a dict containing the search criterias Examples: d = u{'type': 'property_type', 'pattern': 'private'} search_property(d) Returns: list: List of any results, None otherwise. """ result = None query = self.db.query(SmaliProperty) # Search for property if ("type" in args) and ("pattern" in args): # Search for property id if args["type"] == "id": result = query.filter(SmaliProperty.id == int(args["pattern"])).all() # Search for property name elif args["type"] == "property_name": result = query.filter(SmaliProperty.property_name.contains(args["pattern"])).all() # Search for property type elif args["type"] == "property_type": result = query.filter(SmaliProperty.property_type.contains(args["pattern"])).all() # Search for property class elif args["type"] == "property_class": result = query.filter(SmaliProperty.property_class.contains(args["pattern"])).all() else: log.error("Invalid search type: %s" % args["type"]) else: result = query.all() return result
def do_sm(self, params): """Search for methods. Type 'sm --help' for help.""" local_fields = self.method_fields try: results = None # Parse arguments args = self.sm_parser.parse_args(params.split()) if args.search_type: # Print available columns if args.search_type == '?': print([c['name'] for c in local_fields]) return # Search if args.search_pattern: if any(c['name'] == args.search_type for c in local_fields): p = { 'type': args.search_type, 'pattern': args.search_pattern } results = self.analysis.search_method(p) else: log.error("No such column! Type '-c ?' for a list of available columns.") else: log.error("No pattern (-p) specified") else: results = self.analysis.search_method() # Exclude fields if args.exclude_fields: local_fields = [d for d in local_fields if d['name'] not in args.exclude_fields] # Print results self.print_prettytable(args, local_fields, results) except SystemExit: pass
def get_classes(self, args): """Returns classes specified by args Returns: list: Return list of classes if any, otherwise None """ try: results = None if args.search_type: # Print available columns if args.search_type == '?': print([c['name'] for c in self.class_fields]) return # Search if args.search_pattern: if any(c['name'] == args.search_type for c in self.class_fields): p = { 'type': args.search_type, 'pattern': args.search_pattern } results = self.analysis.search_class(p) else: log.error( "No such column! Type '-c ?' for a list of available columns." ) else: log.error("No pattern (-p) specified") else: results = self.analysis.search_class() return results except SystemExit: pass
def do_scs(self, params): """Search for const strings. Type 'scs --help' for help.""" local_fields = self.const_string_fields try: results = None # Parse arguments args = self.scs_parser.parse_args(params.split()) if args.search_type: # Print available columns if args.search_type == '?': print([c['name'] for c in local_fields]) return # Search if args.search_pattern: if any(c['name'] == args.search_type for c in local_fields): p = { 'type': args.search_type, 'pattern': args.search_pattern } results = self.analysis.search_const_string(p) else: log.error( "No such column! Type '-c ?' for a list of available columns." ) else: log.error("No pattern (-p) specified") else: results = self.analysis.search_const_string() # Print results self.print_prettytable(args, local_fields, results) except SystemExit: pass
def search_method(self, args={}): """Searches for class methods Args: args (dict): Specify a dict containing the search criterias Returns: list: List of any results, None otherwise. """ result = None query = self.db.query(SmaliMethod) # Search for method if ("type" in args) and ("pattern" in args): # Search for method id if args["type"] == "id": result = query.filter(SmaliMethod.id == int(args["pattern"])).all() # Search for method name elif args["type"] == "method_name": result = query.filter(SmaliMethod.method_name.contains(args["pattern"])).all() # Search for method type elif args["type"] == "method_type": result = query.filter(SmaliMethod.method_type.contains(args["pattern"])).all() # Search for method class elif args["type"] == "method_class": result = query.filter(SmaliMethod.method_class.contains(args["pattern"])).all() else: log.error("Invalid search type: %s" % args["type"]) else: result = query.all() return result
def search_const_string(self, args={}): """Searches for const strings Args: args (dict): Specify a dict containing the search criterias Returns: list: List of any results, None otherwise. """ result = None query = self.db.query(SmaliConstString) # Search for const strings if ("type" in args) and ("pattern" in args): # Search for id if args["type"] == "id": result = query.filter(SmaliConstString.id == int(args["pattern"])).all() # Search for variable name elif args["type"] == "const_string_var": result = query.filter(SmaliConstString.const_string_var.contains(args["pattern"])).all() # Search for value elif args["type"] == "const_string_value": result = query.filter(SmaliConstString.const_string_value.contains(args["pattern"])).all() # Search for class elif args["type"] == "const_string_class": result = query.filter(SmaliConstString.const_string_class.contains(args["pattern"])).all() else: log.error("Invalid search type: %s" % args["type"]) else: result = query.all() return result
def add_property(self, prop): """Adds property to class Args: prop (dict): Property object to insert """ class_obj = self.get_class_by_name(prop['class']) new_prop = SmaliProperty(property_name=prop['name'], property_type=prop['type'], property_info=prop['info'], property_class=prop['class']) # Append new property to class class_obj.properties.append(new_prop) # Add to DB try: self.db.merge(class_obj) except sql.exc.IntegrityError: self.db.rollback() log.error("Found NOT unique values")
def add_const_string(self, const_string): """Adds const string to class Args: prop (dict): Property object to insert """ class_obj = self.get_class_by_name(const_string['class']) new_const_string = SmaliConstString( const_string_var=const_string['name'], const_string_value=const_string['value'], const_string_class=const_string['class']) # Append new const-string to class class_obj.const_strings.append(new_const_string) # Add to DB try: self.db.merge(class_obj) except: self.db.rollback() log.error("Failed inserting const-string\:%s" % new_const_string)
def add_const_string(self, const_string): """Adds const string to class Args: prop (dict): Property object to insert """ class_obj = self.get_class_by_name(const_string['class']) new_const_string = SmaliConstString( const_string_var=const_string['name'], const_string_value=const_string['value'], const_string_class=const_string['class'] ) # Append new const-string to class class_obj.const_strings.append(new_const_string) # Add to DB try: self.db.merge(class_obj) except: self.db.rollback() log.error("Failed inserting const-string\:%s" % new_const_string)
def get_classes(self, args): """Returns classes specified by args Returns: list: Return list of classes if any, otherwise None """ try: results = None if args.search_type: # Print available columns if args.search_type == '?': print([c['name'] for c in self.class_fields]) return # Search if args.search_pattern: if any(c['name'] == args.search_type for c in self.class_fields): p = { 'type': args.search_type, 'pattern': args.search_pattern } results = self.analysis.search_class(p) else: log.error("No such column! Type '-c ?' for a list of available columns.") else: log.error("No pattern (-p) specified") else: results = self.analysis.search_class() return results except SystemExit: pass
def add_method(self, method): """Adds property to class Args: method (dict): Method object to insert """ class_obj = self.get_class_by_name(method['class']) new_method = SmaliMethod(method_name=method['name'], method_type=method['type'], method_args=method['args'], method_ret=method['return'], method_class=method['class']) # Append new method to class class_obj.methods.append(new_method) # Add to DB try: self.db.merge(class_obj) except sql.exc.IntegrityError: self.db.rollback() log.error("Found NOT unique values")
def do_scs(self, params): """Search for const strings. Type 'scs --help' for help.""" local_fields = self.const_string_fields try: results = None # Parse arguments args = self.scs_parser.parse_args(params.split()) if args.search_type: # Print available columns if args.search_type == '?': print([c['name'] for c in local_fields]) return # Search if args.search_pattern: if any(c['name'] == args.search_type for c in local_fields): p = { 'type': args.search_type, 'pattern': args.search_pattern } results = self.analysis.search_const_string(p) else: log.error("No such column! Type '-c ?' for a list of available columns.") else: log.error("No pattern (-p) specified") else: results = self.analysis.search_const_string() # Print results self.print_prettytable(args, local_fields, results) except SystemExit: pass
def parse_file(self, filename): """Parse specific file This will parse specified file for: * classes * class properties * class methods * calls between methods Args: filename (str): Filename of file to be parsed """ 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 '.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<value>.*)\"", 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) self.classes.append(current_class) elif '.super' in l: match_class_parent = self.is_class_parent(l) if match_class_parent: current_class['parent'] = match_class_parent elif '.field' in l: match_class_property = self.is_class_property(l) if match_class_property: p = self.extract_class_property(match_class_property) current_class['properties'].append(p) elif 'const-string' in l: match_const_string = self.is_const_string(l) if match_const_string: c = self.extract_const_string(match_const_string) current_class['const-strings'].append(c) elif '.method' in l: match_class_method = self.is_class_method(l) if match_class_method: m = self.extract_class_method(match_class_method) current_method = m current_call_index = 0 current_class['methods'].append(m) elif 'invoke' in l: match_method_call = self.is_method_call(l) if match_method_call: m = self.extract_method_call(match_method_call) # Add calling method (src) m['src'] = current_method['name'] # Add call index m['index'] = current_call_index current_call_index += 1 # Add call to current method current_method['calls'].append(m) # Close fd f.close()