windows下cc++创建Java虚拟机加载可执行jar包

windows下cc++创建Java虚拟机加载可执行jar包,第1张

一般的,我们使用java.exe或者javaw.exe来执行我们的java应用程序。但是实际上这两个可执行程序只是java虚拟机的启动器,使用java.exe将会创建一个控制台窗口用于输出,而javaw则不会创建控制台窗口。如果你讨厌黑乎乎的控制台窗口,那么就使用javaw.exe去加载。java虚拟机的主要实现包含在 java.dll 和 jvm.dll这两个动态链接库之中。我们以jdk1.8.0_181为例,

java.dll 位于 C:\Program Files\Java\jdk1.8.0_181\jre\bin下

jvm.dll 位于 C:\Program Files\Java\jdk1.8.0_181\jre\bin\server\jvm.dll

我们可以使用dumpbin查看这两者的导出函数。

先看 java.dll

 

是不是很熟悉呢,比如我们常用的文件 *** 作方法,都是绑定的native方法。

再看jvm.dll

java.exe和javaw.exe则是调用了JNI_CreateJavaVM方法来创建java虚拟机,所以我们也可以通过自己的启动器来创建java虚拟机

那么问题来了,我们在什么情况下需要创建自己的启动器呢,比如我们要刻意隐藏java包和class文件避免被发现我们的程序是java程序、比如我们要实现对jar包加密。当然还有很多的应用场景、还是那句话,存在就是合理的。

以下示例程序中、我们将在windows环境下使用c语言来创建java虚拟机、程序中我们将自动查找exe根目录下的jar包和文件夹目录并调用主类。

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include

