• andorid jar/库源码解析之dumpDex


    目录:andorid jar/库源码解析 

    模板:

      作用:

        对已经加固的APP,进行脱壳,得到dex文件

      栗子:

         1、从 https://github.com/WrBug/dumpDex/releases 下载,release 安装dumpDex

         2、解压app-release.apk文件,拷贝其中文件 libarmeabi-v7alibnativeDump.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

      引入:

  • 相关阅读:
    名词解释字节码
    一次Java解析数独的经历
    Java运行时数据区域
    java中的泛型类和泛型方法
    兼容的一些问题
    js中变量的作用域
    CSS3渐变
    Extjs散记
    Linux系统CentOS下mysql的安装日志
    修改自动亮度下背光和按键的亮度
  • 原文地址:https://www.cnblogs.com/Supperlitt/p/13360502.html
Copyright © 2020-2023  润新知