Esempio n. 1
0
    def run(self) -> None:
        LOGGER.debug('{} start'.format(self.__class__.__name__))

        threads = []

        while True:
            devices = frida.enumerate_devices()

            for device in devices:
                if device.type != 'usb':
                    continue

                duplicated = False

                for t in threads:
                    if t.device.id == device.id:
                        if not t.is_alive():
                            threads.remove(t)
                            break

                        duplicated = True
                        break

                if duplicated:
                    continue
                try:
                    new_thread = FridaThread(device, self.install, self.port,
                                             self.regexps, True)
                    new_thread.start()
                    threads.append(new_thread)
                except Exception as e:
                    LOGGER.error(e)

            time.sleep(0.1)
Esempio n. 2
0
    def hook_apps(self):
        apps = set()

        # monitor apps
        while True:
            time.sleep(0.1)

            new_apps = set(p.name for p in self.device.enumerate_processes())
            if not new_apps:
                continue

            incremental_apps = new_apps - apps
            decremental_apps = apps - new_apps

            for incremental_app in incremental_apps:
                for regexp in self.regexps:
                    if re.search(regexp, incremental_app):
                        # waiting for app startup completely
                        time.sleep(0.1)

                        try:
                            self.hook(incremental_app)
                        except Exception as e:
                            LOGGER.error(e)
                        finally:
                            break

            for decremental_app in decremental_apps:
                for regexp in self.regexps:
                    if re.search(regexp, decremental_app):
                        LOGGER.info('app {} has died'.format(decremental_app))
                        break

            apps = new_apps
Esempio n. 3
0
    def run(self) -> None:
        LOGGER.info("{} start with hook device: id={}, name={}, type={}".format(
            self.__class__.__name__, self.device.id, self.device.name, self.device.type))

        try:
            self.prepare()
            self.hook_apps()
        except Exception as e:
            LOGGER.error(e)
Esempio n. 4
0
def setLoggingLevel(args):
    # Set FileHandler
    filename = os.path.join(paths.w9scan_Output_Path, "log" + "_" + str(int(time.time())) + ".txt")
    logger.info("The log file will be saved on: '%s'"%filename)
    FILE_HANDLER = logging.FileHandler(filename)   
    FORMATTER = logging.Formatter("\r[%(asctime)s] [%(levelname)s] %(message)s", "%H:%M:%S")
    FILE_HANDLER.setFormatter(FORMATTER)
    LOGGER.addHandler(FILE_HANDLER)
    
    if args.debug:
        LOGGER.setLevel(CUSTOM_LOGGING.DEBUG)
Esempio n. 5
0
    def shutdown(self):
        LOGGER.debug('shutdown device ' + self.device.id)

        self.kill_frida_servers()

        if self.device.type == 'remote':
            port_manager.release_port(self.forward_port)
            self.adb.clear_forward(self.forward_port)

        if self.port:
            self.iptables.uninstall()
            self.adb.clear_reverse(self.port)
Esempio n. 6
0
def main():
    parser = argparse.ArgumentParser(description='A tool that hook all apps you need')

    parser.add_argument('regexps', type=str, nargs='*',
                        help=r'Regexps for the apps you want to hook such as "^com\.baidu\.", '
                             r'empty for hooking all apps')
    parser.add_argument('-i', '--install', action='store_true',
                        help='install frida server to /data/local/tmp automatically')
    parser.add_argument('-p', '--port', type=int,
                        help='reverse tcp port, if specified, manipulate iptables automatically')
    parser.add_argument('-v', action='store_true', help='verbose output')

    args = parser.parse_args()

    if args.v:
        LOGGER.setLevel(logging.DEBUG)

    # set log
    os.makedirs(LOG_DIR, mode=0o700, exist_ok=True)
    log_filename = time.strftime('%Y-%m-%d_%H-%M-%S.log')
    log_file = open(os.path.join(LOG_DIR, log_filename), 'a', encoding='utf-8')
    logger_handler = ColorizingStreamHandler(log_file)
    logger_handler.setFormatter(FORMATTER)
    LOGGER.addHandler(logger_handler)

    Adb.start_server()

    try:
        t = WatchThread(args.install, args.port, args.regexps, True)
        t.start()
        t.join()
    except KeyboardInterrupt:
        LOGGER.info('shutdown, thank you for using frida skeleton')
    except Exception as e:
        LOGGER.error(e)