typedef _JNI_IMPORT_OR_EXPORT_ jint(JNICALL *PJNI_CreateJavaVM)(JavaVM **pvm, void **penv, void *args);
jint create_vm(int argc, char* argv[])
{
    JavaVM* jvm1 = NULL;
    JNIEnv* env1 = NULL;
    JavaVMInitArgs args;
    JavaVMOption options[2];
    char buff[256], buff0[256], buff1[1024];
    int nLen = GetModuleFileNameA(GetModuleHandleA(NULL), buff, 256);
    buff[nLen] = '\0';

    char* mainclasspath = getenv("MAINCLASSPATH");
    if (mainclasspath == NULL) {
        sprintf(buff1, "-Djava.class.path=.;");
    }
    else {
        sprintf(buff1, "-Djava.class.path=.;%s", mainclasspath);
    }

    args.version = JNI_VERSION_1_8;
    args.nOptions = sizeof(options) / sizeof(JavaVMOption);
    options[0].optionString = buff0;
    options[1].optionString = buff1;
    args.options = options;
    args.ignoreUnrecognized = JNI_TRUE;

    WIN32_FIND_DATAA p;

    ZeroMemory(&p, sizeof(WIN32_FIND_DATAA));

    HANDLE h = FindFirstFileA("C:\\Program files\\java\\jdk1.8*", &p);
    if (h == INVALID_HANDLE_VALUE) {
        MessageBoxA(NULL, "无法在 C:\\Program files\\java 下找到JDK1.8", "错误", MB_OK);
        return 0;
    }
    int jvmCount = 1;

    char tbuf[256];
    sprintf(tbuf, "C:\\Program files\\java\\%s\\jre\\bin\\server\\jvm.dll", p.cFileName);

    HMODULE hModJVM = LoadLibraryA(tbuf);
    if (hModJVM == NULL) {
        MessageBoxA(NULL, tbuf, "未成功加载JVM.DLL", MB_OK);
        return  0;
    }
    PJNI_CreateJavaVM JNI_CreateJavaVM = (PJNI_CreateJavaVM)GetProcAddress(hModJVM, "JNI_CreateJavaVM");
    printf("作者:[陈平平],邮箱[[email protected]]\n");
    jint iret = JNI_CreateJavaVM(&jvm1, (void **)&env1, &args);

    if (iret != JNI_OK) {
        printf("JVM初始化失败:iret:%d\n", iret);
        return 1;
    }

    printf("JVM Created [%s]\n", tbuf);
    char* mainClsName = NULL;
    if (argc > 1) {
        char* mainClassChrs = argv[1];
        while (*mainClassChrs != '\0') {
            if (*mainClassChrs == '.') {
                *mainClassChrs = '/';
            }
            mainClassChrs++;
        }
        mainClsName = argv[1];
    }
    else {
        char* cdBuff[256];
        WIN32_FIND_DATAA p;
        ZeroMemory(&p, sizeof(WIN32_FIND_DATAA));
        char * jarPath = NULL;
        char*mainModFn[256];
        int cdL = GetCurrentDirectoryA(sizeof(cdBuff), cdBuff);
        cdBuff[cdL] = '\0';
        int mfL = GetModuleFileNameA(GetModuleHandleA(NULL), mainModFn, sizeof(mainModFn));
        mainModFn[mfL] = '\0';
        char* peM = (char*)((INT64)mainModFn + mfL);

        while (*peM != '\\') {
            peM--;
        }
        *peM = '\0';
        if (lstrcmpA(cdBuff, mainModFn) != 0) {
            printf("进程启动目录不正确\n");
            return 1;
        }

        char* mainjarname = getenv("MAINJARNAME");
        char srcBuff[256], msgBuff[256], fullJarName[256];
        if (mainjarname == NULL) {
            sprintf(srcBuff, "%s\\*.jar", cdBuff);
            sprintf(msgBuff, "目录 %s 下无任何jar包,可设置 MAINCLASSPATH 环境变量指定主类根目录路径\n", cdBuff);
            HANDLE h = FindFirstFileA(srcBuff, &p);
            if (h == INVALID_HANDLE_VALUE) {
                printf(msgBuff);
                return 0;
            }
            if (FindNextFileA(h, &p)) {
                CloseHandle(h);
                printf("发现多个Jar包,请指定环境变量 MAINJARNAME 的值\n");
                return 1;
            }
            sprintf(fullJarName, "%s\\%s", cdBuff, p.cFileName);
            printf("MainJar [%s]\n", fullJarName);

            CloseHandle(h);

            printf("请指定环境变量 MAINJARNAME 的值\n");
            return 1;
        }
        else {
            sprintf(srcBuff, "%s\\%s.jar", cdBuff, mainjarname);
            sprintf(msgBuff, "目录 %s 下找不到包含 %s 的jar包", cdBuff, mainjarname);
            HANDLE h = FindFirstFileA(srcBuff, &p);
            if (h == INVALID_HANDLE_VALUE) {
                printf(msgBuff);
                return 0;
            }
            sprintf(fullJarName, "%s\\%s.jar", cdBuff, mainjarname);
        }

        jclass loaderCls = (*env1)->FindClass(env1, "java/lang/ClassLoader");
        jmethodID mdsysLoader = (*env1)->GetStaticMethodID(env1, loaderCls, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
        jobject appLoaderObj = (*env1)->CallStaticObjectMethod(env1, loaderCls, mdsysLoader);
        jclass apploader = (*env1)->FindClass(env1, "sun/misc/Launcher$AppClassLoader");
        jmethodID add2SysPath = (*env1)->GetMethodID(env1, apploader, "appendToClassPathForInstrumentation", "(Ljava/lang/String;)V");

        (*env1)->CallObjectMethod(env1, appLoaderObj, add2SysPath, (*env1)->NewStringUTF(env1, fullJarName));

        jclass jarFileCls = (*env1)->FindClass(env1, "java/util/jar/JarFile");
        jobject jfObj = (*env1)->NewObject(env1, jarFileCls, (*env1)->GetMethodID(env1, jarFileCls, "", "(Ljava/lang/String;)V"), (*env1)->NewStringUTF(env1, fullJarName));
        jclass jarMFCls = (*env1)->FindClass(env1, "java/util/jar/Manifest");
        jobject jarMFObj = (*env1)->CallObjectMethod(env1, jfObj, (*env1)->GetMethodID(env1, jarFileCls, "getManifest", "()Ljava/util/jar/Manifest;"));
        if (jarMFObj == NULL) {
            printf("未找到清单文件MANIFEST.MF\n");
            return 1;
        }
        jclass jarAttrCls = (*env1)->FindClass(env1, "java/util/jar/Attributes");
        jobject jarAttrObj = (*env1)->CallObjectMethod(env1, jarMFObj, (*env1)->GetMethodID(env1, jarMFCls, "getMainAttributes", "()Ljava/util/jar/Attributes;"));
        jstring mainClassStr = (*env1)->CallObjectMethod(env1, jarAttrObj, (*env1)->GetMethodID(env1, jarAttrCls, "getValue",
            "(Ljava/lang/String;)Ljava/lang/String;"),
            (*env1)->NewStringUTF(env1, "Main-Class")
        );
        if (mainClassStr == NULL) {
            printf("清单文件未指定Main-Class\n");
            return 1;
        }
        char * mainClassChrs = (*env1)->GetStringUTFChars(env1, mainClassStr, 0);
        char* mainClassNameRef = mainClassChrs;
        while (*mainClassChrs != '\0') {
            if (*mainClassChrs == '.') {
                *mainClassChrs = '/';
            }
            mainClassChrs++;
        }
        mainClsName = mainClassNameRef;

    }


    jclass mainCls = (*env1)->FindClass(env1, mainClsName);
    if (mainCls == 0) {
        printf("主类 [%s] 未找到\n", mainClsName);
        return 1;
    }

    jobjectArray arr = (*env1)->NewObjectArray(env1, 0, mainCls, 0);
    jmethodID mid = (*env1)->GetStaticMethodID(env1, mainCls, "main", "([Ljava/lang/String;)V");
    (*env1)->CallStaticObjectMethod(env1, mainCls, mid, arr);
    return iret;
}

int argcG = 0;
char** argvG = 0;
DWORD WINAPI ThreadFun(LPVOID pM)
{
    create_vm(argcG, argvG);
    return 0;
}

int main(int argc, char* argv[]) {
    argcG = argc;
    argvG = argv;
    HANDLE handle = CreateThread(NULL, 0, ThreadFun, NULL, 0, NULL);
    WaitForSingleObject(handle, INFINITE);
    handle = GetCurrentThread();
    SuspendThread(handle);
    return 0;
}

加载文件夹的主类并输出helloworld,运行结果如下图

 

 

 加载jar包中的主类并输出helloworld,运行结果如下图

 

 

 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/728759.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-26
下一篇 2022-04-26

发表评论

登录后才能评论

评论列表(0条)

保存