我必须编辑原帖,因为它有误导性。我有一个使用JNI创建JavaVM的应用程序。它是用C ++编写的QT5框架。如果我在我的应用程序的.exe文件旁边提供.class和.jar文件,那么从我的java应用程序创建jvm和调用函数没有问题。 现在,由于java应用程序可以被反编译,我公司的标准不允许我将此应用程序分发给本地用户,因为它确实包含他们无法访问的关键密码。像安全同事一样,我得到了一个响应,他们对应用程序感到满意,如果我在.exe文件中捆绑了java源代码。 QT资源文件对于这项工作来说非常棒,我已经定义如下:
<RCC>
<qresource prefix="/javaApplication">
<file>resources/bytecodes/helloworld/HelloWorld.class</file>
<file>resources/bytecodes/helloworld/HelloWorld.jar</file>
</qresource>
</RCC>
因此我可以使用以下路径访问文件:
:/javaApplication/resources/bytecodes/helloworld/HelloWorld.class
:/javaApplication/resources/bytecodes/helloworld/HelloWorld.jar
很好而且流畅,但这些路径似乎不适用于JavaVMArgs:
// Does work but violates security policies:
options[1].optionString = "-Djava.class.path=C:/Users/johorvat/Documents/NetBeansProjects/HelloWorld/build/classes/helloworld/HelloWorld.class;C:/Users/johorvat/Documents/NetBeansProjects/HelloWorld/dist/HelloWorld.jar";
// Does not work, sadly I try to achieve something like this:
options[1].optionString = "-Djava.class.path=:/javaApplication/resources/bytecodes/helloworld/HelloWorld.class;:/javaApplication/resources/bytecodes/helloworld/HelloWorld.jar";
如何让第二个变体启动并运行?
答案 0 :(得分:2)
您的问题与Qt几乎无关,可以简单地改为:
有没有办法将类或jar文件的内容传递给JVM而不在磁盘上明确保存?
I've asked this question。答案是:它是可能的,但不是没有先将一些代码加载到JVM中。所以你实际上可以做你想做的事情,首先启动你自己的加载器,然后传递数据,例如通过本地套接字或localhost网络连接。您的数据也可以来自本机方法,您当然可以使用Qt编写JNI DLL。
Qt资源系统对您的应用程序以外的任何内容都是不可见的。您使用Qt特定资源路径的参数调用JVM或任何其他可执行文件没有任何意义。 JVM对这些文件一无所知,也不会知道。除非你在java中重新实现Qt资源系统,否则你需要那些初始类文件。
Qt资源只是zlib压缩的二进制blob,从编译的可执行文件中提取是微不足道的。它们并没有真正意义上的“编译”。它们实际上通过利用链接器和编译器连接到可执行文件,但这只是一个实现细节。
我公司的标准不允许我将此应用程序分发给本地用户,因为它确实包含无法访问的关键密码
所有内容都可以反编译,因此无论您的密码是在显式的java类文件中还是在qrc-obfuscated类文件中都无关紧要。可能的结果是相同的。
为了让逆向工程师的生活更加艰难,你可以合理地做到:
使用SSL保护连接。
验证服务器的签名,以防止中间人攻击。
在应用程序可执行文件中捆绑一个加密的私有客户端密钥。使用它而不是密码。服务器可以事先知道允许的客户端密钥。
与您最喜欢的SSL库静态链接。
如果您的方案允许,您可以使用密码短语保护客户端密钥,并要求用户每次打算连接到服务器时都输入密码。这可以防止泄漏的可执行文件在没有密码短语的情况下允许服务器入侵。
这就是它,真的。
答案 1 :(得分:0)
如果JNI_CreateJavaVM
成功,那么这只是第一步。您已经创建了Java环境,但现在您需要告诉它该做什么。
您接下来的步骤将是这样的:
1)加载你想要使用的类(例如HelloWorld)
2)实例化你的班级
3)在你的班级上调用一个方法
//step 1
jclass HelloWorldClass = env->FindClass( "path/to/package/HellowWorld" );
jobject helloWorldInst = NULL;
if( HelloWorldClass != NULL )
{
//step 2 - use javah to determine your constructor/method signatures
jmethodID helloWorldConstructorSignature = env->GetMethodID(env, HelloWorldClass, "<init>", "()V");
helloWorldInst = env->NewObject(env, HelloWorldClass, helloWorldConstructorSignature);
}
//step 3 - Load your method's signature
if( helloWorldInst != NULL )
{
jmethodID myMethodSignature = env->GetMethodID(env, HelloWorldClass, "myMethod", "()I" );
int result = env->CallIntMethod( helloWorldInst, myMethodSignature );
}