- PR -

JNIを使ってクラスをロード。(技術情報保持による対策)

投稿者投稿内容
トーキー
会議室デビュー日: 2004/11/19
投稿数: 6
投稿日時: 2004-12-11 14:11
クラスファイルからリバースコンパイルによってJavaソースを
盗み見されるのを防ぐ為に以下のように考えたのですがうまくいきませんでした。

1オブジェクトをClassLoaderクラスを使って生成。
2ファイルまたはネットワークを介して暗号化されたデータを取得。
3複合化して取り出したクラスファイルのデータをロードし、
 defineClassメソッドを使ってインスタンスを生成。
4JNIを使って、1〜3のインスタンス生成処理部分をネイティブコードで実装。

これで、肝心のクラスファイルは盗み見されないと考えています。

以下、コードです。
JAVA部分-------------------------------------
・JNIClassLoader.java・・・クラスをロードするクラス
public class JNIClassLoader extends ClassLoader {
private Object getJNIClassLoader( String strClassName, byte[] bytBuf ){
Class cls = null;
Object obj = null;
try{
cls = (Class)defineClass( strClassName, bytBuf, 0, bytBuf.length );
obj = cls.newInstance();
} catch( Throwable th ){
System.out.println("****** エラー ******");
th.printStackTrace();
}
return obj;
}
}

・CallJNIClassLoader.java・・・ロードクラスの呼び出しクラス
import java.io.*;

public class CallJNIClassLoader{
static{
System.loadLibrary("c");
}
// ネイティブメソッドの宣言
private native Object doGetInstance( String strClassName, byte[] bytBuf );

public static void main(String args[]){
CallJNIClassLoader calljni = new CallJNIClassLoader();
Object obj = calljni.getInstance( args[0], args[1] );
}

// クラスパスとクラス名から暗号化されたクラスデータを取得
public Object getInstance( String strPath, String strClassName ) {
Object obj = null;
FileInputStream fis = null;
try{
File file = new File(strPath);
if( !file.isFile() ){
System.out.println("ファイルオープンエラー");
return obj;
}
byte[] bytBuf = new byte[ (int)file.length() ];
fis= new FileInputStream( file );
int intReadSize = fis.read( bytBuf );
if( file.length() != intReadSize ){
System.out.println("ファイル読み込み中のエラー");
return obj;
} else {
try{
// ************ ネイティブメソッド呼び出し ************
obj = doGetInstance( strClassName, bytBuf );
} catch( Throwable th ){
System.out.println("****** エラー ******");
th.printStackTrace();
}
}
} catch( IOException ioe ){
System.out.println("ファイル読み込みエラー");
ioe.printStackTrace();
} finally{
try{
if( fis != null ){
fis.close();
}
} catch( IOException ioe ){
System.out.println("ファイルクローズエラー");
ioe.printStackTrace();
} finally {
if( fis != null ){
fis = null;
}
}
}
return obj;
}
}

C部分----------------------------------------
・NativeJNIClassLoader.cpp・・・ネイティブメソッドを実装する。作成されるモジュールはc.dll
#include "CallJNIClassLoader.h"

JNIEXPORT jobject JNICALL Java_CallJNIClassLoader_doGetInstance
(JNIEnv *env, jobject thiss, jstring str, jbyteArray bytArray ){
jobject objRes = NULL;
jsize iBufSize = env->GetArrayLength(bytArray);

if( bytArray != NULL ){
printf("bytArray is NOT NULL.\\n" );
jclass class2 = env->FindClass( "JNIClassLoader" );
jmethodID mid = env->GetMethodID( class2, "getJNIClassLoader", "(Ljava/lang/String;[B)Ljava/lang/Object;");
if( mid != NULL ){
printf("mid is NOT NULL.\\n" );
objRes = (jobject)env->CallObjectMethod(class2, mid, str, bytArray );
} else {
printf("mid is NULL.\\n" );
}
} else {
printf("bytArray is NULL.\\n" );
}
return objRes;
}

