forked from sim1222-mirror/wrapper
update
This commit is contained in:
parent
caf52b1f91
commit
de7cff2b54
2
.github/workflows/build-for-arm64.yml
vendored
2
.github/workflows/build-for-arm64.yml
vendored
@ -47,3 +47,5 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
rootfs
|
rootfs
|
||||||
wrapper
|
wrapper
|
||||||
|
Dockerfile
|
||||||
|
|
||||||
|
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@ -44,3 +44,6 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
rootfs
|
rootfs
|
||||||
wrapper
|
wrapper
|
||||||
|
Dockerfile
|
||||||
|
|
||||||
|
|
||||||
|
47
.github/workflows/wrapper-qemu.yml
vendored
47
.github/workflows/wrapper-qemu.yml
vendored
@ -1,47 +0,0 @@
|
|||||||
name: wrapper-qemu
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_run:
|
|
||||||
workflows: ["Build"]
|
|
||||||
types: [completed]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
on-success:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Download wrapper-qemu basic image
|
|
||||||
run: wget https://github.com/WorldObservationLog/wrapper/releases/download/wrapper-qemu/wrapper.qcow2
|
|
||||||
|
|
||||||
- name: Mount image
|
|
||||||
run: |
|
|
||||||
sudo apt-get install -y qemu-utils
|
|
||||||
sudo modprobe nbd max_part=8
|
|
||||||
sudo qemu-nbd --connect=/dev/nbd0 wrapper.qcow2
|
|
||||||
sudo mkdir /mnt/wrapper
|
|
||||||
sudo mount /dev/nbd0p3 /mnt/wrapper/
|
|
||||||
|
|
||||||
- name: Download latest artifact
|
|
||||||
uses: dawidd6/action-download-artifact@v6
|
|
||||||
with:
|
|
||||||
github_token: ${{secrets.ACTION_TOKEN}}
|
|
||||||
run_id: ${{ github.event.workflow_run.id }}
|
|
||||||
|
|
||||||
- name: Copy wrapper to image
|
|
||||||
run: |
|
|
||||||
mv Wrapper.x86_64.* wrapper
|
|
||||||
sudo mv wrapper /mnt/wrapper/root/wrapper
|
|
||||||
sudo chmod +x /mnt/wrapper/root/wrapper/wrapper
|
|
||||||
|
|
||||||
- name: Unmount image
|
|
||||||
run: |
|
|
||||||
sudo umount /mnt/wrapper/
|
|
||||||
sudo qemu-nbd --disconnect /dev/nbd0
|
|
||||||
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: wrapper-qemu
|
|
||||||
path: wrapper.qcow2
|
|
@ -13,8 +13,8 @@ set(CMAKE_C_COMPILER "${TOOLCHAIN}/bin/aarch64-linux-android22-clang")
|
|||||||
set(CMAKE_CXX_COMPILER "${TOOLCHAIN}/bin/aarch64-linux-android22-clang++")
|
set(CMAKE_CXX_COMPILER "${TOOLCHAIN}/bin/aarch64-linux-android22-clang++")
|
||||||
set(C_COMPILER "${TOOLCHAIN}/bin/clang")
|
set(C_COMPILER "${TOOLCHAIN}/bin/clang")
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "-Wall -Werror -O3")
|
set(CMAKE_C_FLAGS "-g -Wall -Werror")
|
||||||
set(CMAKE_CXX_FLAGS "-Wall -Werror -O3")
|
set(CMAKE_CXX_FLAGS "-g -Wall -Werror")
|
||||||
|
|
||||||
set(CMDLINE_SOURCE cmdline.c)
|
set(CMDLINE_SOURCE cmdline.c)
|
||||||
set(HANDLE_SOURCE main.cpp)
|
set(HANDLE_SOURCE main.cpp)
|
||||||
|
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
FROM ubuntu:latest
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . /app
|
||||||
|
ENV args ""
|
||||||
|
|
||||||
|
CMD ["bash", "-c", "./wrapper ${args}"]
|
||||||
|
|
||||||
|
EXPOSE 10020 20020
|
16
Makefile
16
Makefile
@ -1,16 +0,0 @@
|
|||||||
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/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 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
|
|
||||||
~/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 cmdline.o
|
|
10
README.md
10
README.md
@ -8,6 +8,15 @@ Get the pre-built version from this project's Actions.
|
|||||||
|
|
||||||
Or you can refer to the Actions configuration file for compilation.
|
Or you can refer to the Actions configuration file for compilation.
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
Available for x86_64 and arm64. Need to download prebuilt version from releases or actions.
|
||||||
|
|
||||||
|
Build image: `docker build --tag wrapper .`
|
||||||
|
|
||||||
|
Login: `docker run -v ./rootfs/data:/app/rootfs/data -p 10020:10020 -e args="-L username:password -F -H 0.0.0.0" wrapper`
|
||||||
|
|
||||||
|
Run: `docker run -v ./rootfs/data:/app/rootfs/data -p 10020:10020 -e args="-H 0.0.0.0" wrapper`
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
```
|
```
|
||||||
Usage: wrapper [OPTION]...
|
Usage: wrapper [OPTION]...
|
||||||
@ -19,6 +28,7 @@ Usage: wrapper [OPTION]...
|
|||||||
-M, --m3u8-port=INT (default=`20020')
|
-M, --m3u8-port=INT (default=`20020')
|
||||||
-P, --proxy=STRING (default=`')
|
-P, --proxy=STRING (default=`')
|
||||||
-L, --login=STRING (username:password)
|
-L, --login=STRING (username:password)
|
||||||
|
-F, --code-from-file (default=off)
|
||||||
```
|
```
|
||||||
|
|
||||||
# Special thanks
|
# Special thanks
|
||||||
|
28
cmdline.c
28
cmdline.c
@ -40,11 +40,13 @@ const char *gengetopt_args_info_help[] = {
|
|||||||
" -D, --decrypt-port=INT (default=`10020')",
|
" -D, --decrypt-port=INT (default=`10020')",
|
||||||
" -M, --m3u8-port=INT (default=`20020')",
|
" -M, --m3u8-port=INT (default=`20020')",
|
||||||
" -P, --proxy=STRING (default=`')",
|
" -P, --proxy=STRING (default=`')",
|
||||||
" -L, --login=STRING ",
|
" -L, --login=STRING username:password",
|
||||||
|
" -F, --code-from-file (default=off)",
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {ARG_NO
|
typedef enum {ARG_NO
|
||||||
|
, ARG_FLAG
|
||||||
, ARG_STRING
|
, ARG_STRING
|
||||||
, ARG_INT
|
, ARG_INT
|
||||||
} cmdline_parser_arg_type;
|
} cmdline_parser_arg_type;
|
||||||
@ -72,6 +74,7 @@ void clear_given (struct gengetopt_args_info *args_info)
|
|||||||
args_info->m3u8_port_given = 0 ;
|
args_info->m3u8_port_given = 0 ;
|
||||||
args_info->proxy_given = 0 ;
|
args_info->proxy_given = 0 ;
|
||||||
args_info->login_given = 0 ;
|
args_info->login_given = 0 ;
|
||||||
|
args_info->code_from_file_given = 0 ;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@ -88,6 +91,7 @@ void clear_args (struct gengetopt_args_info *args_info)
|
|||||||
args_info->proxy_orig = NULL;
|
args_info->proxy_orig = NULL;
|
||||||
args_info->login_arg = NULL;
|
args_info->login_arg = NULL;
|
||||||
args_info->login_orig = NULL;
|
args_info->login_orig = NULL;
|
||||||
|
args_info->code_from_file_flag = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +107,7 @@ void init_args_info(struct gengetopt_args_info *args_info)
|
|||||||
args_info->m3u8_port_help = gengetopt_args_info_help[4] ;
|
args_info->m3u8_port_help = gengetopt_args_info_help[4] ;
|
||||||
args_info->proxy_help = gengetopt_args_info_help[5] ;
|
args_info->proxy_help = gengetopt_args_info_help[5] ;
|
||||||
args_info->login_help = gengetopt_args_info_help[6] ;
|
args_info->login_help = gengetopt_args_info_help[6] ;
|
||||||
|
args_info->code_from_file_help = gengetopt_args_info_help[7] ;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,6 +249,8 @@ cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info)
|
|||||||
write_into_file(outfile, "proxy", args_info->proxy_orig, 0);
|
write_into_file(outfile, "proxy", args_info->proxy_orig, 0);
|
||||||
if (args_info->login_given)
|
if (args_info->login_given)
|
||||||
write_into_file(outfile, "login", args_info->login_orig, 0);
|
write_into_file(outfile, "login", args_info->login_orig, 0);
|
||||||
|
if (args_info->code_from_file_given)
|
||||||
|
write_into_file(outfile, "code-from-file", 0, 0 );
|
||||||
|
|
||||||
|
|
||||||
i = EXIT_SUCCESS;
|
i = EXIT_SUCCESS;
|
||||||
@ -410,6 +417,9 @@ int update_arg(void *field, char **orig_field,
|
|||||||
val = possible_values[found];
|
val = possible_values[found];
|
||||||
|
|
||||||
switch(arg_type) {
|
switch(arg_type) {
|
||||||
|
case ARG_FLAG:
|
||||||
|
*((int *)field) = !*((int *)field);
|
||||||
|
break;
|
||||||
case ARG_INT:
|
case ARG_INT:
|
||||||
if (val) *((int *)field) = strtol (val, &stop_char, 0);
|
if (val) *((int *)field) = strtol (val, &stop_char, 0);
|
||||||
break;
|
break;
|
||||||
@ -440,6 +450,7 @@ int update_arg(void *field, char **orig_field,
|
|||||||
/* store the original value */
|
/* store the original value */
|
||||||
switch(arg_type) {
|
switch(arg_type) {
|
||||||
case ARG_NO:
|
case ARG_NO:
|
||||||
|
case ARG_FLAG:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (value && orig_field) {
|
if (value && orig_field) {
|
||||||
@ -507,10 +518,11 @@ cmdline_parser_internal (
|
|||||||
{ "m3u8-port", 1, NULL, 'M' },
|
{ "m3u8-port", 1, NULL, 'M' },
|
||||||
{ "proxy", 1, NULL, 'P' },
|
{ "proxy", 1, NULL, 'P' },
|
||||||
{ "login", 1, NULL, 'L' },
|
{ "login", 1, NULL, 'L' },
|
||||||
|
{ "code-from-file", 0, NULL, 'F' },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
c = getopt_long (argc, argv, "hVH:D:M:P:L:", long_options, &option_index);
|
c = getopt_long (argc, argv, "hVH:D:M:P:L:F", long_options, &option_index);
|
||||||
|
|
||||||
if (c == -1) break; /* Exit from `while (1)' loop. */
|
if (c == -1) break; /* Exit from `while (1)' loop. */
|
||||||
|
|
||||||
@ -574,7 +586,7 @@ cmdline_parser_internal (
|
|||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'L': /* . */
|
case 'L': /* username:password. */
|
||||||
|
|
||||||
|
|
||||||
if (update_arg( (void *)&(args_info->login_arg),
|
if (update_arg( (void *)&(args_info->login_arg),
|
||||||
@ -586,6 +598,16 @@ cmdline_parser_internal (
|
|||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case 'F': /* . */
|
||||||
|
|
||||||
|
|
||||||
|
if (update_arg((void *)&(args_info->code_from_file_flag), 0, &(args_info->code_from_file_given),
|
||||||
|
&(local_args_info.code_from_file_given), optarg, 0, 0, ARG_FLAG,
|
||||||
|
check_ambiguity, override, 1, 0, "code-from-file", 'F',
|
||||||
|
additional_error))
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case 0: /* Long option with no short option */
|
case 0: /* Long option with no short option */
|
||||||
case '?': /* Invalid option. */
|
case '?': /* Invalid option. */
|
||||||
|
@ -51,9 +51,11 @@ struct gengetopt_args_info
|
|||||||
char * proxy_arg; /**< @brief (default=''). */
|
char * proxy_arg; /**< @brief (default=''). */
|
||||||
char * proxy_orig; /**< @brief original value given at command line. */
|
char * proxy_orig; /**< @brief original value given at command line. */
|
||||||
const char *proxy_help; /**< @brief help description. */
|
const char *proxy_help; /**< @brief help description. */
|
||||||
char * login_arg; /**< @brief . */
|
char * login_arg; /**< @brief username:password. */
|
||||||
char * login_orig; /**< @brief original value given at command line. */
|
char * login_orig; /**< @brief username:password original value given at command line. */
|
||||||
const char *login_help; /**< @brief help description. */
|
const char *login_help; /**< @brief username:password help description. */
|
||||||
|
int code_from_file_flag; /**< @brief (default=off). */
|
||||||
|
const char *code_from_file_help; /**< @brief help description. */
|
||||||
|
|
||||||
unsigned int help_given ; /**< @brief Whether help was given. */
|
unsigned int help_given ; /**< @brief Whether help was given. */
|
||||||
unsigned int version_given ; /**< @brief Whether version was given. */
|
unsigned int version_given ; /**< @brief Whether version was given. */
|
||||||
@ -62,6 +64,7 @@ struct gengetopt_args_info
|
|||||||
unsigned int m3u8_port_given ; /**< @brief Whether m3u8-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 proxy_given ; /**< @brief Whether proxy was given. */
|
||||||
unsigned int login_given ; /**< @brief Whether login was given. */
|
unsigned int login_given ; /**< @brief Whether login was given. */
|
||||||
|
unsigned int code_from_file_given ; /**< @brief Whether code-from-file was given. */
|
||||||
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
34
main.c
34
main.c
@ -10,6 +10,7 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "import.h"
|
#include "import.h"
|
||||||
#include "cmdline.h"
|
#include "cmdline.h"
|
||||||
@ -22,6 +23,11 @@ static uint8_t leaseMgr[16];
|
|||||||
struct gengetopt_args_info args_info;
|
struct gengetopt_args_info args_info;
|
||||||
char *amUsername, *amPassword;
|
char *amUsername, *amPassword;
|
||||||
|
|
||||||
|
int file_exists(char *filename) {
|
||||||
|
struct stat buffer;
|
||||||
|
return (stat (filename, &buffer) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
static void dialogHandler(long j, struct shared_ptr *protoDialogPtr,
|
static void dialogHandler(long j, struct shared_ptr *protoDialogPtr,
|
||||||
struct shared_ptr *respHandler) {
|
struct shared_ptr *respHandler) {
|
||||||
const char *const title = std_string_data(
|
const char *const title = std_string_data(
|
||||||
@ -79,8 +85,32 @@ static void credentialHandler(struct shared_ptr *credReqHandler,
|
|||||||
int passLen = strlen(amPassword);
|
int passLen = strlen(amPassword);
|
||||||
|
|
||||||
if (need2FA) {
|
if (need2FA) {
|
||||||
printf("2FA code: ");
|
if (args_info.code_from_file_flag) {
|
||||||
scanf("%6s", amPassword + passLen);
|
fprintf(stderr, "[!] Enter your 2FA code into rootfs/data/code.txt\n");
|
||||||
|
fprintf(stderr, "[!] Example command: echo -n 114514 > rootfs/data/2fa.txt\n");
|
||||||
|
fprintf(stderr, "[!] Waiting for input...\n");
|
||||||
|
int count = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (count >= 20) {
|
||||||
|
fprintf(stderr, "[!] Failed to get 2FA Code in 60s. Exiting...\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if (file_exists("/data/2fa.txt")) {
|
||||||
|
FILE *fp = fopen("/data/2fa.txt", "r");
|
||||||
|
fscanf(fp, "%6s", amPassword + passLen);
|
||||||
|
remove("/data/2fa.txt");
|
||||||
|
fprintf(stderr, "[!] Code file detected! Logging in...\n");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
sleep(3);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("2FA code: ");
|
||||||
|
scanf("%6s", amPassword + passLen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *const ptr = malloc(80);
|
uint8_t *const ptr = malloc(80);
|
||||||
|
554
test.c
554
test.c
@ -1,554 +0,0 @@
|
|||||||
#include <errno.h>
|
|
||||||
#include <setjmp.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
|
|
||||||
#include "import.h"
|
|
||||||
#include "cmdline.h"
|
|
||||||
#ifndef MyRelease
|
|
||||||
#include "subhook/subhook.c"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct shared_ptr apInf;
|
|
||||||
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) {
|
|
||||||
const char *const title = std_string_data(
|
|
||||||
_ZNK17storeservicescore14ProtocolDialog5titleEv(protoDialogPtr->obj));
|
|
||||||
fprintf(stderr, "[.] dialogHandler: {title: %s, message: %s}\n", title,
|
|
||||||
std_string_data(_ZNK17storeservicescore14ProtocolDialog7messageEv(
|
|
||||||
protoDialogPtr->obj)));
|
|
||||||
|
|
||||||
unsigned char ptr[72];
|
|
||||||
memset(ptr + 8, 0, 16);
|
|
||||||
*(void **)(ptr) =
|
|
||||||
&_ZTVNSt6__ndk120__shared_ptr_emplaceIN17storeservicescore22ProtocolDialogResponseENS_9allocatorIS2_EEEE +
|
|
||||||
2;
|
|
||||||
struct shared_ptr diagResp = {.obj = ptr + 24, .ctrl_blk = ptr};
|
|
||||||
_ZN17storeservicescore22ProtocolDialogResponseC1Ev(diagResp.obj);
|
|
||||||
|
|
||||||
struct std_vector *butVec =
|
|
||||||
_ZNK17storeservicescore14ProtocolDialog7buttonsEv(protoDialogPtr->obj);
|
|
||||||
if (strcmp("Sign In", title) == 0) {
|
|
||||||
for (struct shared_ptr *b = butVec->begin; b != butVec->end; ++b) {
|
|
||||||
if (strcmp("Use Existing Apple ID",
|
|
||||||
std_string_data(
|
|
||||||
_ZNK17storeservicescore14ProtocolButton5titleEv(
|
|
||||||
b->obj))) == 0) {
|
|
||||||
_ZN17storeservicescore22ProtocolDialogResponse17setSelectedButtonERKNSt6__ndk110shared_ptrINS_14ProtocolButtonEEE(
|
|
||||||
diagResp.obj, b);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (struct shared_ptr *b = butVec->begin; b != butVec->end; ++b) {
|
|
||||||
fprintf(
|
|
||||||
stderr, "[.] button %p: %s\n", b->obj,
|
|
||||||
std_string_data(
|
|
||||||
_ZNK17storeservicescore14ProtocolButton5titleEv(b->obj)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ZN20androidstoreservices28AndroidPresentationInterface28handleProtocolDialogResponseERKlRKNSt6__ndk110shared_ptrIN17storeservicescore22ProtocolDialogResponseEEE(
|
|
||||||
apInf.obj, &j, &diagResp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void credentialHandler(struct shared_ptr *credReqHandler,
|
|
||||||
struct shared_ptr *credRespHandler) {
|
|
||||||
const uint8_t need2FA =
|
|
||||||
_ZNK17storeservicescore18CredentialsRequest28requiresHSA2VerificationCodeEv(
|
|
||||||
credReqHandler->obj);
|
|
||||||
fprintf(
|
|
||||||
stderr, "[.] credentialHandler: {title: %s, message: %s, 2FA: %s}\n",
|
|
||||||
std_string_data(_ZNK17storeservicescore18CredentialsRequest5titleEv(
|
|
||||||
credReqHandler->obj)),
|
|
||||||
std_string_data(_ZNK17storeservicescore18CredentialsRequest7messageEv(
|
|
||||||
credReqHandler->obj)),
|
|
||||||
need2FA ? "true" : "false");
|
|
||||||
|
|
||||||
int passLen = strlen(amPassword);
|
|
||||||
|
|
||||||
if (need2FA) {
|
|
||||||
printf("2FA code: ");
|
|
||||||
scanf("%6s", amPassword + passLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *const ptr = malloc(80);
|
|
||||||
memset(ptr + 8, 0, 16);
|
|
||||||
*(void **)(ptr) =
|
|
||||||
&_ZTVNSt6__ndk120__shared_ptr_emplaceIN17storeservicescore19CredentialsResponseENS_9allocatorIS2_EEEE +
|
|
||||||
2;
|
|
||||||
struct shared_ptr credResp = {.obj = ptr + 24, .ctrl_blk = ptr};
|
|
||||||
_ZN17storeservicescore19CredentialsResponseC1Ev(credResp.obj);
|
|
||||||
|
|
||||||
union std_string username = new_std_string(amUsername);
|
|
||||||
_ZN17storeservicescore19CredentialsResponse11setUserNameERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(
|
|
||||||
credResp.obj, &username);
|
|
||||||
|
|
||||||
union std_string password = new_std_string(amPassword);
|
|
||||||
_ZN17storeservicescore19CredentialsResponse11setPasswordERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(
|
|
||||||
credResp.obj, &password);
|
|
||||||
|
|
||||||
_ZN17storeservicescore19CredentialsResponse15setResponseTypeENS0_12ResponseTypeE(
|
|
||||||
credResp.obj, 2);
|
|
||||||
|
|
||||||
_ZN20androidstoreservices28AndroidPresentationInterface25handleCredentialsResponseERKNSt6__ndk110shared_ptrIN17storeservicescore19CredentialsResponseEEE(
|
|
||||||
apInf.obj, &credResp);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef MyRelease
|
|
||||||
static uint8_t allDebug() { return 1; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline void init() {
|
|
||||||
// srand(time(0));
|
|
||||||
|
|
||||||
// raise(SIGSTOP);
|
|
||||||
fprintf(stderr, "[+] starting...\n");
|
|
||||||
setenv("ANDROID_DNS_MODE", "local", 1);
|
|
||||||
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(
|
|
||||||
_ZN13mediaplatform26DebugLogEnabledForPriorityENS_11LogPriorityE,
|
|
||||||
allDebug, SUBHOOK_64BIT_OFFSET));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// static char android_id[16];
|
|
||||||
// for (int i = 0; i < 16; ++i) {
|
|
||||||
// android_id[i] = "0123456789abcdef"[rand() % 16];
|
|
||||||
// }
|
|
||||||
union std_string conf1 = new_std_string(android_id);
|
|
||||||
union std_string conf2 = new_std_string("");
|
|
||||||
_ZN14FootHillConfig6configERKNSt6__ndk112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE(
|
|
||||||
&conf1);
|
|
||||||
|
|
||||||
// union std_string root = new_std_string("/");
|
|
||||||
// union std_string natLib = new_std_string("/system/lib64/");
|
|
||||||
// void *foothill = malloc(120);
|
|
||||||
// _ZN8FootHillC2ERKNSt6__ndk112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_(
|
|
||||||
// foothill, &root, &natLib);
|
|
||||||
// _ZN8FootHill24defaultContextIdentifierEv(foothill);
|
|
||||||
|
|
||||||
struct shared_ptr GUID;
|
|
||||||
_ZN17storeservicescore10DeviceGUID8instanceEv(&GUID);
|
|
||||||
|
|
||||||
static uint8_t ret[88];
|
|
||||||
static unsigned int conf3 = 29;
|
|
||||||
static uint8_t conf4 = 1;
|
|
||||||
_ZN17storeservicescore10DeviceGUID9configureERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_RKjRKb(
|
|
||||||
&ret, GUID.obj, &conf1, &conf2, &conf3, &conf4);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct shared_ptr init_ctx() {
|
|
||||||
fprintf(stderr, "[+] initializing ctx...\n");
|
|
||||||
union std_string strBuf =
|
|
||||||
new_std_string("/data/data/com.apple.android.music/files/mpl_db");
|
|
||||||
|
|
||||||
struct shared_ptr reqCtx;
|
|
||||||
_ZNSt6__ndk110shared_ptrIN17storeservicescore14RequestContextEE11make_sharedIJRNS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEEEES3_DpOT_(
|
|
||||||
&reqCtx, &strBuf);
|
|
||||||
|
|
||||||
static uint8_t ptr[480];
|
|
||||||
*(void **)(ptr) =
|
|
||||||
&_ZTVNSt6__ndk120__shared_ptr_emplaceIN17storeservicescore20RequestContextConfigENS_9allocatorIS2_EEEE +
|
|
||||||
2;
|
|
||||||
struct shared_ptr reqCtxCfg = {.obj = ptr + 32, .ctrl_blk = ptr};
|
|
||||||
|
|
||||||
_ZN17storeservicescore20RequestContextConfigC2Ev(reqCtxCfg.obj);
|
|
||||||
// _ZN17storeservicescore20RequestContextConfig9setCPFlagEb(reqCtx.obj, 1);
|
|
||||||
_ZN17storeservicescore20RequestContextConfig20setBaseDirectoryPathERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(
|
|
||||||
reqCtxCfg.obj, &strBuf);
|
|
||||||
strBuf = new_std_string("Music");
|
|
||||||
_ZN17storeservicescore20RequestContextConfig19setClientIdentifierERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(
|
|
||||||
reqCtxCfg.obj, &strBuf);
|
|
||||||
strBuf = new_std_string("4.9");
|
|
||||||
_ZN17storeservicescore20RequestContextConfig20setVersionIdentifierERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(
|
|
||||||
reqCtxCfg.obj, &strBuf);
|
|
||||||
strBuf = new_std_string("Android");
|
|
||||||
_ZN17storeservicescore20RequestContextConfig21setPlatformIdentifierERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(
|
|
||||||
reqCtxCfg.obj, &strBuf);
|
|
||||||
strBuf = new_std_string("10");
|
|
||||||
_ZN17storeservicescore20RequestContextConfig17setProductVersionERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(
|
|
||||||
reqCtxCfg.obj, &strBuf);
|
|
||||||
strBuf = new_std_string("Samsung S9");
|
|
||||||
_ZN17storeservicescore20RequestContextConfig14setDeviceModelERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(
|
|
||||||
reqCtxCfg.obj, &strBuf);
|
|
||||||
strBuf = new_std_string("7663313");
|
|
||||||
_ZN17storeservicescore20RequestContextConfig15setBuildVersionERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(
|
|
||||||
reqCtxCfg.obj, &strBuf);
|
|
||||||
strBuf = new_std_string("en-US");
|
|
||||||
_ZN17storeservicescore20RequestContextConfig19setLocaleIdentifierERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(
|
|
||||||
reqCtxCfg.obj, &strBuf);
|
|
||||||
_ZN17storeservicescore20RequestContextConfig21setLanguageIdentifierERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(
|
|
||||||
reqCtxCfg.obj, &strBuf);
|
|
||||||
|
|
||||||
_ZN21RequestContextManager9configureERKNSt6__ndk110shared_ptrIN17storeservicescore14RequestContextEEE(
|
|
||||||
&reqCtx);
|
|
||||||
static uint8_t buf[88];
|
|
||||||
_ZN17storeservicescore14RequestContext4initERKNSt6__ndk110shared_ptrINS_20RequestContextConfigEEE(
|
|
||||||
&buf, reqCtx.obj, &reqCtxCfg);
|
|
||||||
strBuf = new_std_string("/data/data/com.apple.android.music/files");
|
|
||||||
_ZN17storeservicescore14RequestContext24setFairPlayDirectoryPathERKNSt6__ndk112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(
|
|
||||||
reqCtx.obj, &strBuf);
|
|
||||||
|
|
||||||
_ZNSt6__ndk110shared_ptrIN20androidstoreservices28AndroidPresentationInterfaceEE11make_sharedIJEEES3_DpOT_(
|
|
||||||
&apInf);
|
|
||||||
|
|
||||||
_ZN20androidstoreservices28AndroidPresentationInterface16setDialogHandlerEPFvlNSt6__ndk110shared_ptrIN17storeservicescore14ProtocolDialogEEENS2_INS_36AndroidProtocolDialogResponseHandlerEEEE(
|
|
||||||
apInf.obj, &dialogHandler);
|
|
||||||
|
|
||||||
_ZN20androidstoreservices28AndroidPresentationInterface21setCredentialsHandlerEPFvNSt6__ndk110shared_ptrIN17storeservicescore18CredentialsRequestEEENS2_INS_33AndroidCredentialsResponseHandlerEEEE(
|
|
||||||
apInf.obj, &credentialHandler);
|
|
||||||
|
|
||||||
_ZN17storeservicescore14RequestContext24setPresentationInterfaceERKNSt6__ndk110shared_ptrINS_21PresentationInterfaceEEE(
|
|
||||||
reqCtx.obj, &apInf);
|
|
||||||
|
|
||||||
return reqCtx;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void *endLeaseCallback;
|
|
||||||
extern void *pbErrCallback;
|
|
||||||
|
|
||||||
inline static uint8_t login(struct shared_ptr reqCtx) {
|
|
||||||
fprintf(stderr, "[+] logging in...\n");
|
|
||||||
struct shared_ptr flow;
|
|
||||||
_ZNSt6__ndk110shared_ptrIN17storeservicescore16AuthenticateFlowEE11make_sharedIJRNS0_INS1_14RequestContextEEEEEES3_DpOT_(
|
|
||||||
&flow, &reqCtx);
|
|
||||||
_ZN17storeservicescore16AuthenticateFlow3runEv(flow.obj);
|
|
||||||
struct shared_ptr *resp =
|
|
||||||
_ZNK17storeservicescore16AuthenticateFlow8responseEv(flow.obj);
|
|
||||||
if (resp == NULL || resp->obj == NULL)
|
|
||||||
return 0;
|
|
||||||
const int respType =
|
|
||||||
_ZNK17storeservicescore20AuthenticateResponse12responseTypeEv(
|
|
||||||
resp->obj);
|
|
||||||
fprintf(stderr, "[.] response type %d\n", respType);
|
|
||||||
return respType == 6;
|
|
||||||
// struct shared_ptr subStatMgr;
|
|
||||||
// _ZN20androidstoreservices30SVSubscriptionStatusMgrFactory6createEv(&subStatMgr);
|
|
||||||
// struct shared_ptr data;
|
|
||||||
// int method = 2;
|
|
||||||
// _ZN20androidstoreservices27SVSubscriptionStatusMgrImpl33checkSubscriptionStatusFromSourceERKNSt6__ndk110shared_ptrIN17storeservicescore14RequestContextEEERKNS_23SVSubscriptionStatusMgr26SVSubscriptionStatusSourceE(&data,
|
|
||||||
// subStatMgr.obj, &reqCtx, &method);
|
|
||||||
// return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint8_t readfull(const int connfd, void *const buf,
|
|
||||||
const size_t size) {
|
|
||||||
size_t red = 0;
|
|
||||||
while (size > red) {
|
|
||||||
const ssize_t b = read(connfd, ((uint8_t *)buf) + red, size - red);
|
|
||||||
if (b <= 0)
|
|
||||||
return 0;
|
|
||||||
red += b;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void writefull(const int connfd, void *const buf,
|
|
||||||
const size_t size) {
|
|
||||||
size_t red = 0;
|
|
||||||
while (size > red) {
|
|
||||||
const ssize_t b = write(connfd, ((uint8_t *)buf) + red, size - red);
|
|
||||||
if (b <= 0) {
|
|
||||||
perror("write");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
red += b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *FHinstance = NULL;
|
|
||||||
static void *preshareCtx = NULL;
|
|
||||||
|
|
||||||
inline static void *getKdContext(const char *const adam,
|
|
||||||
const char *const uri) {
|
|
||||||
uint8_t isPreshare = (strcmp("0", adam) == 0);
|
|
||||||
if (isPreshare && preshareCtx != NULL) {
|
|
||||||
return preshareCtx;
|
|
||||||
}
|
|
||||||
fprintf(stderr, "[.] adamId: %s, uri: %s\n", adam, uri);
|
|
||||||
|
|
||||||
union std_string defaultId = new_std_string(adam);
|
|
||||||
union std_string keyUri = new_std_string(uri);
|
|
||||||
union std_string keyFormat =
|
|
||||||
new_std_string("com.apple.streamingkeydelivery");
|
|
||||||
union std_string keyFormatVer = new_std_string("1");
|
|
||||||
union std_string serverUri = new_std_string(
|
|
||||||
"https://play.itunes.apple.com/WebObjects/MZPlay.woa/music/fps");
|
|
||||||
union std_string protocolType = new_std_string("simplified");
|
|
||||||
union std_string fpsCert = new_std_string(fairplayCert);
|
|
||||||
|
|
||||||
struct shared_ptr persistK = {.obj = NULL};
|
|
||||||
_ZN21SVFootHillSessionCtrl16getPersistentKeyERKNSt6__ndk112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_S8_S8_S8_S8_S8_(
|
|
||||||
&persistK, FHinstance, &defaultId, &defaultId, &keyUri, &keyFormat,
|
|
||||||
&keyFormatVer, &serverUri, &protocolType, &fpsCert);
|
|
||||||
|
|
||||||
if (persistK.obj == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
struct shared_ptr SVFootHillPContext;
|
|
||||||
_ZN21SVFootHillSessionCtrl14decryptContextERKNSt6__ndk112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERKN11SVDecryptor15SVDecryptorTypeERKb(
|
|
||||||
&SVFootHillPContext, FHinstance, persistK.obj);
|
|
||||||
|
|
||||||
if (SVFootHillPContext.obj == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
void *kdContext =
|
|
||||||
*_ZNK18SVFootHillPContext9kdContextEv(SVFootHillPContext.obj);
|
|
||||||
if (kdContext != NULL && isPreshare)
|
|
||||||
preshareCtx = kdContext;
|
|
||||||
return kdContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle(const int connfd) {
|
|
||||||
while (1) {
|
|
||||||
uint8_t adamSize;
|
|
||||||
if (!readfull(connfd, &adamSize, sizeof(uint8_t)))
|
|
||||||
return;
|
|
||||||
if (adamSize <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
char adam[adamSize + 1];
|
|
||||||
if (!readfull(connfd, adam, adamSize))
|
|
||||||
return;
|
|
||||||
adam[adamSize] = '\0';
|
|
||||||
|
|
||||||
uint8_t uri_size;
|
|
||||||
if (!readfull(connfd, &uri_size, sizeof(uint8_t)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
char uri[uri_size + 1];
|
|
||||||
if (!readfull(connfd, uri, uri_size))
|
|
||||||
return;
|
|
||||||
uri[uri_size] = '\0';
|
|
||||||
|
|
||||||
void **const kdContext = getKdContext(adam, uri);
|
|
||||||
if (kdContext == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
uint32_t size;
|
|
||||||
if (!readfull(connfd, &size, sizeof(uint32_t))) {
|
|
||||||
perror("read");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
void *sample = malloc(size);
|
|
||||||
if (sample == NULL) {
|
|
||||||
perror("malloc");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!readfull(connfd, sample, size)) {
|
|
||||||
free(sample);
|
|
||||||
perror("read");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NfcRKVnxuKZy04KWbdFu71Ou(*kdContext, 5, sample, sample, size);
|
|
||||||
writefull(connfd, sample, size);
|
|
||||||
free(sample);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern uint8_t handle_cpp(int);
|
|
||||||
|
|
||||||
inline static int new_socket() {
|
|
||||||
const int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
|
|
||||||
if (fd == -1) {
|
|
||||||
perror("socket");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
const int optval = 1;
|
|
||||||
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
|
|
||||||
|
|
||||||
static struct sockaddr_in serv_addr = {.sin_family = AF_INET};
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listen(fd, 5) == -1) {
|
|
||||||
perror("listen");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
while (1) {
|
|
||||||
const int connfd = accept4(fd, (struct sockaddr *)&peer_addr,
|
|
||||||
&peer_addr_size, SOCK_CLOEXEC);
|
|
||||||
if (connfd == -1) {
|
|
||||||
if (errno == ENETDOWN || errno == EPROTO || errno == ENOPROTOOPT ||
|
|
||||||
errno == EHOSTDOWN || errno == ENONET ||
|
|
||||||
errno == EHOSTUNREACH || errno == EOPNOTSUPP ||
|
|
||||||
errno == ENETUNREACH)
|
|
||||||
continue;
|
|
||||||
perror("accept4");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!handle_cpp(connfd)) {
|
|
||||||
uint8_t autom = 1;
|
|
||||||
_ZN22SVPlaybackLeaseManager12requestLeaseERKb(leaseMgr, &autom);
|
|
||||||
}
|
|
||||||
// if (sigsetjmp(catcher.env, 0) == 0) {
|
|
||||||
// catcher.do_jump = 1;
|
|
||||||
// handle(connfd);
|
|
||||||
// }
|
|
||||||
// catcher.do_jump = 0;
|
|
||||||
|
|
||||||
if (close(connfd) == -1) {
|
|
||||||
perror("close");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char* get_m3u8_method_play(uint8_t leaseMgr[16], unsigned long adam) {
|
|
||||||
union std_string HLS = new_std_string_short_mode("HLS");
|
|
||||||
struct std_vector HLSParam = new_std_vector(&HLS);
|
|
||||||
static uint8_t z0 = 1;
|
|
||||||
struct shared_ptr *ptr_result = (struct shared_ptr *) malloc(32);
|
|
||||||
_ZN22SVPlaybackLeaseManager12requestAssetERKmRKNSt6__ndk16vectorINS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS7_IS9_EEEERKb(
|
|
||||||
ptr_result, leaseMgr, &adam, &HLSParam, &z0
|
|
||||||
);
|
|
||||||
if (_ZNK23SVPlaybackAssetResponse13hasValidAssetEv(ptr_result->obj)) {
|
|
||||||
struct shared_ptr *playbackAsset = _ZNK23SVPlaybackAssetResponse13playbackAssetEv(ptr_result->obj);
|
|
||||||
union std_string *m3u8 = (union std_string *) malloc(24);
|
|
||||||
_ZNK17storeservicescore13PlaybackAsset9URLStringEv(m3u8, playbackAsset->obj);
|
|
||||||
return std_string_data(m3u8);
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_m3u8(const int connfd) {
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
uint8_t adamSize;
|
|
||||||
if (!readfull(connfd, &adamSize, sizeof(uint8_t))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (adamSize <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char adam[adamSize];
|
|
||||||
for (int i=0; i<adamSize; i=i+1) {
|
|
||||||
readfull(connfd, &adam[i], sizeof(uint8_t));
|
|
||||||
}
|
|
||||||
char *ptr;
|
|
||||||
unsigned long adamID = strtoul(adam, &ptr, 10);
|
|
||||||
const char *m3u8 = get_m3u8_method_play(leaseMgr, adamID);
|
|
||||||
if (m3u8 == NULL) {
|
|
||||||
fprintf(stderr, "[.] failed to get m3u8 of adamId: %ld\n", adamID);
|
|
||||||
writefull(connfd, NULL, sizeof(NULL));
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "[.] m3u8 adamId: %ld, url: %s\n", adamID, m3u8);
|
|
||||||
strcat((char *)m3u8, "\n");
|
|
||||||
writefull(connfd, (void *)m3u8, strlen(m3u8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *new_socket_m3u8(void *args) {
|
|
||||||
const int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
|
|
||||||
if (fd == -1) {
|
|
||||||
perror("socket");
|
|
||||||
}
|
|
||||||
const int optval = 1;
|
|
||||||
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
|
|
||||||
|
|
||||||
static struct sockaddr_in serv_addr = {.sin_family = AF_INET};
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listen(fd, 5) == -1) {
|
|
||||||
perror("listen");
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
while (1) {
|
|
||||||
const int connfd = accept4(fd, (struct sockaddr *)&peer_addr,
|
|
||||||
&peer_addr_size, SOCK_CLOEXEC);
|
|
||||||
if (connfd == -1) {
|
|
||||||
if (errno == ENETDOWN || errno == EPROTO || errno == ENOPROTOOPT ||
|
|
||||||
errno == EHOSTDOWN || errno == ENONET ||
|
|
||||||
errno == EHOSTUNREACH || errno == EOPNOTSUPP ||
|
|
||||||
errno == ENETUNREACH)
|
|
||||||
continue;
|
|
||||||
perror("accept4");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
handle_m3u8(connfd);
|
|
||||||
|
|
||||||
if (close(connfd) == -1) {
|
|
||||||
perror("close");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
cmdline_parser(argc, argv, &args_info);
|
|
||||||
|
|
||||||
init();
|
|
||||||
const struct shared_ptr ctx = init_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;
|
|
||||||
}
|
|
||||||
_ZN22SVPlaybackLeaseManagerC2ERKNSt6__ndk18functionIFvRKiEEERKNS1_IFvRKNS0_10shared_ptrIN17storeservicescore19StoreErrorConditionEEEEEE(
|
|
||||||
leaseMgr, &endLeaseCallback, &pbErrCallback);
|
|
||||||
uint8_t autom = 1;
|
|
||||||
_ZN22SVPlaybackLeaseManager25refreshLeaseAutomaticallyERKb(leaseMgr,
|
|
||||||
&autom);
|
|
||||||
_ZN22SVPlaybackLeaseManager12requestLeaseERKb(leaseMgr, &autom);
|
|
||||||
FHinstance = _ZN21SVFootHillSessionCtrl8instanceEv();
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
10
wrapper.c
10
wrapper.c
@ -1,6 +1,6 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sched.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@ -35,21 +35,19 @@ int main(int argc, char *argv[], char *envp[]) {
|
|||||||
chmod("/system/bin/linker64", 0755);
|
chmod("/system/bin/linker64", 0755);
|
||||||
chmod("/system/bin/main", 0755);
|
chmod("/system/bin/main", 0755);
|
||||||
|
|
||||||
if (unshare(CLONE_NEWPID)) {
|
|
||||||
perror("unshare");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
child_proc = fork();
|
child_proc = fork();
|
||||||
if (child_proc == -1) {
|
if (child_proc == -1) {
|
||||||
perror("fork");
|
perror("fork");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child_proc > 0) {
|
if (child_proc > 0) {
|
||||||
close(STDOUT_FILENO);
|
close(STDOUT_FILENO);
|
||||||
wait(NULL);
|
wait(NULL); // Parent waits for the child process to terminate
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Child process logic
|
||||||
mkdir("/data/data/com.apple.android.music/files", 0777);
|
mkdir("/data/data/com.apple.android.music/files", 0777);
|
||||||
mkdir("/data/data/com.apple.android.music/files/mpl_db", 0777);
|
mkdir("/data/data/com.apple.android.music/files/mpl_db", 0777);
|
||||||
execve("/system/bin/main", argv, envp);
|
execve("/system/bin/main", argv, envp);
|
||||||
|
@ -5,4 +5,5 @@ option "host" H "" string optional default="127.0.0.1"
|
|||||||
option "decrypt-port" D "" int optional default="10020"
|
option "decrypt-port" D "" int optional default="10020"
|
||||||
option "m3u8-port" M "" int optional default="20020"
|
option "m3u8-port" M "" int optional default="20020"
|
||||||
option "proxy" P "" string optional default=""
|
option "proxy" P "" string optional default=""
|
||||||
option "login" L "" string optional
|
option "login" L "username:password" string optional
|
||||||
|
option "code-from-file" F "" flag off
|
Loading…
x
Reference in New Issue
Block a user