1

Under one of my project I need to read VTextField GUI object of running oracle forms application, and set new value in it, I am able to inject my DLL into application and i am able to attach thorugh the current thread below is my code for this

JNIEnv* env;
JavaVM *jvm = NULL;
jsize jvm_count = 0;
jint res = 0;
#ifdef __STATIC_LIB_JVM
    res = JNI_GetCreatedJavaVMs(&jvm, 1, &jvm_count);
#else
{
    HINSTANCE hLibJVM;
    typedef jint(JNICALL GetCreatedJavaVMs_t)(JavaVM**, jsize, jsize*);
    GetCreatedJavaVMs_t *MyGetCreatedJavaVMs;
    hLibJVM = LoadLibrary(L"jvm.dll");
    MyGetCreatedJavaVMs = (GetCreatedJavaVMs_t*)GetProcAddress(hLibJVM,  "JNI_GetCreatedJavaVMs");
    res = MyGetCreatedJavaVMs(&jvm, 1, &jvm_count);
}
#endif
if (res == 0)
{
    if (jvm_count == 0)
    {
        jvm = NULL;
    }
}
else jvm = NULL;
bool mustDetach = false;
//jint retval = jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
jint retval = jvm->GetEnv((void**)&env, JNI_VERSION_1_6);

if (retval == JNI_EDETACHED)
{
    JavaVMAttachArgs args;
    args.version = JNI_VERSION_1_6;
    args.name = NULL;
    args.group = NULL;
    retval = jvm->AttachCurrentThread((void**)&env, &args);
    mustDetach = true; // to clean up afterwards
}
else{
    fprintf(JNIStatus, "JNI is not processing\n"); // should never happen
}
if (retval != JNI_OK){
    fprintf(JNIStatus, "JNI is not ok\n"); // should never happen
}
else{
fprintf(JNIStatus, "JNI is  ok\n"); // should never happen
}
if (retval>=0)
    fprintf(JNIStatus, "Attachcurrentthread was successfull\n"); 

here i am getting output as Attach current thread was successful, but after this when i am trying to find class using below code , system is not able to find class for this

char* strin;
strin = "abcdef";
jstring str = env->NewStringUTF(strin);
jfieldID fid;
jclass clazz = env->FindClass("oracle/forms/ui/VTextField");
if (clazz == NULL) {
    fprintf(JNIStatus, "Can't find class %s", clazz);
}

Even i thought of that it because of local reference , but i tried to make jclass ob ject as global reference also but no luck :(

/* Create a global reference */
jclass clazzLUSCore = (_jclass*)env->NewGlobalRef(clazz);

/* The local reference is no longer useful */
env->DeleteLocalRef(clazz);

/* Is the global reference created successfully? */
if (clazzLUSCore == NULL) {
    fprintf(JNIStatus, "Error - clazzLUSCore is still null when it is suppose to be global\n");
}

I am newbie in c++, please help me on this , i am not able to find running application class , I need to attain this without accessing server code.

As per @michael comment, i tried to add this but its throwing exception i think. so not able to get class name

   JavaVM* gJvm = nullptr;
   static jobject gClassLoader;
   static jmethodID gFindClassMethod;

    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) {
     gJvm = pjvm;  // cache the JavaVM pointer
     auto env = getEnv();
     //replace with one of your classes in the line below
     auto randomClass = env->FindClass("oracle/forms/ui/VTextField");
     jclass classClass = env->GetObjectClass(randomClass);
     auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
     auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader",
    "()Ljava/lang/ClassLoader;");
      gClassLoader = env->CallObjectMethod(randomClass, getClassLoaderMethod);
     gFindClassMethod = env->GetMethodID(classLoaderClass, "findClass",
    "(Ljava/lang/String;)Ljava/lang/Class;");

return JNI_VERSION_1_6;
    }

  jclass findClass(const char* name) {
   return static_cast<jclass>(getEnv()->CallObjectMethod(gClassLoader, gFindClassMethod, getEnv()->NewStringUTF(name)));

}

JNIEnv* getEnv() {
 JNIEnv *env;
 int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
 if (status < 0) {
    status = gJvm->AttachCurrentThread((void**)&env, NULL);
    if (status < 0) {
        return nullptr;
    }
 }
 return env;

}

