Skip to content

Instantly share code, notes, and snippets.

@sleirsgoevy
Created February 15, 2022 19:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sleirsgoevy/a90d2b0ebae5831b6ac95c7579e5aab8 to your computer and use it in GitHub Desktop.
Save sleirsgoevy/a90d2b0ebae5831b6ac95c7579e5aab8 to your computer and use it in GitHub Desktop.
Firefox for Android custom addons hack
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <stddef.h>
void write_request(int fd, const char* c)
{
dprintf(fd, "%d:%s", strlen(c), c);
}
void read_response(char** p, size_t* psz, int fd)
{
size_t sz = 0;
char c;
for(;;)
{
read(fd, &c, 1);
if(c == ':')
break;
sz = 10 * sz + c - '0';
}
size_t cur = *psz;
while(cur <= sz)
{
cur *= 2;
if(!cur)
cur = 1;
}
if(cur != *psz)
{
*psz = cur;
*p = realloc(*p, *psz);
}
char* pp = *p;
while(sz > 0)
{
ssize_t chk = read(fd, pp, sz);
if(chk <= 0)
break;
pp += chk;
sz -= chk;
}
*pp++ = 0;
}
int main(int argc, const char** argv)
{
setbuf(stdout, NULL);
if(argc != 2)
{
printf("usage: ff-addons <addon_dir>\n");
return 1;
}
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un un = {
.sun_family = AF_UNIX,
.sun_path = "\0org.mozilla.fenix/firefox-debugger-socket",
};
printf("connecting to debug... ");
while(connect(sock, (struct sockaddr*)&un, offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path+1) + 1));
printf("ok\n");
char* p = 0;
size_t sz = 0;
read_response(&p, &sz, sock);
printf("< %s\n", p);
char* out1 = "{\"to\": \"root\", \"type\": \"getRoot\"}";
printf("> %s\n", out1);
write_request(sock, out1);
read_response(&p, &sz, sock);
printf("< %s\n", p);
char* pp = strstr(p, "\"addonsActor\":");
if(!pp)
return 1;
pp += 14;
while(*pp != '"')
pp++;
char* ppp = pp+1;
while(*ppp != '"')
{
if(*ppp == '\\')
ppp++;
ppp++;
}
*++ppp = 0;
char* addons_actor = pp;
size_t addons_actor_size = ppp - pp;
DIR* d = opendir(argv[1]);
struct dirent* de;
while((de = readdir(d)))
{
if(de->d_name[0] == '.' && (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2])))
continue;
printf("installing %s\n", de->d_name);
char path[strlen(argv[1])+strlen(de->d_name)+2];
sprintf(path, "%s/%s", argv[1], de->d_name);
char escaped[strlen(path)*2+1];
char* p1 = escaped;
for(char* i = path; *i; i++)
{
switch(*i)
{
case '\b':
*p1++ = '\\';
*p1++ = 'b';
break;
case '\f':
*p1++ = '\\';
*p1++ = 'r';
break;
case '\n':
*p1++ = '\\';
*p1++ = 'n';
break;
case '\r':
*p1++ = '\\';
*p1++ = 'r';
break;
case '\t':
*p1++ = '\\';
*p1++ = 't';
break;
case '"':
case '\\':
*p1++ = '\\';
*p1++ = *i;
break;
default:
*p1++ = *i;
}
}
*p1++ = 0;
char out3[addons_actor_size+(p1-escaped)+80];
sprintf(out3, "{\"to\": %s, \"type\": \"installTemporaryAddon\", \"addonPath\": \"%s\"}", addons_actor, escaped);
printf("> %s\n", out3);
write_request(sock, out3);
read_response(&p, &sz, sock);
printf("< %s\n", p);
}
close(sock);
return 0;
}
# build c file with android ndk, and run this as root
# org.mozilla.fenix is for ff nightly, replace with org.mozilla.firefox for normal one
# you also need to enable remote debugging in ff settings
# then you can put xpis into /data/data/org.mozilla.fenix/files/addon_sideload
# and they will be loaded on each app start; swipe it off the alt-tab screen to force a restart
mkdir /data/data/org.mozilla.fenix/files/addon_sideload
cp ff-addons /data/data/org.mozilla.fenix/lib/
setprop wrap.org.mozilla.fenix 'p=/data/data/org.mozilla.fenix; $p/lib/ff-addons $p/files/addon_sideload & '
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment