4

難読化されたC#とJavaの逆コンパイルは、StringなどのフレームワークAPIへの呼び出しの存在によって単純化されると言われています。しかし、これは私にはまったく意味がありません。なぜなら、Cプログラムには、C#apiと同等のいくつかの標準ライブラリへの明白な呼び出しもあるべきではないからです。

また、逆コンパイルの複雑さには、レジスタマシン(Cからアセンブリを実行するハードウェア)とスタックマシン(バイトコードを実行する仮想マシン)の区別が重要であると言われています。

それで、スタック/レジスターマシンの問題はここで主なものですか?CLR仮想マシンがレジスタマシンとして再実装された場合、C#バイトコードはC実行可能ファイルと同じように突然逆コンパイルが困難になるでしょうか?または、そのようなプラットフォームのオーバーホールで解消されない他の主要な複雑さの違いはありますか?

4

3 に答える 3

7

スタックマシンとレジスタマシンの間に違いはありません。両方の表現から式ツリーを分解するのは比較的簡単です。

.NETとJVMは、主にメタデータ(タイプやメソッド名など)があるため、逆コンパイルが非常に簡単です。

削除されたネイティブ実行可能ファイルを使用すると、すべての楽しみが得られます。関数の意味のある名前、明示的なデータ型、インライン化された(さらに最適化によって大幅に切断された)コードのロード、展開されたループ、還元不可能な制御フロー、展開された末尾呼び出しなど。

バイトコードでは、この種の最適化のほとんどは実行されていないため(JITに任せています)、メタデータを削除して最適化を適用した場合よりも、元のソースにはるかに近くなります。スタックマシン、レジスタベース、スレッド化されたForthコードなどは関係ありません。

于 2012-05-10T12:31:45.830 に答える
3

実際のハードウェア向けのマシンコードでは、コードがメモリ内のどこから始まるかを常に把握しているとは限りません。x86命令は可変長であるため、逆アセンブラが誤ったオフセットで命令をデコードする可能性があります。また、ポインタ演算の可能性は役に立ちません。.NET ILおよびJavaオペコードでは、コードの開始位置と終了位置が常に明確であり、任意のポインター演算は許可されていません。したがって、生成されたアセンブリコードが読みにくい場合でも、逆アセンブルは100%正確です。実際のマシンコードでは、少なくともx86では、コードモーフィングが行われていないと仮定しても、プログラムを実行しない限り、正確な制御フローとコードエントリポイントを知ることはできません。

于 2012-05-10T12:33:34.750 に答える
1

リバースエンジニアリングの容易さの観点からのC++とJavaの比較については、私の記事のイントロセクションをお読みください。(「Java」の代わりに「C#」、「JVM」の代わりに「CLR」と読むことができます:))

C標準ライブラリの呼び出しについては、静的にリンクすると、バイナリにライブラリ関数名がなくなります。さらに、C ++コンパイラは、テンプレートで何をするかは言うまでもなく、ヘッダーファイルで定義された小さなメソッドをインライン化します...

于 2012-06-03T09:23:48.743 に答える