Esempio n. 7
0
def setLoggingLevel(args):
    #日志文件处理函数
    filename = os.path.join(paths.Ajatar_Output_PATH,
                            "log" + "_" + str(int(time.time())) + ".txt")

    logger.info("Log file saved on %s" % filename)
    FILE_HANDLER = logging.FileHandler(filename)  #日志设置文件为对象
    FORMATTER = logging.Formatter(
        "\r[%(asctime)s] [%(levelname)s] %(message)s", "%H:%M:%S")  #输出格式
    FILE_HANDLER.setFormatter(FORMATTER)
    LOGGER.addHandler(FILE_HANDLER)

    if args.debug:
        LOGGER.setLevel(CUSTOM_LOGGING.DEBUG)  #日志级别为DEBUG
Esempio n. 8
0
    def __init__(self, device, install: bool, port: int, regexps: list):
        super().__init__()

        if device.type == FakeDevice.type:
            # init remote device
            LOGGER.debug(
                'device {} does not support get_usb_device, changing to get_remote_device'
                .format(device.id))
            self.forward_port = port_manager.acquire_port()
            self.device = frida.get_device_manager().add_remote_device(
                '127.0.0.1:{}'.format(self.forward_port))
            self.device.id = device.id
        else:
            self.device = device

        self.install = install
        self.port = port
        self.regexps = regexps if regexps else ['.*']

        self.adb = Adb(self.device.id)

        if device.type == FakeDevice.type:
            self.adb.forward(self.forward_port, FRIDA_SERVER_DEFAULT_PORT)

        if self.port:
            self.iptables = Iptables(self.adb, self.port)

        self.arch = self.adb.unsafe_shell("getprop ro.product.cpu.abi")['out']
        # maybe get 'arm64-v8a', 'arm-v7a' ...
        if 'arm64' in self.arch:
            self.arch = 'arm64'
        elif 'arm' in self.arch:
            self.arch = 'arm'
        elif 'x86_64' in self.arch:
            self.arch = 'x86_64'
        elif 'x86' in self.arch:
            self.arch = 'x86'
        else:
            raise RuntimeError('unknown arch: ' + self.arch)

        self.server_name = 'frida-server-{}-android-{}'.format(
            frida.__version__, self.arch)

        self.stop_flag = False

        thread_manager.add_thread(self)
Esempio n. 9
0
    def install_frida_server(self):
        server_path = os.path.join(ROOT_DIR, 'assets', self.server_name)
        server_path_xz = server_path + '.xz'

        # if not exist frida server then install it
        if not self.adb.unsafe_shell("ls /data/local/tmp/" + self.server_name)['out']:
            LOGGER.info('download {} from github ...'.format(self.server_name))
            with __lock__:
                download('https://github.com/frida/frida/releases/download/{}/{}.xz'
                         .format(frida.__version__, self.server_name), server_path_xz)

            # extract frida server
            with open(server_path, 'wb') as f:
                with lzma.open(server_path_xz) as xz:
                    f.write(xz.read())

            # upload frida server
            self.adb.push(server_path, '/data/local/tmp/')
Esempio n. 10
0
    def hook(self, app: str):
        app = app.strip()
        if not app:
            raise RuntimeError('try to hook empty app name')

        LOGGER.info('hook app ' + app)
        process = self.device.attach(app)
        js = 'Java.perform(function() {'

        # load all scripts under folder 'scripts'
        for (dirpath, dirnames, filenames) in os.walk(os.path.join(ROOT_DIR, 'scripts')):
            for filename in filenames:
                _ = open(os.path.join(dirpath, filename), encoding="utf-8").read()
                if _.startswith(r'''/*Deprecated*/'''):
                    continue
                js += _
                js += '\n'

        js += '});'
        script = process.create_script(js)
        script.on('message', self.on_message)
        script.load()
