コンパイルされたJavaクラスをロックして逆コンパイルを防ぐ方法は?


96

コンパイルされたJavaクラスをロックして逆コンパイルを防ぐにはどうすればよいですか?

これはインターネットで非常によく議論されているトピックであることは知っていますが、それらを参照しても結論を出すことはできませんでした。

多くの人が難読化ツールを提案していますが、覚えにくい文字列でクラス、メソッド、フィールドの名前を変更するだけですが、機密定数値はどうですか?

たとえば、パスワードベースの暗号化技術に基づいた暗号化および復号化コンポーネントを開発しました。この場合、平均的なJavaの人なら誰でもJADを使用してクラスファイルを逆コンパイルし、ソルトだけでなくパスワード値(定数として定義)を簡単に取得できます。次に、小さな独立したプログラムを作成してデータを復号化できます。

または、そのような機密コンポーネントをネイティブコード(たとえば、VC ++)でビルドし、JNI経由で呼び出す必要がありますか?


逆アセンブルされたネイティブコードでさえ、一部の人にとってはかなり読みやすいですが、難読化ツールまたは手作りのアセンブリを使用して、それを非自明にする必要があります(最適化でコンパイルされた一般的なC ++は十分に読みやすくなります)。ユーザーのデバイスで実行されるコードが何であれ、傍受される可能性があります。そのような傍受のコスト/スキル要件は非常に高くなる可能性がありますが、たとえば、スマートカードの「改ざん防止」チップコードに侵入することは簡単ではなく、最高の機器とスキルでのみ実行可能です。Javaクラスがあれば...あまり気になりませんが、スクリプトの子供たちを遠ざけるのに十分なだけ暗号化できるでしょう。
Ped7g 2016

回答:


96

より高度なJavaバイトコード難読化プログラムのいくつかは、クラス名のマングリングだけではありません。たとえば、Zelix KlassMasterは、コードフローをスクランブルして、追跡を非常に困難にし、優れたコードオプティマイザーとして機能させることもできます...

また、難読化ツールの多くは、文字列定数をスクランブルして未使用のコードを削除することもできます。

別の可能な解決策(必ずしも難読化を除外する必要はありません)は、暗号化されたJARファイルと、(できればネイティブランタイムライブラリを使用して)復号化を行うカスタムクラスローダーを使用することです。

3番目の(そしておそらく最も強力な保護を提供する)は、GCCExcelsior JETなどのネイティブの事前コンパイラーを使用することです。たとえば、Javaコードをプラットフォーム固有のネイティブバイナリに直接コンパイルします。

いずれにせよ、エストニア語で「水門は動物のためのものだ」ということわざにあるように、覚えておく必要があります。ランタイム中にコードのすべてのビットが利用可能(メモリにロード)であり、十分なスキル、決断力、および動機付けが与えられているということは、人々がコードを逆コンパイル、スクランブル解除、およびハッキングできることです...あなたの仕事は、プロセスをあなたはまだ物事を動かし続けることができます...


13
「鍵は動物用」の+1。ここで適切な用語はスクリプトキディでしょう。
アンチモン2013

あなたはGCJを意味し、それは死んでいます。
ローンの侯爵

1
Componio jarファイルの暗号化も無効です。代わりにJarProtectorを使用してください。
J.Profi 2017

16

暗号化されたデータとそれを解読するソフトウェアの両方にアクセスできる限り、基本的にこれを完全に安全にする方法はありません。これが以前に解決された方法は、ドングル、リモート認証サーバーなどの外部ブラックボックスを使用して暗号化/復号化を処理することです。しかし、それでも、ユーザーが自分のシステムにフルアクセスできる場合、困難ではありませんが、不可能ではありません。たとえば、オンラインゲームサーバーのように、「ブラックボックス」に格納されている機能に製品を直接結び付けることができる場合を除きます。


13

免責事項:私はセキュリティの専門家ではありません。

これは悪い考えのように聞こえます:あなたが誰かに、あなたに与えた「隠された」鍵で何かを暗号化させています。これを安全にすることはできないと思います。

多分非対称キーがうまくいくかもしれません:

  • 復号化する公開鍵を使用して暗号化されたライセンスを展開する
  • 顧客が新しいライセンスを作成し、暗号化のためにあなたに送信するようにします
  • 新しいライセンスをクライアントに送り返します。

確かではありませんが、クライアントが実際にライセンスキーを、あなたが提供した公開キーで暗号化できると思います。その後、秘密鍵で暗号化を解除し、再暗号化することもできます。