----- 返される出力結果は以下のとおりです。 -------
bytArray is NOT NULL.
mid is NOT NULL.
****** エラー ******
java.lang.SecurityException: ClassLoader object not initialized
at java.lang.ClassLoader.check(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at JNIClassLoader.getJNIClassLoader(JNIClassLoader.java:6)
at CallJNIClassLoader.doGetInstance(Native Method)
at CallJNIClassLoader.getInstance(CallJNIClassLoader.java:33)
at CallJNIClassLoader.main(CallJNIClassLoader.java:11)

※どなたか詳しい方、ご教授願います。
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2004-12-11 15:37
トーキーさん、こんにちは。

いろいろ問題ありますが、
・JNIClassLoaderクラスのインスタンス化を忘れてませんか?
・それとも、getJNIClassLoaderメソッドをクラスメソッドにし忘れたとか?
トーキー
会議室デビュー日: 2004/11/19
投稿数: 6
投稿日時: 2004-12-11 18:06
Kissingerさん、カキコありがとうございます。
>JNIClassLoaderクラスのインスタンス化を忘れてませんか?
JNIClassLoaderをインスタンス化するにはどうしたらよいのでしょうか?
自分では、
1.クラスID取得。2.メソッドID取得。3.メソッド呼び出し。
で、うまく呼び出せると認識していますが、勘違いでしょうか?

>それとも、getJNIClassLoaderメソッドをクラスメソッドにし忘れたとか?
getJNIClassLoaderメソッドは内部でdefineClassメソッドを呼び出しているため、
static化はできません。
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2004-12-11 18:58
わかりやすいように JNIのコードを Java風に直してみると、
コード:
	Class c = JNIClassLoader.class;
	c.getJNIClassLoader(...);


のようになっています。

コード:
	Class c = JNIClassLoader.class;
	JNIClassLoader loader = c.newInstance();
	loader.getJNIClassLoader(...);


のようにしたかったのではないでしょうか?
トーキー
会議室デビュー日: 2004/11/19
投稿数: 6
投稿日時: 2004-12-13 23:53
Kissingerさん、カキコありがとうございます。
返信送れてもうしわけありませんでした。
何度かいろいろな方法で試してみたのですが、
どうやらインスタンスの生成はうまくいっているようです。
getJNIClassLoaderメソッドの内部で呼び出すメソッドを
toStringメソッドやHashCodeメソッドなどで変えてみたら、
正しく処理が通りました。
問題は、defineClassメソッドを呼び出している所です。
何か呼び出し方を工夫したほうが良いかと自分では思っているんですが。。。

Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2004-12-15 01:31
『正しく処理が通りました。』というのはどう言うことでしょう。
返ってくるべき文字列、返ってくるべきハッシュ値が正しい
値だったことを確認されたのでしょうか?

まさか、例外にならずに何かの値が返されたということでは
ないでしょうね。
トーキー
会議室デビュー日: 2004/11/19
投稿数: 6
投稿日時: 2004-12-15 21:49
Kissingerさん、カキコありがとうございます。

>『正しく処理が通りました。』というのはどう言うことでしょう。
例外が発生せず、返されるべき値が返されたという事です。
説明が足りませんでした。

この原因はdefineClassメソッドが抽象化メソッドという事が原因かもしれませんが、
いろいろと試したいことが出てきましたのでもう少し調べてみようと思います。
ちなみに、JNIClassLoaderクラスをインスタンス化した後に、
JNIインタフェースのGetObjectClassメソッドの引数にオブジェクトを
渡す方法でも同じエラーが返されました。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2005-01-27 12:03
興味深いスレ age。

とりあえず、Kissinger さんのご指摘の通りインスタンス化してないのが原因のはず。トーキーさんが、うまく動いていると言っているのが かなり謎…。

コード:
jclass class2 = env->FindClass(...);
jmethodID mid = env->GetMethodID(class2, ...);
objRes = (jobject)env->CallObjectMethod(class2, mid, str, bytArray );


原因はここ。CallObjectMethod の第1引数に jclass を渡してるけど、ここにはオブジェクトインスタンス jobject を渡さないといけない。Call*MethodA を使ってれば、型チェックに引っかかるはずなんだけど、可変長引数をとれる Call*Method では型チェックが働かないんだね…。

コード:
jclass class2 = env->FindClass(...);
jobject instance2 = env->NewObjectA(...);
jmethodID mid = env->GetMethodID(class2, ...);
objRes = (jobject)env->CallObjectMethod(instance2, mid, str, bytArray );


とれすば良いはず。

スキルアップ/キャリアアップ(JOB@IT)