149 lines
4.3 KiB
C
149 lines
4.3 KiB
C
/*
|
|
* This file is part of LSPosed.
|
|
*
|
|
* LSPosed is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* LSPosed is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with LSPosed. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* Copyright (C) 2022 LSPosed Contributors
|
|
*/
|
|
|
|
//
|
|
// Created by Nullptr on 2022/4/1.
|
|
//
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <unistd.h>
|
|
|
|
#include "logging.h"
|
|
|
|
#if defined(__LP64__)
|
|
#define LP_SELECT(lp32, lp64) lp64
|
|
#else
|
|
#define LP_SELECT(lp32, lp64) lp32
|
|
#endif
|
|
|
|
#define ID_VEC(is64, is_debug) (((is64) << 1) | (is_debug))
|
|
|
|
const char kSockName[] = "5291374ceda0aef7c5d86cd2a4f6a3ac\0";
|
|
|
|
static ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) {
|
|
int rec = recvmsg(sockfd, msg, flags);
|
|
if (rec < 0) {
|
|
PLOGE("recvmsg");
|
|
}
|
|
return rec;
|
|
}
|
|
|
|
static void *recv_fds(int sockfd, char *cmsgbuf, size_t bufsz, int cnt) {
|
|
struct iovec iov = {
|
|
.iov_base = &cnt,
|
|
.iov_len = sizeof(cnt),
|
|
};
|
|
struct msghdr msg = {
|
|
.msg_iov = &iov, .msg_iovlen = 1, .msg_control = cmsgbuf, .msg_controllen = bufsz};
|
|
|
|
xrecvmsg(sockfd, &msg, MSG_WAITALL);
|
|
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
|
|
|
if (msg.msg_controllen != bufsz || cmsg == NULL ||
|
|
cmsg->cmsg_len != CMSG_LEN(sizeof(int) * cnt) || cmsg->cmsg_level != SOL_SOCKET ||
|
|
cmsg->cmsg_type != SCM_RIGHTS) {
|
|
return NULL;
|
|
}
|
|
|
|
return CMSG_DATA(cmsg);
|
|
}
|
|
|
|
static int recv_fd(int sockfd) {
|
|
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
|
|
|
void *data = recv_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), 1);
|
|
if (data == NULL) return -1;
|
|
|
|
int result;
|
|
memcpy(&result, data, sizeof(int));
|
|
return result;
|
|
}
|
|
|
|
static int read_int(int fd) {
|
|
int val;
|
|
if (read(fd, &val, sizeof(val)) != sizeof(val)) return -1;
|
|
return val;
|
|
}
|
|
|
|
static void write_int(int fd, int val) {
|
|
if (fd < 0) return;
|
|
write(fd, &val, sizeof(val));
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
LOGD("dex2oat wrapper ppid=%d", getppid());
|
|
struct sockaddr_un sock = {};
|
|
sock.sun_family = AF_UNIX;
|
|
strlcpy(sock.sun_path + 1, kSockName, sizeof(sock.sun_path) - 1);
|
|
|
|
int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
size_t len = sizeof(sa_family_t) + strlen(sock.sun_path + 1) + 1;
|
|
if (connect(sock_fd, (struct sockaddr *)&sock, len)) {
|
|
PLOGE("failed to connect to %s", sock.sun_path + 1);
|
|
return 1;
|
|
}
|
|
write_int(sock_fd, ID_VEC(LP_SELECT(0, 1), strstr(argv[0], "dex2oatd") != NULL));
|
|
int stock_fd = recv_fd(sock_fd);
|
|
read_int(sock_fd);
|
|
close(sock_fd);
|
|
|
|
sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
if (connect(sock_fd, (struct sockaddr *)&sock, len)) {
|
|
PLOGE("failed to connect to %s", sock.sun_path + 1);
|
|
return 1;
|
|
}
|
|
write_int(sock_fd, LP_SELECT(4, 5));
|
|
int hooker_fd = recv_fd(sock_fd);
|
|
read_int(sock_fd);
|
|
close(sock_fd);
|
|
|
|
if (hooker_fd == -1) {
|
|
PLOGE("failed to read liboat_hook.so");
|
|
}
|
|
LOGD("sock: %s %d", sock.sun_path + 1, stock_fd);
|
|
|
|
const char *new_argv[argc + 2];
|
|
for (int i = 0; i < argc; i++) new_argv[i] = argv[i];
|
|
new_argv[argc] = "--inline-max-code-units=0";
|
|
new_argv[argc + 1] = NULL;
|
|
|
|
if (getenv("LD_LIBRARY_PATH") == NULL) {
|
|
char const *libenv = LP_SELECT(
|
|
"LD_LIBRARY_PATH=/apex/com.android.art/lib:/apex/com.android.os.statsd/lib",
|
|
"LD_LIBRARY_PATH=/apex/com.android.art/lib64:/apex/com.android.os.statsd/lib64");
|
|
putenv((char *)libenv);
|
|
}
|
|
|
|
// Set LD_PRELOAD to load liboat_hook.so
|
|
const int STRING_BUFFER = 50;
|
|
char env_str[STRING_BUFFER];
|
|
snprintf(env_str, STRING_BUFFER, "LD_PRELOAD=/proc/%d/fd/%d", getpid(), hooker_fd);
|
|
putenv(env_str);
|
|
LOGD("Set env %s", env_str);
|
|
|
|
fexecve(stock_fd, (char **)new_argv, environ);
|
|
|
|
PLOGE("fexecve failed");
|
|
return 2;
|
|
}
|