あなたはあなたが実際に適切な顧客からのものを得ている作るために、顧客ごとに個別の公開鍵/秘密鍵のペアを保つことができる-今、あなたは、キーを担当しています...


2
私は以前にこのテクニックを使用したことがあり、うまく機能します。ただし、攻撃の観点からは、最初のアプローチは、ライセンスチェックを実行するコードを変更して削除することです。この攻撃ベクトルを困難にするためにできることはいくつかありますが、攻撃者がハードウェアを制御できるようにすると、適切に動機付けられた熟練した攻撃者で失敗する運命にあります。実際には、目標はほとんど正直な人々を正直に保つことです。
ジムラッシュ

12

何をしても、「逆コンパイル」することができます。一体、あなたはそれを分解することができます。または、メモリダンプを調べて定数を見つけます。ご覧のとおり、コンピュータはそれらを認識する必要があるため、コードも認識する必要があります。

これについて何をしますか?

キーをコード内のハードコードされた定数として出荷しないようにしてください。ユーザーごとの設定として保持してください。ユーザーにそのキーの世話をする責任を持たせます。


6

@jatanp:さらに良いことに、逆コンパイル、ライセンスコードの削除、再コンパイルを行うことができます。Javaでは、この問題に対する適切なハッキング防止ソリューションが実際にあるとは思いません。邪悪な小さなドングルでさえ、Javaでこれを防ぐことはできません。

私自身のビズマネージャーはこれを心配しています。しかし、その場合も、ライセンス条件を順守する傾向がある大企業にアプリケーションを販売します。一般的には、豆売り場や弁護士のおかげで安全な環境です。ライセンスが正しく記述されている場合、それ自体を逆コンパイルする行為は違法になる可能性があります。

それで、私は尋ねなければなりませ、あなたはあなたがあなたのアプリケーションを求めているように本当に強化された保護必要ですか?あなたの顧客ベースはどのように見えますか?(企業?それとも問題の多い10代のゲーマーの大衆?)


実際には、ところでドングルのように見えることを、適切な、ハックプルーフソリューションがあります: excelsior-usa.com/blog/excelsior-jet/...
ドミトリーLeskov

@DmitryLeskov「ハック耐性」、たぶん。しかし、それは、コードを求めている人にとっては、単なるスピードバンプです。結局のところ、バイトコードは暗号化されていないホストプラットフォームで実行する必要があります。フルストップ。
Stu Thompson

リンクした投稿をまだ読んでいない。バイトコードはドングルのCPUコードに変換され、暗号化されます。エンドユーザーが保護されたアプリを実行すると、その暗号化されたコードが「ドングル」に転送されます。ドングルはそれを復号化し、CPUで実行します。
Dmitry Leskov 2013

2
企業の10代のゲーマー。
odiszapc 2015年

3

ライセンスソリューションをお探しの場合は、TrueLicense APIをご覧ください。これは、非対称キーの使用に基づいています。ただし、アプリケーションがクラックできないという意味ではありません。すべてのアプリケーションは十分な労力で解読できます。Stuが答えたように、本当に重要なのは、どの程度強力な保護が必要かを理解することです。


2

効果的なオフラインの著作権侵害対策方法は存在しないと思います。ビデオゲーム業界は何度もそのことを発見しようとし、そのプログラムは常に解読されてきました。唯一の解決策は、プログラムをサーバーに接続してオンラインで実行する必要があることです。これにより、ライセンスキーを検証でき、ライセンス所有者によるアクティブな接続は一度に1つだけになります。これがWorld of WarcraftまたはDiabloの仕組みです。彼らがセキュリティを回避するために開発されたプライベートサーバーがあります。

そうは言っても、中/大企業が違法にコピーされたソフトウェアを使用しているとは思わない。なぜなら、それらのライセンスのコストは最小限に抑えられているからだろう(おそらく、あなたがあなたのプログラムに対してどれだけの費用を払わなければならないのかわからない)。試用版のコスト。


2

恐れることなくバイトコード暗号化を使用できます。

実際のところ、上記の論文「Cracking Java byte-code encryption」には論理的な誤りが含まれています。この論文の主な主張は、実行前にすべてのクラスを復号化してClassLoader.defineClass(...)メソッドに渡す必要があることです。しかし、これは真実ではありません。

