andorid jar/库源码解析之dumpDex

目录:andorid jar/库源码解析 

模板:

  作用:

    对已经加固的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
上一篇:在Andorid开发项目中遇到的Bug记录(续)


下一篇:字节跳动Andorid岗25k 的面试题,真的太香了!