Skip to content

Commit 2d5318e

Browse files
Merge pull request #6 from glomatico/main
[Mostly Vibe Coded] Add account info endpoint and improve documentation
2 parents 41bbfab + f6df87d commit 2d5318e

6 files changed

Lines changed: 205 additions & 24 deletions

File tree

Dockerfile

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
FROM ubuntu:latest
1+
FROM debian:stable-slim
22

3+
ENV args=""
4+
5+
COPY ./rootfs /app/rootfs
6+
COPY ./wrapper /app
37
WORKDIR /app
4-
#COPY --from=builder /app /app
5-
COPY . /app
6-
ENV args ""
78

8-
CMD ["bash", "-c", "./wrapper ${args}"]
9+
CMD ["bash", "-c", "/app/wrapper $args"]
910

10-
EXPOSE 10020 20020
11+
EXPOSE 10020 20020 30020

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,46 @@ Usage: wrapper [OPTION]...
2626
-H, --host=STRING (default=`127.0.0.1')
2727
-D, --decrypt-port=INT (default=`10020')
2828
-M, --m3u8-port=INT (default=`20020')
29+
-A, --account-port=INT (default=`30020')
2930
-P, --proxy=STRING (default=`')
3031
-L, --login=STRING (username:password)
3132
-F, --code-from-file (default=off)
3233
```
3334

35+
# Build from source
36+
37+
1. Install dependencies:
38+
39+
- Build tools:
40+
41+
```
42+
sudo apt install build-essential cmake wget unzip git
43+
```
44+
45+
- LLVM:
46+
47+
```
48+
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)
49+
```
50+
51+
- Android NDK r23b:
52+
```
53+
wget -O android-ndk-r23b-linux.zip https://dl.google.com/android/repository/android-ndk-r23b-linux.zip
54+
unzip -q -d ~ android-ndk-r23b-linux.zip
55+
```
56+
57+
2. Build:
58+
59+
```
60+
git clone https://github.com/WorldObservationLog/wrapper
61+
cd wrapper
62+
mkdir build
63+
cd build
64+
cmake ..
65+
make -j$(nproc)
66+
```
67+
68+
3469
# Special thanks
3570
- Anonymous, for providing the original version of this project and the legacy Frida decryption method.
3671
- chocomint, for providing support for arm64 arch.

cmdline.c

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const char *gengetopt_args_info_help[] = {
3939
" -H, --host=STRING (default=`127.0.0.1')",
4040
" -D, --decrypt-port=INT (default=`10020')",
4141
" -M, --m3u8-port=INT (default=`20020')",
42+
" -A, --account-port=INT (default=`30020')",
4243
" -P, --proxy=STRING (default=`')",
4344
" -L, --login=STRING username:password",
4445
" -F, --code-from-file (default=off)",
@@ -74,6 +75,7 @@ void clear_given (struct gengetopt_args_info *args_info)
7475
args_info->host_given = 0 ;
7576
args_info->decrypt_port_given = 0 ;
7677
args_info->m3u8_port_given = 0 ;
78+
args_info->account_port_given = 0 ;
7779
args_info->proxy_given = 0 ;
7880
args_info->login_given = 0 ;
7981
args_info->code_from_file_given = 0 ;
@@ -91,6 +93,8 @@ void clear_args (struct gengetopt_args_info *args_info)
9193
args_info->decrypt_port_orig = NULL;
9294
args_info->m3u8_port_arg = 20020;
9395
args_info->m3u8_port_orig = NULL;
96+
args_info->account_port_arg = 30020;
97+
args_info->account_port_orig = NULL;
9498
args_info->proxy_arg = gengetopt_strdup ("");
9599
args_info->proxy_orig = NULL;
96100
args_info->login_arg = NULL;
@@ -113,11 +117,12 @@ void init_args_info(struct gengetopt_args_info *args_info)
113117
args_info->host_help = gengetopt_args_info_help[2] ;
114118
args_info->decrypt_port_help = gengetopt_args_info_help[3] ;
115119
args_info->m3u8_port_help = gengetopt_args_info_help[4] ;
116-
args_info->proxy_help = gengetopt_args_info_help[5] ;
117-
args_info->login_help = gengetopt_args_info_help[6] ;
118-
args_info->code_from_file_help = gengetopt_args_info_help[7] ;
119-
args_info->base_dir_help = gengetopt_args_info_help[8] ;
120-
args_info->device_info_help = gengetopt_args_info_help[9] ;
120+
args_info->account_port_help = gengetopt_args_info_help[5] ;
121+
args_info->proxy_help = gengetopt_args_info_help[6] ;
122+
args_info->login_help = gengetopt_args_info_help[7] ;
123+
args_info->code_from_file_help = gengetopt_args_info_help[8] ;
124+
args_info->base_dir_help = gengetopt_args_info_help[9] ;
125+
args_info->device_info_help = gengetopt_args_info_help[10] ;
121126

122127
}
123128

@@ -211,6 +216,7 @@ cmdline_parser_release (struct gengetopt_args_info *args_info)
211216
free_string_field (&(args_info->host_orig));
212217
free_string_field (&(args_info->decrypt_port_orig));
213218
free_string_field (&(args_info->m3u8_port_orig));
219+
free_string_field (&(args_info->account_port_orig));
214220
free_string_field (&(args_info->proxy_arg));
215221
free_string_field (&(args_info->proxy_orig));
216222
free_string_field (&(args_info->login_arg));
@@ -259,6 +265,8 @@ cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info)
259265
write_into_file(outfile, "decrypt-port", args_info->decrypt_port_orig, 0);
260266
if (args_info->m3u8_port_given)
261267
write_into_file(outfile, "m3u8-port", args_info->m3u8_port_orig, 0);
268+
if (args_info->account_port_given)
269+
write_into_file(outfile, "account-port", args_info->account_port_orig, 0);
262270
if (args_info->proxy_given)
263271
write_into_file(outfile, "proxy", args_info->proxy_orig, 0);
264272
if (args_info->login_given)
@@ -534,6 +542,7 @@ cmdline_parser_internal (
534542
{ "host", 1, NULL, 'H' },
535543
{ "decrypt-port", 1, NULL, 'D' },
536544
{ "m3u8-port", 1, NULL, 'M' },
545+
{ "account-port", 1, NULL, 'A' },
537546
{ "proxy", 1, NULL, 'P' },
538547
{ "login", 1, NULL, 'L' },
539548
{ "code-from-file", 0, NULL, 'F' },
@@ -542,7 +551,7 @@ cmdline_parser_internal (
542551
{ 0, 0, 0, 0 }
543552
};
544553

545-
c = getopt_long (argc, argv, "hVH:D:M:P:L:FB:I:", long_options, &option_index);
554+
c = getopt_long (argc, argv, "hVH:D:M:A:P:L:FB:I:", long_options, &option_index);
546555

547556
if (c == -1) break; /* Exit from `while (1)' loop. */
548557

@@ -593,6 +602,18 @@ cmdline_parser_internal (
593602
additional_error))
594603
goto failure;
595604

605+
break;
606+
case 'A': /* . */
607+
608+
609+
if (update_arg( (void *)&(args_info->account_port_arg),
610+
&(args_info->account_port_orig), &(args_info->account_port_given),
611+
&(local_args_info.account_port_given), optarg, 0, "30020", ARG_INT,
612+
check_ambiguity, override, 0, 0,
613+
"account-port", 'A',
614+
additional_error))
615+
goto failure;
616+
596617
break;
597618
case 'P': /* . */
598619

cmdline.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ struct gengetopt_args_info
4848
int m3u8_port_arg; /**< @brief (default='20020'). */
4949
char * m3u8_port_orig; /**< @brief original value given at command line. */
5050
const char *m3u8_port_help; /**< @brief help description. */
51+
int account_port_arg; /**< @brief (default='30020'). */
52+
char * account_port_orig; /**< @brief original value given at command line. */
53+
const char *account_port_help; /**< @brief help description. */
5154
char * proxy_arg; /**< @brief (default=''). */
5255
char * proxy_orig; /**< @brief original value given at command line. */
5356
const char *proxy_help; /**< @brief help description. */
@@ -68,6 +71,7 @@ struct gengetopt_args_info
6871
unsigned int host_given ; /**< @brief Whether host was given. */
6972
unsigned int decrypt_port_given ; /**< @brief Whether decrypt-port was given. */
7073
unsigned int m3u8_port_given ; /**< @brief Whether m3u8-port was given. */
74+
unsigned int account_port_given ; /**< @brief Whether account-port was given. */
7175
unsigned int proxy_given ; /**< @brief Whether proxy was given. */
7276
unsigned int login_given ; /**< @brief Whether login was given. */
7377
unsigned int code_from_file_given ; /**< @brief Whether code-from-file was given. */

main.c

Lines changed: 131 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ struct shared_ptr GUID;
2929
int decryptCount = 1000;
3030
char *device_infos[9];
3131

32+
// Account info cache
33+
static char *g_storefront_id = NULL;
34+
static char *g_dev_token = NULL;
35+
static char *g_music_token = NULL;
36+
3237
#ifndef MyRelease
3338
int32_t CURLOPT_SSL_VERIFYPEER = 64;
3439
int32_t CURLOPT_SSL_VERIFYHOST = 81;
@@ -714,6 +719,114 @@ static inline void *new_socket_m3u8(void *args) {
714719
}
715720
}
716721

722+
void handle_account(const int connfd)
723+
{
724+
char buffer[4096];
725+
ssize_t n = read(connfd, buffer, sizeof(buffer) - 1);
726+
if (n <= 0) {
727+
return;
728+
}
729+
buffer[n] = '\0';
730+
731+
// Parse HTTP request (simple check for GET)
732+
if (strncmp(buffer, "GET", 3) != 0 && strncmp(buffer, "POST", 4) != 0) {
733+
const char *error_response = "HTTP/1.1 400 Bad Request\r\nContent-Type: application/json\r\nContent-Length: 0\r\n\r\n";
734+
writefull(connfd, (void *)error_response, strlen(error_response));
735+
return;
736+
}
737+
738+
// Format JSON response body
739+
size_t json_size = 1024;
740+
char *json_body = (char *)malloc(json_size);
741+
if (json_body == NULL)
742+
{
743+
fprintf(stderr, "[.] failed to allocate memory for account response\n");
744+
const char *error_response = "HTTP/1.1 500 Internal Server Error\r\nContent-Type: application/json\r\nContent-Length: 0\r\n\r\n";
745+
writefull(connfd, (void *)error_response, strlen(error_response));
746+
return;
747+
}
748+
749+
snprintf(json_body, json_size, "{\"storefront_id\":\"%s\",\"dev_token\":\"%s\",\"music_token\":\"%s\"}",
750+
g_storefront_id, g_dev_token, g_music_token);
751+
752+
int json_len = strlen(json_body);
753+
754+
// Format HTTP response with headers
755+
size_t response_size = 512;
756+
char *http_response = (char *)malloc(response_size);
757+
if (http_response == NULL)
758+
{
759+
fprintf(stderr, "[.] failed to allocate memory for HTTP response\n");
760+
free(json_body);
761+
const char *error_response = "HTTP/1.1 500 Internal Server Error\r\nContent-Type: application/json\r\nContent-Length: 0\r\n\r\n";
762+
writefull(connfd, (void *)error_response, strlen(error_response));
763+
return;
764+
}
765+
766+
snprintf(http_response, response_size, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: %d\r\nConnection: close\r\n\r\n",
767+
json_len);
768+
769+
fprintf(stderr, "[.] returning account info, storefront: %s\n", g_storefront_id);
770+
writefull(connfd, http_response, strlen(http_response));
771+
writefull(connfd, json_body, json_len);
772+
773+
free(http_response);
774+
free(json_body);
775+
}
776+
777+
static inline void *new_socket_account(void *args)
778+
{
779+
const int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
780+
if (fd == -1)
781+
{
782+
perror("socket");
783+
return NULL;
784+
}
785+
const int optval = 1;
786+
setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
787+
788+
static struct sockaddr_in serv_addr = {.sin_family = AF_INET};
789+
inet_pton(AF_INET, args_info.host_arg, &serv_addr.sin_addr);
790+
serv_addr.sin_port = htons(args_info.account_port_arg);
791+
if (bind(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
792+
{
793+
perror("bind");
794+
return NULL;
795+
}
796+
797+
if (listen(fd, 5) == -1)
798+
{
799+
perror("listen");
800+
return NULL;
801+
}
802+
803+
fprintf(stderr, "[!] listening account info request on %s:%d\n", args_info.host_arg, args_info.account_port_arg);
804+
805+
static struct sockaddr_in peer_addr;
806+
static socklen_t peer_addr_size = sizeof(peer_addr);
807+
while (1)
808+
{
809+
const int connfd = accept4(fd, (struct sockaddr *)&peer_addr,
810+
&peer_addr_size, SOCK_CLOEXEC);
811+
if (connfd == -1)
812+
{
813+
if (errno == ENETDOWN || errno == EPROTO || errno == ENOPROTOOPT ||
814+
errno == EHOSTDOWN || errno == ENONET ||
815+
errno == EHOSTUNREACH || errno == EOPNOTSUPP ||
816+
errno == ENETUNREACH)
817+
continue;
818+
perror("accept4");
819+
}
820+
821+
handle_account(connfd);
822+
823+
if (close(connfd) == -1)
824+
{
825+
perror("close");
826+
}
827+
}
828+
}
829+
717830
char* get_account_storefront_id(struct shared_ptr reqCtx) {
718831
union std_string *region = malloc(sizeof(union std_string));
719832
struct shared_ptr urlbag = {.obj = 0x0, .ctrl_blk = 0x0};
@@ -727,11 +840,10 @@ char* get_account_storefront_id(struct shared_ptr reqCtx) {
727840
return NULL;
728841
}
729842

730-
void write_storefront_id(struct shared_ptr reqCtx) {
843+
void write_storefront_id(void) {
731844
FILE *fp = fopen(strcat_b(args_info.base_dir_arg, "/STOREFRONT_ID"), "w");
732-
char *storefront_id = get_account_storefront_id(reqCtx);
733-
printf("[+] StoreFront ID: %s\n", storefront_id);
734-
fprintf(fp, "%s", get_account_storefront_id(reqCtx));
845+
printf("[+] StoreFront ID: %s\n", g_storefront_id);
846+
fprintf(fp, "%s", g_storefront_id);
735847
fclose(fp);
736848
}
737849

@@ -836,7 +948,7 @@ char* get_dev_token(struct shared_ptr reqCtx) {
836948
return result;
837949
}
838950

839-
void write_music_token(struct shared_ptr reqCtx) {
951+
void write_music_token(void) {
840952
int token_file_available = 0;
841953
if (file_exists(strcat_b(args_info.base_dir_arg, "/MUSIC_TOKEN"))) {
842954
FILE *fp = fopen(strcat_b(args_info.base_dir_arg, "/MUSIC_TOKEN"), "r");
@@ -857,11 +969,8 @@ void write_music_token(struct shared_ptr reqCtx) {
857969
return;
858970
}
859971
FILE *fp = fopen(strcat_b(args_info.base_dir_arg, "/MUSIC_TOKEN"), "w");
860-
char *guid = get_guid();
861-
char *dev_token = get_dev_token(reqCtx);
862-
char *token = get_music_user_token(guid, dev_token, reqCtx);
863-
printf("[+] Music-Token: %.14s...\n", token);
864-
fprintf(fp, "%s", token);
972+
printf("[+] Music-Token: %.14s...\n", g_music_token);
973+
fprintf(fp, "%s", g_music_token);
865974
fclose(fp);
866975
}
867976

@@ -895,12 +1004,22 @@ int main(int argc, char *argv[]) {
8951004
_ZN22SVPlaybackLeaseManager12requestLeaseERKb(leaseMgr, &autom);
8961005
FHinstance = _ZN21SVFootHillSessionCtrl8instanceEv();
8971006

898-
write_storefront_id(ctx);
899-
write_music_token(ctx);
1007+
// Cache account info
1008+
g_storefront_id = get_account_storefront_id(ctx);
1009+
g_dev_token = get_dev_token(ctx);
1010+
g_music_token = get_music_user_token(get_guid(), g_dev_token, ctx);
1011+
fprintf(stderr, "[+] account info cached successfully\n");
1012+
1013+
write_storefront_id();
1014+
write_music_token();
9001015

9011016
pthread_t m3u8_thread;
9021017
pthread_create(&m3u8_thread, NULL, &new_socket_m3u8, NULL);
9031018
pthread_detach(m3u8_thread);
9041019

1020+
pthread_t account_thread;
1021+
pthread_create(&account_thread, NULL, &new_socket_account, NULL);
1022+
pthread_detach(account_thread);
1023+
9051024
return new_socket();
9061025
}

wrapper.ggo

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ version "1.2.0"
44
option "host" H "" string optional default="127.0.0.1"
55
option "decrypt-port" D "" int optional default="10020"
66
option "m3u8-port" M "" int optional default="20020"
7+
option "account-port" A "" int optional default="30020"
78
option "proxy" P "" string optional default=""
89
option "login" L "username:password" string optional
910
option "code-from-file" F "" flag off

0 commit comments

Comments
 (0)