Esempio n. 11
0
def shutdown(signum, frame):
    if signum == signal.SIGINT:
        LOGGER.debug('keyboard interrupt event detected')
    elif signum == signal.SIGTERM:
        LOGGER.debug('termination event detected')
    else:
        LOGGER.warn('unknown event detected')

    raise MainExit
Esempio n. 12
0
    def run(self) -> None:
        LOGGER.info(
            "{} start with hook device: id={}, name={}, type={}".format(
                self.__class__.__name__, self.device.id, self.device.name,
                self.device.type))

        try:
            self.prepare()
            self.hook_apps()
        except Exception as e:
            LOGGER.error('device {}: {}'.format(self.device.id, e))

        try:
            self.shutdown()
        except Exception as e:
            LOGGER.error(
                'unexpected error occurred when shutdown device {}: {}'.format(
                    self.device.id, e))

        LOGGER.debug('device {} exit'.format(self.device.id))
        thread_manager.del_thread(self)
Esempio n. 13
0
    def download(self, url, file_path):
        # get total size of file
        r1 = requests.get(url, stream=True, verify=False)
        total_size = int(r1.headers['Content-Length'])

        # check downloaded size
        if os.path.exists(file_path):
            temp_size = os.path.getsize(file_path)
        else:
            temp_size = 0

        if temp_size == total_size:
            LOGGER.info('{} has downloaded completely'.format(file_path))
            return

        if temp_size > total_size:
            LOGGER.error(
                '{} has corrupted, download it again'.format(file_path))
            os.remove(file_path)
            return self.download(url, file_path)

        LOGGER.debug('{} of {} needs to be download'.format(
            total_size - temp_size, total_size))

        # download from temp size to end
        headers = {'Range': 'bytes={}-'.format(temp_size)}

        r = requests.get(url, stream=True, verify=False, headers=headers)

        with open(file_path, "ab") as f:
            for chunk in r.iter_content(chunk_size=1024):
                if self.stop_flag:
                    break

                if chunk:
                    temp_size += len(chunk)
                    f.write(chunk)
                    f.flush()

                    # download progress
                    done = int(50 * temp_size / total_size)
                    sys.stdout.write("\r[{}{}] {}%".format(
                        '█' * done, ' ' * (50 - done),
                        100 * temp_size / total_size))
                    sys.stdout.flush()

        sys.stdout.write(os.linesep)
Esempio n. 14
0
    def cmd_and_debug(cls, cmd) -> map:
        ret = {'out': '', 'err': ''}

        LOGGER.debug(cmd)
        p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, close_fds=True)

        err = p.stderr.read().decode().strip()
        if err:
            LOGGER.error('shell error: ' + err)
            ret['err'] = err

        out = p.stdout.read().decode().strip()
        if out:
            LOGGER.debug('shell output: ' + out)
            ret['out'] = out

        return ret
Esempio n. 15
0
    def on_message(self, message, data):
        try:
            if message['type'] == 'error':
                text = message['description'].strip()

                if not text:
                    return

                LOGGER.error(text)
            else:
                text = message['payload'].strip() if message['type'] == 'send' else message.strip()

                if not text:
                    return

                LOGGER.info(text)
        except Exception as e:
            LOGGER.error(e)
Esempio n. 16
0
    def cmd_and_debug(cls, cmd: str, debug=True) -> map:
        ret = {'out': '', 'err': ''}

        if debug:
            LOGGER.debug(cmd)

        p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, close_fds=True)

        err = p.stderr.read().decode().strip()
        if err:
            if err != 'Unable to start: Error binding to address: Address already in use':
                LOGGER.error('shell error: ' + err)
                ret['err'] = err

        out = p.stdout.read().decode().strip()
        if out:
            if debug:
                LOGGER.debug('shell output: ' + out)
            ret['out'] = out

        return ret
