Java、VB.NET、C#、ActionScript 3.0などのバイトコードベースの仮想マシン言語では、インターネットからデコンパイラーをダウンロードしてバイトコードを1回実行するだけの簡単さについて時々耳にします。多くの場合、数秒で元のソースコードからそれほど離れていないものを見つけます。おそらく、この種の言語はそれに対して特に脆弱です。
私は最近、ネイティブバイナリコードに関して、これが元々どの言語で書かれていたのか(したがって、どの言語に逆コンパイルしようとするのか)を少なくとも知っているのに、なぜこれについて聞いていないのだろうと思い始めました。長い間、ネイティブマシン言語が典型的なバイトコードよりも非常にクレイジーで複雑だからだと考えていました。
しかし、バイトコードはどのように見えますか?次のようになります。
1000: 2A 40 F0 14
1001: 2A 50 F1 27
1002: 4F 00 F0 F1
1003: C9 00 00 F2
そして、ネイティブマシンコードは(16進数で)どのように見えますか?もちろん、次のようになります。
1000: 2A 40 F0 14
1001: 2A 50 F1 27
1002: 4F 00 F0 F1
1003: C9 00 00 F2
そして、指示はやや似たような心構えから来ています。
1000: mov EAX, 20
1001: mov EBX, loc1
1002: mul EAX, EBX
1003: push ECX
それでは、C ++などのネイティブバイナリを逆コンパイルしようとする言語を考えると、何がそんなに難しいのでしょうか。すぐに頭に浮かぶ2つのアイデアは、1)バイトコードよりもはるかに複雑なこと、または2)オペレーティングシステムがプログラムをページ分割し、その断片をばらまく傾向があり、多くの問題を引き起こすという事実です。それらの可能性のいずれかが正しい場合、説明してください。しかし、いずれにせよ、基本的にこれを聞いたことがないのはなぜですか?
注意
私は答えの一つを受け入れようとしていますが、まず何かを言及したいと思います。ほとんどすべての人が、元のソースコードの異なる部分が同じマシンコードにマッピングされる可能性があるという事実に言及しています。ローカル変数名は失われ、元々使用されていたループのタイプなどはわかりません。
しかし、今述べた2つのような例は、私の目にはささいなものです。しかし、いくつかの答えは、マシンコードと元のソースの違いは、この些細なことよりもはるかに大きいと述べる傾向があります。
しかし、たとえば、ローカル変数名やループ型などに至ると、バイトコードもこの情報を失います(少なくともActionScript 3.0の場合)。私は前に逆コンパイラによってその原料のバックを引っ張ってきた、と私は本当に変数が呼び出されたかどうか気にしませんでしたstrMyLocalString:String
かloc1
。私はまだその小さなローカルスコープを調べて、それがどのように使用されているのかをそれほど問題なく見ることができました。そして、for
ループはまったく同じものですwhile
あなたがそれについて考えるなら、ループ。また、ソースをirrFuscator(secureSWFとは異なり、メンバー変数と関数名をランダム化するだけではありません)を介して実行する場合でも、特定の変数と関数を小さなクラスで分離し始めるように見えますそれらの使用方法を確認し、独自の名前を割り当てて、そこから作業します。
これが大したことであるためには、マシンコードはそれより多くの情報を失う必要があります、そして、答えのいくつかはこれに入ります。