def main(args) -> None: """ Function that create the process :param args: :return: """ Database.set_configuration(config) device = None device_type = config['GLOBAL'].get('device_type') if device_type == "physical": device = Physical.Physical(config['PATH'], config['PHYSICAL']) elif device_type == "emulator": device = Emulator.Emulator(config['PATH'], config) elif device_type == "docker": device = DockerEmulator.DockerEmulator(config['PATH'], config['DOCKER']) else: logging.error( "You must choose a device type (physical, emulator, docker)") logging.info("Launching device") try: device.start() logging.info( f"Architecture of the device is : {device.get_device_arch()} ") core = Core.Core(config, device, ModuleGeneral.ModuleGeneral, args.path) core.start_analysis() device.kill_emulators() except Exception as e: logging.error(e)
def parse(module, message, data): if(message['plugin'] == "sharedprefs"): logging.debug("SharedPreferences edited !") # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) shared_pref = SharedPreferences(message['method'], message['file'], message['value']) shared_pref.application_id = module.application.id logging.debug(repr(shared_pref)) query = session.query(SharedPreferences).filter(SharedPreferences.application_id==module.application.id).filter(SharedPreferences.value==shared_pref.value).filter(SharedPreferences.method==shared_pref.method).filter(SharedPreferences.file_path==shared_pref.file_path) resultQuery = query.all() # Prevent duplicates in DB if len(resultQuery) == 0: session.add(shared_pref) session.commit()
def parse(module, message, data): if (message.startswith("dexclassloader:")): # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) args = message[len("dexclassloader:"):].split("|") stackTrace = args[4].split(',') dexclassloader = DexClassLoader(args[0], args[1], args[2], args[3], args[4]) dexclassloader.application_id = module.application.id logging.debug(repr(dexclassloader)) query = session.query(DexClassLoader).filter( DexClassLoader.application_id == module.application.id).filter( DexClassLoader.dexPath == dexclassloader.dexPath).filter( DexClassLoader.optimizedDirectory == dexclassloader.optimizedDirectory).filter( DexClassLoader.librarySearchPath == dexclassloader.librarySearchPath).filter( DexClassLoader.parent == dexclassloader.parent) resultQuery = query.all() if len(resultQuery) == 0: session.add(dexclassloader) session.commit()
def parse(module, message, data): if (message.startswith("file:")): logging.debug("FileInteraction !") # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) method = message[len("file:"):message.index("|")] name = message[message.index("|") + 1:] fileInteraction = File(method, name) fileInteraction.application_id = module.application.id logging.debug(repr(fileInteraction)) query = session.query(File).filter( File.application_id == module.application.id).filter( File.name == fileInteraction.name).filter( File.method == fileInteraction.method) resultQuery = query.all() # Prevent duplicates in DB if len(resultQuery) == 0: session.add(fileInteraction) session.commit()
def parse(module, message, data): if (message['plugin'] == "proxyURL"): # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) proxyURL = ProxyURL(message) proxyURL.application_id = module.application.id logging.debug(repr(proxyURL)) query = session.query(ProxyURL).filter( ProxyURL.application_id == module.application.id).filter( ProxyURL.response_code == proxyURL.response_code).filter( ProxyURL.req_method == proxyURL.req_method).filter( ProxyURL.url == proxyURL.url).filter( ProxyURL.request == proxyURL.request).filter( ProxyURL.response == proxyURL.response) resultQuery = query.all() # Prevent duplicates in DB if len(resultQuery) == 0: session.add(proxyURL) session.commit()
def parse(module, message, data): if (message.startswith("to_string:")): # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) string = String(message[len("to_String:"):]) string.application_id = module.application.id logging.debug(repr(string)) query = session.query(String).filter( String.application_id == module.application.id).filter( String.value == string.value) resultQuery = query.all() # Prevent duplicates in DB if len(resultQuery) == 0: session.add(string) session.commit()
def parse(module, message, data): if (message.startswith('base64:')): logging.debug("base64:parse()") method = message[len("base64: "):] # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() try: data = data.decode() except Exception as e: data = data.hex() logging.error(f"Base64: {e}") base64Module = Base64(method, data) base64Module.application_id = module.application.id logging.debug(repr(base64Module)) query = session.query(Base64).filter( Base64.application_id == module.application.id).filter( Base64.method == base64Module.method).filter( Base64.value == base64Module.value) resultQuery = query.all() # Prevent duplicates in DB if len(resultQuery) == 0: session.add(base64Module) session.commit()
def get_result_plugins(self): # Get result of plugins i.e. Frida Hooks session = Database.get_session() counter = 0 for i in range(len(self.plugins)): # Name of plugin clazzName = list(self.plugins[i].__dict__.keys())[11] # Get plugin's class clazz = self.plugins[i].__getattribute__(clazzName) query = session.query(clazz).filter( clazz.application_id == self.current_application.id) resultQuery = query.all() clazzDict = clazz.__dict__ keys = list(clazzDict.keys()) pluginList = [] for plugin in query: attributesDict = {} for key in keys: if not key.startswith('_'): attributesDict[key] = plugin.__getattribute__(key) if len(attributesDict) != 0: pluginList.append(attributesDict) if len(pluginList) != 0: self.renderPlugins[clazzName] = pluginList
def parse(module, message, data): if (message['plugin'] == "json"): # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) json_value = Json(message['method'], message['value']) json_value.application_id = module.application.id logging.debug(repr(json_value)) query = session.query(Json).filter( Json.application_id == module.application.id).filter( Json.value == json_value.value).filter( Json.method == json_value.method) resultQuery = query.all() # Prevent duplicates in DB if len(resultQuery) == 0: session.add(json_value) session.commit()
def key(self, type, key): ''' Add a key to the database :param type: :param key: :return: ''' # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) application = session.query(Application.Application).get( self.application.id) key = Key(type, key) logging.debug(repr(key)) application.key.append(key) session.add(key) session.add(application) session.commit()
def parse(module, message, data): if (message.startswith('Bypass:')): logging.debug("antiEmulator:parse()") # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() property_name = message[len("Bypass:"******"&")] real_value = message[message.index("&")+1:message.index("|")] return_value = message[message.index("|")+1:] antiEmulator = AntiEmulator(property_name, real_value, return_value) antiEmulator.application_id = module.application.id logging.debug(repr(antiEmulator)) query = session.query(AntiEmulator).filter(AntiEmulator.application_id==module.application.id).filter(AntiEmulator.property==antiEmulator.property).filter(AntiEmulator.real_value==antiEmulator.real_value).filter(AntiEmulator.return_value==antiEmulator.return_value) resultQuery = query.all() # Prevent duplicates in DB if len(resultQuery) == 0: session.add(antiEmulator) session.commit()
def parse(module, message, data): if (message.startswith('delete file:')): logging.debug("deletedFile:parse()") # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() deletedFile = DeletedFiles(message[len("delete file:"):]) deletedFile.application_id = module.application.id logging.debug(repr(deletedFile)) query = session.query(DeletedFiles).filter( DeletedFiles.application_id == module.application.id).filter( DeletedFiles.name == deletedFile.name) resultQuery = query.all() # Prevent duplicates in DB if len(resultQuery) == 0: session.add(deletedFile) session.commit()
def parse(module, message, data): if(message['plugin'] == "library"): logging.debug("Library !") # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) library = Library(message['name']) library.application_id = module.application.id logging.debug(repr(library)) query = session.query(Library).filter(Library.application_id==library.application_id).filter(Library.name==library.name) resultQuery = query.all() # Prevent duplicates in DB if len(resultQuery) == 0: session.add(library) session.commit()
def main(args) -> None: """ Function that create the process :param args: :return: """ Database.set_configuration(config) device = None if config['GLOBAL'].getboolean('use_physical_device'): device = Physical.Physical(config['PATH'], config['PHYSICAL']) else: device = Emulator.Emulator(config['PATH'], config) logging.info("Launching device") device.start() core = Core.Core(config, device, ModuleGeneral.ModuleGeneral, args.path) core.start_analysis() device.kill_emulators()
def url(self, url): ''' Add an url to the database :param url: :return: ''' logging.debug("ModuleGeneral:url()") # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() url = Url(url) # Whitelist Google # whitelist = ['0.0.0.0', '172.', '216.58.'] whitelist = ['0.0.0.0'] add = True if url.ip is not None: for i in whitelist: if url.ip.startswith(i): add = False if add: # Fetch application for this session ( could not use self.application # because the usage must be thread local ) application = session.query(Application.Application).get( self.application.id) logging.debug(repr(url)) query = session.query(Url).filter( Url.application_id == self.application.id).filter( Url.scheme == url.scheme).filter( Url.domain == url.domain).filter( Url.uri == url.uri).filter( Url.ip == url.ip).filter( Url.query == url.query) resultQuery = query.all() if len(resultQuery) == 0: application.url.append(url) session.add(url) session.add(application) else: previous_nb = getattr(url, "nb") setattr(resultQuery[0], "nb", previous_nb + 1) session.commit()
def analyse_sample(self, apk_path): ''' Analyze the given apk :param apk_path: :return: ''' logging.debug("Core:analyse_sample()") self.current_application = Application.Application(apk_path) if not self.check_apk_is_valid(): logging.error( f"The apk architecture and the device architecture ({self.device.get_device_arch()}) doesn't match for application : {self.current_application.filename}" ) return # Database storing session = Database.get_session() self.analysis.application.append(self.current_application) session.add(self.current_application) session.commit() logging.info(f"Package name: {self.current_application.package}") logging.info( f"Main activity: {self.current_application.get_main_activity()}") logging.info(f"Path : {self.current_application.path}") logging.info(f"SHA256 : {self.current_application.get_sha256_hash()}") time_init = time.time() module = self.module(self.current_application, self.plugins) try: if (self.device.type == "Physical" and self.current_application.package in self.device.list_third_party()): self.device.uninstall_application( self.current_application.package) self.device.install_application(self.current_application.path) self.start_receivers(module) current_time = 0 while current_time < self.timeout or self.module.stop == False or ( self.timeout == -1 and self.device.check_is_up()): current_time = time.time() - time_init logging.debug(current_time) time.sleep(1) self.stop_receivers() if (self.timeout != -1): self.device.uninstall_application( self.current_application.package) except Exception as e: self.device.uninstall_application(self.current_application.package) self.stop_receivers() print(e)
def __init__(self, configuration, device: Device, module, path: str): self.configuration = configuration self.device = device self.path = path self.module = module self.session = None self.timeout = int(configuration['ANALYSIS'].get('analysis_timeout')) self.plugins = self.load_plugins() # Object used by the core self.current_application = None self.receivers = [] # Database initialisation session = Database.get_session() self.analysis = Analysis(uuid=str(uuid.uuid4()), date=datetime.now()) session.add(self.analysis) session.commit()
def parse(module,message): if(message.startswith("to_string:")): # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) shared_pref = String(message[len("to_String:"):]) shared_pref.application_id = module.application.id logging.debug(repr(shared_pref)) session.add(shared_pref) session.commit()
def analyse_sample(self, apk_path): ''' Analyze the given apk :param apk_path: :return: ''' logging.debug("Core:analyse_sample()") self.current_application = Application.Application(apk_path) # Database storing session = Database.get_session() self.analysis.application.append(self.current_application) session.add(self.current_application) session.commit() logging.info(f"Package name: {self.current_application.package}") logging.info( f"Main activity: {self.current_application.get_main_activity()}") logging.info(f"Path : {self.current_application.path}") logging.info(f"SHA256 : {self.current_application.get_sha256_hash()}") time_init = time.time() module = self.module(self.current_application, self.plugins) if (self.device.type == "Physical"): self.device.uninstall_application(self.current_application.package) self.device.install_application(self.current_application.path) self.start_receivers(module) current_time = 0 while current_time < self.timeout or self.module.stop == False or ( self.timeout == -1 and self.device.check_is_up()): current_time = time.time() - time_init logging.debug(current_time) time.sleep(1) self.stop_receivers() if (self.timeout != -1): self.device.uninstall_application(self.current_application.package)
def key(self, typeOfMsg, key): ''' Add a key to the database :param type: :param key: :return: ''' # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) application = session.query(Application.Application).get( self.application.id) key = Key(typeOfMsg, key.hex()) logging.debug(repr(key)) query = session.query(Key).filter( Key.application_id == self.application.id).filter( Key.type == key.type).filter(Key.value == key.value) resultQuery = query.all() if len(resultQuery) == 0: application.key.append(key) session.add(key) session.add(application) # else: # previous_nb = getattr(key, "nb") # print(previous_nb) # print(resultQuery[0]) # setattr(resultQuery[0], "nb", previous_nb+1) # print(getattr(resultQuery[0], "nb")) session.commit()
def url(self, url): ''' Add an url to the database :param url: :return: ''' logging.debug("ModuleGeneral:url()") # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() url = Url(url) whitelist = ['0.0.0.0', '172.', '216.58.'] # whitelist = [] add = True if url.ip is not None: for i in whitelist: if url.ip.startswith(i): add = False if add: # Fetch application for this session ( could not use self.application # because the usage must be thread local ) application = session.query(Application.Application).get( self.application.id) logging.debug(repr(url)) application.url.append(url) session.add(url) session.add(application) session.commit()
def get_result_plugins(self): # Get result of plugins i.e. Frida Hooks session = Database.get_session() for i in range(len(self.plugins)): # if there is an instance of the plugin in the database # logging.error(self.plugins[i].__dict__) if "Database" in list(self.plugins[i].__dict__.keys()): # Name of plugin pluginName = list(self.plugins[i].__dict__.keys())[11] # Get plugin's class clazz = self.plugins[i].__getattribute__(pluginName) # Get plugins for all apps that were analyzed str_filter = "application_id" for i in range(len(self.app_ids)): if i == len(self.app_ids) - 1: str_filter += f"=={self.app_ids[i]}" else: str_filter += f"=={self.app_ids[i]} or application_id" # query = session.query(clazz).filter(clazz.application_id==self.current_application.id) query = session.query(clazz).filter(text(str_filter)) resultQuery = query.all() clazzDict = clazz.__dict__ keys = list(clazzDict.keys()) pluginList = [] for plugin in query: attributesDict = {} for key in keys: if not key.startswith('_'): attributesDict[key] = plugin.__getattribute__(key) if len(attributesDict) != 0: pluginList.append(attributesDict) if len(pluginList) != 0: self.renderPlugins[pluginName] = pluginList
def parse(module, message, data): if (message['plugin'] == 'dexclassloader'): # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) dexclassloader = DexClassLoader(message['dexPath'], message['optimizedDirectory'], message['librarySearchPath'], message['parent'], message['entrypoint'], message['stack']) dexclassloader.application_id = module.application.id logging.debug(repr(dexclassloader)) query = session.query(DexClassLoader).filter( DexClassLoader.application_id == module.application.id ).filter(DexClassLoader.dexPath == dexclassloader.dexPath).filter( DexClassLoader.optimizedDirectory == dexclassloader.optimizedDirectory).filter( DexClassLoader.librarySearchPath == dexclassloader.librarySearchPath).filter( DexClassLoader.parent == dexclassloader.parent).filter( DexClassLoader.entrypoint == dexclassloader.entrypoint) resultQuery = query.all() if len(resultQuery) == 0: session.add(dexclassloader) session.commit()
def parse(module, message, data): if (message['plugin'] == "hash"): # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) try: input_value = binascii.unhexlify( message['input_value']).decode('utf-8') except: input_value = binascii.unhexlify(message['input_value']) hash_value = Hash(message['algo'], input_value, binascii.unhexlify(message['output_value']).hex()) hash_value.application_id = module.application.id logging.debug(repr(hash_value)) query = session.query(Hash).filter( Hash.application_id == module.application.id).filter( Hash.algorithm == hash_value.algorithm).filter( Hash.input_value == hash_value.input_value).filter( Hash.output_value == hash_value.output_value) resultQuery = query.all() # Prevent duplicates in DB if len(resultQuery) == 0: session.add(hash_value) session.commit()
import datetime from lib.model.database.Database import Database from sqlalchemy import Column, Integer, String, Date, DateTime, ForeignKey Base = Database.get_declarative_base() class Hash(Base): __tablename__ = 'hash' id = Column(Integer, primary_key=True) date = Column(DateTime, default=datetime.datetime.utcnow) algorithm = Column(String) input_value = Column(String) output_value = Column(String) application_id = Column(Integer, ForeignKey('application.id')) def __init__(self, algo, input_value, output_value): self.algorithm = algo self.input_value = input_value self.output_value = output_value def __repr__(self): return f'<Hash(id={self.id},algorithm="{self.algorithm}",input_value="{self.input_value}",output_value="{self.output_value}",date="{self.date}")>'
def parse(module, message, data): if (message['plugin'] == "cipher"): # Create a thread local session engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() # Fetch application for this session ( could not use self.application # because the usage must be thread local ) key_value = binascii.unhexlify(message["key"]).hex() iv = binascii.unhexlify(message["iv"]).hex() # TODO have link from base64 kind_input = filetype.guess(binascii.unhexlify(message["arg"])) kind_result = filetype.guess(binascii.unhexlify(message["result"])) # print('File extension: %s' % kind.extension) # print('File MIME type: %s' % kind.mime) if message["opmode"] == 1: opmode_info = "ENCRYPT_MODE" try: input_value = binascii.unhexlify(message["arg"]).decode('utf8') except: input_value = base64.b64encode( binascii.unhexlify(message["arg"])).decode('utf8') output_value = binascii.unhexlify(message["result"]).hex() elif message["opmode"] == 2: opmode_info = "DECRYPT_MODE" try: output_value = binascii.unhexlify( message["result"]).decode('utf8') except: output_value = base64.b64encode( binascii.unhexlify(message["result"])).decode('utf8') input_value = binascii.unhexlify(message["arg"]).hex() cipher = Cipher(message["algo"], key_value, iv, opmode_info, input_value, output_value, message["stack"]) cipher.application_id = module.application.id logging.debug(repr(cipher)) query = session.query(Cipher).filter( Cipher.application_id == cipher.application_id ).filter(Cipher.algorithm == cipher.algorithm).filter( Cipher.key == cipher.key).filter(Cipher.iv == cipher.iv).filter( Cipher.opmode == cipher.opmode).filter( Cipher.input_value == cipher.input_value).filter( Cipher.output_value == cipher.output_value) resultQuery = query.all() # Prevent duplicates in DB if len(resultQuery) == 0: session.add(cipher) session.commit()
from lib.model.Url import Url from lib.model.database.Database import Database from lib.model.Analysis import Analysis import uuid import datetime import configparser from lib.report.ReportGenerator import ReportGenerator if __name__ == '__main__': config = configparser.ConfigParser() config.read("../config/config.ini") Database.set_configuration(config) print(Analysis, Application, Url) engine = Database.get_engine() session_factory = sessionmaker(bind=engine) Session = scoped_session(session_factory) session = Session() Session.remove() analysis = session.query(Analysis).all()[0] for i in range(len(analysis.application)): app = Application(analysis.application[i].path) app.url = analysis.application[i].url analysis.application[i] = app generator = ReportGenerator()
def analyse_sample(self, apk_path): ''' Analyze the given apk :param apk_path: :return: ''' logging.debug("Core:analyse_sample()") self.current_application = Application.Application(apk_path) if not self.check_apk_is_valid(): logging.error( f"The apk architecture and the device architecture ({self.device.get_device_arch()}) doesn't match for application : {self.current_application.filename}" ) return # Database storing session = Database.get_session() self.analysis.application.append(self.current_application) session.add(self.current_application) session.commit() self.app_ids.append(self.current_application.id) logging.info(f"Package name: {self.current_application.package}") logging.info( f"Main activity: {self.current_application.get_main_activity()}") logging.info(f"Path : {self.current_application.path}") logging.info(f"SHA256 : {self.current_application.get_sha256_hash()}") logging.info( f"Accessibility services : {self.current_application.get_accessibility_services()}" ) logging.info( f"Administrator receivers : {self.current_application.get_administrator_receivers()}" ) logging.info( f"Permissions : {self.current_application.get_permissions()}") time_init = time.time() module = self.module(self.device, self.current_application, self.plugins) try: if (self.device.type == "Physical" and self.current_application.package in self.device.list_third_party()): self.device.uninstall_application( self.current_application.package) self.device.install_application( self.current_application.path, self.configuration['ANALYSIS'].getboolean( 'auto_grant_permissions')) self.start_receivers(module) # Automatically enable accessibility services of an application if (self.configuration['ANALYSIS'].getboolean( 'auto_grant_accessibility')): self.device.enable_accessibility_services( self.current_application) current_time = 0 while current_time < self.timeout or self.module.stop == False or ( self.timeout == -1 and self.device.check_is_up()): current_time = time.time() - time_init logging.debug(f"{int(current_time)}/{self.timeout} seconds") time.sleep(1) self.stop_receivers() # pulling the internal files if the options is choosed if (self.configuration['ANALYSIS'].getboolean("pull_files")): self.device.pull_application_internal_files( self.current_application.package, f"{self.report_path}/{self.current_application.package}_{self.current_application.get_sha256_hash()}" ) if (self.timeout != -1): self.device.uninstall_application( self.current_application.package) except Exception as e: logging.error(e) self.device.uninstall_application(self.current_application.package) self.stop_receivers()