【问题标题】:Not able to attach through oracle forms GUI object using dll injection and JNI无法使用 dll 注入和 JNI 通过 Oracle 表单 GUI 对象附加
【发布时间】:2016-01-07 12:34:43
【问题描述】:

在我的一个项目下,我需要读取正在运行的 oracle 表单应用程序的 VTextField GUI 对象,并在其中设置新值,我能够将我的 DLL 注入到应用程序中,并且我能够附加下面的当前线程是我的代码

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"); 

在这里我得到输出,因为附加当前线程成功,但是在此之后当我尝试使用下面的代码查找类时,系统无法为此找到类

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);
}

即使我认为它是因为本地引用,但我也尝试将 jclass 对象作为全局引用但没有运气:(

/* 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");
}

我是 C++ 的新手,请帮帮我,我找不到正在运行的应用程序类,我需要在不访问服务器代码的情况下实现这一点。

根据@michael 的评论,我尝试添加它,但我认为它会抛出异常。所以无法获取类名

   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;

}

【问题讨论】:

  • 我不知道您的特定环境是如何工作的,但这里引用了 Android 文档中的一个引用,其中提到了您在使用 FindClass 时可能遇到的问题:“您可能会遇到麻烦如果您自己创建一个线程(可能通过调用 pthread_create 然后使用 AttachCurrentThread 附加它)。现在您的应用程序中没有堆栈帧。如果您从该线程调用 FindClass,JavaVM 将在“系统”类加载器中启动,而不是与您的应用程序关联的类,因此尝试查找特定于应用程序的类将失败。”
  • (上述报价为Source)。
  • 谢谢迈克尔,我会查看您的评论,并会回复您
  • 你不能使用任何现有线程的Thread.getContextClassLoader() 来获取正确的类加载器吗?
  • @VIP thread.getContextClassLoader() 是 java 的实现方式,问题是我无法从 c++ 连接到 java 类,应用程序已经在运行,我无法访问源代码,只有我能够在那个应用程序中注入我的 dll,但是现在,我想在那个应用程序中编辑文本框,我不能它是一个基于 java 的应用程序,所以 window spy 也无法获得 GUI 对象定义,我想要该对象定义,以便我可以在编辑框或单击按钮中设置值,如果您能指导我这样做,我将非常感激,我现在​​是 java 但在 c++ 中我的知识很少。

标签: java c++ java-native-interface oracleforms dll-injection


【解决方案1】:

您需要获取正确的类加载器。

  1. 使用 Win32 FindWindow API 获取应用程序主窗口的 HWND。您可以使用 Spy++ 工具来获取该窗口的确切属性。
  2. 使用 Win32 LoadLibrary API 动态加载 jawt.dll。该 DLL 通常位于包含jvm.dll 的目录的父目录中。示例:
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

您有很多方法可以让LoadLibrary 调用成功:

  • 只需使用"jawt.dll"
  • 获取已加载的jvm.dll 的路径,使用GetModuleFileName 并用它构建一个新路径。
  • 获取当前可执行文件的路径(应该是java.exe),将NULL 模块句柄传递给GetModuleFileName。你应该得到bin 路径。

成功加载jawt.dll后,使用GetProcAdress获取_JAWT_GetAWT@8函数,并调用它。示例:

// 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 );

现在,您可以调用美妙的GetComponent API:

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

然后,使用JNI获取那个主窗口的jclass,然后调用Class类的getClassLoader方法。

使用 那个 类加载器,FindClass 应该会更好地工作。

【讨论】:

  • 非常感谢哥们,我一定会试试这个,非常抱歉延迟回复有一段时间了,一旦我能够破解这个,我会回复你。
  • 嘿伙计,抱歉延迟响应,我厌倦了使用 Java 的 Attach API 的不同方法,我当时能够获取加载的类,但无法获取组件并执行任何操作,以及我们如何做到这一点的想法?
  • @Yogi 如果我的回答帮助您获得了有效的类加载器,请批准或投票。如果您还有其他问题,请再问一个问题,说明您尝试了哪些方法,哪些方法似乎不起作用。如果您提出其他问题,请在此处通知我。以我的拙见,您将无法仅通过在评论中说“但不能”来做所有您想做的事情。
猜你喜欢
  • 1970-01-01
  • 2018-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多