void __libc_init_AT_SECURE(char** env) { // Check that the kernel provided a value for AT_SECURE. errno = 0; unsignedlong is_AT_SECURE = getauxval(AT_SECURE); if (errno != 0) __early_abort(__LINE__);
// Always ensure that STDIN/STDOUT/STDERR exist. This prevents file // descriptor confusion bugs where a parent process closes // STD*, the exec()d process calls open() for an unrelated reason, // the newly created file descriptor is assigned // 0<=FD<=2, and unrelated code attempts to read / write to the STD* // FDs. // In particular, this can be a security bug for setuid/setgid programs. // For example: // https://www.freebsd.org/security/advisories/FreeBSD-SA-02:23.stdio.asc // However, for robustness reasons, we don't limit these protections to // just security critical executables. // // Init is excluded from these protections unless AT_SECURE is set, as // /dev/null and/or /sys/fs/selinux/null will not be available at // early boot. if ((getpid() != 1) || is_AT_SECURE) { __nullify_closed_stdio(); }
if (is_AT_SECURE) { __sanitize_environment_variables(env); }
// Now the environment has been sanitized, make it available. environ = __libc_shared_globals()->init_environ = env;
// When the kernel starts the dynamic linker, it passes a pointer to a block // of memory containing argc, the argv array, the environment variable array, // and the array of ELF aux vectors. This class breaks that block up into its // constituents for easy access. classKernelArgumentBlock { public: explicitKernelArgumentBlock(void* raw_args){ uintptr_t* args = reinterpret_cast<uintptr_t*>(raw_args); argc = static_cast<int>(*args); argv = reinterpret_cast<char**>(args + 1); // 此处初始化环境变量 envp = argv + argc + 1;
// Skip over all environment variable definitions to find the aux vector. // The end of the environment block is marked by a NULL pointer. char** p = envp; while (*p != nullptr) { ++p; } ++p; // Skip the NULL itself.
auxv = reinterpret_cast<ElfW(auxv_t)*>(p); }
// Similar to ::getauxval but doesn't require the libc global variables to be set up, // so it's safe to call this really early on. unsignedlonggetauxval(unsignedlong type){ for (ElfW(auxv_t)* v = auxv; v->a_type != AT_NULL; ++v) { if (v->a_type == type) { return v->a_un.a_val; } } return0; }
int argc; char** argv; char** envp; ElfW(auxv_t)* auxv;
private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor pipeFd, boolean isZygote){ /* * By the time we get here, the native code has closed the two actual Zygote * socket connections, and substituted /dev/null in their place. The LocalSocket * objects still need to be closed properly. */
closeSocket();
Zygote.setAppProcessName(parsedArgs, TAG);
// End of the postFork event. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); if (parsedArgs.mInvokeWith != null) { // 不为null则是第三种Wrap shell script情况 WrapperInit.execApplication(parsedArgs.mInvokeWith, parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion, VMRuntime.getCurrentInstructionSet(), pipeFd, parsedArgs.mRemainingArgs);
// Should not get here. thrownew IllegalStateException("WrapperInit.execApplication unexpectedly returned"); } else { if (!isZygote) { // 这里直接执行初始化跳转至ActivityThread执行 return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mDisabledCompatChanges, parsedArgs.mRemainingArgs, null/* classLoader */); } else { return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mRemainingArgs, null/* classLoader */); } } }
return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote); } else { // In the parent. A pid < 0 indicates a failure and will be handled in // handleParentProc. IoUtils.closeQuietly(childPipeFd); childPipeFd = null; handleParentProc(pid, serverPipeFd); returnnull; } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); } }
publicstaticvoidexecApplication(String invokeWith, String niceName, int targetSdkVersion, String instructionSet, FileDescriptor pipeFd, String[] args){ StringBuilder command = new StringBuilder(invokeWith);
final String appProcess; if (VMRuntime.is64BitInstructionSet(instructionSet)) { appProcess = "/system/bin/app_process64"; } else { appProcess = "/system/bin/app_process32"; } command.append(' '); command.append(appProcess);
// Generate bare minimum of debug information to be able to backtrace through JITed code. // We assume that if the invoke wrapper is used, backtraces are desirable: // * The wrap.sh script can only be used by debuggable apps, which would enable this flag // without the script anyway (the fork-zygote path). So this makes the two consistent. // * The wrap.* property can only be used on userdebug builds and is likely to be used by // developers (e.g. enable debug-malloc), in which case backtraces are also useful. command.append(" -Xcompiler-option --generate-mini-debug-info");
binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); findViewById(R.id.btn_test).setOnClickListener(this); findViewById(R.id.btn_test1).setOnClickListener(this); // Example of a call to a native method }
596-789/? W/InputDispatcher: channel '7c0090b org.sfandroid.nativehook.test/org.sfandroid.nativehook.test.MainActivity (server)' ~ Consumer closed input channel or an error occurred. events=0x9 596-789/? E/InputDispatcher: channel '7c0090b org.sfandroid.nativehook.test/org.sfandroid.nativehook.test.MainActivity (server)' ~ Channel is unrecoverably broken and will be disposed! 596-2056/? I/system_server: oneway function results will be dropped but finished with status OK and parcel size 4 0-0/? I/binder: undelivered TRANSACTION_COMPLETE 0-0/? I/binder: undelivered transaction 858386, process died. 9687-9687/? D/PreloadTest: Hook模块监听access函数,路径: /dev/urandom, mode: 4 9687-9687/? D/PreloadTest: Hook模块监听access函数,路径: /dev/__properties__/property_info, mode: 4 9687-9687/? D/PreloadTest: LD_PRELOAD模块被加载 9687-9687/? D/PreloadTest: Hook模块监听access函数,路径: /system/bin/app_process64, mode: 1 596-2930/? I/WindowManager: WIN DEATH: Window{7c0090b u0 org.sfandroid.nativehook.test/org.sfandroid.nativehook.test.MainActivity} 596-2930/? W/InputDispatcher: Attempted to unregister already unregistered input channel '7c0090b org.sfandroid.nativehook.test/org.sfandroid.nativehook.test.MainActivity (server)' 596-2921/? I/ActivityManager: Process org.sfandroid.nativehook.test (pid 9687) has died: fg TOP 9687-9687/? I/sh: type=1400 audit(0.0:180): avc: denied { execute } for path="/data/local/tmp/libld-test.so" dev="dm-5" ino=65540 scontext=u:r:untrusted_app:s0:c153,c256,c512,c768 tcontext=u:object_r:shell_data_file:s0 tclass=file permissive=1 app=org.sfandroid.nativehook.test 300-300/? I/Zygote: Process 9687 exited due to signal 9 (Killed) 596-2056/? I/system_server: oneway function results will be dropped but finished with status OK and parcel size 4 0-0/? I/init: Untracked pid 9723 received signal 9 596-2921/? W/ActivityTaskManager: Force removing ActivityRecord{c639d07 u0 org.sfandroid.nativehook.test/.MainActivity t34}: app died, no saved state
ActivityManager: Process org.sfandroid.nativehook.test (pid 9687) has died: fg TOP 最终进程会死亡被kill掉,当然你有可能看不到PreloadTest: LD_PRELOAD模块被加载该日志,因为进程过早就被杀死掉了,多次尝试可能会查看到(我也试了很多次才出现),这证明exec执行确实我们的环境变量已生效,只是因为其它原因被杀死而已。这与wrap.sh方式相同只是执行时机一个在zygote fork后就执行,一个在APP启动后才执行,而之所以被杀也不难猜测,因为APP环境全部都准备好的system_server里已经包含该APP的进程信息,而我们执行execv又把这些数据给清除掉了,这理所当然会被system_server认为APP可能已经死亡了因此被杀死。而在zygote fork后执行该APP环境根本还未执行,system_server没有它的记录,因此可以成功。具体原因可以分析源码,这里就不分析了,因为这离我们主题更远,且我们不走这条路径。
staticElfW(Addr)linker_main(KernelArgumentBlock& args, constchar* exe_to_load){ ...省略 if (!getauxval(AT_SECURE)) { ldpath_env = getenv("LD_LIBRARY_PATH"); if (ldpath_env != nullptr) { INFO("[ LD_LIBRARY_PATH set to \"%s\" ]", ldpath_env); } // 获取该环境变量 ldpreload_env = getenv("LD_PRELOAD"); if (ldpreload_env != nullptr) { INFO("[ LD_PRELOAD set to \"%s\" ]", ldpreload_env); } }
...省略
// Use LD_LIBRARY_PATH and LD_PRELOAD (but only if we aren't setuid/setgid). parse_LD_LIBRARY_PATH(ldpath_env); // 解析环境变量 parse_LD_PRELOAD(ldpreload_env);
if (!si->prelink_image()) __linker_cannot_link(g_argv[0]);
// add somain to global group si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); // ... and add it to all other linked namespaces for (auto linked_ns : namespaces) { if (linked_ns != &g_default_namespace) { linked_ns->add_soinfo(somain); somain->add_secondary_namespace(linked_ns); } }
for (size_t i = 0; i < library_names_count; ++i) { constchar* name = library_names[i]; load_tasks.push_back(LoadTask::create(name, start_with, ns, &readers_map)); }
// If soinfos array is null allocate one on stack. // The array is needed in case of failure; for example // when library_names[] = {libone.so, libtwo.so} and libone.so // is loaded correctly but libtwo.so failed for some reason. // In this case libone.so should be unloaded on return. // See also implementation of failure_guard below.
// list of libraries to link - see step 2. size_t soinfos_count = 0;
auto scope_guard = android::base::make_scope_guard([&]() { for (LoadTask* t : load_tasks) { LoadTask::deleter(t); } });
ZipArchiveCache zip_archive_cache;
// Step 1: expand the list of load_tasks to include // all DT_NEEDED libraries (do not load them just yet) for (size_t i = 0; i<load_tasks.size(); ++i) { LoadTask* task = load_tasks[i]; soinfo* needed_by = task->get_needed_by();
// Note: start from the namespace that is stored in the LoadTask. This namespace // is different from the current namespace when the LoadTask is for a transitive // dependency and the lib that created the LoadTask is not found in the // current namespace but in one of the linked namespace. if (!find_library_internal(const_cast<android_namespace_t*>(task->get_start_from()), task, &zip_archive_cache, &load_tasks, rtld_flags)) { returnfalse; }
soinfo* si = task->get_soinfo();
if (is_dt_needed) { needed_by->add_child(si); }
// When ld_preloads is not null, the first // ld_preloads_count libs are in fact ld_preloads. // 如果预加载库不为空则保存到ld_preloads中 if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) { ld_preloads->push_back(si); }
// Step 2: Load libraries in random order (see b/24047022) LoadTaskList load_list; for (auto&& task : load_tasks) { soinfo* si = task->get_soinfo(); auto pred = [&](const LoadTask* t) { return t->get_soinfo() == si; };
// Step 3: pre-link all DT_NEEDED libraries in breadth first order. for (auto&& task : load_tasks) { soinfo* si = task->get_soinfo(); // 第三步预链接解析所有Dynamic Section if (!si->is_linked() && !si->prelink_image()) { returnfalse; } register_soinfo_tls(si); }
// Step 4: Construct the global group. Note: DF_1_GLOBAL bit of a library is // determined at step 3.
// Step 4-1: DF_1_GLOBAL bit is force set for LD_PRELOADed libs because they // must be added to the global group // 第四步构造全局组,这里使用了上面的预加载库,设置全局标志 if (ld_preloads != nullptr) { for (auto&& si : *ld_preloads) { si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL); } }
// Step 4-2: Gather all DF_1_GLOBAL libs which were newly loaded during this // run. These will be the new member of the global group soinfo_list_t new_global_group_members; for (auto&& task : load_tasks) { soinfo* si = task->get_soinfo(); if (!si->is_linked() && (si->get_dt_flags_1() & DF_1_GLOBAL) != 0) { // 本次加载的全局库作为新的全局组 new_global_group_members.push_back(si); } }
// Step 4-3: Add the new global group members to all the linked namespaces if (namespaces != nullptr) { for (auto linked_ns : *namespaces) { // 将新的全局组添加到所有链接命名空间 for (auto si : new_global_group_members) { if (si->get_primary_namespace() != linked_ns) { linked_ns->add_soinfo(si); si->add_secondary_namespace(linked_ns); } } } }
// Step 5: Collect roots of local_groups. // Whenever needed_by->si link crosses a namespace boundary it forms its own local_group. // Here we collect new roots to link them separately later on. Note that we need to avoid // collecting duplicates. Also the order is important. They need to be linked in the same // BFS order we link individual libraries. std::vector<soinfo*> local_group_roots; if (start_with != nullptr && add_as_children) { local_group_roots.push_back(start_with); } else { CHECK(soinfos_count == 1); local_group_roots.push_back(soinfos[0]); }
if (!si->is_linked() && si->get_primary_namespace() != needed_by_ns) { auto it = std::find(local_group_roots.begin(), local_group_roots.end(), si); LD_LOG(kLogDlopen, "Crossing namespace boundary (si=%s@%p, si_ns=%s@%p, needed_by=%s@%p, ns=%s@%p, needed_by_ns=%s@%p) adding to local_group_roots: %s", si->get_realpath(), si, si->get_primary_namespace()->get_name(), si->get_primary_namespace(), needed_by == nullptr ? "(nullptr)" : needed_by->get_realpath(), needed_by, ns->get_name(), ns, needed_by_ns->get_name(), needed_by_ns, it == local_group_roots.end() ? "yes" : "no");
if (it == local_group_roots.end()) { local_group_roots.push_back(si); } } }
// Step 6: Link all local groups for (auto root : local_group_roots) { soinfo_list_t local_group; android_namespace_t* local_group_ns = root->get_primary_namespace();
bool linked = local_group.visit([&](soinfo* si) { // Even though local group may contain accessible soinfos from other namespaces // we should avoid linking them (because if they are not linked -> they // are in the local_group_roots and will be linked later). if (!si->is_linked() && si->get_primary_namespace() == local_group_ns) { const android_dlextinfo* link_extinfo = nullptr; if (si == soinfos[0] || reserved_address_recursive) { // Only forward extinfo for the first library unless the recursive // flag is set. link_extinfo = extinfo; } if (__libc_shared_globals()->load_hook) { __libc_shared_globals()->load_hook(si->load_bias, si->phdr, si->phnum); } lookup_list.set_dt_symbolic_lib(si->has_DT_SYMBOLIC ? si : nullptr); // 链接库使用上面的lookup_list if (!si->link_image(lookup_list, local_group_root, link_extinfo, &relro_fd_offset) || !get_cfi_shadow()->AfterLoad(si, solist_get_head())) { returnfalse; } }
// Once the tlsdesc_args_ vector's size is finalized, we can write the addresses of its elements // into the TLSDESC relocations. #if defined(__aarch64__) // Bionic currently only implements TLSDESC for arm64. for (conststd::pair<TlsDescriptor*, size_t>& pair : relocator.deferred_tlsdesc_relocs) { TlsDescriptor* desc = pair.first; desc->func = tlsdesc_resolver_dynamic; desc->arg = reinterpret_cast<size_t>(&tlsdesc_args_[pair.second]); } #endif
while (true) { const SymbolLookupLib* lib; uint32_t sym_idx;
// Iterate over libraries until we find one whose Bloom filter matches the symbol we're // searching for. // 每个库挨个查找有没有指定符号 while (true) { if (it == end) returnnullptr; lib = it++;
// If shared - clone the parent namespace // Java调用完全继承所有soinfo add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns); // and copy parent namespace links // 同时继承链接命名空间 for (auto& link : parent_namespace->linked_namespaces()) { ns->add_linked_namespace(link.linked_namespace(), link.shared_lib_sonames(), link.allow_all_shared_libs()); } } else { // If not shared - copy only the shared group // 非Java调用只复制共享的库 add_soinfos_to_namespace(parent_namespace->get_shared_group(), ns); }