diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 71318ea..9bd355d 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -23,19 +23,21 @@ jobs: - name: Set up Android NDK r23b run: | aria2c -o android-ndk-r23b-linux.zip https://dl.google.com/android/repository/android-ndk-r23b-linux.zip - unzip -q android-ndk-r23b-linux.zip + unzip -q -d ~ android-ndk-r23b-linux.zip - name: Build run: | - android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android22-clang++ -Wall -Werror -nostdlib -c -O3 -o handle.o main.cpp - android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android22-clang -DMyRelease -Wall -Werror -L ./rootfs/system/lib64 -landroidappmusic -lstoreservicescore -lmediaplatform -lc++_shared -O3 -Wall -o rootfs/system/bin/main handle.o test.c - clang -O3 -Wall -o wrapper wrapper.c + make + + - name: Set outputs + id: vars + run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: Wrapper.x86_64 + name: Wrapper.x86_64.${{ steps.vars.outputs.sha_short }} + include-hidden-files: true path: | rootfs - handle.o wrapper diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..02afee2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,91 @@ + +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +rootfs/ +.vscode/ +wrapper +rootfs/system/bin/linker64 diff --git a/Makefile b/Makefile index a008196..94ec809 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,16 @@ -all: handle.o main wrapper +all: cmdline.o handle.o main wrapper + +cmdline.o: + ~/android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android22-clang -Wall -Werror -nostdlib -c -O3 -o cmdline.o cmdline.c handle.o: main.cpp - ~/android-ndk-r23b/standalone/bin/clang++ -Wall -Werror -nostdlib -c -O3 -o handle.o main.cpp + ~/android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android22-clang++ -Wall -Werror -nostdlib -c -O3 -o handle.o main.cpp -main: handle.o test.c - ~/android-ndk-r23b/standalone/bin/clang -DMyRelease -Wall -Werror -L ./rootfs/system/lib64 -landroidappmusic -lstoreservicescore -lmediaplatform -lc++_shared -O3 -Wall -o rootfs/system/bin/main handle.o test.c +main: handle.o test.c cmdline.o + ~/android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android22-clang -DMyRelease -Wall -Werror -L ./rootfs/system/lib64 -landroidappmusic -lstoreservicescore -lmediaplatform -lc++_shared -O3 -Wall -o rootfs/system/bin/main cmdline.o handle.o test.c wrapper: wrapper.c - clang -O3 -Wall -o wrapper wrapper.c + ~/android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -O3 -Wall -o wrapper wrapper.c clean: - rm handle.o wrapper rootfs/system/bin/main + rm handle.o wrapper rootfs/system/bin/main cmdline.o diff --git a/README.md b/README.md index 49669d6..19cb8ab 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,41 @@ -# wrapper -All files from anonymous, No need for an Android emulator to decrypt alac +## Wrapper +No need for an Android emulator to decrypt ALAC files. This solution works on all files from Anonymous. -### 安装 -推荐Windows Subsystem for Linux (WSL)使用 -usage: `./wrapper [port] ([username] [password])` -get-m3u8为port+10000 +### Recommended Environment +For best results, it's recommended to use **Windows Subsystem for Linux (WSL)**. +--- + +### Version 2 + +#### Usage: +```shell +./wrapper [OPTION]... + -h, --help Print help and exit + -V, --version Print version and exit + -H, --host=STRING (default: `127.0.0.1`) + -D, --decrypt-port=INT (default: `10020`) + -M, --m3u8-port=INT (default: `20020`) + -P, --proxy=STRING (default: `''`) + -L, --login=STRING ([username]:[password]) +``` +#### Installation: +```shell +sudo -i +wget "https://github.com/zhaarey/wrapper/releases/download/linux/wrapper.linux.x86_64.V2.tar.gz" +mkdir wrapper +tar -xzf wrapper.linux.x86_64.V2.tar.gz -C wrapper +cd wrapper +./wrapper +``` + + +--- +### Version 1 +#### Usage: +`./wrapper [port] ([username] [password])` +#### Installation: ```shell sudo -i wget "https://github.com/zhaarey/wrapper/releases/download/linux/wrapper.linux.x86_64.tar.gz" diff --git a/cmdline.c b/cmdline.c new file mode 100644 index 0000000..49e2d89 --- /dev/null +++ b/cmdline.c @@ -0,0 +1,617 @@ +/* + File autogenerated by gengetopt version 2.23 + generated with the following command: + gengetopt -i wrapper.ggo + + The developers of gengetopt consider the fixed text that goes in all + gengetopt output files to be in the public domain: + we make no copyright claims on it. +*/ + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#ifndef FIX_UNUSED +#define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ +#endif + +#include + +#include "cmdline.h" + +const char *gengetopt_args_info_purpose = ""; + +const char *gengetopt_args_info_usage = "Usage: wrapper [OPTION]..."; + +const char *gengetopt_args_info_versiontext = ""; + +const char *gengetopt_args_info_description = ""; + +const char *gengetopt_args_info_help[] = { + " -h, --help Print help and exit", + " -V, --version Print version and exit", + " -H, --host=STRING (default=`127.0.0.1')", + " -D, --decrypt-port=INT (default=`10020')", + " -M, --m3u8-port=INT (default=`20020')", + " -P, --proxy=STRING (default=`')", + " -L, --login=STRING ", + 0 +}; + +typedef enum {ARG_NO + , ARG_STRING + , ARG_INT +} cmdline_parser_arg_type; + +static +void clear_given (struct gengetopt_args_info *args_info); +static +void clear_args (struct gengetopt_args_info *args_info); + +static int +cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params, const char *additional_error); + + +static char * +gengetopt_strdup (const char *s); + +static +void clear_given (struct gengetopt_args_info *args_info) +{ + args_info->help_given = 0 ; + args_info->version_given = 0 ; + args_info->host_given = 0 ; + args_info->decrypt_port_given = 0 ; + args_info->m3u8_port_given = 0 ; + args_info->proxy_given = 0 ; + args_info->login_given = 0 ; +} + +static +void clear_args (struct gengetopt_args_info *args_info) +{ + FIX_UNUSED (args_info); + args_info->host_arg = gengetopt_strdup ("127.0.0.1"); + args_info->host_orig = NULL; + args_info->decrypt_port_arg = 10020; + args_info->decrypt_port_orig = NULL; + args_info->m3u8_port_arg = 20020; + args_info->m3u8_port_orig = NULL; + args_info->proxy_arg = gengetopt_strdup (""); + args_info->proxy_orig = NULL; + args_info->login_arg = NULL; + args_info->login_orig = NULL; + +} + +static +void init_args_info(struct gengetopt_args_info *args_info) +{ + + + args_info->help_help = gengetopt_args_info_help[0] ; + args_info->version_help = gengetopt_args_info_help[1] ; + args_info->host_help = gengetopt_args_info_help[2] ; + args_info->decrypt_port_help = gengetopt_args_info_help[3] ; + args_info->m3u8_port_help = gengetopt_args_info_help[4] ; + args_info->proxy_help = gengetopt_args_info_help[5] ; + args_info->login_help = gengetopt_args_info_help[6] ; + +} + +void +cmdline_parser_print_version (void) +{ + printf ("%s %s\n", + (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), + CMDLINE_PARSER_VERSION); + + if (strlen(gengetopt_args_info_versiontext) > 0) + printf("\n%s\n", gengetopt_args_info_versiontext); +} + +static void print_help_common(void) +{ + size_t len_purpose = strlen(gengetopt_args_info_purpose); + size_t len_usage = strlen(gengetopt_args_info_usage); + + if (len_usage > 0) { + printf("%s\n", gengetopt_args_info_usage); + } + if (len_purpose > 0) { + printf("%s\n", gengetopt_args_info_purpose); + } + + if (len_usage || len_purpose) { + printf("\n"); + } + + if (strlen(gengetopt_args_info_description) > 0) { + printf("%s\n\n", gengetopt_args_info_description); + } +} + +void +cmdline_parser_print_help (void) +{ + int i = 0; + print_help_common(); + while (gengetopt_args_info_help[i]) + printf("%s\n", gengetopt_args_info_help[i++]); +} + +void +cmdline_parser_init (struct gengetopt_args_info *args_info) +{ + clear_given (args_info); + clear_args (args_info); + init_args_info (args_info); +} + +void +cmdline_parser_params_init(struct cmdline_parser_params *params) +{ + if (params) + { + params->override = 0; + params->initialize = 1; + params->check_required = 1; + params->check_ambiguity = 0; + params->print_errors = 1; + } +} + +struct cmdline_parser_params * +cmdline_parser_params_create(void) +{ + struct cmdline_parser_params *params = + (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); + cmdline_parser_params_init(params); + return params; +} + +static void +free_string_field (char **s) +{ + if (*s) + { + free (*s); + *s = 0; + } +} + + +static void +cmdline_parser_release (struct gengetopt_args_info *args_info) +{ + + free_string_field (&(args_info->host_arg)); + free_string_field (&(args_info->host_orig)); + free_string_field (&(args_info->decrypt_port_orig)); + free_string_field (&(args_info->m3u8_port_orig)); + free_string_field (&(args_info->proxy_arg)); + free_string_field (&(args_info->proxy_orig)); + free_string_field (&(args_info->login_arg)); + free_string_field (&(args_info->login_orig)); + + + + clear_given (args_info); +} + + +static void +write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) +{ + FIX_UNUSED (values); + if (arg) { + fprintf(outfile, "%s=\"%s\"\n", opt, arg); + } else { + fprintf(outfile, "%s\n", opt); + } +} + + +int +cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) +{ + int i = 0; + + if (!outfile) + { + fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); + return EXIT_FAILURE; + } + + if (args_info->help_given) + write_into_file(outfile, "help", 0, 0 ); + if (args_info->version_given) + write_into_file(outfile, "version", 0, 0 ); + if (args_info->host_given) + write_into_file(outfile, "host", args_info->host_orig, 0); + if (args_info->decrypt_port_given) + write_into_file(outfile, "decrypt-port", args_info->decrypt_port_orig, 0); + if (args_info->m3u8_port_given) + write_into_file(outfile, "m3u8-port", args_info->m3u8_port_orig, 0); + if (args_info->proxy_given) + write_into_file(outfile, "proxy", args_info->proxy_orig, 0); + if (args_info->login_given) + write_into_file(outfile, "login", args_info->login_orig, 0); + + + i = EXIT_SUCCESS; + return i; +} + +int +cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) +{ + FILE *outfile; + int i = 0; + + outfile = fopen(filename, "w"); + + if (!outfile) + { + fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); + return EXIT_FAILURE; + } + + i = cmdline_parser_dump(outfile, args_info); + fclose (outfile); + + return i; +} + +void +cmdline_parser_free (struct gengetopt_args_info *args_info) +{ + cmdline_parser_release (args_info); +} + +/** @brief replacement of strdup, which is not standard */ +char * +gengetopt_strdup (const char *s) +{ + char *result = 0; + if (!s) + return result; + + result = (char*)malloc(strlen(s) + 1); + if (result == (char*)0) + return (char*)0; + strcpy(result, s); + return result; +} + +int +cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info) +{ + return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); +} + +int +cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params) +{ + int result; + result = cmdline_parser_internal (argc, argv, args_info, params, 0); + + if (result == EXIT_FAILURE) + { + cmdline_parser_free (args_info); + exit (EXIT_FAILURE); + } + + return result; +} + +int +cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) +{ + int result; + struct cmdline_parser_params params; + + params.override = override; + params.initialize = initialize; + params.check_required = check_required; + params.check_ambiguity = 0; + params.print_errors = 1; + + result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); + + if (result == EXIT_FAILURE) + { + cmdline_parser_free (args_info); + exit (EXIT_FAILURE); + } + + return result; +} + +int +cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) +{ + FIX_UNUSED (args_info); + FIX_UNUSED (prog_name); + return EXIT_SUCCESS; +} + + +static char *package_name = 0; + +/** + * @brief updates an option + * @param field the generic pointer to the field to update + * @param orig_field the pointer to the orig field + * @param field_given the pointer to the number of occurrence of this option + * @param prev_given the pointer to the number of occurrence already seen + * @param value the argument for this option (if null no arg was specified) + * @param possible_values the possible values for this option (if specified) + * @param default_value the default value (in case the option only accepts fixed values) + * @param arg_type the type of this option + * @param check_ambiguity @see cmdline_parser_params.check_ambiguity + * @param override @see cmdline_parser_params.override + * @param no_free whether to free a possible previous value + * @param multiple_option whether this is a multiple option + * @param long_opt the corresponding long option + * @param short_opt the corresponding short option (or '-' if none) + * @param additional_error possible further error specification + */ +static +int update_arg(void *field, char **orig_field, + unsigned int *field_given, unsigned int *prev_given, + char *value, const char *possible_values[], + const char *default_value, + cmdline_parser_arg_type arg_type, + int check_ambiguity, int override, + int no_free, int multiple_option, + const char *long_opt, char short_opt, + const char *additional_error) +{ + char *stop_char = 0; + const char *val = value; + int found; + char **string_field; + FIX_UNUSED (field); + + stop_char = 0; + found = 0; + + if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) + { + if (short_opt != '-') + fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", + package_name, long_opt, short_opt, + (additional_error ? additional_error : "")); + else + fprintf (stderr, "%s: `--%s' option given more than once%s\n", + package_name, long_opt, + (additional_error ? additional_error : "")); + return 1; /* failure */ + } + + FIX_UNUSED (default_value); + + if (field_given && *field_given && ! override) + return 0; + if (prev_given) + (*prev_given)++; + if (field_given) + (*field_given)++; + if (possible_values) + val = possible_values[found]; + + switch(arg_type) { + case ARG_INT: + if (val) *((int *)field) = strtol (val, &stop_char, 0); + break; + case ARG_STRING: + if (val) { + string_field = (char **)field; + if (!no_free && *string_field) + free (*string_field); /* free previous string */ + *string_field = gengetopt_strdup (val); + } + break; + default: + break; + }; + + /* check numeric conversion */ + switch(arg_type) { + case ARG_INT: + if (val && !(stop_char && *stop_char == '\0')) { + fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val); + return 1; /* failure */ + } + break; + default: + ; + }; + + /* store the original value */ + switch(arg_type) { + case ARG_NO: + break; + default: + if (value && orig_field) { + if (no_free) { + *orig_field = value; + } else { + if (*orig_field) + free (*orig_field); /* free previous string */ + *orig_field = gengetopt_strdup (value); + } + } + }; + + return 0; /* OK */ +} + + +int +cmdline_parser_internal ( + int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params, const char *additional_error) +{ + int c; /* Character of the parsed option. */ + + int error_occurred = 0; + struct gengetopt_args_info local_args_info; + + int override; + int initialize; + int check_required; + int check_ambiguity; + + package_name = argv[0]; + + /* TODO: Why is this here? It is not used anywhere. */ + override = params->override; + FIX_UNUSED(override); + + initialize = params->initialize; + check_required = params->check_required; + + /* TODO: Why is this here? It is not used anywhere. */ + check_ambiguity = params->check_ambiguity; + FIX_UNUSED(check_ambiguity); + + if (initialize) + cmdline_parser_init (args_info); + + cmdline_parser_init (&local_args_info); + + optarg = 0; + optind = 0; + opterr = params->print_errors; + optopt = '?'; + + while (1) + { + int option_index = 0; + + static struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { "host", 1, NULL, 'H' }, + { "decrypt-port", 1, NULL, 'D' }, + { "m3u8-port", 1, NULL, 'M' }, + { "proxy", 1, NULL, 'P' }, + { "login", 1, NULL, 'L' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long (argc, argv, "hVH:D:M:P:L:", long_options, &option_index); + + if (c == -1) break; /* Exit from `while (1)' loop. */ + + switch (c) + { + case 'h': /* Print help and exit. */ + cmdline_parser_print_help (); + cmdline_parser_free (&local_args_info); + exit (EXIT_SUCCESS); + + case 'V': /* Print version and exit. */ + cmdline_parser_print_version (); + cmdline_parser_free (&local_args_info); + exit (EXIT_SUCCESS); + + case 'H': /* . */ + + + if (update_arg( (void *)&(args_info->host_arg), + &(args_info->host_orig), &(args_info->host_given), + &(local_args_info.host_given), optarg, 0, "127.0.0.1", ARG_STRING, + check_ambiguity, override, 0, 0, + "host", 'H', + additional_error)) + goto failure; + + break; + case 'D': /* . */ + + + if (update_arg( (void *)&(args_info->decrypt_port_arg), + &(args_info->decrypt_port_orig), &(args_info->decrypt_port_given), + &(local_args_info.decrypt_port_given), optarg, 0, "10020", ARG_INT, + check_ambiguity, override, 0, 0, + "decrypt-port", 'D', + additional_error)) + goto failure; + + break; + case 'M': /* . */ + + + if (update_arg( (void *)&(args_info->m3u8_port_arg), + &(args_info->m3u8_port_orig), &(args_info->m3u8_port_given), + &(local_args_info.m3u8_port_given), optarg, 0, "20020", ARG_INT, + check_ambiguity, override, 0, 0, + "m3u8-port", 'M', + additional_error)) + goto failure; + + break; + case 'P': /* . */ + + + if (update_arg( (void *)&(args_info->proxy_arg), + &(args_info->proxy_orig), &(args_info->proxy_given), + &(local_args_info.proxy_given), optarg, 0, "", ARG_STRING, + check_ambiguity, override, 0, 0, + "proxy", 'P', + additional_error)) + goto failure; + + break; + case 'L': /* . */ + + + if (update_arg( (void *)&(args_info->login_arg), + &(args_info->login_orig), &(args_info->login_given), + &(local_args_info.login_given), optarg, 0, 0, ARG_STRING, + check_ambiguity, override, 0, 0, + "login", 'L', + additional_error)) + goto failure; + + break; + + case 0: /* Long option with no short option */ + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + goto failure; + + default: /* bug: option not considered. */ + fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); + abort (); + } /* switch */ + } /* while */ + + + + FIX_UNUSED(check_required); + + cmdline_parser_release (&local_args_info); + + if ( error_occurred ) + return (EXIT_FAILURE); + + return 0; + +failure: + + cmdline_parser_release (&local_args_info); + return (EXIT_FAILURE); +} +/* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ diff --git a/cmdline.h b/cmdline.h new file mode 100644 index 0000000..9073b37 --- /dev/null +++ b/cmdline.h @@ -0,0 +1,193 @@ +/** @file cmdline.h + * @brief The header file for the command line option parser + * generated by GNU Gengetopt version 2.23 + * http://www.gnu.org/software/gengetopt. + * DO NOT modify this file, since it can be overwritten + * @author GNU Gengetopt */ + +#ifndef CMDLINE_H +#define CMDLINE_H + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* for FILE */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef CMDLINE_PARSER_PACKAGE +/** @brief the program name (used for printing errors) */ +#define CMDLINE_PARSER_PACKAGE "wrapper" +#endif + +#ifndef CMDLINE_PARSER_PACKAGE_NAME +/** @brief the complete program name (used for help and version) */ +#define CMDLINE_PARSER_PACKAGE_NAME "wrapper" +#endif + +#ifndef CMDLINE_PARSER_VERSION +/** @brief the program version */ +#define CMDLINE_PARSER_VERSION "1.2.0" +#endif + +/** @brief Where the command line options are stored */ +struct gengetopt_args_info +{ + const char *help_help; /**< @brief Print help and exit help description. */ + const char *version_help; /**< @brief Print version and exit help description. */ + char * host_arg; /**< @brief (default='127.0.0.1'). */ + char * host_orig; /**< @brief original value given at command line. */ + const char *host_help; /**< @brief help description. */ + int decrypt_port_arg; /**< @brief (default='10020'). */ + char * decrypt_port_orig; /**< @brief original value given at command line. */ + const char *decrypt_port_help; /**< @brief help description. */ + int m3u8_port_arg; /**< @brief (default='20020'). */ + char * m3u8_port_orig; /**< @brief original value given at command line. */ + const char *m3u8_port_help; /**< @brief help description. */ + char * proxy_arg; /**< @brief (default=''). */ + char * proxy_orig; /**< @brief original value given at command line. */ + const char *proxy_help; /**< @brief help description. */ + char * login_arg; /**< @brief . */ + char * login_orig; /**< @brief original value given at command line. */ + const char *login_help; /**< @brief help description. */ + + unsigned int help_given ; /**< @brief Whether help was given. */ + unsigned int version_given ; /**< @brief Whether version was given. */ + unsigned int host_given ; /**< @brief Whether host was given. */ + unsigned int decrypt_port_given ; /**< @brief Whether decrypt-port was given. */ + unsigned int m3u8_port_given ; /**< @brief Whether m3u8-port was given. */ + unsigned int proxy_given ; /**< @brief Whether proxy was given. */ + unsigned int login_given ; /**< @brief Whether login was given. */ + +} ; + +/** @brief The additional parameters to pass to parser functions */ +struct cmdline_parser_params +{ + int override; /**< @brief whether to override possibly already present options (default 0) */ + int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ + int check_required; /**< @brief whether to check that all required options were provided (default 1) */ + int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ + int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ +} ; + +/** @brief the purpose string of the program */ +extern const char *gengetopt_args_info_purpose; +/** @brief the usage string of the program */ +extern const char *gengetopt_args_info_usage; +/** @brief the description string of the program */ +extern const char *gengetopt_args_info_description; +/** @brief all the lines making the help output */ +extern const char *gengetopt_args_info_help[]; + +/** + * The command line parser + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser (int argc, char **argv, + struct gengetopt_args_info *args_info); + +/** + * The command line parser (version with additional parameters - deprecated) + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @param override whether to override possibly already present options + * @param initialize whether to initialize the option structure my_args_info + * @param check_required whether to check that all required options were provided + * @return 0 if everything went fine, NON 0 if an error took place + * @deprecated use cmdline_parser_ext() instead + */ +int cmdline_parser2 (int argc, char **argv, + struct gengetopt_args_info *args_info, + int override, int initialize, int check_required); + +/** + * The command line parser (version with additional parameters) + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @param params additional parameters for the parser + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_ext (int argc, char **argv, + struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params); + +/** + * Save the contents of the option struct into an already open FILE stream. + * @param outfile the stream where to dump options + * @param args_info the option struct to dump + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_dump(FILE *outfile, + struct gengetopt_args_info *args_info); + +/** + * Save the contents of the option struct into a (text) file. + * This file can be read by the config file parser (if generated by gengetopt) + * @param filename the file where to save + * @param args_info the option struct to save + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_file_save(const char *filename, + struct gengetopt_args_info *args_info); + +/** + * Print the help + */ +void cmdline_parser_print_help(void); +/** + * Print the version + */ +void cmdline_parser_print_version(void); + +/** + * Initializes all the fields a cmdline_parser_params structure + * to their default values + * @param params the structure to initialize + */ +void cmdline_parser_params_init(struct cmdline_parser_params *params); + +/** + * Allocates dynamically a cmdline_parser_params structure and initializes + * all its fields to their default values + * @return the created and initialized cmdline_parser_params structure + */ +struct cmdline_parser_params *cmdline_parser_params_create(void); + +/** + * Initializes the passed gengetopt_args_info structure's fields + * (also set default values for options that have a default) + * @param args_info the structure to initialize + */ +void cmdline_parser_init (struct gengetopt_args_info *args_info); +/** + * Deallocates the string fields of the gengetopt_args_info structure + * (but does not deallocate the structure itself) + * @param args_info the structure to deallocate + */ +void cmdline_parser_free (struct gengetopt_args_info *args_info); + +/** + * Checks that all the required options were specified + * @param args_info the structure to check + * @param prog_name the name of the program that will be used to print + * possible errors + * @return + */ +int cmdline_parser_required (struct gengetopt_args_info *args_info, + const char *prog_name); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CMDLINE_H */ diff --git a/rootfs/data/data/com.apple.android.music/.gitkeep b/rootfs/data/data/com.apple.android.music/.gitkeep index e69de29..67b08f3 100644 --- a/rootfs/data/data/com.apple.android.music/.gitkeep +++ b/rootfs/data/data/com.apple.android.music/.gitkeep @@ -0,0 +1 @@ +GITKEEP \ No newline at end of file diff --git a/rootfs/dev/.gitkeep b/rootfs/dev/.gitkeep index e69de29..67b08f3 100644 --- a/rootfs/dev/.gitkeep +++ b/rootfs/dev/.gitkeep @@ -0,0 +1 @@ +GITKEEP \ No newline at end of file diff --git a/test.c b/test.c index becadeb..b4e7313 100644 --- a/test.c +++ b/test.c @@ -7,19 +7,20 @@ #include #include +#include #include #include #include "import.h" +#include "cmdline.h" #ifndef MyRelease #include "subhook/subhook.c" #endif static struct shared_ptr apInf; -static size_t passLen; -static char *amUsername, *amPassword; -static uint16_t port; static uint8_t leaseMgr[16]; +struct gengetopt_args_info args_info; +char *amUsername, *amPassword; static void dialogHandler(long j, struct shared_ptr *protoDialogPtr, struct shared_ptr *respHandler) { @@ -75,6 +76,8 @@ static void credentialHandler(struct shared_ptr *credReqHandler, credReqHandler->obj)), need2FA ? "true" : "false"); + int passLen = strlen(amPassword); + if (need2FA) { printf("2FA code: "); scanf("%6s", amPassword + passLen); @@ -113,7 +116,13 @@ static inline void init() { // raise(SIGSTOP); fprintf(stderr, "[+] starting...\n"); setenv("ANDROID_DNS_MODE", "local", 1); - static const char *resolvers[2] = {"1.1.1.1", "223.5.5.5"}; + if (args_info.proxy_given) { + fprintf(stderr, "[+] Using proxy %s", args_info.proxy_arg); + setenv("http_proxy", args_info.proxy_arg, 1); + setenv("https_proxy", args_info.proxy_arg, 1); + } + + static const char *resolvers[2] = {"1.1.1.1", "1.0.0.1"}; _resolv_set_nameservers_for_net(0, resolvers, 2, "."); #ifndef MyRelease subhook_install(subhook_new( @@ -364,8 +373,6 @@ void handle(const int connfd) { } extern uint8_t handle_cpp(int); -static char *selfPath; -static char *portStr; inline static int new_socket() { const int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP); @@ -377,8 +384,8 @@ inline static int new_socket() { setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); static struct sockaddr_in serv_addr = {.sin_family = AF_INET}; - serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); - serv_addr.sin_port = htons(port); + inet_pton(AF_INET, args_info.host_arg, &serv_addr.sin_addr); + serv_addr.sin_port = htons(args_info.decrypt_port_arg); if (bind(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) { perror("bind"); return EXIT_FAILURE; @@ -389,8 +396,8 @@ inline static int new_socket() { return EXIT_FAILURE; } - fprintf(stderr, "[!] listening 0.0.0.0:%d\n", port); - close(STDOUT_FILENO); + fprintf(stderr, "[!] listening %s:%d\n", args_info.host_arg, args_info.decrypt_port_arg); + // close(STDOUT_FILENO); static struct sockaddr_in peer_addr; static socklen_t peer_addr_size = sizeof(peer_addr); @@ -477,12 +484,11 @@ static inline void *new_socket_m3u8(void *args) { perror("socket"); } const int optval = 1; - const int m3u8_port = port + 10000; setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); static struct sockaddr_in serv_addr = {.sin_family = AF_INET}; - serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); - serv_addr.sin_port = htons(m3u8_port); + inet_pton(AF_INET, args_info.host_arg, &serv_addr.sin_addr); + serv_addr.sin_port = htons(args_info.m3u8_port_arg); if (bind(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) { perror("bind"); } @@ -491,8 +497,8 @@ static inline void *new_socket_m3u8(void *args) { perror("listen"); } - fprintf(stderr, "[!] listening m3u8 request on 0.0.0.0:%d\n", m3u8_port); - close(STDOUT_FILENO); + fprintf(stderr, "[!] listening m3u8 request on %s:%d\n", args_info.host_arg, args_info.m3u8_port_arg); + // close(STDOUT_FILENO); static struct sockaddr_in peer_addr; static socklen_t peer_addr_size = sizeof(peer_addr); @@ -506,6 +512,7 @@ static inline void *new_socket_m3u8(void *args) { errno == ENETUNREACH) continue; perror("accept4"); + } handle_m3u8(connfd); @@ -517,23 +524,15 @@ static inline void *new_socket_m3u8(void *args) { } int main(int argc, char *argv[]) { - selfPath = argv[0]; - if (argc != 2) { - if (argc != 4) { - fprintf(stderr, "usage: %s [port] ([username] [password])\n", - argv[0]); - return EXIT_FAILURE; - } - amUsername = argv[2]; - passLen = strlen(argv[3]); - amPassword = malloc(passLen + 7); - strcpy(amPassword, argv[3]); - } - port = atoi(portStr = argv[1]); + cmdline_parser(argc, argv, &args_info); init(); const struct shared_ptr ctx = init_ctx(); - if (argc == 4 && !login(ctx)) { + if (args_info.login_given) { + amUsername = strtok(args_info.login_arg, ":"); + amPassword = strtok(NULL, ":"); + } + if (args_info.login_given && !login(ctx)) { fprintf(stderr, "[!] login failed\n"); return EXIT_FAILURE; } @@ -545,7 +544,11 @@ int main(int argc, char *argv[]) { _ZN22SVPlaybackLeaseManager12requestLeaseERKb(leaseMgr, &autom); FHinstance = _ZN21SVFootHillSessionCtrl8instanceEv(); - pthread_t m3u8_thread; - pthread_create(&m3u8_thread, NULL, &new_socket_m3u8, NULL); + if (args_info.m3u8_port_given) { + pthread_t m3u8_thread; + pthread_create(&m3u8_thread, NULL, &new_socket_m3u8, NULL); + } else { + fprintf(stderr, "[!] The feature of getting m3u8 is defaultly disabled because it's unstable now. To enable it, please manually specify m3u8-port param.\n"); + } return new_socket(); } diff --git a/wrapper.c b/wrapper.c index 3872cc3..2bac137 100644 --- a/wrapper.c +++ b/wrapper.c @@ -23,10 +23,6 @@ int main(int argc, char *argv[], char *envp[]) { return 1; } - if (argc > 2) { - system("rm -r ./rootfs/data/data/com.apple.android.music/files/"); - } - if (chdir("./rootfs") != 0) { perror("chdir"); return 1; diff --git a/wrapper.ggo b/wrapper.ggo new file mode 100644 index 0000000..b03edbc --- /dev/null +++ b/wrapper.ggo @@ -0,0 +1,8 @@ +package "wrapper" +version "1.2.0" + +option "host" H "" string optional default="127.0.0.1" +option "decrypt-port" D "" int optional default="10020" +option "m3u8-port" M "" int optional default="20020" +option "proxy" P "" string optional default="" +option "login" L "" string optional