mirror of
https://github.com/hyugogirubato/KeyDive.git
synced 2026-07-15 18:40:02 +02:00
release v3.0.0
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
from pathlib import Path
|
||||
|
||||
# https://cs.android.com/android/platform/superproject/+/android14-qpr3-release:bionic/libc/libc.map.txt
|
||||
NATIVE_C_API = (
|
||||
'__assert', '__assert2', '__atomic_cmpxchg', '__atomic_dec', '__atomic_inc', '__atomic_swap', '__b64_ntop',
|
||||
'__b64_pton', '__cmsg_nxthdr', '__connect', '__ctype_get_mb_cur_max', '__cxa_atexit', '__cxa_finalize',
|
||||
'__cxa_thread_atexit_impl', '__dn_comp', '__dn_count_labels', '__dn_skipname', '__epoll_pwait', '__errno', '__exit',
|
||||
'__fadvise64', '__fbufsize', '__fcntl64', '__FD_CLR_chk', '__FD_ISSET_chk', '__FD_SET_chk', '__fgets_chk', '__flbf',
|
||||
'__fp_nquery', '__fp_query', '__fpclassify', '__fpclassifyd', '__fpclassifyf', '__fpclassifyl', '__fpending',
|
||||
'__fpurge', '__freadable', '__fsetlocking', '__fstatfs64', '__fwritable', '__get_h_errno', '__getcpu', '__getcwd',
|
||||
'__getpid', '__getpriority', '__gnu_basename', '__gnu_strerror_r', '__hostalias', '__ioctl', '__isfinite',
|
||||
'__isfinitef', '__isfinitel', '__isinf', '__isinff', '__isinfl', '__isnan', '__isnanf', '__isnanl', '__isnormal',
|
||||
'__isnormalf', '__isnormall', '__isthreaded', '__libc_current_sigrtmax', '__libc_current_sigrtmin', '__libc_init',
|
||||
'__llseek', '__loc_aton', '__loc_ntoa', '__memchr_chk', '__memcpy_chk', '__memmove_chk', '__memrchr_chk',
|
||||
'__memset_chk', '__mmap2', '__ns_format_ttl', '__ns_get16', '__ns_get32', '__ns_initparse', '__ns_makecanon',
|
||||
'__ns_msg_getflag', '__ns_name_compress', '__ns_name_ntol', '__ns_name_ntop', '__ns_name_pack', '__ns_name_pton',
|
||||
'__ns_name_rollback', '__ns_name_skip', '__ns_name_uncompress', '__ns_name_unpack', '__ns_parserr', '__ns_put16',
|
||||
'__ns_put32', '__ns_samename', '__ns_skiprr', '__ns_sprintrr', '__ns_sprintrrf', '__open_2', '__openat',
|
||||
'__openat_2', '__p_cdname', '__p_cdnname', '__p_class', '__p_class_syms', '__p_fqname', '__p_fqnname', '__p_option',
|
||||
'__p_query', '__p_rcode', '__p_secstodate', '__p_time', '__p_type', '__p_type_syms', '__poll_chk', '__ppoll',
|
||||
'__ppoll_chk', '__ppoll64_chk', '__pread64_chk', '__pread_chk', '__progname', '__pselect6', '__pthread_cleanup_pop',
|
||||
'__pthread_cleanup_push', '__ptrace', '__putlong', '__putshort', '__read_chk', '__readlink_chk', '__readlinkat_chk',
|
||||
'__reboot', '__recvfrom_chk', '__register_atfork', '__res_close', '__res_dnok', '__res_hnok', '__res_hostalias',
|
||||
'__res_isourserver', '__res_mailok', '__res_nameinquery', '__res_nclose', '__res_ninit', '__res_nmkquery',
|
||||
'__res_nquery', '__res_nquerydomain', '__res_nsearch', '__res_nsend', '__res_ownok', '__res_queriesmatch',
|
||||
'__res_querydomain', '__res_send', '__res_send_setqhook', '__res_send_setrhook', '__rt_sigaction',
|
||||
'__rt_sigpending', '__rt_sigprocmask', '__rt_sigsuspend', '__rt_sigtimedwait', '__sched_cpualloc',
|
||||
'__sched_cpucount', '__sched_cpufree', '__sched_getaffinity', '__set_thread_area', '__set_tid_address', '__set_tls',
|
||||
'__sF', '__sigaction', '__snprintf_chk', '__socket', '__sprintf_chk', '__stack_chk_fail', '__stack_chk_guard',
|
||||
'__statfs64', '__stpcpy_chk', '__stpncpy_chk', '__stpncpy_chk2', '__strcat_chk', '__strchr_chk', '__strcpy_chk',
|
||||
'__strlcat_chk', '__strlcpy_chk', '__strlen_chk', '__strncat_chk', '__strncpy_chk', '__strncpy_chk2',
|
||||
'__strrchr_chk', '__sym_ntop', '__sym_ntos', '__sym_ston', '__system_property_area_serial',
|
||||
'__system_property_find', '__system_property_find_nth', '__system_property_foreach', '__system_property_get',
|
||||
'__system_property_read', '__system_property_serial', '__system_property_set', '__timer_create', '__timer_delete',
|
||||
'__timer_getoverrun', '__timer_gettime', '__timer_settime', '__umask_chk', '__vsnprintf_chk', '__vsprintf_chk',
|
||||
'__waitid', '_ctype_', '_Exit', '_exit', '_flushlbf', '_getlong', '_getshort', '_longjmp',
|
||||
'_resolv_delete_cache_for_net', '_resolv_flush_cache_for_net', '_resolv_set_nameservers_for_net', '_setjmp',
|
||||
'_tolower', '_tolower_tab_', '_toupper', '_toupper_tab_', 'abort', 'abs', 'accept', 'accept4', 'access', 'acct',
|
||||
'alarm', 'alphasort', 'alphasort64', 'android_set_abort_message', 'arc4random', 'arc4random_buf',
|
||||
'arc4random_uniform', 'asctime', 'asctime64', 'asctime64_r', 'asctime_r', 'asprintf', 'at_quick_exit', 'atof',
|
||||
'atoi', 'atol', 'atoll', 'basename', 'basename_r', 'bind', 'bindresvport', 'brk', 'bsearch', 'btowc', 'c16rtomb',
|
||||
'c32rtomb', 'cacheflush', 'calloc', 'capget', 'capset', 'cfgetispeed', 'cfgetospeed', 'cfmakeraw', 'cfsetispeed',
|
||||
'cfsetospeed', 'cfsetspeed', 'chdir', 'chmod', 'chown', 'chroot', 'clearenv', 'clearerr', 'clearerr_unlocked',
|
||||
'clock', 'clock_getcpuclockid', 'clock_getres', 'clock_gettime', 'clock_nanosleep', 'clock_settime', 'clone',
|
||||
'close', 'closedir', 'closelog', 'connect', 'creat', 'creat64', 'ctime', 'ctime64', 'ctime64_r', 'ctime_r',
|
||||
'daemon', 'daylight', 'delete_module', 'difftime', 'dirfd', 'dirname', 'dirname_r', 'div', 'dn_expand', 'dprintf',
|
||||
'drand48', 'dup', 'dup2', 'dup3', 'duplocale', 'endmntent', 'endservent', 'endutent', 'environ', 'epoll_create',
|
||||
'epoll_create1', 'epoll_ctl', 'epoll_pwait', 'epoll_wait', 'erand48', 'err', 'error', 'error_at_line',
|
||||
'error_message_count', 'error_one_per_line', 'error_print_progname', 'errx', 'ether_aton', 'ether_aton_r',
|
||||
'ether_ntoa', 'ether_ntoa_r', 'eventfd', 'eventfd_read', 'eventfd_write', 'execl', 'execle', 'execlp', 'execv',
|
||||
'execve', 'execvp', 'execvpe', 'exit', 'faccessat', 'fallocate', 'fallocate64', 'fchdir', 'fchmod', 'fchmodat',
|
||||
'fchown', 'fchownat', 'fclose', 'fcntl', 'fdatasync', 'fdopen', 'fdopendir', 'fdprintf', 'feof', 'feof_unlocked',
|
||||
'ferror', 'ferror_unlocked', 'fflush', 'ffs', 'fgetc', 'fgetln', 'fgetpos', 'fgets', 'fgetwc', 'fgetws',
|
||||
'fgetxattr', 'fileno', 'flistxattr', 'flock', 'flockfile', 'fmemopen', 'fnmatch', 'fopen', 'fork', 'forkpty',
|
||||
'fpathconf', 'fprintf', 'fpurge', 'fputc', 'fputs', 'fputwc', 'fputws', 'fread', 'free', 'freeaddrinfo',
|
||||
'freelocale', 'fremovexattr', 'freopen', 'fscanf', 'fseek', 'fseeko', 'fsetpos', 'fsetxattr', 'fstat', 'fstat64',
|
||||
'fstatat', 'fstatat64', 'fstatfs', 'fstatfs64', 'fstatvfs', 'fstatvfs64', 'fsync', 'ftell', 'ftello', 'ftok',
|
||||
'ftruncate', 'ftruncate64', 'ftrylockfile', 'fts_children', 'fts_close', 'fts_open', 'fts_read', 'fts_set', 'ftw',
|
||||
'ftw64', 'funlockfile', 'funopen', 'futimens', 'fwide', 'fwprintf', 'fwrite', 'fwscanf', 'gai_strerror',
|
||||
'get_avphys_pages', 'get_nprocs', 'get_nprocs_conf', 'get_phys_pages', 'getaddrinfo', 'getauxval', 'getc',
|
||||
'getc_unlocked', 'getchar', 'getchar_unlocked', 'getcwd', 'getdelim', 'getegid', 'getenv', 'geteuid', 'getgid',
|
||||
'getgrgid', 'getgrnam', 'getgrouplist', 'getgroups', 'gethostbyaddr', 'gethostbyaddr_r', 'gethostbyname',
|
||||
'gethostbyname2', 'gethostbyname2_r', 'gethostbyname_r', 'gethostent', 'gethostname', 'getitimer', 'getline',
|
||||
'getlogin', 'getmntent', 'getmntent_r', 'getnameinfo', 'getnetbyaddr', 'getnetbyname', 'getopt', 'getopt_long',
|
||||
'getopt_long_only', 'getpagesize', 'getpeername', 'getpgid', 'getpgrp', 'getpid', 'getppid', 'getpriority',
|
||||
'getprogname', 'getprotobyname', 'getprotobynumber', 'getpt', 'getpwnam', 'getpwnam_r', 'getpwuid', 'getpwuid_r',
|
||||
'getresgid', 'getresuid', 'getrlimit', 'getrlimit64', 'getrusage', 'gets', 'getservbyname', 'getservbyport',
|
||||
'getservent', 'getsid', 'getsockname', 'getsockopt', 'gettid', 'gettimeofday', 'getuid', 'getutent', 'getwc',
|
||||
'getwchar', 'getxattr', 'gmtime', 'gmtime64', 'gmtime64_r', 'gmtime_r', 'grantpt', 'herror', 'hstrerror', 'htonl',
|
||||
'htons', 'if_indextoname', 'if_nametoindex', 'imaxabs', 'imaxdiv', 'inet_addr', 'inet_aton', 'inet_lnaof',
|
||||
'inet_makeaddr', 'inet_netof', 'inet_network', 'inet_nsap_addr', 'inet_nsap_ntoa', 'inet_ntoa', 'inet_ntop',
|
||||
'inet_pton', 'init_module', 'initgroups', 'initstate', 'inotify_add_watch', 'inotify_init', 'inotify_init1',
|
||||
'inotify_rm_watch', 'insque', 'ioctl', 'isalnum', 'isalnum_l', 'isalpha', 'isalpha_l', 'isascii', 'isatty',
|
||||
'isblank', 'isblank_l', 'iscntrl', 'iscntrl_l', 'isdigit', 'isdigit_l', 'isfinite', 'isfinitef', 'isfinitel',
|
||||
'isgraph', 'isgraph_l', 'isinf', 'isinff', 'isinfl', 'islower', 'islower_l', 'isnan', 'isnanf', 'isnanl',
|
||||
'isnormal', 'isnormalf', 'isnormall', 'isprint', 'isprint_l', 'ispunct', 'ispunct_l', 'isspace', 'isspace_l',
|
||||
'isupper', 'isupper_l', 'iswalnum', 'iswalnum_l', 'iswalpha', 'iswalpha_l', 'iswblank', 'iswblank_l', 'iswcntrl',
|
||||
'iswcntrl_l', 'iswctype', 'iswctype_l', 'iswdigit', 'iswdigit_l', 'iswgraph', 'iswgraph_l', 'iswlower',
|
||||
'iswlower_l', 'iswprint', 'iswprint_l', 'iswpunct', 'iswpunct_l', 'iswspace', 'iswspace_l', 'iswupper',
|
||||
'iswupper_l', 'iswxdigit', 'iswxdigit_l', 'isxdigit', 'isxdigit_l', 'jrand48', 'kill', 'killpg', 'klogctl', 'labs',
|
||||
'lchown', 'lcong48', 'ldexp', 'ldiv', 'lfind', 'lgetxattr', 'link', 'linkat', 'listen', 'listxattr', 'llabs',
|
||||
'lldiv', 'llistxattr', 'localeconv', 'localtime', 'localtime64', 'localtime64_r', 'localtime_r', 'login_tty',
|
||||
'longjmp', 'lrand48', 'lremovexattr', 'lsearch', 'lseek', 'lseek64', 'lsetxattr', 'lstat', 'lstat64', 'madvise',
|
||||
'mallinfo', 'malloc', 'malloc_info', 'malloc_usable_size', 'mbrlen', 'mbrtoc16', 'mbrtoc32', 'mbrtowc', 'mbsinit',
|
||||
'mbsnrtowcs', 'mbsrtowcs', 'mbstowcs', 'mbtowc', 'memalign', 'memccpy', 'memchr', 'memcmp', 'memcpy', 'memmem',
|
||||
'memmove', 'mempcpy', 'memrchr', 'memset', 'mincore', 'mkdir', 'mkdirat', 'mkdtemp', 'mkfifo', 'mkfifoat', 'mknod',
|
||||
'mknodat', 'mkostemp', 'mkostemp64', 'mkostemps', 'mkostemps64', 'mkstemp', 'mkstemp64', 'mkstemps', 'mkstemps64',
|
||||
'mktemp', 'mktime', 'mktime64', 'mlock', 'mlockall', 'mmap', 'mmap64', 'mount', 'mprotect', 'mrand48', 'mremap',
|
||||
'msync', 'munlock', 'munlockall', 'munmap', 'nanosleep', 'newlocale', 'nftw', 'nftw64', 'nice', 'nrand48',
|
||||
'ns_format_ttl', 'ns_get16', 'ns_get32', 'ns_initparse', 'ns_makecanon', 'ns_msg_getflag', 'ns_name_compress',
|
||||
'ns_name_ntol', 'ns_name_ntop', 'ns_name_pack', 'ns_name_pton', 'ns_name_rollback', 'ns_name_skip',
|
||||
'ns_name_uncompress', 'ns_name_unpack', 'ns_parserr', 'ns_put16', 'ns_put32', 'ns_samename', 'ns_skiprr',
|
||||
'ns_sprintrr', 'ns_sprintrrf', 'nsdispatch', 'ntohl', 'ntohs', 'open', 'open64', 'open_memstream',
|
||||
'open_wmemstream', 'openat', 'openat64', 'opendir', 'openlog', 'openpty', 'optarg', 'opterr', 'optind', 'optopt',
|
||||
'optreset', 'pathconf', 'pause', 'pclose', 'perror', 'personality', 'pipe', 'pipe2', 'poll', 'popen',
|
||||
'posix_fadvise', 'posix_fadvise64', 'posix_fallocate', 'posix_fallocate64', 'posix_madvise', 'posix_memalign',
|
||||
'posix_openpt', 'ppoll', 'prctl', 'pread', 'pread64', 'printf', 'prlimit', 'prlimit64', 'process_vm_readv',
|
||||
'process_vm_writev', 'pselect', 'psiginfo', 'psignal', 'pthread_atfork', 'pthread_attr_destroy',
|
||||
'pthread_attr_getdetachstate', 'pthread_attr_getguardsize', 'pthread_attr_getschedparam',
|
||||
'pthread_attr_getschedpolicy', 'pthread_attr_getscope', 'pthread_attr_getstack', 'pthread_attr_getstacksize',
|
||||
'pthread_attr_init', 'pthread_attr_setdetachstate', 'pthread_attr_setguardsize', 'pthread_attr_setschedparam',
|
||||
'pthread_attr_setschedpolicy', 'pthread_attr_setscope', 'pthread_attr_setstack', 'pthread_attr_setstacksize',
|
||||
'pthread_cond_broadcast', 'pthread_cond_destroy', 'pthread_cond_init', 'pthread_cond_signal',
|
||||
'pthread_cond_timedwait', 'pthread_cond_timedwait_monotonic', 'pthread_cond_timedwait_monotonic_np',
|
||||
'pthread_cond_timedwait_relative_np', 'pthread_cond_timeout_np', 'pthread_cond_wait', 'pthread_condattr_destroy',
|
||||
'pthread_condattr_getclock', 'pthread_condattr_getpshared', 'pthread_condattr_init', 'pthread_condattr_setclock',
|
||||
'pthread_condattr_setpshared', 'pthread_create', 'pthread_detach', 'pthread_equal', 'pthread_exit',
|
||||
'pthread_getattr_np', 'pthread_getcpuclockid', 'pthread_getschedparam', 'pthread_getspecific', 'pthread_gettid_np',
|
||||
'pthread_join', 'pthread_key_create', 'pthread_key_delete', 'pthread_kill', 'pthread_mutex_destroy',
|
||||
'pthread_mutex_init', 'pthread_mutex_lock', 'pthread_mutex_lock_timeout_np', 'pthread_mutex_timedlock',
|
||||
'pthread_mutex_trylock', 'pthread_mutex_unlock', 'pthread_mutexattr_destroy', 'pthread_mutexattr_getpshared',
|
||||
'pthread_mutexattr_gettype', 'pthread_mutexattr_init', 'pthread_mutexattr_setpshared', 'pthread_mutexattr_settype',
|
||||
'pthread_once', 'pthread_rwlock_destroy', 'pthread_rwlock_init', 'pthread_rwlock_rdlock',
|
||||
'pthread_rwlock_timedrdlock', 'pthread_rwlock_timedwrlock', 'pthread_rwlock_tryrdlock', 'pthread_rwlock_trywrlock',
|
||||
'pthread_rwlock_unlock', 'pthread_rwlock_wrlock', 'pthread_rwlockattr_destroy', 'pthread_rwlockattr_getkind_np',
|
||||
'pthread_rwlockattr_getpshared', 'pthread_rwlockattr_init', 'pthread_rwlockattr_setkind_np',
|
||||
'pthread_rwlockattr_setpshared', 'pthread_self', 'pthread_setname_np', 'pthread_setschedparam',
|
||||
'pthread_setspecific', 'pthread_sigmask', 'ptrace', 'ptsname', 'ptsname_r', 'putc', 'putc_unlocked', 'putchar',
|
||||
'putchar_unlocked', 'putenv', 'puts', 'pututline', 'putw', 'putwc', 'putwchar', 'pvalloc', 'pwrite', 'pwrite64',
|
||||
'qsort', 'quick_exit', 'raise', 'rand', 'rand_r', 'random', 'read', 'readahead', 'readdir', 'readdir64',
|
||||
'readdir64_r', 'readdir_r', 'readlink', 'readlinkat', 'readv', 'realloc', 'realpath', 'reboot', 'recv', 'recvfrom',
|
||||
'recvmmsg', 'recvmsg', 'regcomp', 'regerror', 'regexec', 'regfree', 'remove', 'removexattr', 'remque', 'rename',
|
||||
'renameat', 'res_init', 'res_mkquery', 'res_query', 'res_search', 'rewind', 'rewinddir', 'rmdir', 'sbrk', 'scandir',
|
||||
'scandir64', 'scanf', 'sched_get_priority_max', 'sched_get_priority_min', 'sched_getaffinity', 'sched_getcpu',
|
||||
'sched_getparam', 'sched_getscheduler', 'sched_rr_get_interval', 'sched_setaffinity', 'sched_setparam',
|
||||
'sched_setscheduler', 'sched_yield', 'seed48', 'seekdir', 'select', 'sem_close', 'sem_destroy', 'sem_getvalue',
|
||||
'sem_init', 'sem_open', 'sem_post', 'sem_timedwait', 'sem_trywait', 'sem_unlink', 'sem_wait', 'send', 'sendfile',
|
||||
'sendfile64', 'sendmmsg', 'sendmsg', 'sendto', 'setbuf', 'setbuffer', 'setegid', 'setenv', 'seteuid', 'setfsgid',
|
||||
'setfsuid', 'setgid', 'setgroups', 'sethostname', 'setitimer', 'setjmp', 'setlinebuf', 'setlocale', 'setlogmask',
|
||||
'setmntent', 'setns', 'setpgid', 'setpgrp', 'setpriority', 'setprogname', 'setregid', 'setresgid', 'setresuid',
|
||||
'setreuid', 'setrlimit', 'setrlimit64', 'setservent', 'setsid', 'setsockopt', 'setstate', 'settimeofday', 'setuid',
|
||||
'setutent', 'setvbuf', 'setxattr', 'shutdown', 'sigaction', 'sigaddset', 'sigaltstack', 'sigblock', 'sigdelset',
|
||||
'sigemptyset', 'sigfillset', 'siginterrupt', 'sigismember', 'siglongjmp', 'signal', 'signalfd', 'sigpending',
|
||||
'sigprocmask', 'sigqueue', 'sigsetjmp', 'sigsetmask', 'sigsuspend', 'sigtimedwait', 'sigwait', 'sigwaitinfo',
|
||||
'sleep', 'snprintf', 'socket', 'socketpair', 'splice', 'sprintf', 'srand', 'srand48', 'srandom', 'sscanf', 'stat',
|
||||
'stat64', 'statfs', 'statfs64', 'statvfs', 'statvfs64', 'stderr', 'stdin', 'stdout', 'stpcpy', 'stpncpy',
|
||||
'strcasecmp', 'strcasecmp_l', 'strcasestr', 'strcat', 'strchr', 'strcmp', 'strcoll', 'strcoll_l', 'strcpy',
|
||||
'strcspn', 'strdup', 'strerror', 'strerror_l', 'strerror_r', 'strftime', 'strftime_l', 'strlcat', 'strlcpy',
|
||||
'strlen', 'strncasecmp', 'strncasecmp_l', 'strncat', 'strncmp', 'strncpy', 'strndup', 'strnlen', 'strpbrk',
|
||||
'strptime', 'strrchr', 'strsep', 'strsignal', 'strspn', 'strstr', 'strtod', 'strtof', 'strtoimax', 'strtok',
|
||||
'strtok_r', 'strtol', 'strtold', 'strtold_l', 'strtoll', 'strtoll_l', 'strtoul', 'strtoull', 'strtoull_l',
|
||||
'strtoumax', 'strxfrm', 'strxfrm_l', 'swapoff', 'swapon', 'swprintf', 'swscanf', 'symlink', 'symlinkat', 'sync',
|
||||
'sys_siglist', 'sys_signame', 'syscall', 'sysconf', 'sysinfo', 'syslog', 'system', 'tcdrain', 'tcflow', 'tcflush',
|
||||
'tcgetattr', 'tcgetpgrp', 'tcgetsid', 'tcsendbreak', 'tcsetattr', 'tcsetpgrp', 'tdelete', 'tdestroy', 'tee',
|
||||
'telldir', 'tempnam', 'tfind', 'tgkill', 'time', 'timegm', 'timegm64', 'timelocal', 'timelocal64', 'timer_create',
|
||||
'timer_delete', 'timer_getoverrun', 'timer_gettime', 'timer_settime', 'timerfd_create', 'timerfd_gettime',
|
||||
'timerfd_settime', 'times', 'timezone', 'tmpfile', 'tmpnam', 'toascii', 'tolower', 'tolower_l', 'toupper',
|
||||
'toupper_l', 'towlower', 'towlower_l', 'towupper', 'towupper_l', 'truncate', 'truncate64', 'tsearch', 'ttyname',
|
||||
'ttyname_r', 'twalk', 'tzname', 'tzset', 'umask', 'umount', 'umount2', 'uname', 'ungetc', 'ungetwc', 'unlink',
|
||||
'unlinkat', 'unlockpt', 'unsetenv', 'unshare', 'uselocale', 'usleep', 'utime', 'utimensat', 'utimes', 'utmpname',
|
||||
'valloc', 'vasprintf', 'vdprintf', 'verr', 'verrx', 'vfdprintf', 'vfork', 'vfprintf', 'vfscanf', 'vfwprintf',
|
||||
'vfwscanf', 'vmsplice', 'vprintf', 'vscanf', 'vsnprintf', 'vsprintf', 'vsscanf', 'vswprintf', 'vswscanf', 'vsyslog',
|
||||
'vwarn', 'vwarnx', 'vwprintf', 'vwscanf', 'wait', 'wait4', 'waitid', 'waitpid', 'warn', 'warnx', 'wcpcpy',
|
||||
'wcpncpy', 'wcrtomb', 'wcscasecmp', 'wcscasecmp_l', 'wcscat', 'wcschr', 'wcscmp', 'wcscoll', 'wcscoll_l', 'wcscpy',
|
||||
'wcscspn', 'wcsdup', 'wcsftime', 'wcslcat', 'wcslcpy', 'wcslen', 'wcsncasecmp', 'wcsncasecmp_l', 'wcsncat',
|
||||
'wcsncmp', 'wcsncpy', 'wcsnlen', 'wcsnrtombs', 'wcspbrk', 'wcsrchr', 'wcsrtombs', 'wcsspn', 'wcsstr', 'wcstod',
|
||||
'wcstof', 'wcstoimax', 'wcstok', 'wcstol', 'wcstold', 'wcstold_l', 'wcstoll', 'wcstoll_l', 'wcstombs', 'wcstoul',
|
||||
'wcstoull', 'wcstoull_l', 'wcstoumax', 'wcswidth', 'wcsxfrm', 'wcsxfrm_l', 'wctob', 'wctomb', 'wctype', 'wctype_l',
|
||||
'wcwidth', 'wmemchr', 'wmemcmp', 'wmemcpy', 'wmemmove', 'wmempcpy', 'wmemset', 'wprintf', 'write', 'writev',
|
||||
'wscanf', 'main'
|
||||
)
|
||||
|
||||
# https://github.com/kaltura/kaltura-device-info-android
|
||||
DRM_PLAYER = {
|
||||
'name': 'Kaltura Device Info',
|
||||
'package': 'com.kaltura.kalturadeviceinfo',
|
||||
'url': 'https://github.com/kaltura/kaltura-device-info-android/releases/download/t3/kaltura-device-info-release.apk',
|
||||
'path': Path(__file__).parent.parent / 'docs' / 'server' / 'kaltura.apk'
|
||||
}
|
||||
|
||||
DRM_WEB = 'https://bitmovin.com/demos/drm'
|
||||
@@ -0,0 +1,371 @@
|
||||
import logging
|
||||
import re
|
||||
import shutil
|
||||
|
||||
from subprocess import run
|
||||
from typing import Optional, List, Tuple
|
||||
from pathlib import Path
|
||||
|
||||
import frida
|
||||
import requests
|
||||
|
||||
from frida.core import Device
|
||||
|
||||
# Suppress urllib3 warnings
|
||||
logging.getLogger('urllib3.connectionpool').setLevel(logging.ERROR)
|
||||
|
||||
|
||||
def shell(prompt: List[str]) -> Tuple[bool, str]:
|
||||
"""
|
||||
Executes a shell command and returns its success status along with the output.
|
||||
|
||||
Args:
|
||||
prompt (List[str]): A list representing the command and its arguments to be executed.
|
||||
|
||||
Returns:
|
||||
Tuple[bool, str]: A tuple where the first value is True if the command failed,
|
||||
and the second value is the decoded standard output (stdout) string.
|
||||
|
||||
Example:
|
||||
shell(["ls", "-l"])
|
||||
(False, "total 0\n-rw-r--r-- 1 user ...")
|
||||
|
||||
Note:
|
||||
The return status is inverted (True means failure), which should be considered
|
||||
when checking execution outcomes.
|
||||
|
||||
"""
|
||||
# Convert all arguments to strings in case any are not
|
||||
prompt = list(map(str, prompt))
|
||||
|
||||
# Uncomment for debugging shell command execution
|
||||
# logging.getLogger('Shell').debug('Executing command: %s', ' '.join(prompt))
|
||||
try:
|
||||
# Execute the command and capture the output
|
||||
# TODO: Redirect standard output and error in PIP
|
||||
sp = run(prompt, capture_output=True)
|
||||
|
||||
# Return True if the command failed (non-zero exit), along with stdout
|
||||
return sp.returncode != 0, sp.stdout.decode('utf-8').strip()
|
||||
except KeyboardInterrupt:
|
||||
return False, ''
|
||||
|
||||
|
||||
class Remote:
|
||||
"""
|
||||
Handles ADB-based operations on Android devices using Frida.
|
||||
|
||||
This class provides a set of utilities for interacting with Android devices connected via ADB,
|
||||
including retrieving system properties, managing applications, enumerating processes, and executing shell commands.
|
||||
"""
|
||||
|
||||
def __init__(self, serial: Optional[str] = None, timeout: int = 5):
|
||||
"""
|
||||
Initializes and connects to an Android device using ADB and Frida.
|
||||
|
||||
Args:
|
||||
serial (Optional[str]): Specific device serial number. If not provided,
|
||||
the first connected USB device will be used.
|
||||
timeout (int): Timeout (in seconds) for connecting to the device.
|
||||
|
||||
Raises:
|
||||
EnvironmentError: If ADB is not found in the system PATH.
|
||||
Exception: If connection to the Android device fails.
|
||||
KeyError: If essential properties (e.g., SDK or ABI) cannot be retrieved.
|
||||
"""
|
||||
self.logger = logging.getLogger('Remote')
|
||||
|
||||
# Ensure ADB is installed and available in the system PATH
|
||||
if not shutil.which('adb'):
|
||||
raise EnvironmentError(
|
||||
'ADB is not recognized as an environment variable. '
|
||||
'Ensure ADB is installed and refer to the documentation: '
|
||||
'https://github.com/hyugogirubato/KeyDive/blob/main/docs/PACKAGE.md#adb-android-debug-bridge'
|
||||
)
|
||||
|
||||
# Start the ADB server if it's not already running
|
||||
sp = shell(['adb', 'start-server'])
|
||||
if sp[0]:
|
||||
self.logger.warning('Unable to start ADB server (Error: %s)', sp[1])
|
||||
|
||||
# Attempt to connect to the device (or default to the first USB device)
|
||||
try:
|
||||
self.socket: Device = frida.get_device(serial, timeout) if serial else frida.get_usb_device(timeout)
|
||||
self.logger.info('Connected to device: %s (%s)', self.socket.name, self.socket.id)
|
||||
except Exception as e:
|
||||
self.logger.critical('Could not connect to any device: %s', e)
|
||||
raise e
|
||||
|
||||
# Construct the shell command prefix using the connected device ID
|
||||
self.__prefix = ['adb', '-s', self.socket.id, 'shell']
|
||||
|
||||
# Retrieve system properties (e.g., SDK version, CPU ABI)
|
||||
properties = self.enumerate_properties()
|
||||
|
||||
try:
|
||||
self.sdk = properties['ro.build.version.sdk']
|
||||
self.abi = properties['ro.product.cpu.abi']
|
||||
except Exception as e:
|
||||
raise KeyError('Failed to enumerate properties: %s', e)
|
||||
|
||||
self.logger.info('SDK API: %s', self.sdk)
|
||||
self.logger.info('ABI CPU: %s', self.abi)
|
||||
|
||||
def enumerate_properties(self) -> dict:
|
||||
"""
|
||||
Retrieves Android system properties from the connected device via ADB.
|
||||
|
||||
This method parses the output of the `getprop` shell command, casting values
|
||||
to appropriate Python types (e.g., integers or booleans) when possible. It is
|
||||
useful for gathering device configuration, build info, and environment metadata.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of system properties where keys are property names and
|
||||
values are their corresponding parsed values.
|
||||
"""
|
||||
# https://source.android.com/docs/core/architecture/configuration/add-system-properties?#shell-commands
|
||||
properties = {}
|
||||
|
||||
# Execute shell command to fetch all system properties using 'getprop'
|
||||
sp = shell([*self.__prefix, 'getprop', '|', 'strings'])
|
||||
if sp[0]:
|
||||
self.logger.error('Unable to retrieve system properties from the device (error: %s)', sp[1])
|
||||
return properties
|
||||
|
||||
# Parse each line of the output and extract key-value pairs
|
||||
for line in sp[1].splitlines():
|
||||
match = re.match(r'\[(.*?)]: \[(.*?)]', line)
|
||||
if match:
|
||||
key, value = match.groups()
|
||||
|
||||
# Try casting numeric strings to integers
|
||||
if value.isdigit():
|
||||
value = int(value)
|
||||
|
||||
# Try converting string booleans to Python boolean
|
||||
elif value.lower() in ('true', 'false'):
|
||||
value = value.lower() == 'true'
|
||||
|
||||
# Store the parsed key-value pair
|
||||
properties[key] = value
|
||||
|
||||
return properties
|
||||
|
||||
def enumerate_processes(self, pids: List[int] = None, names: List[str] = None) -> dict:
|
||||
"""
|
||||
Retrieves a list of running processes from the connected Android device.
|
||||
|
||||
This method uses ADB to run the `ps` command, processes the output, and filters
|
||||
the result by provided process IDs or names if specified. It gracefully handles
|
||||
variability in output format across Android versions.
|
||||
|
||||
Args:
|
||||
pids (List[int], optional): A list of process IDs to filter against. Only
|
||||
processes with these PIDs will be included in the result.
|
||||
names (List[str], optional): A list of process names to filter against.
|
||||
Only processes with these names will be included in the result.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary mapping process IDs (int) to process names (str).
|
||||
|
||||
Exception:
|
||||
Logs and returns an empty dictionary if the `ps` command fails to execute.
|
||||
"""
|
||||
# https://github.com/frida/frida/issues/1225#issuecomment-604181822
|
||||
processes = {}
|
||||
|
||||
# Attempt to get the list of processes using the 'ps -A' command
|
||||
prompt = [*self.__prefix, 'ps']
|
||||
sp = shell([*prompt, '-A'])
|
||||
lines = sp[1].splitlines()
|
||||
|
||||
# Retry with simpler 'ps' if output seems too short (older Android or restricted shell)
|
||||
if len(lines) < 10:
|
||||
sp = shell(prompt)
|
||||
if sp[0]:
|
||||
self.logger.error('Failed to execute ps command (Error: %s)', sp[1])
|
||||
return processes
|
||||
lines = sp[1].splitlines()
|
||||
|
||||
# Iterate through process list, skipping the header
|
||||
for line in lines[1:]:
|
||||
try:
|
||||
parts = line.split() # USER,PID,PPID,VSZ,RSS,WCHAN,ADDR,S,NAME
|
||||
pid = int(parts[1]) # Extract the PID from the 2nd column
|
||||
name = ' '.join(parts[8:]).strip() # Extract the process name (column 9+)
|
||||
|
||||
# Handle cases where process name might be in brackets (e.g., kernel threads)
|
||||
name = name if name.startswith('[') else Path(name).name
|
||||
|
||||
# Apply optional filters
|
||||
if (pids and pid not in pids) or (names and name not in names):
|
||||
continue
|
||||
processes[pid] = name
|
||||
except Exception as e:
|
||||
# Suppress and skip lines that cannot be parsed correctly
|
||||
pass
|
||||
|
||||
return processes
|
||||
|
||||
def enumerate_applications(self, user: bool = True, system: bool = False) -> dict:
|
||||
"""
|
||||
Lists installed Android applications on the connected device.
|
||||
|
||||
This method uses ADB's package manager (pm) to list installed apps,
|
||||
with optional filtering for user-installed or system apps. It returns
|
||||
a mapping of package names to their corresponding APK file paths.
|
||||
|
||||
Args:
|
||||
user (bool): If True, include user-installed applications (default: True).
|
||||
system (bool): If True, include system applications (default: False).
|
||||
|
||||
Returns:
|
||||
dict: A dictionary where the keys are package names (str) and the values
|
||||
are file paths (str) to their APKs.
|
||||
"""
|
||||
applications = {}
|
||||
|
||||
# Validate input to ensure at least one filter is active
|
||||
if not user and not system:
|
||||
return applications # Nothing to return if both are disabled
|
||||
|
||||
# Construct the command to retrieve package info
|
||||
prompt = [*self.__prefix, 'pm', 'list', 'packages', '-f']
|
||||
if user and not system:
|
||||
prompt.append('-3') # Filter only user-installed apps
|
||||
elif not user and system:
|
||||
prompt.append('-s') # Filter only system apps
|
||||
|
||||
# Run the shell command to get the list of packages
|
||||
sp = shell(prompt)
|
||||
if sp[0]:
|
||||
self.logger.error('Unable to list installed apps (Error: %s)', sp[0])
|
||||
return applications
|
||||
|
||||
# Parse command output line-by-line
|
||||
for line in sp[1].splitlines():
|
||||
try:
|
||||
# Example line format: package:/data/app/com.example.app-1/base.apk=com.example.app
|
||||
path, package = line.strip().split(':', 1)[1].rsplit('=', 1)
|
||||
applications[package] = path
|
||||
except Exception as e:
|
||||
# Skip lines that do not conform to expected structure
|
||||
pass
|
||||
|
||||
return applications
|
||||
|
||||
def open_url(self, url: str) -> bool:
|
||||
"""
|
||||
Launches the specified URL on the connected Android device using the default browser.
|
||||
|
||||
This uses Android's Activity Manager (am) to start an intent with the action
|
||||
`android.intent.action.VIEW`, which is the standard way to launch URLs.
|
||||
|
||||
Args:
|
||||
url (str): The web address to open on the device (e.g., "https://example.com").
|
||||
|
||||
Returns:
|
||||
bool: True if the command executed successfully and the intent was launched;
|
||||
False if the shell command failed or was rejected by the system.
|
||||
"""
|
||||
# Execute the shell command to open the URL using the Android 'am' (Activity Manager) command.
|
||||
sp = shell([*self.__prefix, 'am', 'start', '-a', 'android.intent.action.VIEW', '-d', url])
|
||||
if sp[0]:
|
||||
self.logger.error('Failed to open URL: %s (Error: %s)', url, sp[1])
|
||||
|
||||
# Return True if command succeeded (sp[0] is 0), False otherwise
|
||||
return not sp[0]
|
||||
|
||||
def install_application(self, path: Optional[Path] = None, url: Optional[str] = None) -> bool:
|
||||
"""
|
||||
Installs an APK on the connected Android device from either a local file or a remote URL.
|
||||
|
||||
Args:
|
||||
path (Optional[Path]): Path to the APK file stored locally.
|
||||
url (Optional[str]): Direct URL to download the APK from.
|
||||
|
||||
Returns:
|
||||
bool: True if the application was successfully installed, False otherwise.
|
||||
"""
|
||||
# Prepare the shell command for installation
|
||||
prompt = [*self.__prefix[:-1], 'install']
|
||||
|
||||
# If a valid local path is provided, attempt to install the APK from that file
|
||||
if path and path.is_file():
|
||||
sp = shell([*prompt, path]) # Run the installation command with the local file path
|
||||
if not sp[0]:
|
||||
return True # Installation succeeded
|
||||
self.logger.error('Could not install the APK from local path: %s (Error: %s)', path, sp[1])
|
||||
|
||||
# If a URL is provided, try to download the APK and install it temporarily
|
||||
status = False
|
||||
if url:
|
||||
file = Path('tmp.apk') # Temporary file to store the downloaded APK
|
||||
try:
|
||||
# Send a GET request to download the APK
|
||||
r = requests.request(
|
||||
method='GET',
|
||||
url=url,
|
||||
headers={
|
||||
'Accept': '*/*',
|
||||
'User-Agent': 'KeyDive/ADB'
|
||||
}
|
||||
)
|
||||
r.raise_for_status()
|
||||
|
||||
# Write the downloaded content to a temporary APK file
|
||||
file.write_bytes(r.content)
|
||||
|
||||
# Attempt to install the downloaded APK
|
||||
status = self.install_application(path=file)
|
||||
except Exception as e:
|
||||
self.logger.error('Failed to download or install APK from URL: %s (Error: %s)', url, e)
|
||||
finally:
|
||||
# Clean up the temporary file regardless of success or failure
|
||||
file.unlink(missing_ok=True)
|
||||
|
||||
return status
|
||||
|
||||
def start_application(self, package: str) -> bool:
|
||||
"""
|
||||
Attempts to start an Android application using its package name by locating
|
||||
and invoking its main activity via the Activity Manager.
|
||||
|
||||
Args:
|
||||
package (str): The package name of the application to start.
|
||||
|
||||
Returns:
|
||||
bool: True if the application was successfully launched, False otherwise.
|
||||
"""
|
||||
# Get package information using dumpsys
|
||||
sp = shell([*self.__prefix, 'dumpsys', 'package', package])
|
||||
if sp[0]:
|
||||
self.logger.error('Unable to retrieve package information (Error: %s)', sp[1])
|
||||
return False
|
||||
|
||||
# Clean up output and filter out empty lines for consistency
|
||||
lines = sp[1].splitlines()
|
||||
lines = [l.strip() for l in lines if l.strip()]
|
||||
|
||||
# Scan for the MAIN intent line and extract the associated activity
|
||||
for i, line in enumerate(lines):
|
||||
if 'android.intent.action.MAIN' in line:
|
||||
match = re.search(fr'({package}/[^ ]+)', lines[i + 1])
|
||||
if match:
|
||||
# Format: com.example.package/.MainActivity
|
||||
main_activity = match.group()
|
||||
|
||||
# Attempt to start the application using the resolved activity
|
||||
sp = shell([*self.__prefix, 'am', 'start', '-n', main_activity])
|
||||
if not sp[0]:
|
||||
return True
|
||||
|
||||
self.logger.error('Failed to start app %s (Error: %s)', package, sp[1])
|
||||
break
|
||||
|
||||
# TODO: adb shell monkey -p com.topjohnwu.magisk -c android.intent.category.LAUNCHER 1
|
||||
self.logger.error('No MAIN activity found for package "%s" or package not installed.', package)
|
||||
return False
|
||||
|
||||
|
||||
__all__ = ('Remote',)
|
||||
@@ -0,0 +1,114 @@
|
||||
import re
|
||||
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
|
||||
class Vendor:
|
||||
"""
|
||||
Represents a vendor-specific configuration including process name, minimum SDK version,
|
||||
OEM versioning information, and the name of a related native library.
|
||||
|
||||
This class is used to identify vendor-specific behaviors on Android devices and provides
|
||||
regex-based helpers for pattern matching against processes and libraries.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
process: str,
|
||||
min_sdk: int,
|
||||
min_oem: Tuple[int, str],
|
||||
library: str
|
||||
):
|
||||
"""
|
||||
Initializes a Vendor instance with identifying details.
|
||||
|
||||
Args:
|
||||
process (str): The name of the process to identify for the vendor (can be pattern-based).
|
||||
min_sdk (int): The minimum required Android SDK version for compatibility.
|
||||
min_oem (Tuple[int, str]): Tuple defining the minimum OEM version, e.g., (version_code, version_name).
|
||||
library (str): The shared library name or pattern used by the vendor.
|
||||
|
||||
"""
|
||||
self.process = process
|
||||
self.min_sdk = min_sdk
|
||||
self.min_oem = min_oem
|
||||
self.library = library
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""
|
||||
Generates a string representation of the current instance for debugging purposes.
|
||||
|
||||
This method is primarily used to help developers understand the state of the object
|
||||
during logging or interactive debugging by displaying all attribute names and values
|
||||
in a clean, readable format.
|
||||
|
||||
Returns:
|
||||
str: A string showing the class name and its instance variables with their values.
|
||||
"""
|
||||
# Construct a formatted string with the class name and a list of key=value pairs from the instance's attributes
|
||||
return '{name}({items})'.format(
|
||||
name=self.__class__.__name__,
|
||||
items=', '.join([f'{k}={repr(v)}' for k, v in self.__dict__.items()])
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def __pattern(value: str) -> str:
|
||||
"""
|
||||
Converts a given string into a regex-compatible pattern that allows for matching
|
||||
flexible naming conventions found in Android service or library identifiers.
|
||||
|
||||
This is particularly useful when dealing with variant suffixes (e.g., `-lazy`, version tags),
|
||||
or optional annotations (e.g., `@<version>` in `.so` or `.widevine` modules).
|
||||
|
||||
Args:
|
||||
value (str): The base string (e.g., filename or service name) to convert into a regex pattern.
|
||||
|
||||
Returns:
|
||||
str: A regex pattern that can be used to match common variants of the input string.
|
||||
"""
|
||||
return (value
|
||||
.replace('-service', r'-service(?:-lazy)?')
|
||||
.replace('.widevine', r'.widevine(?:@\S+)?')
|
||||
.replace('.so', r'(?:@\S+)?.so')
|
||||
.replace('.', r'\.'))
|
||||
|
||||
def is_process(self, value: str) -> bool:
|
||||
"""
|
||||
Determines whether the provided process name matches the expected vendor-specific process pattern.
|
||||
|
||||
This is useful when trying to detect or hook into a known target process,
|
||||
especially when its name can include runtime-specific suffixes (e.g., versioned .so files or services).
|
||||
|
||||
Args:
|
||||
value (str): The name of the process to evaluate.
|
||||
|
||||
Returns:
|
||||
bool: True if the process name matches the generated pattern; otherwise, False.
|
||||
"""
|
||||
# Generate a regex pattern from the expected process name
|
||||
pattern = self.__pattern(self.process)
|
||||
|
||||
# Check if the input value matches the regex pattern
|
||||
return bool(re.match(pattern, value))
|
||||
|
||||
def get_library(self, values: List[dict]) -> Optional[dict]:
|
||||
"""
|
||||
Retrieves the first matching library dictionary from a provided list based on a dynamically generated regex pattern.
|
||||
|
||||
This method is useful when trying to identify a target library in a list of shared objects (e.g., `.so` files),
|
||||
especially when the exact name may include version tags or runtime decorations (e.g., `libxyz@1.2.so`).
|
||||
|
||||
Args:
|
||||
values (List[dict]): A list of dictionaries, each expected to contain a 'name' key with the library's filename.
|
||||
|
||||
Returns:
|
||||
Optional[dict]: The first dictionary whose 'name' matches the expected regex pattern; returns None if no match is found.
|
||||
"""
|
||||
# Create a regex pattern based on the expected library name, allowing flexibility for suffixes or variants
|
||||
pattern = self.__pattern(self.library)
|
||||
|
||||
# Iterate through the list and return the first dictionary with a matching 'name'
|
||||
return next((v for v in values if re.match(pattern, v['name'])), None)
|
||||
|
||||
|
||||
__all__ = ('Vendor',)
|
||||
Reference in New Issue
Block a user