diff --git a/Makefile b/Makefile index 6ee49d7fb..247c29072 100644 --- a/Makefile +++ b/Makefile @@ -81,7 +81,7 @@ $(MODULE_DONE): $(LOADER_DONE) $(ZYGISKD_DONE) $(MODULE_INPUTS) module/src/module.prop > $(MODULE_OUT)/module.prop @echo "Customizing scripts..." - @for script in customize.sh post-fs-data.sh service.sh uninstall.sh; do \ + @for script in customize.sh post-fs-data.sh late-load.sh service.sh uninstall.sh; do \ sed -e 's/@DEBUG@/$(if $(filter debug,$(BUILD_TYPE)),true,false)/g' \ -e 's/@MIN_APATCH_VERSION@/$(MIN_APATCH_VERSION)/g' \ -e 's/@MIN_KSU_VERSION@/$(MIN_KSU_VERSION)/g' \ diff --git a/loader/src/ptracer/remote_csoloader.c b/loader/src/ptracer/remote_csoloader.c index 478de34df..84210a3bc 100644 --- a/loader/src/ptracer/remote_csoloader.c +++ b/loader/src/ptracer/remote_csoloader.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -19,6 +20,13 @@ #undef SYS_mmap #define SYS_mmap LP_SELECT(__NR_mmap2, __NR_mmap) +#ifndef SYS_memfd_create +#define SYS_memfd_create __NR_memfd_create +#endif +#ifndef MFD_CLOEXEC +#define MFD_CLOEXEC 0x0001U +#endif + #include "socket_utils.h" #ifndef ALIGN_DOWN @@ -746,14 +754,48 @@ bool remote_csoloader_load_and_resolve_entry(int pid, struct user_regs_struct *r regs->REG_SP = remote_path; long args[6]; - args[0] = AT_FDCWD; - args[1] = (long)remote_path; - args[2] = O_RDONLY | O_CLOEXEC; - args[3] = 0; - long remote_fd = remote_syscall(pid, regs, syscall_gadget, SYS_openat, args, 4); + /* INFO: DEFEX on Samsung blocks app_process64 from open()ing + /data/adb/modules paths (remote openat returns -1). Use an + anonymous memfd instead: it has no filesystem path, so DEFEX + cannot flag it. The tracer (root) fills it through + /proc//fd/, which is not a protected path. */ + args[0] = (long)remote_path; /* memfd name, cosmetic only */ + args[1] = MFD_CLOEXEC; + + long remote_fd = remote_syscall(pid, regs, syscall_gadget, SYS_memfd_create, args, 2); if (remote_fd < 0) { - LOGE("Failed to open remote file: %s (%ld)", lib_path, remote_fd); + LOGE("Failed to create remote memfd for %s (%ld)", lib_path, remote_fd); + + free(phdr); + close(fd); + + return false; + } + + char memfd_proc_path[64]; + snprintf(memfd_proc_path, sizeof(memfd_proc_path), "/proc/%d/fd/%ld", pid, remote_fd); + + int memfd_writer = open(memfd_proc_path, O_WRONLY | O_CLOEXEC); + if (memfd_writer < 0) { + PLOGE("open %s", memfd_proc_path); + + args[0] = remote_fd; + remote_syscall(pid, regs, syscall_gadget, SYS_close, args, 1); + + free(phdr); + close(fd); + + return false; + } + + if (lseek(fd, 0, SEEK_SET) < 0) { + PLOGE("lseek %s", lib_path); + + close(memfd_writer); + + args[0] = remote_fd; + remote_syscall(pid, regs, syscall_gadget, SYS_close, args, 1); free(phdr); close(fd); @@ -761,6 +803,45 @@ bool remote_csoloader_load_and_resolve_entry(int pid, struct user_regs_struct *r return false; } + /* INFO: Copy the whole file into the memfd */ + char copy_buf[8192]; + ssize_t copy_n; + while ((copy_n = read(fd, copy_buf, sizeof(copy_buf))) > 0) { + ssize_t off = 0; + while (off < copy_n) { + ssize_t w = write(memfd_writer, copy_buf + off, (size_t)(copy_n - off)); + if (w < 0) { + PLOGE("write %s", memfd_proc_path); + + close(memfd_writer); + + args[0] = remote_fd; + remote_syscall(pid, regs, syscall_gadget, SYS_close, args, 1); + + free(phdr); + close(fd); + + return false; + } + off += w; + } + } + if (copy_n < 0) { + PLOGE("read %s", lib_path); + + close(memfd_writer); + + args[0] = remote_fd; + remote_syscall(pid, regs, syscall_gadget, SYS_close, args, 1); + + free(phdr); + close(fd); + + return false; + } + + close(memfd_writer); + void *remote_path_zerod = calloc(1, ALIGN_UP(path_len, 16)); if (!remote_path_zerod) { LOGE("Failed to allocate memory for zeroed path"); diff --git a/module/src/customize.sh b/module/src/customize.sh index f4e083315..61005a456 100644 --- a/module/src/customize.sh +++ b/module/src/customize.sh @@ -95,6 +95,7 @@ fi ui_print "- Extracting module files" extract "$ZIPFILE" 'module.prop' "$MODPATH" extract "$ZIPFILE" 'post-fs-data.sh' "$MODPATH" +extract "$ZIPFILE" 'late-load.sh' "$MODPATH" extract "$ZIPFILE" 'service.sh' "$MODPATH" extract "$ZIPFILE" 'uninstall.sh' "$MODPATH" extract "$ZIPFILE" 'rezygisk.sh' "/data/adb/post-fs-data.d/" diff --git a/module/src/late-load.sh b/module/src/late-load.sh new file mode 100644 index 000000000..a2334942c --- /dev/null +++ b/module/src/late-load.sh @@ -0,0 +1,21 @@ +#!/system/bin/sh + +MODDIR=${0%/*} + +if [ "$ZYGISK_ENABLED" ]; then + exit 0 +fi + +cd "$MODDIR" + +monitor_running() { + pidof zygisk-ptrace64 >/dev/null 2>&1 && return 0 + pidof zygisk-ptrace32 >/dev/null 2>&1 && return 0 + return 1 +} + +if ! monitor_running; then + sh "$MODDIR/post-fs-data.sh" +fi + +exit 0 diff --git a/scripts/sign.py b/scripts/sign.py index bf0580285..031a66a39 100755 --- a/scripts/sign.py +++ b/scripts/sign.py @@ -50,7 +50,7 @@ def sign_machikado(module_dir: str, sig_name: str, abi: str, is_64bit: bool, pri entries = [] # INFO: The files where virtual = real - for fname in ["module.prop", "rezygisk.sh", "sepolicy.rule", "post-fs-data.sh", "service.sh", "uninstall.sh"]: + for fname in ["module.prop", "rezygisk.sh", "sepolicy.rule", "post-fs-data.sh", "late-load.sh", "service.sh", "uninstall.sh"]: vpath = root / fname entries.append((str(vpath), fname, str(vpath)))