模板:
作用:
对已经加固的APP,进行脱壳,得到dex文件
栗子:
1、从 https://github.com/WrBug/dumpDex/releases 下载,release 安装dumpDex
2、解压app-release.apk文件,拷贝其中文件 lib\armeabi-v7a\libnativeDump.so 文件到手机目录:/data/local/tmp/libnativeDump64.so (因为我是64位手机,所以,so文件,的名字是这么多,如果是32位的,就没有64这个)(源so,不需要使用64位的)
(记得 chmod 777 赋值权限 可执行,我一般在上层给权限 /data/local>chmod 777 -R *)
3、adb shell su,root下执行命令 setenforce 0 (取消Selinux检查,听说是这个说法)
4、xposed勾选,重启,进入需要dump的apk即可。
5、结果dex文件,在 /data/data/需要dump,apk的包名/dump/ 文件夹下面
源码解读:(这里使用Art 7.1.2为例)
1、从xposed 入口开始,检查,并且创建文件夹,/data/data/包名/dump
2、使用 System.load 载入 so (因为已经执行了 setenforce 0,所以这里可以成功
try { System.load("/data/local/tmp/libnativeDump.so"); } catch (Throwable t) { System.load("/data/local/tmp/libnativeDump64.so"); }
3、然后执行so方法,dump(String packageName)
3.1、进入 so 执行,ndk_init https://github.com/Rprop/ndk_dlopen,因为 7.0之后,需要 bypass Android N's classloader-namespace restriction
3.2、使用 void *handle = ndk_dlopen("libart.so", RTLD_NOW); 得到 libart.so的地址
3.3、void *open_common_addr = ndk_dlsym(handle, get_open_function_flag()); 使用方法得到特定符号函数的地址
3.4、注册inlinehook。if (registerInlineHook((uint32_t) open_common_addr, (uint32_t) get_new_open_function_addr(), (uint32_t **) get_old_open_function_addr()) != ELE7EN_OK) {
4、由于inlinehook,替换了目标方法,然后再响应目标方法的时候,就进入到自己的方法。(具体细节,请在目录处查看inlinehook详情)
5、通过替换方法拿到了,dex的地址和长度,void *p = fopen(".../t.dex", "r"); int dex = open(".../t.dex", O_CREAT | O_WRONLY, 0644); int ret = (int) write(dex, data, length); 三个操作,把dex写入文件即可。length大小可以作为文件名的一部分,防止重复。
源码扩展System.load的过程:(这里使用Android 7.1.2为例)
System.load载入过程
public static void load(String filename) { Runtime.getRuntime().load0(VMStack.getStackClass1(), filename); } Runtime.getRuntime().load0(VMStack.getStackClass1(), filename); public void load(String filename) { load0(VMStack.getStackClass1(), filename); } load0(VMStack.getStackClass1(), filename); synchronized void load0(Class<?> fromClass, String filename) { if (!(new File(filename).isAbsolute())) { throw new UnsatisfiedLinkError( "Expecting an absolute path of the library: " + filename); } if (filename == null) { throw new NullPointerException("filename == null"); } String error = doLoad(filename, fromClass.getClassLoader()); if (error != null) { throw new UnsatisfiedLinkError(error); } } doLoad(filename, fromClass.getClassLoader()); private String doLoad(String name, ClassLoader loader) { String librarySearchPath = null; if (loader != null && loader instanceof BaseDexClassLoader) { BaseDexClassLoader dexClassLoader = (BaseDexClassLoader) loader; librarySearchPath = dexClassLoader.getLdLibraryPath(); } synchronized (this) { return nativeLoad(name, loader, librarySearchPath); } } private static native String nativeLoad(String filename, ClassLoader loader, String librarySearchPath); JNIEXPORT jstring JNICALL Runtime_nativeLoad(JNIEnv* env, jclass ignored, jstring javaFilename, jobject javaLoader, jstring javaLibrarySearchPath) { return JVM_NativeLoad(env, javaFilename, javaLoader, javaLibrarySearchPath); } JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env, jstring javaFilename, jobject javaLoader, jstring javaLibrarySearchPath) { ScopedUtfChars filename(env, javaFilename); if (filename.c_str() == NULL) { return NULL; } std::string error_msg; { art::JavaVMExt* vm = art::Runtime::Current()->GetJavaVM(); bool success = vm->LoadNativeLibrary(env, filename.c_str(), javaLoader, javaLibrarySearchPath, &error_msg); if (success) { return nullptr; } } env->ExceptionClear(); return env->NewStringUTF(error_msg.c_str()); } JavaVMExt::LoadNativeLibrary(JNIEnv* env, const std::string& path,jobject class_loader,jstring library_path,std::string* error_msg) android::OpenNativeLibrary(env,runtime_->GetTargetSdkVersion(),path_str,class_loader,library_path); return android_dlopen_ext(path, RTLD_NOW, &extinfo); / return dlopen(path, RTLD_NOW); OpenNativeLibrary 内部判断 // namespace-classloader android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader); if (ns == nullptr) { // This is the case where the classloader was not created by ApplicationLoaders // In this case we create an isolated not-shared namespace for it. ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr); if (ns == nullptr) { return nullptr; } }
JavaVMExt::LoadNativeLibrary
bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, const std::string& path, jobject class_loader, jstring library_path, std::string* error_msg) { error_msg->clear(); SharedLibrary* library; Thread* self = Thread::Current(); { MutexLock mu(self, *Locks::jni_libraries_lock_); library = libraries_->Get(path); } void* class_loader_allocator = nullptr; { ScopedObjectAccess soa(env); mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(class_loader); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); if (class_linker->IsBootClassLoader(soa, loader)) { loader = nullptr; class_loader = nullptr; } class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader); CHECK(class_loader_allocator != nullptr); } if (library != nullptr) { if (library->GetClassLoaderAllocator() != class_loader_allocator) { StringAppendF(error_msg, "Shared library \"%s\" already opened by ClassLoader %p; can't open in ClassLoader %p", path.c_str(),library->GetClassLoader(), class_loader); LOG(WARNING) << error_msg; return false; } VLOG(jni) << "[Shared library \"" << path << "\" already loaded in " << " ClassLoader " << class_loader << "]"; if (!library->CheckOnLoadResult()) { StringAppendF(error_msg, "JNI_OnLoad failed on a previous attempt to load \"%s\"", path.c_str()); return false; } return true; } Locks::mutator_lock_->AssertNotHeld(self); const char* path_str = path.empty() ? nullptr : path.c_str(); void* handle = android::OpenNativeLibrary(env, runtime_->GetTargetSdkVersion(), path_str, class_loader, library_path); bool needs_native_bridge = false; if (handle == nullptr) { if (android::NativeBridgeIsSupported(path_str)) { handle = android::NativeBridgeLoadLibrary(path_str, RTLD_NOW); needs_native_bridge = true; } } VLOG(jni) << "[Call to dlopen(\"" << path << "\", RTLD_NOW) returned " << handle << "]"; if (handle == nullptr) { *error_msg = dlerror(); VLOG(jni) << "dlopen(\"" << path << "\", RTLD_NOW) failed: " << *error_msg; return false; } if (env->ExceptionCheck() == JNI_TRUE) { LOG(ERROR) << "Unexpected exception:"; env->ExceptionDescribe(); env->ExceptionClear(); } bool created_library = false; { std::unique_ptr<SharedLibrary> new_library( new SharedLibrary(env, self, path, handle, class_loader, class_loader_allocator)); MutexLock mu(self, *Locks::jni_libraries_lock_); library = libraries_->Get(path); if (library == nullptr) { // We won race to get libraries_lock. library = new_library.release(); libraries_->Put(path, library); created_library = true; } } if (!created_library) { LOG(INFO) << "WOW: we lost a race to add shared library: " << "\"" << path << "\" ClassLoader=" << class_loader; return library->CheckOnLoadResult(); } VLOG(jni) << "[Added shared library \"" << path << "\" for ClassLoader " << class_loader << "]"; bool was_successful = false; void* sym; if (needs_native_bridge) { library->SetNeedsNativeBridge(); } sym = library->FindSymbol("JNI_OnLoad", nullptr); if (sym == nullptr) { VLOG(jni) << "[No JNI_OnLoad found in \"" << path << "\"]"; was_successful = true; } else { ScopedLocalRef<jobject> old_class_loader(env, env->NewLocalRef(self->GetClassLoaderOverride())); self->SetClassLoaderOverride(class_loader); VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]"; typedef int (*JNI_OnLoadFn)(JavaVM*, void*); JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym); int version = (*jni_on_load)(this, nullptr); if (runtime_->GetTargetSdkVersion() != 0 && runtime_->GetTargetSdkVersion() <= 21) { fault_manager.EnsureArtActionInFrontOfSignalChain(); } self->SetClassLoaderOverride(old_class_loader.get()); if (version == JNI_ERR) { StringAppendF(error_msg, "JNI_ERR returned from JNI_OnLoad in \"%s\"", path.c_str()); } else if (IsBadJniVersion(version)) { StringAppendF(error_msg, "Bad JNI version returned from JNI_OnLoad in \"%s\": %d", path.c_str(), version); } else { was_successful = true; } VLOG(jni) << "[Returned " << (was_successful ? "successfully" : "failure") << " from JNI_OnLoad in \"" << path << "\"]"; } library->SetResult(was_successful); return was_successful; }
OpenNativeLibrary
void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path, jobject class_loader, jstring library_path) { #if defined(__ANDROID__) UNUSED(target_sdk_version); if (class_loader == nullptr) { return dlopen(path, RTLD_NOW); } std::lock_guard<std::mutex> guard(g_namespaces_mutex); android_namespace_t* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader); if (ns == nullptr) { ns = g_namespaces->Create(env, class_loader, false, library_path, nullptr); if (ns == nullptr) { return nullptr; } } android_dlextinfo extinfo; extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; extinfo.library_namespace = ns; return android_dlopen_ext(path, RTLD_NOW, &extinfo); #else UNUSED(env, target_sdk_version, class_loader, library_path); return dlopen(path, RTLD_NOW); #endif } #if defined(__ANDROID__) android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) { std::lock_guard<std::mutex> guard(g_namespaces_mutex); return g_namespaces->FindNamespaceByClassLoader(env, class_loader); } #endif }; // android namespace android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) { auto it = std::find_if(namespaces_.begin(), namespaces_.end(), [&](const std::pair<jweak, android_namespace_t*>& value) { return env->IsSameObject(value.first, class_loader); }); return it != namespaces_.end() ? it->second : nullptr; }
源码:https://github.com/WrBug/dumpDex
引入:
源码引入
http://androidxref.com/7.1.2_r36/xref/system/core/libnativeloader/native_loader.cpp#Create
http://androidxref.com/7.1.2_r36/xref/art/runtime/java_vm_ext.cc#720