android|Magisk注入Zygisk的过程

简介: android|Magisk注入Zygisk的过程
+关注继续查看

Magisk注入Zygisk的过程

magisk 版本 https://github.com/topjohnwu/Magisk/tree/366dd524197d207be76322cb4f45044f9b466e93

Magisk开启zygisk 最终会进入mount_zygisk

0x1 mount_zygisk
#define mount_zygisk(bit)                                                               \
if (access("/system/bin/app_process" #bit, F_OK) == 0) {                                \
    app_process_##bit = xopen("/system/bin/app_process" #bit, O_RDONLY | O_CLOEXEC);    \
    string zbin = zygisk_bin + "/app_process" #bit;                                     \
    string mbin = MAGISKTMP + "/magisk" #bit;                                           \
    int src = xopen(mbin.data(), O_RDONLY | O_CLOEXEC);                                 \
    int out = xopen(zbin.data(), O_CREAT | O_WRONLY | O_CLOEXEC, 0);                    \
    xsendfile(out, src, nullptr, INT_MAX);                                              \
    close(out);                                                                         \
    close(src);                                                                         \
    clone_attr("/system/bin/app_process" #bit, zbin.data());                            \
    bind_mount("zygisk", zbin.data(), "/system/bin/app_process" #bit);                  \
}

主要做了以下工作

  • 保存应位数的/system/bin/app_process文件 ("/system/bin/app_process" #bit)
  • 将 /sbin/magisk(32/64) 复制到 /sbin/.magisk/zygisk/app_process(32/64) (android 11 以下是 /sbin,11之上在/dev下随机创建一个文件夹)
  • 将系统 /system/bin/app_process(32/64) 的属性复制给/sbin/.magisk/zygisk/app_process(32/64)
  • 最后将 /sbin/.magisk/zygisk/app_process(32/64) 挂载到 /system/bin/app_process(32/64)
  • 执行 /system/bin/app_process(32/64) 就是 执行 /sbin/.magisk/zygisk/app_process(32/64)

最终/system/bin 下的 app_process 就变成了 magisk ,而原先的 app_process 的 fd 被 magiskd持有。执行 app_process 的时候就是执行了 magisk 。

0x2 magisk 的 main
// native/src/core/applets.cpp
int main(int argc, char *argv[]) {
    if (argc < 1)
        return 1;

    enable_selinux();
    cmdline_logging();
    init_argv0(argc, argv);

    string_view argv0 = basename(argv[0]);

    // app_process is actually not an applet
    if (argv0.starts_with("app_process")) {
        return app_process_main(argc, argv); // 入口
    }
    // ...
    return 1;
}
2-1 app_process_main
// Magisk/native/src/zygisk/main.cpp
// Entrypoint for app_process overlay
int app_process_main(int argc, char *argv[]) {
    android_logging();
    char buf[PATH_MAX];

    //...
    if (int socket = zygisk_request(ZygiskRequest::SETUP); socket >= 0) {
        // 和 magisk 进行通信 通信成功
        do {
            if (read_int(socket) != 0)
                break;

            // Send over zygisk loader
            // zygisk_ld 在 native/out/generated/arm64-v8a_binaries.h 
            write_int(socket, sizeof(zygisk_ld));
            xwrite(socket, zygisk_ld, sizeof(zygisk_ld)); // zygisk_ld 来自python 脚本组装的, 保存内容是 libzygisk-ld.so -》 zygisk/loader.c -> zygisk_inject_entry 注入入口

            int app_proc_fd = recv_fd(socket); // 接收 系统的/system/bin/app_process(32/64) 的文件符
            if (app_proc_fd < 0)
                break;

            string tmp = read_string(socket); // 获取 MAGISKTMP 路径
            if (char *ld = getenv("LD_PRELOAD")) {
                string env = ld;
                env += ':';
                env += HIJACK_BIN;
                setenv("LD_PRELOAD", env.data(), 1); // 设置 LD_PRELOAD 是已经被magisk接收并挂载到HIJACK_BIN上的 zygisk_ld.so 
            } else {
                setenv("LD_PRELOAD", HIJACK_BIN, 1); // 设置 LD_PRELOAD 预加载so 启动进程前设置LD_PRELOAD变量(https://blog.csdn.net/whatday/article/details/108890018)
            }
            setenv(MAGISKTMP_ENV, tmp.data(), 1);

            close(socket);

            // 执行一个新程序,同时确保在执行过程中关闭了不需要的文件描述符(FD_CLOEXEC)
            fcntl(app_proc_fd, F_SETFD, FD_CLOEXEC);
            fexecve(app_proc_fd, argv, environ); // environ 是全局变量 设置了LD_PRELOAD 会预先脚在 环境变量设置的so 
        } while (false);

        close(socket);
    }

    // If encountering any errors, unmount and execute the original app_process
    xreadlink("/proc/self/exe", buf, sizeof(buf));
    xumount2("/proc/self/exe", MNT_DETACH);
    execve(buf, argv, environ);
    return 1;
}
2-2 zygisk 的处理函数zygisk_handler(client, &cred)

zygisk_handler 有多个信号处理对应的函数

void zygisk_handler(int client, const sock_cred *cred) {
    int code = read_int(client);
    char buf[256];
    switch (code) {
    case ZygiskRequest::SETUP:
        setup_files(client, cred); //  处理 SETUP 信号
        break;
    case ZygiskRequest::PASSTHROUGH:
        magiskd_passthrough(client);
        break;
    case ZygiskRequest::GET_INFO:
        get_process_info(client, cred);
        break;
    case ZygiskRequest::GET_LOG_PIPE:
        send_log_pipe(client);
        break;
    case ZygiskRequest::CONNECT_COMPANION:
        if (get_exe(cred->pid, buf, sizeof(buf))) {
            connect_companion(client, str_ends(buf, "64"));
        } else {
            LOGW("zygisk: remote process %d probably died, abort\n", cred->pid);
        }
        break;
    case ZygiskRequest::GET_MODDIR:
        get_moddir(client);
        break;
    default:
        // Unknown code
        break;
    }
    close(client);
}
2-3 setup_files
// #define HIJACK_BIN64   "/system/bin/appwidget"
// #define HIJACK_BIN32   "/system/bin/bu"

// #define SEPOL_FILE_TYPE     "magisk_file"
// native/src/zygisk/entry.cpp
static void setup_files(int client, const sock_cred *cred) {
    LOGD("zygisk: setup files for pid=[%d]\n", cred->pid);

    // ...
    // Hijack some binary in /system/bin to host loader
    const char *hbin;
    string mbin;
    int app_fd;
    bool is_64_bit = str_ends(buf, "64");
    if (is_64_bit) {
        hbin = HIJACK_BIN64;
        mbin = MAGISKTMP + "/" ZYGISKBIN "/loader64.so";
        app_fd = app_process_64;
    } else {
        hbin = HIJACK_BIN32;
        mbin = MAGISKTMP + "/" ZYGISKBIN "/loader32.so";
        app_fd = app_process_32;
    }

    // ...

    // Ack
    write_int(client, 0); // 写入0 继续执行

    // Receive and bind mount loader  // 接受传过来的二进制(libzygisk-ld.so)
    int ld_fd = xopen(mbin.data(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0755);
    string ld_data = read_string(client); // 先读取大小再读取内容
    xwrite(ld_fd, ld_data.data(), ld_data.size()); // 写入mbin文件(/sbin/.magisk/zygisk/loader64.so)内
    close(ld_fd);
    // 设置文件的安全上下文(SELinux 上下文)
    setfilecon(mbin.data(), "u:object_r:" SEPOL_FILE_TYPE ":s0");
    xmount(mbin.data(), hbin, nullptr, MS_BIND, nullptr); //  mbin(/sbin/.magisk/zygisk/loader64.so) 文件挂在到hbin(/system/bin/appwidget)文件上

    send_fd(client, app_fd); // 发送系统原来的 /system/bin/app_process(32/64) 文件符号
    write_string(client, MAGISKTMP); // 写入 路径"/sbin"
}

完成在/system/bin/app_process zygote 上注入在 libzygisk-ld.so

0x3 注入zygisk流程图

zygisk注入

接下来分析libzygisk-ld.so做了些什么

0x4 llibzygisk-ld.so 的初始化函数

根据编译文件定位文件loader.c

LOCAL_MODULE := zygisk-ld
LOCAL_SRC_FILES := zygisk/loader.c
// native/src/zygisk/loader.c
#if defined(__LP64__)
// Use symlink to workaround linker bug on old broken Android
// https://issuetracker.google.com/issues/36914295
#define SECOND_STAGE_PATH "/system/bin/app_process"
#else
#define SECOND_STAGE_PATH "/system/bin/app_process32"
#endif

__attribute__((constructor))
static void zygisk_loader() {
    android_dlextinfo info = {
        .flags = ANDROID_DLEXT_FORCE_LOAD
    };
    // Android 5.x doesn't support ANDROID_DLEXT_FORCE_LOAD
    void *handle =
            android_dlopen_ext(SECOND_STAGE_PATH, RTLD_LAZY, &info) ?:
            dlopen(SECOND_STAGE_PATH, RTLD_LAZY); 
    if (handle) {
        void(*entry)(void*) = dlsym(handle, "zygisk_inject_entry"); // 找到符号zygisk_inject_entry
        if (entry) {
            entry(handle); // 执行 zygisk_inject_entry 方法
        }
    }
}

加载/system/bin/app_process(已经被替换为magisk)找到符号zygisk_inject_entr并执行。

4-1 zygisk_inject_entr
// native/src/zygisk/entry.cpp
extern "C" void zygisk_inject_entry(void *handle) {  // 注入入口
    zygisk_logging();
    ZLOGD("load success\n");

    // 如果包含多个路径,代码会截取第一个路径,并将其设置回 LD_PRELOAD 环境变量中。如果只有一个路径或没有路径,它会将 LD_PRELOAD 环境变量删除。
    char *ld = getenv("LD_PRELOAD");
    if (char *c = strrchr(ld, ':')) {
        *c = '\0';
        setenv("LD_PRELOAD", ld, 1);  // Restore original LD_PRELOAD
    } else {
        unsetenv("LD_PRELOAD");
    }

    MAGISKTMP = getenv(MAGISKTMP_ENV);
    self_handle = handle;

    unsetenv(MAGISKTMP_ENV);
    sanitize_environ(); // 让环境变量对齐,避免检测到被删除的环境变量留下的空白
    hook_functions(); // 核心函数
    new_daemon_thread(&unload_first_stage, nullptr);
}
4-2 hook_functions

这部分才是 zygisk 的核心 plt hook fork unshare 等函数 androidSetCreateThreadFunc (重点函数)

// native/src/zygisk/hook.cpp
hash_map<xstring, tree_map<xstring, tree_map<xstring, void *>>> *jni_method_map;
// template<class T>
// static inline void default_new(T *&p) { p = new T(); }
// template<class T>
// static inline void default_new(std::unique_ptr<T> &p) { p.reset(new T()); }

void hook_functions() {
    default_new(plt_hook_list);
    default_new(jni_hook_list);
    default_new(jni_method_map);

    ino_t android_runtime_inode = 0;
    dev_t android_runtime_dev = 0;
    for (auto &map : lsplt::MapInfo::Scan()) {
        if (map.path.ends_with("libandroid_runtime.so")) {
            android_runtime_inode = map.inode;
            android_runtime_dev = map.dev;
            break;
        }
    }

    PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, fork);
    PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, unshare);
    PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, selinux_android_setcontext);
    PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, androidSetCreateThreadFunc);
    PLT_HOOK_REGISTER_SYM(android_runtime_dev, android_runtime_inode, "__android_log_close", android_log_close);
    hook_commit();
    // Remove unhooked methods
    plt_hook_list->erase(
            std::remove_if(plt_hook_list->begin(), plt_hook_list->end(),
            [](auto &t) { return *std::get<3>(t) == nullptr;}),
            plt_hook_list->end());
}

首先看几个定义的宏,最终通过lsplt::RegisterHook进行hook,发现 hook_register symbol 和 new_func 是拼接的,如androidSetCreateThreadFunc 该位置是

(void **) &old_androidSetCreateThreadFunc

(void*)new_androidSetCreateThreadFunc

// native/src/zygisk/hook.cpp
static void hook_register(dev_t dev, ino_t inode, const char *symbol, void *new_func, void **old_func) {
    if (!lsplt::RegisterHook(dev, inode, symbol, new_func, old_func)) {
        ZLOGE("Failed to register plt_hook \"%s\"\n", symbol);
        return;
    }
    plt_hook_list->emplace_back(dev, inode, symbol, old_func);
}

#define PLT_HOOK_REGISTER_SYM(DEV, INODE, SYM, NAME) \
    hook_register(DEV, INODE, SYM, (void*) new_##NAME, (void **) &old_##NAME)

#define PLT_HOOK_REGISTER(DEV, INODE, NAME) \
    PLT_HOOK_REGISTER_SYM(DEV, INODE, #NAME, NAME)
4-3 跟踪androidSetCreateThreadFunc

定位函数指针定义的位置,找到了一个DCL_HOOK_FUNC宏是用于声明 hook 函数和备份函数的。

// native/src/zygisk/hook.cpp
// Current context
HookContext *g_ctx;
const JNINativeInterface *old_functions = nullptr;
JNINativeInterface *new_functions = nullptr;

} // namespace

#define DCL_HOOK_FUNC(ret, func, ...) \
ret (*old_##func)(__VA_ARGS__);       \
ret new_##func(__VA_ARGS__)

jint env_RegisterNatives(
        JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint numMethods) {
    auto className = get_class_name(env, clazz);
    ZLOGV("JNIEnv->RegisterNatives [%s]\n", className.data());
    // 调用hookAndSaveJNIMethods
    auto newMethods = hookAndSaveJNIMethods(className.data(), methods, numMethods);
    // 调用原来的jni方法 有newMethods 就使用newMethods(替换后的函数)
    return old_functions->RegisterNatives(env, clazz, newMethods.get() ?: methods, numMethods);
}

DCL_HOOK_FUNC(void, androidSetCreateThreadFunc, void *func) {
    //new_androidSetCreateThreadFunc 函数体
    ZLOGD("androidSetCreateThreadFunc\n");
    using method_sig = jint(*)(JavaVM **, jsize, jsize *);
    do {
        auto get_created_vms = reinterpret_cast<method_sig>(
                dlsym(RTLD_DEFAULT, "JNI_GetCreatedJavaVMs")); // RTLD_DEFAULT 是一个特殊的句柄,用于指示 dlsym 在所有已加载的共享库中搜索符号
        if (!get_created_vms) {
            for (auto &map: lsplt::MapInfo::Scan()) {
                if (!map.path.ends_with("/libnativehelper.so")) continue;
                void *h = dlopen(map.path.data(), RTLD_LAZY);
                if (!h) {
                    LOGW("cannot dlopen libnativehelper.so: %s\n", dlerror());
                    break;
                }
                // 从 libnativehelper.so 获取JNI_GetCreatedJavaVMs 方法
                get_created_vms = reinterpret_cast<method_sig>(dlsym(h, "JNI_GetCreatedJavaVMs"));
                dlclose(h);
                break;
            }
            if (!get_created_vms) {
                LOGW("JNI_GetCreatedJavaVMs not found\n");
                break;
            }
        }
        JavaVM *vm = nullptr;
        jsize num = 0;
        jint res = get_created_vms(&vm, 1, &num);
        if (res != JNI_OK || vm == nullptr) break;
        JNIEnv *env = nullptr;
        res = vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
        if (res != JNI_OK || env == nullptr) break;
        default_new(new_functions); // new一个JNINativeInterface空函数
        memcpy(new_functions, env->functions, sizeof(*new_functions)); // 复制env->functions
        new_functions->RegisterNatives = &env_RegisterNatives;  // 替换RegisterNatives方法

        // Replace the function table in JNIEnv to hook RegisterNatives
        old_functions = env->functions; // 将原来的jni函数进行保存
        env->functions = new_functions; // 替换env->functions 修改了RegisterNatives
    } while (false);
    old_androidSetCreateThreadFunc(func); // 执行原来的 androidSetCreateThreadFunc 函数
}
  • 当系统调用androidSetCreateThreadFunc方法时先替换jni中的RegisterNatives方法再执行原来的androidSetCreateThreadFunc方法

  • 执行当jni执行RegisterNatives会先执行hookAndSaveJNIMethods再执行原的RegisterNatives

  • 为什么选择hookRegisterNatives,是因为zyogte 启动过程过程中会调用androidSetCreateThreadFunc->RegisterNatives,时机比较早

4-4 hookAndSaveJNIMethods
  • 只有 className 是 com/android/internal/os/Zygote才进行hook
// native/src/zygisk/jni_hooks.hpp
unique_ptr<JNINativeMethod[]> hookAndSaveJNIMethods(const char *className, const JNINativeMethod *methods, int numMethods) {
    unique_ptr<JNINativeMethod[]> newMethods;
    int clz_id = -1;
    int hook_cnt = 0;
    do {
        if (className == "com/android/internal/os/Zygote"sv) {
            // "com/android/internal/os/Zygote" 是一个 Android 系统中的类,它是 Android 启动过程中的第一个特定于 Android 的进程,它负责预加载所有系统资源和类,并为每个应用程序创建新的进程
            clz_id = 0;
            hook_cnt = 3;
            break;
        }
    } while (false);
    if (hook_cnt) {
        newMethods = make_unique<JNINativeMethod[]>(numMethods);
        memcpy(newMethods.get(), methods, sizeof(JNINativeMethod) * numMethods);
    }
    auto &class_map = (*jni_method_map)[className]; // 返回这个新创建的 tree_map 的引用
    for (int i = 0; i < numMethods; ++i) {
        if (hook_cnt && clz_id == 0) {// 重点hook的三个函数
            HOOK_JNI(nativeForkAndSpecialize)
            HOOK_JNI(nativeSpecializeAppProcess)
            HOOK_JNI(nativeForkSystemServer)
        }
        class_map[methods[i].name][methods[i].signature] = methods[i].fnPtr;
    }
    return newMethods;
}
4-4 HOOK_JNI
// 用zygisk的方法(method##_methods[j])替换, 之后执行的方法就是zygisk中定义的函数
// method##_orig = methods[i].fnPtr;  保存原来的函数指针
// native/src/zygisk/hook.cpp  
#define HOOK_JNI(method)                                                                     \
if (methods[i].name == #method##sv) {                                                        \
    int j = 0;                                                                               \
    for (; j < method##_methods_num; ++j) {                                                  \
        if (strcmp(methods[i].signature, method##_methods[j].signature) == 0) {              \
            jni_hook_list->try_emplace(className).first->second.push_back(methods[i]);       \
            method##_orig = methods[i].fnPtr;                                                \
            newMethods[i] = method##_methods[j];                                             \
            ZLOGI("replaced %s#" #method "\n", className);                                   \
            --hook_cnt;                                                                      \
            break;                                                                           \
        }                                                                                    \
    }                                                                                        \
    if (j == method##_methods_num) {                                                         \
        ZLOGE("unknown signature of %s#" #method ": %s\n", className, methods[i].signature); \
    }                                                                                        \
    continue;                                                                                \
}

三个函数的逻辑基本一致,这里挑选一个比较简短的函数进行跟踪

nativeForkSystemServer

// native/src/zygisk/jni_hooks.hpp
// 收集了android不同版本同一个函数不同的签名 比如 nativeForkSystemServer
// newMethods[i] = method##_methods[j]; => newMethods[i] = nativeForkSystemServer_methods[j];   替换函数
const JNINativeMethod nativeForkSystemServer_methods[] = {
    {
        "nativeForkSystemServer",
        "(II[II[[IJJ)I",
        (void *) &nativeForkSystemServer_l
    },
    {
        "nativeForkSystemServer",
        "(II[IIII[[IJJ)I",
        (void *) &nativeForkSystemServer_samsung_q
    },
};
constexpr int nativeForkSystemServer_methods_num = std::size(nativeForkSystemServer_methods);

void *nativeForkSystemServer_orig = nullptr;
[[clang::no_stack_protector]] jint nativeForkSystemServer_l(JNIEnv *env, jclass clazz, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities, jlong effective_capabilities) {
    ServerSpecializeArgs_v1 args(uid, gid, gids, runtime_flags, permitted_capabilities, effective_capabilities);
    HookContext ctx;
    ctx.env = env;
    ctx.args = { &args };
    ctx.nativeForkSystemServer_pre(); // nativeForkSystemServer 执行前
    reinterpret_cast<decltype(&nativeForkSystemServer_l)>(nativeForkSystemServer_orig)(
        env, clazz, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities
    ); // 执行原函数
    ctx.nativeForkSystemServer_post();// nativeForkSystemServer 执行后
    return ctx.pid;
}

nativeForkSystemServer_pre

void HookContext::nativeForkSystemServer_pre() {
    ZLOGV("pre  forkSystemServer\n");
    flags[SERVER_FORK_AND_SPECIALIZE] = true;

    fork_pre();
    if (pid != 0)
        return;

    vector<int> module_fds;
    int fd = remote_get_info(1000, "system_server", &info_flags, module_fds);
    if (fd >= 0) {
        if (module_fds.empty()) {
            write_int(fd, 0);
        } else {
            run_modules_pre(module_fds); // 运行modules插入的hook代码

            // Send the bitset of module status back to magiskd from system_server
            dynamic_bitset bits;
            for (const auto &m : modules)
                bits[m.getId()] = true;
            write_int(fd, static_cast<int>(bits.slots()));
            for (int i = 0; i < bits.slots(); ++i) {
                auto l = bits.get_slot(i);
                xwrite(fd, &l, sizeof(l));
            }
        }
        close(fd);
    }

    sanitize_fds();
}

void HookContext::nativeForkSystemServer_post() {
    if (pid == 0) {
        ZLOGV("post forkSystemServer\n");
        run_modules_post();
    }
    fork_post();
}
  • Zygisk 加载是通过替换 app_process ,修改 LD_PRELOAD ,再执行原 app_process 实现
  • LD_PRELOAD 执行的so,hook三个和创建进程开辟进程空间有关系的关键函数

参考文章:

https://gist.github.com/5ec1cff/bfe06429f5bf1da262c40d0145e9f190#file-zygisk-md

[完]
目录
相关文章
|
3月前
|
编解码 开发工具 Android开发
Android平台如何实现外部RTSP|RTMP流注入轻量级RTSP服务模块(内网RTSP网关)
今天分享的是外部RTSP或RTMP流,拉取后注入到本地轻量级RTSP服务模块,供内网小并发场景下使用,这里我们叫做内网RTSP网关模块。
|
安全 Android开发
android中对某app注入框架的检测的探索
android中对注入框架的检测
273 1
android中对某app注入框架的检测的探索
|
Java 数据库 Android开发
Android注入框架ButterKnife使用解析
Android注入框架ButterKnife使用解析
149 0
|
安全 Android开发
android的注入技术
通过原理和源码方式进行实践分析android的注入技术
400 0
android的注入技术
|
Java Linux Android开发
【Android 逆向】Android 进程注入工具开发 ( 远程进程注入动态库文件操作 | 注入动态库 加载 业务动态库 | 业务动态库启动 | pthread_create 线程开发 )
【Android 逆向】Android 进程注入工具开发 ( 远程进程注入动态库文件操作 | 注入动态库 加载 业务动态库 | 业务动态库启动 | pthread_create 线程开发 )
154 0
|
Android开发 C语言
【Android 逆向】Android 进程注入工具开发 ( 远程进程 注入动态库 文件操作 | Android 进程读取文件所需的权限 | fopen 打开文件标志位 | 验证文件权限 )
【Android 逆向】Android 进程注入工具开发 ( 远程进程 注入动态库 文件操作 | Android 进程读取文件所需的权限 | fopen 打开文件标志位 | 验证文件权限 )
205 0
【Android 逆向】Android 进程注入工具开发 ( 远程进程 注入动态库 文件操作 | Android 进程读取文件所需的权限 | fopen 打开文件标志位 | 验证文件权限 )
|
Android开发
【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 注入工具收尾操作 | 关闭注入的动态库 | 恢复寄存器 | 脱离远程调试附着 )
【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 注入工具收尾操作 | 关闭注入的动态库 | 恢复寄存器 | 脱离远程调试附着 )
134 0
|
Android开发
【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 获取注入的 libbridge.so 动态库中的 load 函数地址 并 通过 远程调用 执行该函数 )
【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 获取注入的 libbridge.so 动态库中的 load 函数地址 并 通过 远程调用 执行该函数 )
152 0
|
Android开发
【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 获取 linker 中的 dlopen 函数地址 并 通过 远程调用 执行该函数 )
【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 获取 linker 中的 dlopen 函数地址 并 通过 远程调用 执行该函数 )
183 0
|
Android开发
【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 三 | 等待远程函数执行完毕 | 寄存器获取返回值 )
【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 三 | 等待远程函数执行完毕 | 寄存器获取返回值 )
126 0
热门文章
最新文章
相关产品
云迁移中心
推荐文章
更多