Esempio n. 17
0
def main():
    parser = argparse.ArgumentParser(
        description='A tool that hook all apps you need')

    parser.add_argument(
        'regexps',
        type=str,
        nargs='*',
        help=r'Regexps for the apps you want to hook such as "^com\.baidu\.", '
        r'empty for hooking all apps')
    parser.add_argument(
        '-i',
        '--install',
        action='store_true',
        help='install frida server to /data/local/tmp automatically')
    parser.add_argument(
        '-p',
        '--port',
        type=int,
        help='reverse tcp port, if specified, manipulate iptables automatically'
    )
    parser.add_argument('-v', action='store_true', help='verbose output')

    args = parser.parse_args()

    try:
        if args.v:
            LOGGER.setLevel(logging.DEBUG)

        # set log
        os.makedirs(LOG_DIR, mode=0o700, exist_ok=True)
        log_filename = time.strftime('%Y-%m-%d_%H-%M-%S.log')
        log_file = open(os.path.join(LOG_DIR, log_filename),
                        'a',
                        encoding='utf-8')
        logger_handler = ColorizingStreamHandler(log_file)
        logger_handler.setFormatter(FORMATTER)
        LOGGER.addHandler(logger_handler)

        # set handling interrupt exceptions
        signal.signal(signal.SIGTERM, shutdown)
        signal.signal(signal.SIGINT, shutdown)

        Adb.start_server()

        watch_thread = WatchThread(args.install, args.port, args.regexps)
    except (KeyboardInterrupt, InterruptedError) as e:
        LOGGER.info(e)
        sys.exit(-1)

    try:
        watch_thread.start()
        while True:
            time.sleep(1)
    except MainExit:
        while True:
            try:
                LOGGER.info(
                    'shutdown command received, wait for clean up please...')
                watch_thread.cancel()
                break
            except MainExit:
                pass

    # waiting for sub threads
    while True:
        try:
            while True:
                should_we_exit()
                time.sleep(1)
        except MainExit:
            try:
                n = len(thread_manager.thread_map)
                if n > 0:
                    LOGGER.info(
                        'running sub threads: {}, wait a second please'.format(
                            n))
            except MainExit:
                pass
Esempio n. 18
0
    def run(self) -> None:
        LOGGER.debug('{} start'.format(self.__class__.__name__))

        while True:
            if self.stop_flag:
                break

            devices = frida.enumerate_devices()

            # usb devices from frida api
            usb_devices = [
                device for device in devices if device.type == 'usb'
            ]
            usb_devices_ids = [device.id for device in usb_devices]

            # devices strings from "adb devices"
            adb_devices_strings = Shell.cmd_and_debug(
                'adb devices', debug=False)['out'].split('\n')[1:]
            adb_devices_strings = [
                _.split('\t')[0] for _ in adb_devices_strings
            ]

            # we need to access these devices remotely
            remote_devices_strings = set(adb_devices_strings) - set(
                usb_devices_ids)
            remote_devices = []

            for _ in remote_devices_strings:
                new_device = FakeDevice()
                new_device.id = _
                remote_devices.append(new_device)

            for device in usb_devices + remote_devices:
                duplicated = False

                for t in self.frida_threads:
                    if t.device.id == device.id:
                        if not t.is_alive():
                            self.frida_threads.remove(t)
                            break

                        duplicated = True
                        break

                if duplicated:
                    continue

                try:
                    frida_thread = FridaThread(device, self.install, self.port,
                                               self.regexps)
                except RuntimeError as e:
                    LOGGER.error(
                        'error occurred when init frida thread: {}'.format(e))
                else:
                    frida_thread.start()
                    self.frida_threads.append(frida_thread)

            time.sleep(0.1)

        self.shutdown()
        LOGGER.debug('watch thread exit')
Esempio n. 19
0
def should_we_exit():
    if thread_manager.is_empty():
        LOGGER.info('sub threads exit completely, bye!')
        sys.exit(0)