Yogi
  • 11
  • 3
  • I don't know how your particular environment works, but here's a quote from the Android documentation that mentions a problem you can run into when using `FindClass`: _"You can get into trouble if you create a thread yourself (perhaps by calling pthread_create and then attaching it with AttachCurrentThread). Now there are no stack frames from your application. If you call FindClass from this thread, the JavaVM will start in the "system" class loader instead of the one associated with your application, so attempts to find app-specific classes will fail."_ – Michael Jan 07 '16 at 12:52
  • ([Source](http://developer.android.com/training/articles/perf-jni.html#faq_FindClass) for the aforementioned quote). – Michael Jan 07 '16 at 12:53
  • Thanks Michael i will go through your comment,and will get back to you – Yogi Jan 07 '16 at 13:06
  • Can't you use `Thread.getContextClassLoader()` of any existing thread to get the correct classloader? – vlp Jan 11 '16 at 00:01
  • @VIP thread.getContextClassLoader() is java way to doing it, problem is i am not able to connect from c++ to java class, application is already running, i don't have access of source code, on ly i am able to inject my dll in that application but now, i want to edit text box in that application, i can't its a java based application so window spy also not able to get the GUI object definition, i want that object definition, so that i can set values in edit box or click button,if you can guide me along this i will really appreciate it, i now java but in c++ i have very less knowledge. – Yogi Jan 11 '16 at 09:28
  • I am trying to replicate this , http://stackoverflow.com/questions/34227178/how-to-choose-an-awt-eventqueue-thread-when-there-are-several-of-them/34492567#34492567 – Yogi Jan 11 '16 at 09:31
  • (Sorry quite short on time now so I did not study your case thoroughly) Can't you use a java agent instead? It can be injected into a running jvm. See e.g. [here](http://dhruba.name/2010/02/07/creation-dynamic-loading-and-instrumentation-with-javaagents/). – vlp Jan 12 '16 at 23:40
  • You might find [JavaSnoop](http://www.aspectsecurity.com/tools/javasnoop) interesting (at least for some inspiration) – vlp Jan 13 '16 at 16:50
  • @vIp I tried with javaagent but problem with java agent is , its should launch in the same environment or in same vm on which Application is running , but i don't have access of source code so and application launched from url , so i can''t launch it from ProcessBuilder(if we launch any java application from processbuilder we can launch java agent using same env ), thats why it is not big help :( – Yogi Jan 14 '16 at 10:03
  • @manuell is already done this, so its doable for sure, only problem is due to my lack of knowledge i am not able to do it here you can refer what i am tryng to do ,problem statement is different, but i am trying to replicate same scenario http://stackoverflow.com/questions/34227178/how-to-choose-an-awt-eventqueue-thread-when-there-are-several-of-them/34492567#34492567 – Yogi Jan 14 '16 at 10:06
  • @Yogi AFAIK it is possible to attach an agent to an already running VM. See e.g. [here](http://stackoverflow.com/a/25638403/5128464), which leads [here](http://docs.oracle.com/javase/7/docs/technotes/guides/attach/index.html). The above-mentioned [JavaSnoop](http://www.aspectsecurity.com/tools/javasnoop) uses this approach (see [here](https://media.blackhat.com/bh-us-10/whitepapers/Dabirsiaghi/BlackHat-USA-2010-Dabirsiaghi-JavaSnoop-wp.pdf)). – vlp Jan 14 '16 at 22:53
  • @vIp, sorry for late response was trying multiple ways to solve problem, I even tried with JavaSnoop also , but when it is attaching to the client process server stop connection with client and i get error as connection got interrupted from oracle forms server.:( any suggestion – Yogi Jan 22 '16 at 08:23
  • Just seen your question. Will try to help. Bur be aware that it may be complex. Will update in the next few days. – manuell Feb 09 '16 at 17:46

1 Answers1

1

You need to get the correct class loader.

  1. Use the Win32 FindWindow API to get a HWND for the main window of the application. You may use the Spy++ tool to get the exact properties of that window.
  2. Dynamically load the jawt.dll, using the Win32 LoadLibrary API. That DLL is typically located in the parent directory of the directory containing the jvm.dll. Exemple :
C:\Program Files (x86)\Java\jre1.8.0_73\bin\jawt.dll
C:\Program Files (x86)\Java\jre1.8.0_73\bin\client\jvm.dll

You have many ways to get the LoadLibrary call to succeed:

  • just use "jawt.dll"
  • get the path of the already loaded jvm.dll, using GetModuleFileName and build a new path with it.
  • get the path of the current executable (should be java.exe) passing a NULL module handle to GetModuleFileName. You should get the bin path.

Once you successfully loaded jawt.dll, use GetProcAdress to get the _JAWT_GetAWT@8 function, and call it. Exemple:

// error checking committed (for clarity...)
typedef jboolean (JNICALL * PGETAWT)(JNIEnv* env, JAWT* awt);
PGETAWT pGetAWT = (PGETAWT)GetProcAddress( hModJAWT, "_JAWT_GetAWT@8" );
JAWT jawt;
jawt.version = JAWT_VERSION_1_4;
pGetAWT( env, &jawt );

Now, you are able to call the wonderful GetComponent API:

jobject jObjMainWindow = jawt->GetComponent( env, (void*)hWndOfTheMainOracleWindow );

Then, use JNI to obtain the jclass of that main window, and then call the getClassLoader method of the Class Class.

With that Class Loader, FindClass should work much better.

manuell
  • 7,528
  • 5
  • 31
  • 58
  • thanks a lot buddy ,i will definitely try this, very sorry for the delayed reply was out for a while, i will get back to you once i will be able to crack this. – Yogi Feb 22 '16 at 05:50
  • hey buddy , sorry for delayed response , i tired with little different approach using Attach API of java, i am able to get the loaded classes at that moment but not able to get the component and perform any operation, and idea how we can do that ? – Yogi Mar 31 '16 at 10:34
  • @Yogi If my answer helped you to get a valid Class Loader, then approve it or upvote it. If you have another problem, then ask another question stating what you have tried, what doesn't seem to work. Keep me informed here if you ask another question. You will not be able to do all you want to do just by saying "but not able" in a comment, in my humble opinion. – manuell Apr 19 '16 at 14:14