ここで見落とされている前提は、それらが本物の、または標準のJavaランタイム環境で実行されていることを前提としています。保護されたJavaアプリがこれらのクラスを起動するだけでなく、復号化してに渡すことを義務付けることはできませんClassLoader。言い換えると、標準のJREをdefineClass(...)使用している場合、標準のJavaにはこの目的のためのAPIがないため、メソッドをインターセプトすることはClassLoaderできません。 Javaアプリはまったく機能しないため、傍受するものはありません。また、使用される「パッチファインダー」やハッカーが使用するトリックはまったく関係ありません。これらの技術的な詳細はかなり異なる話です。


パッチが適用されたJVMをどの程度正確に検出するつもりですか?とにかく、これはすべてが少し難しいことです。
アンチモン2013

あなたはあなたのアプリランチャーでdefineClass()への呼び出しを見つけることができませんか?その呼び出しを行うときは、とにかく復号されたバイトの配列を渡す必要があります。元のソースがリークする可能性がある別のポイントではありませんか?
アセンダント2013

4
私はこの答えに本当に同意しません。「質問:Piを見つける最も簡単な方法は何ですか?回答:2 * Piを取り、2で除算してください。」私はその考えに反対していませんが、詳細を含めることができますか?たとえば、メインプログラムが純粋なJavaで記述されることを期待していますか?変更を探すコードが含まれていますか?
Patrick M

-1

Q:.classファイルを暗号化し、カスタムクラスローダーを使用してオンザフライでロードおよび復号化すると、逆コンパイルが防止されますか?

A:Javaバイトコードの逆コンパイルを防ぐ問題は、言語自体とほとんど同じです。市場で利用できるさまざまな難読化ツールにもかかわらず、初心者のJavaプログラマーは、知的財産を保護するための新しく賢い方法を考え続けています。このJava Q&Aの記事では、ディスカッションフォーラムで頻繁に再ハッシュ化されたアイデアに関するいくつかの神話を払拭します。

Java .classファイルを元のJavaソースに非常に似たJavaソースに再構築するのが非常に簡単であることは、Javaバイトコードの設計目標とトレードオフに大きく関係しています。とりわけ、Javaバイトコードは、バイトコードインタープリターとJIT(ジャストインタイム)/ HotSpot動的コンパイラーによって、コンパクトさ、プラットフォーム非依存性、ネットワークモビリティ、および分析の容易さのために設計されました。間違いなく、コンパイルされた.classファイルはプログラマの意図を表現しているため、元のソースコードよりも簡単に分析できます。

少なくとも逆コンパイルをより困難にするために、逆コンパイルを完全に防止しないために、いくつかのことができます。たとえば、コンパイル後の手順として、.classデータをマッサージして、バイトコードを逆コンパイル時に読みにくくするか、有効なJavaコードに逆コンパイルすることを困難にすることができます(またはその両方)。前者には極端なメソッド名のオーバーロードを実行したり、制御フローを操作してJava構文では表現できない制御構造を作成したりする手法は、後者にはうまく機能します。より成功した商用の難読化ツールは、これらのテクニックと他のテクニックを組み合わせて使用​​します。

残念ながら、どちらのアプローチでもJVMが実行するコードを実際に変更する必要があり、多くのユーザーは(当然のことながら)この変換によってアプリケーションに新しいバグが追加されることを恐れています。さらに、メソッドとフィールドの名前を変更すると、リフレクション呼び出しが機能しなくなる可能性があります。実際のクラス名とパッケージ名を変更すると、他のいくつかのJava API(JNDI(Javaネーミングおよびディレクトリインターフェース)、URLプロバイダーなど)が壊れる可能性があります。名前の変更に加えて、クラスのバイトコードオフセットとソース行番号の間の関連付けが変更されると、元の例外スタックトレースの回復が困難になる可能性があります。

次に、元のJavaソースコードを難読化するオプションがあります。しかし、基本的にこれは同様の一連の問題を引き起こします。暗号化し、難読化しませんか?

おそらく上記のことから、「バイトコードを操作する代わりに、コンパイル後にすべてのクラスを暗号化し、JVM内でその場で復号化するとどうなるでしょうか(カスタムクラスローダーで実行できます)。元のバイトコードですが、逆コンパイルまたはリバースエンジニアリングするものは何もありませんよね?」

残念ながら、あなたはこのアイデアを思いついた最初の人であると考えることと、それが実際に機能することを考えることの両方で間違っているでしょう。そして、その理由はあなたの暗号化スキームの強さとは何の関係もありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.