mardi 12 mai 2020

Is it possible to get class object of an app from injected DEX by using Java Reflection?

I started learning Java and I have an app installed on my Android device. The app simply has a MainActivity(com.example.myapplication.MainActivity) only. Inside MainActivity there are a public(doSomething1) and a private(doSomething2) methods. Let's assume that I don't have the source files of the app. What I am going to do is to call those methods from another app(DEX) by using Java Reflection. Here is the code of performing runtime Dex injection.


JNIEnv* (*getJNIEnv)();

/**
* Inject the DEX file and execute the method.
* @param dexPath: The dex file to inject
* @param dexOptDir: Cache path
* @param className: Class name to be executed after injection
* @param methodName: Method name to execute
* @param argc: number of arguments
* @param argv: arguments
* @return
*/

 int invoke_dex_method(const char* dexPath, const char* dexOptDir, const char* className, const char* methodName, int argc, char *argv[]) {

      LOGD("dexPath = %s, dexOptDir = %s, className = %s, methodName = %s\n", dexPath, dexOptDir, className, methodName);
      // Acquisition of JNIEnv
      void* handle = dlopen("/system/lib/libandroid_runtime.so", RTLD_NOW);
      LOGD("dlopen = %x, %s\n", handle, strerror(errno));
      getJNIEnv = dlsym(handle, "_ZN7android14AndroidRuntime9getJNIEnvEv");
      LOGD("dlsym = %x, %s\n", getJNIEnv, strerror(errno));
      JNIEnv* env = getJNIEnv();
      LOGD("JNIEnv = %x\n", env);

      // Call getSystemClassLoader of ClassLoader to get ClassLoader of current process
      jclass classloaderClass = (*env)->FindClass(env,"java/lang/ClassLoader");
      jmethodID getsysloaderMethod = (*env)->GetStaticMethodID(env,classloaderClass, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
      jobject loader = (*env)->CallStaticObjectMethod(env, classloaderClass, getsysloaderMethod);
      LOGD("loader = %x\n", loader);

      // Read the dex file with DexClassLoader for processing with the current ClassLoader
      jstring dexpath = (*env)->NewStringUTF(env, dexPath);
      jstring dex_odex_path = (*env)->NewStringUTF(env,dexOptDir);
      jclass dexLoaderClass = (*env)->FindClass(env,"dalvik/system/DexClassLoader");
      jmethodID initDexLoaderMethod = (*env)->GetMethodID(env, dexLoaderClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");
      jobject dexLoader = (*env)->NewObject(env, dexLoaderClass, initDexLoaderMethod,dexpath,dex_odex_path,NULL,loader);
      LOGD("dexLoader = %x\n", dexLoader);

      // Load code to execute using DexClassLoader
      jmethodID findclassMethod = (*env)->GetMethodID(env,dexLoaderClass,"findClass","(Ljava/lang/String;)Ljava/lang/Class;");
      jstring javaClassName = (*env)->NewStringUTF(env,className);
      jclass javaClientClass = (*env)->CallObjectMethod(env,dexLoader,findclassMethod,javaClassName);
      if (!javaClientClass) {
              LOGD("Failed to load target class %s\n", className);
              printf("Failed to load target class %s\n", className);
              return -1;
      }

      // Get the method to inject
      jmethodID start_inject_method = (*env)->GetStaticMethodID(env, javaClientClass, methodName, "()V");
      if (!start_inject_method) {
              LOGD("Failed to load target method %s\n", methodName);
              printf("Failed to load target method %s\n", methodName);
              return -1;
      }

      // Execute method (this method must be a public static void method)
      (*env)->CallStaticVoidMethod(env,javaClientClass,start_inject_method);
      return 0;
}

The above code works well without any problem and the method(4th param) got called. Here is the code of Java class in Dex file.

public class HookTool {
      public static final String TAG = "INJECT";

      public static void dexInject() throws ClassNotFoundException, IllegalAccessException {
              Log.d(TAG, "This is dex code. Start hooking process in Java world.");

              try {
                      Class<?> activityClass = Class.forName("com.example.myapplication.MainActivity");

                      Method method2 = activityClass.getMethod("doSomething1");
                      Method method1 = activityClass.getDeclaredMethod("doSomething2");

              } catch (ClassNotFoundException | NoSuchMethodException e) {
                      e.printStackTrace();
              }
      }

}

I am not getting the expected result from the above code. Here is the logcat result printed.

D/INJECT   (15393): This is dex code. Start hooking process in Java world.
W/System.err(15393): java.lang.ClassNotFoundException: com.example.myapplication.MainActivity
W/System.err(15393):       at java.lang.Class.classForName(Native Method)
W/System.err(15393):       at java.lang.Class.forName(Class.java:309)
W/System.err(15393):       at java.lang.Class.forName(Class.java:273)
W/System.err(15393):       at net.cimadai.hookerApp.HookTool.dexInject(HookTool.java:43)
W/System.err(15393):       at android.os.MessageQueue.nativePollOnce(Native Method)
W/System.err(15393):       at android.os.MessageQueue.next(MessageQueue.java:143)
W/System.err(15393):       at android.os.Looper.loop(Looper.java:122)
W/System.err(15393):       at android.app.ActivityThread.main(ActivityThread.java:5254)
W/System.err(15393):       at java.lang.reflect.Method.invoke(Native Method)
W/System.err(15393):       at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err(15393):       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
W/System.err(15393):       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
W/System.err(15393): Caused by: java.lang.ClassNotFoundException: Didn't find class "com.example.myapplication.MainActivity" on path: DexPathList[[zip file "/data/local/tmp/app-debug.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
W/System.err(15393):       at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
W/System.err(15393):       at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
W/System.err(15393):       at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
W/System.err(15393):       ... 12 more
W/System.err(15393):       Suppressed: java.lang.ClassNotFoundException: Didn't find class "com.example.myapplication.MainActivity" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
W/System.err(15393):                       at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
W/System.err(15393):                       at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
W/System.err(15393):                       at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
W/System.err(15393):                       ... 13 more
W/System.err(15393):                       Suppressed: java.lang.ClassNotFoundException: com.example.myapplication.MainActivityW/System.err(15393):                                       at java.lang.Class.classForName(Native Method)
W/System.err(15393):                                       at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
W/System.err(15393):                                       at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
W/System.err(15393):                                       at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
W/System.err(15393):                                       ... 14 more
W/System.err(15393):                       Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available

So questions are

  1. Is it possible to invoke method in an app from another app by using Java Reflection?
  2. If not, what is the approach to getting this work?

Could you someone please explain to me?

Thank you in advance





Aucun commentaire:

Enregistrer un commentaire