fix(tng): 修复区号页 HWUI 闪退并放行 Compose HW 绘制
拦截 HardwareRenderer.setName,校验/缓存 libandroid.so,避免软件绘制撞 hardware bitmap;附带 Money Packet hook 与 mitm 脚本。
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
* pc==lr 循环 SEGV 也 skip;libc++abi __cxa_guard_acquire → SIGABRT 吞掉。
|
||||
*/
|
||||
#include <android/log.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <linux/audit.h>
|
||||
#include <linux/filter.h>
|
||||
@@ -174,11 +175,20 @@ static void fatal_skip_handler(int sig, siginfo_t *info, void *ctx) {
|
||||
freeze_forever();
|
||||
}
|
||||
int n = ++g_abrt_swallow;
|
||||
if (n <= 5 || n % 50 == 0) {
|
||||
LOGI("ABRT pc+4 tid=%d pc=%lx lr=%lx streak=%d", (int)tid,
|
||||
(unsigned long)pc, (unsigned long)lr, streak);
|
||||
/* 主线程:abort 后 _exit 被 seccomp 拦 → abort 内部死循环(还复位 handler)→
|
||||
* 主线程永久卡死 → 黑屏/ANR。主线程 ABRT 时跳回 lr(Looper pollOnce)恢复;
|
||||
* 仅当 lr 距 pc 远(不在 abort 内部)才跳,否则仍在 abort epilogue 内跳 LR 会再 abort。 */
|
||||
uintptr_t target = pc + 4;
|
||||
if (tid == g_main_tid.load() && lr != 0 && pc != 0
|
||||
&& (lr < pc - 0x1000 || lr > pc + 0x1000)) {
|
||||
target = lr;
|
||||
}
|
||||
uc->uc_mcontext.pc = pc + 4;
|
||||
if (n <= 5 || n % 50 == 0) {
|
||||
LOGI("ABRT tid=%d pc=%lx lr=%lx streak=%d -> %lx", (int)tid,
|
||||
(unsigned long)pc, (unsigned long)lr, streak,
|
||||
(unsigned long)target);
|
||||
}
|
||||
uc->uc_mcontext.pc = target;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -236,14 +246,23 @@ static void install_soft_signals() {
|
||||
((struct sock_filter){(unsigned short)(code), (jt), (jf), (unsigned int)(k)})
|
||||
|
||||
static int install_seccomp_exit_group_only() {
|
||||
/* exit_group 拦 + 精准拦 Promon 自杀 kill(SIGABRT)(SI_USER)。
|
||||
* 只拦 kill()(nr=129):Promon 自杀是 kill(pid,SIGABRT) → si_code=SI_USER。
|
||||
* 不拦 tgkill/tkill:ART 的 abort() 用 tgkill(self) → si_code=SI_TKILL,
|
||||
* 拦它会让 libart 状态错乱 → 进程崩(之前验证)。 */
|
||||
struct sock_filter filter[] = {
|
||||
// 0: arch
|
||||
_BPFI(BPF_LD | BPF_W | BPF_ABS, 0, 0, offsetof(struct seccomp_data, arch)),
|
||||
_BPFI(BPF_JMP | BPF_JEQ | BPF_K, 1, 0, AUDIT_ARCH_AARCH64),
|
||||
_BPFI(BPF_RET | BPF_K, 0, 0, SC_RET_ALLOW),
|
||||
_BPFI(BPF_RET | BPF_K, 0, 0, SC_RET_ALLOW), // 2: not aarch64
|
||||
_BPFI(BPF_LD | BPF_W | BPF_ABS, 0, 0, offsetof(struct seccomp_data, nr)),
|
||||
_BPFI(BPF_JMP | BPF_JEQ | BPF_K, 0, 1, 94),
|
||||
_BPFI(BPF_RET | BPF_K, 0, 0, SC_RET_ERRNO_EPERM),
|
||||
_BPFI(BPF_RET | BPF_K, 0, 0, SC_RET_ALLOW),
|
||||
_BPFI(BPF_JMP | BPF_JEQ | BPF_K, 0, 1, __NR_exit_group), // 4: exit_group? true→5
|
||||
_BPFI(BPF_RET | BPF_K, 0, 0, SC_RET_ERRNO_EPERM), // 5: EPERM exit_group
|
||||
_BPFI(BPF_JMP | BPF_JEQ | BPF_K, 0, 3, __NR_kill), // 6: kill? true→7
|
||||
_BPFI(BPF_LD | BPF_W | BPF_ABS, 0, 0, offsetof(struct seccomp_data, args) + 8), // 7: args[1]=sig
|
||||
_BPFI(BPF_JMP | BPF_JEQ | BPF_K, 0, 1, SIGABRT), // 8: sig==SIGABRT? true→9
|
||||
_BPFI(BPF_RET | BPF_K, 0, 0, SC_RET_ERRNO_EPERM), // 9: EPERM kill ABRT
|
||||
_BPFI(BPF_RET | BPF_K, 0, 0, SC_RET_ALLOW), // 10: allow
|
||||
};
|
||||
struct sock_fprog prog = {
|
||||
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
|
||||
@@ -258,9 +277,9 @@ static int install_seccomp_exit_group_only() {
|
||||
LOGE("seccomp failed errno=%d", errno);
|
||||
return -1;
|
||||
}
|
||||
LOGI("seccomp exit_group via prctl");
|
||||
LOGI("seccomp exit_group+kill-ABRT via prctl");
|
||||
} else {
|
||||
LOGI("seccomp exit_group via TSYNC");
|
||||
LOGI("seccomp exit_group+kill-ABRT via TSYNC");
|
||||
}
|
||||
g_seccomp_ok.store(1);
|
||||
return 0;
|
||||
@@ -277,10 +296,31 @@ using pthread_kill_fn = int (*)(pthread_t, int);
|
||||
using cxa_guard_acquire_fn = int (*)(void *);
|
||||
using cxa_guard_abort_fn = void (*)();
|
||||
using dlopen_fn = void *(*)(const char *, int);
|
||||
using android_dlopen_ext_fn = void *(*)(const char *, int, const void *);
|
||||
using sphal_load_fn = void *(*)(const char *, int);
|
||||
using open_passthrough_hal_fn = void *(*)(const char *, const char *, int);
|
||||
|
||||
static cxa_guard_acquire_fn orig_cxa_guard_acquire = nullptr;
|
||||
static cxa_guard_abort_fn orig_cxa_guard_abort = nullptr;
|
||||
static dlopen_fn orig_dlopen = nullptr;
|
||||
static android_dlopen_ext_fn orig_android_dlopen_ext = nullptr;
|
||||
static sphal_load_fn orig_sphal_load = nullptr;
|
||||
static open_passthrough_hal_fn orig_open_passthrough_hal = nullptr;
|
||||
static void *g_libandroid_handle = nullptr;
|
||||
static void *g_mapper_pixel_handle = nullptr;
|
||||
|
||||
#ifndef RTLD_NOW
|
||||
#define RTLD_NOW 2
|
||||
#endif
|
||||
#ifndef RTLD_GLOBAL
|
||||
#define RTLD_GLOBAL 0x100
|
||||
#endif
|
||||
#ifndef RTLD_NOLOAD
|
||||
#define RTLD_NOLOAD 0x4
|
||||
#endif
|
||||
#ifndef RTLD_DEFAULT
|
||||
#define RTLD_DEFAULT reinterpret_cast<void *>(static_cast<uintptr_t>(-1))
|
||||
#endif
|
||||
|
||||
static exit_fn orig_exit = nullptr;
|
||||
static exit_fn orig__exit = nullptr;
|
||||
@@ -359,31 +399,186 @@ static void hooked_cxa_guard_abort() {
|
||||
LOGI("blocked __cxa_guard_abort tid=%d depth=%d", (int)gettid(), tl_cxa_depth);
|
||||
}
|
||||
|
||||
static void *try_dlopen_noload(const char *name) {
|
||||
if (!orig_dlopen || name == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
void *h = orig_dlopen(name, RTLD_NOW | RTLD_NOLOAD);
|
||||
if (h != nullptr) {
|
||||
return h;
|
||||
}
|
||||
const char *base = strrchr(name, '/');
|
||||
if (base != nullptr && base[1] != '\0') {
|
||||
h = orig_dlopen(base + 1, RTLD_NOW | RTLD_NOLOAD);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
/** 校验 dlopen 句柄:拒绝空/明显毒化指针,并用 dlsym 探活。 */
|
||||
static bool libandroid_handle_ok(void *h) {
|
||||
if (h == nullptr) return false;
|
||||
uintptr_t p = reinterpret_cast<uintptr_t>(h);
|
||||
// 用户态典型映射;排除明显垃圾(如 0x...c5c5 / 高熵毒化)
|
||||
if (p < 0x10000UL) return false;
|
||||
if ((p & 0xffffUL) == 0xc5c5UL) return false;
|
||||
void *sym = dlsym(h, "ANativeWindow_fromSurface");
|
||||
if (sym == nullptr) {
|
||||
sym = dlsym(h, "AAssetManager_fromJava");
|
||||
}
|
||||
return sym != nullptr;
|
||||
}
|
||||
|
||||
static void preload_hwui_libs() {
|
||||
if (!orig_dlopen) {
|
||||
// PLT 尚未拿到 orig 时,用 libc 直调
|
||||
orig_dlopen = reinterpret_cast<dlopen_fn>(dlsym(RTLD_DEFAULT, "dlopen"));
|
||||
}
|
||||
if (!orig_sphal_load) {
|
||||
orig_sphal_load = reinterpret_cast<sphal_load_fn>(
|
||||
dlsym(RTLD_DEFAULT, "android_load_sphal_library"));
|
||||
}
|
||||
if (g_libandroid_handle != nullptr && !libandroid_handle_ok(g_libandroid_handle)) {
|
||||
LOGI("drop invalid cached libandroid %p", g_libandroid_handle);
|
||||
g_libandroid_handle = nullptr;
|
||||
}
|
||||
if (g_libandroid_handle == nullptr && orig_dlopen) {
|
||||
static const char *kPaths[] = {
|
||||
"libandroid.so",
|
||||
"/system/lib64/libandroid.so",
|
||||
"/apex/com.android.runtime/lib64/libandroid.so",
|
||||
};
|
||||
for (const char *path : kPaths) {
|
||||
void *h = orig_dlopen(path, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (h == nullptr) {
|
||||
h = try_dlopen_noload(path);
|
||||
}
|
||||
if (libandroid_handle_ok(h)) {
|
||||
g_libandroid_handle = h;
|
||||
LOGI("preload libandroid ok path=%s -> %p", path, h);
|
||||
break;
|
||||
}
|
||||
if (h != nullptr) {
|
||||
LOGI("preload libandroid reject path=%s -> %p", path, h);
|
||||
}
|
||||
}
|
||||
if (g_libandroid_handle == nullptr) {
|
||||
LOGI("preload libandroid FAILED");
|
||||
}
|
||||
}
|
||||
if (g_mapper_pixel_handle == nullptr) {
|
||||
if (orig_sphal_load) {
|
||||
g_mapper_pixel_handle = orig_sphal_load("mapper.pixel.so", RTLD_NOW);
|
||||
LOGI("preload mapper via sphal -> %p", g_mapper_pixel_handle);
|
||||
}
|
||||
if (g_mapper_pixel_handle == nullptr && orig_dlopen) {
|
||||
g_mapper_pixel_handle = orig_dlopen(
|
||||
"/vendor/lib64/hw/mapper.pixel.so", RTLD_NOW | RTLD_GLOBAL);
|
||||
LOGI("preload mapper via path -> %p", g_mapper_pixel_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void *hooked_dlopen(const char *name, int flags) {
|
||||
void *handle = orig_dlopen ? orig_dlopen(name, flags) : nullptr;
|
||||
if (handle != nullptr || name == nullptr) {
|
||||
if (name == nullptr) {
|
||||
return handle;
|
||||
}
|
||||
// Compose/HWUI 依赖 libandroid + gralloc mapper;sphal 失败时尝试绝对路径兜底
|
||||
if (strstr(name, "libandroid.so") != nullptr
|
||||
|| strstr(name, "mapper.pixel") != nullptr
|
||||
|| strstr(name, "android.hardware.graphics.mapper") != nullptr) {
|
||||
static const char *kFallbacks[] = {
|
||||
if (handle != nullptr) {
|
||||
// 命名空间下偶发返回毒化非空句柄,HWUI 随后 FATAL
|
||||
if (strstr(name, "libandroid.so") != nullptr && !libandroid_handle_ok(handle)) {
|
||||
LOGI("dlopen got bad handle %p for %s — recover", handle, name);
|
||||
handle = nullptr;
|
||||
} else {
|
||||
if (strstr(name, "libandroid.so") != nullptr) {
|
||||
g_libandroid_handle = handle;
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
// 已映射库:命名空间下按名 dlopen 会失败,RTLD_NOLOAD 可取回句柄
|
||||
handle = try_dlopen_noload(name);
|
||||
if (handle != nullptr) {
|
||||
if (strstr(name, "libandroid.so") == nullptr || libandroid_handle_ok(handle)) {
|
||||
LOGI("dlopen NOLOAD hit name=%s -> %p", name, handle);
|
||||
if (strstr(name, "libandroid.so") != nullptr) {
|
||||
g_libandroid_handle = handle;
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
if (strstr(name, "libandroid.so") != nullptr) {
|
||||
if (g_libandroid_handle != nullptr && !libandroid_handle_ok(g_libandroid_handle)) {
|
||||
LOGI("drop bad cached libandroid %p", g_libandroid_handle);
|
||||
g_libandroid_handle = nullptr;
|
||||
}
|
||||
if (g_libandroid_handle != nullptr) {
|
||||
LOGI("dlopen return cached libandroid %p (from %s)",
|
||||
g_libandroid_handle, name);
|
||||
return g_libandroid_handle;
|
||||
}
|
||||
static const char *kAndroidPaths[] = {
|
||||
"/system/lib64/libandroid.so",
|
||||
"/system/lib/libandroid.so",
|
||||
"/vendor/lib64/hw/mapper.pixel.so",
|
||||
"/vendor/lib/hw/mapper.pixel.so",
|
||||
"libandroid.so",
|
||||
"mapper.pixel.so",
|
||||
};
|
||||
for (const char *path : kFallbacks) {
|
||||
handle = orig_dlopen ? orig_dlopen(path, flags) : nullptr;
|
||||
if (handle != nullptr) {
|
||||
LOGI("dlopen miss name=%s flags=0x%x tid=%d — try fallback",
|
||||
name, flags, (int)gettid());
|
||||
for (const char *path : kAndroidPaths) {
|
||||
handle = try_dlopen_noload(path);
|
||||
if (handle == nullptr && orig_dlopen) {
|
||||
handle = orig_dlopen(path, flags | RTLD_GLOBAL);
|
||||
}
|
||||
if (libandroid_handle_ok(handle)) {
|
||||
g_libandroid_handle = handle;
|
||||
LOGI("dlopen fallback %s -> %p (from %s)", path, handle, name);
|
||||
return handle;
|
||||
}
|
||||
if (handle != nullptr) {
|
||||
LOGI("dlopen fallback reject %s -> %p", path, handle);
|
||||
}
|
||||
}
|
||||
LOGI("dlopen fallback failed name=%s tid=%d", name, (int)gettid());
|
||||
return nullptr;
|
||||
}
|
||||
if (strstr(name, "mapper.pixel") != nullptr
|
||||
|| strstr(name, "mapper.") != nullptr) {
|
||||
if (g_mapper_pixel_handle != nullptr) {
|
||||
LOGI("dlopen return cached mapper %p (from %s)",
|
||||
g_mapper_pixel_handle, name);
|
||||
return g_mapper_pixel_handle;
|
||||
}
|
||||
if (orig_sphal_load) {
|
||||
handle = orig_sphal_load("mapper.pixel.so", RTLD_NOW);
|
||||
if (handle != nullptr) {
|
||||
g_mapper_pixel_handle = handle;
|
||||
LOGI("dlopen sphal mapper -> %p (from %s)", handle, name);
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
if (orig_dlopen) {
|
||||
handle = orig_dlopen("/vendor/lib64/hw/mapper.pixel.so",
|
||||
flags | RTLD_GLOBAL);
|
||||
if (handle != nullptr) {
|
||||
g_mapper_pixel_handle = handle;
|
||||
LOGI("dlopen path mapper -> %p (from %s)", handle, name);
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
LOGI("dlopen mapper failed name=%s tid=%d", name, (int)gettid());
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void *hooked_android_dlopen_ext(const char *name, int flags, const void *extinfo) {
|
||||
void *handle = orig_android_dlopen_ext
|
||||
? orig_android_dlopen_ext(name, flags, extinfo)
|
||||
: nullptr;
|
||||
if (handle != nullptr || name == nullptr) {
|
||||
return handle;
|
||||
}
|
||||
if (strstr(name, "libandroid.so") != nullptr
|
||||
|| strstr(name, "mapper") != nullptr) {
|
||||
LOGI("android_dlopen_ext miss name=%s — try dlopen fallback", name);
|
||||
return hooked_dlopen(name, flags);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
@@ -402,7 +597,7 @@ static bool find_lib_match(const char *suffix, const char *contains,
|
||||
unsigned long inode = 0;
|
||||
char path[512] = {};
|
||||
int n = sscanf(line, "%lx-%lx %7s %llx %31s %lu %511[^\n]",
|
||||
&start, &end, perms, &offset, &deststr, &inode, path);
|
||||
&start, &end, perms, &offset, deststr, &inode, path);
|
||||
if (n < 7 || inode == 0) continue;
|
||||
char *p = path;
|
||||
while (*p == ' ') ++p;
|
||||
@@ -438,12 +633,160 @@ static bool find_libc(dev_t *dev, ino_t *ino) {
|
||||
return find_lib_by_suffix("libc.so", dev, ino);
|
||||
}
|
||||
|
||||
/** 收集 maps 里所有匹配后缀的已加载库(去重)。Zygisk commit 前必须覆盖全部副本,
|
||||
* 否则 libc++ 多副本(/system、/vendor、/apex)时只 hook 一份,调用点仍走原生实现。 */
|
||||
struct lib_devino {
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
};
|
||||
|
||||
static int find_all_lib_by_suffix(const char *suffix, lib_devino *out, int max) {
|
||||
FILE *fp = fopen("/proc/self/maps", "r");
|
||||
if (!fp) return 0;
|
||||
char line[1024];
|
||||
int n = 0;
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
uintptr_t start = 0, end = 0;
|
||||
char perms[8] = {};
|
||||
unsigned long long offset = 0;
|
||||
char deststr[32] = {};
|
||||
unsigned long inode = 0;
|
||||
char path[512] = {};
|
||||
int got = sscanf(line, "%lx-%lx %7s %llx %31s %lu %511[^\n]",
|
||||
&start, &end, perms, &offset, deststr, &inode, path);
|
||||
if (got < 7 || inode == 0) continue;
|
||||
char *p = path;
|
||||
while (*p == ' ') ++p;
|
||||
size_t plen = strlen(p);
|
||||
size_t slen = strlen(suffix);
|
||||
if (plen < slen || strcmp(p + plen - slen, suffix) != 0) continue;
|
||||
unsigned maj = 0, min = 0;
|
||||
if (sscanf(deststr, "%x:%x", &maj, &min) != 2) continue;
|
||||
dev_t d = makedev(maj, min);
|
||||
ino_t in = inode;
|
||||
bool dup = false;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (out[i].dev == d && out[i].ino == in) {
|
||||
dup = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dup) continue;
|
||||
if (n < max) {
|
||||
out[n].dev = d;
|
||||
out[n].ino = in;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void register_plt(zygisk::Api *api, dev_t dev, ino_t ino,
|
||||
const char *sym, void *hook, void **orig) {
|
||||
if (!api || dev == 0 || ino == 0) return;
|
||||
api->pltHookRegister(dev, ino, sym, hook, orig);
|
||||
}
|
||||
|
||||
static void *hooked_sphal_load(const char *name, int flags) {
|
||||
void *handle = orig_sphal_load ? orig_sphal_load(name, flags) : nullptr;
|
||||
if (handle != nullptr || name == nullptr) {
|
||||
return handle;
|
||||
}
|
||||
LOGI("sphal miss name=%s flags=0x%x — try cache/path", name, flags);
|
||||
if (strstr(name, "mapper") != nullptr) {
|
||||
if (g_mapper_pixel_handle != nullptr) {
|
||||
LOGI("sphal return cached mapper %p", g_mapper_pixel_handle);
|
||||
return g_mapper_pixel_handle;
|
||||
}
|
||||
if (orig_dlopen) {
|
||||
handle = orig_dlopen("/vendor/lib64/hw/mapper.pixel.so",
|
||||
RTLD_NOW | RTLD_GLOBAL);
|
||||
if (handle != nullptr) {
|
||||
g_mapper_pixel_handle = handle;
|
||||
LOGI("sphal path mapper -> %p", handle);
|
||||
return handle;
|
||||
}
|
||||
handle = orig_dlopen("mapper.pixel.so", RTLD_NOW | RTLD_GLOBAL);
|
||||
if (handle != nullptr) {
|
||||
g_mapper_pixel_handle = handle;
|
||||
LOGI("sphal name mapper -> %p", handle);
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void *hooked_open_passthrough_hal(const char *interface, const char *instance,
|
||||
int dlopen_flags) {
|
||||
void *handle = orig_open_passthrough_hal
|
||||
? orig_open_passthrough_hal(interface, instance, dlopen_flags)
|
||||
: nullptr;
|
||||
if (handle != nullptr) {
|
||||
return handle;
|
||||
}
|
||||
LOGI("passthroughHal miss iface=%s inst=%s — try mapper path",
|
||||
interface ? interface : "?", instance ? instance : "?");
|
||||
if ((interface && strstr(interface, "mapper") != nullptr)
|
||||
|| (instance && strstr(instance, "pixel") != nullptr)) {
|
||||
if (g_mapper_pixel_handle != nullptr) {
|
||||
return g_mapper_pixel_handle;
|
||||
}
|
||||
if (orig_sphal_load) {
|
||||
handle = orig_sphal_load("mapper.pixel.so", RTLD_NOW);
|
||||
}
|
||||
if (handle == nullptr && orig_dlopen) {
|
||||
handle = orig_dlopen("/vendor/lib64/hw/mapper.pixel.so",
|
||||
RTLD_NOW | RTLD_GLOBAL);
|
||||
}
|
||||
if (handle != nullptr) {
|
||||
g_mapper_pixel_handle = handle;
|
||||
LOGI("passthroughHal mapper recovered -> %p", handle);
|
||||
}
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void register_dlopen_on_lib(zygisk::Api *api, const char *suffix) {
|
||||
dev_t dev = 0;
|
||||
ino_t ino = 0;
|
||||
if (!find_lib_by_suffix(suffix, &dev, &ino)) {
|
||||
return;
|
||||
}
|
||||
// 必须 hook 调用方 PLT(libhwui/libui),只 hook libc 拦不到 HWUI 的 dlopen
|
||||
register_plt(api, dev, ino, "dlopen",
|
||||
(void *)hooked_dlopen, (void **)&orig_dlopen);
|
||||
register_plt(api, dev, ino, "android_dlopen_ext",
|
||||
(void *)hooked_android_dlopen_ext, (void **)&orig_android_dlopen_ext);
|
||||
register_plt(api, dev, ino, "android_load_sphal_library",
|
||||
(void *)hooked_sphal_load, (void **)&orig_sphal_load);
|
||||
register_plt(api, dev, ino, "AServiceManager_openDeclaredPassthroughHal",
|
||||
(void *)hooked_open_passthrough_hal,
|
||||
(void **)&orig_open_passthrough_hal);
|
||||
LOGI("dlopen PLT on %s", suffix);
|
||||
}
|
||||
|
||||
/** 注册所有已加载 libc++ 副本的 __cxa_guard_acquire/abort。返回注册的副本数。 */
|
||||
static int register_cxx_guard_hooks(zygisk::Api *api) {
|
||||
if (!api) return 0;
|
||||
lib_devino libs[8];
|
||||
int n = find_all_lib_by_suffix("libc++.so", libs, 8);
|
||||
if (n == 0) {
|
||||
n = find_all_lib_by_suffix("libc++_shared.so", libs, 8);
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
register_plt(api, libs[i].dev, libs[i].ino, "__cxa_guard_acquire",
|
||||
(void *)hooked_cxa_guard_acquire, (void **)&orig_cxa_guard_acquire);
|
||||
register_plt(api, libs[i].dev, libs[i].ino, "__cxa_guard_abort",
|
||||
(void *)hooked_cxa_guard_abort, (void **)&orig_cxa_guard_abort);
|
||||
}
|
||||
if (n > 0) {
|
||||
LOGI("cxx guard target libc++ copies=%d", n);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void install_plt(zygisk::Api *api) {
|
||||
if (!api) return;
|
||||
dev_t dev = 0;
|
||||
@@ -460,9 +803,25 @@ static void install_plt(zygisk::Api *api) {
|
||||
register_plt(api, dev, ino, "pthread_kill",
|
||||
(void *)hooked_pthread_kill, (void **)&orig_pthread_kill);
|
||||
register_plt(api, dev, ino, "dlopen", (void *)hooked_dlopen, (void **)&orig_dlopen);
|
||||
register_plt(api, dev, ino, "android_dlopen_ext",
|
||||
(void *)hooked_android_dlopen_ext, (void **)&orig_android_dlopen_ext);
|
||||
}
|
||||
// HWUI / libui 直接 PLT→linker,必须单独挂
|
||||
register_dlopen_on_lib(api, "libhwui.so");
|
||||
register_dlopen_on_lib(api, "libui.so");
|
||||
register_dlopen_on_lib(api, "libandroid_runtime.so");
|
||||
register_dlopen_on_lib(api, "libbinder_ndk.so");
|
||||
register_dlopen_on_lib(api, "libvndksupport.so");
|
||||
// libc++ cxa guard 必须在首次 commit 前注册:Zygisk pltHookCommit 二次调用会失败,
|
||||
// 导致 __cxa_guard_acquire 递归 abort 保护从未生效(主线程反复 SIGABRT → 黑屏)。
|
||||
int cxx = register_cxx_guard_hooks(api);
|
||||
bool ok = api->pltHookCommit();
|
||||
LOGI("PLT commit=%d", ok ? 1 : 0);
|
||||
LOGI("PLT commit=%d cxx_guard_copies=%d", ok ? 1 : 0, cxx);
|
||||
if (ok && cxx > 0) {
|
||||
g_cxx_plt.store(1);
|
||||
}
|
||||
// commit 后立刻预加载,抢在 Promon/命名空间收紧之前拿到句柄
|
||||
preload_hwui_libs();
|
||||
}
|
||||
|
||||
static void try_install_cxx_guard_plt() {
|
||||
@@ -470,17 +829,7 @@ static void try_install_cxx_guard_plt() {
|
||||
dev_t dev = 0;
|
||||
ino_t ino = 0;
|
||||
bool any = false;
|
||||
// libc++:必须走 orig acquire(否则 gralloc 静态初始化被跳过 → mapper missing 黑屏)。
|
||||
// 仅在同 guard 递归时 return 1;abort 仍拦截。
|
||||
if (find_lib_by_suffix("libc++.so", &dev, &ino)
|
||||
|| find_lib_by_suffix("libc++_shared.so", &dev, &ino)) {
|
||||
register_plt(g_api, dev, ino, "__cxa_guard_acquire",
|
||||
(void *)hooked_cxa_guard_acquire, (void **)&orig_cxa_guard_acquire);
|
||||
register_plt(g_api, dev, ino, "__cxa_guard_abort",
|
||||
(void *)hooked_cxa_guard_abort, (void **)&orig_cxa_guard_abort);
|
||||
any = true;
|
||||
LOGI("cxx guard target libc++");
|
||||
}
|
||||
// libc++ 副本已由首次 PLT commit 覆盖;此处仅补 libtngdigital_ewallet.so 自身 PLT。
|
||||
if (find_lib_by_suffix("libtngdigital_ewallet.so", &dev, &ino)) {
|
||||
register_plt(g_api, dev, ino, "__cxa_guard_acquire",
|
||||
(void *)hooked_cxa_guard_acquire, (void **)&orig_cxa_guard_acquire);
|
||||
@@ -490,7 +839,9 @@ static void try_install_cxx_guard_plt() {
|
||||
LOGI("cxx guard target libtngdigital_ewallet");
|
||||
}
|
||||
if (!any) return;
|
||||
if (g_api->pltHookCommit()) {
|
||||
bool ok = g_api->pltHookCommit();
|
||||
LOGI("cxx guard commit=%d", ok ? 1 : 0);
|
||||
if (ok) {
|
||||
g_cxx_plt.store(1);
|
||||
LOGI("PLT cxx guards committed (orig acquire + recursive skip)");
|
||||
}
|
||||
@@ -498,9 +849,13 @@ static void try_install_cxx_guard_plt() {
|
||||
|
||||
static void *phase_thread(void *) {
|
||||
install_promon_segv_handler();
|
||||
/* Promon 用 SVC exit_group 绕过 PLT;必须 seccomp。延迟 400ms 避开最早的 fork/getprop。 */
|
||||
usleep(400 * 1000);
|
||||
install_seccomp_exit_group_only();
|
||||
LOGI("seccomp armed @400ms ok=%d", g_seccomp_ok.load());
|
||||
if (install_seccomp_exit_group_only() == 0) {
|
||||
LOGI("seccomp exit_group armed @400ms");
|
||||
} else {
|
||||
LOGE("seccomp install failed");
|
||||
}
|
||||
for (int i = 0; i < 40; i++) {
|
||||
usleep(1000 * 1000);
|
||||
install_soft_signals();
|
||||
@@ -516,7 +871,7 @@ static void *phase_thread(void *) {
|
||||
static void install_all(zygisk::Api *api) {
|
||||
g_api = api;
|
||||
g_main_tid.store(gettid());
|
||||
LOGI("install pid=%d main_tid=%d (PLT+cxx-guard+ABRT-pc+4+SEGV-skip+exit_group@400ms)",
|
||||
LOGI("install pid=%d main_tid=%d (PLT+cxx-guard+ABRT-pc+4+SEGV-skip+seccomp@400ms)",
|
||||
getpid(), (int)g_main_tid.load());
|
||||
install_fatal_skip_handlers();
|
||||
install_soft_signals();
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user