一般的,我们使用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, "
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,运行结果如下图
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)