web-dev-qa-db-ja.com

リバースエンジニアリングを自動化できないのはなぜですか?

私はまだコンピュータセキュリティの学位を取得しており、前学期に最初のアセンブリ言語ベースのクラスを受講しました。リバースエンジニアリングのテーマと、なぜそれがマルウェアや悪意のあるアプリケーションとの戦いの重要な部分であるかについて触れました。

私のクラスでは主にIDA proを使用しましたが、同様の無料のブラウザーベースのアプリケーションもいくつかチェックアウトしました。

これらのアプリケーションでは、命令と低レベルのコードに関する非常に多くの情報を得ることができたので、なぜそれを越えて高レベルの言語を再作成する必要があるのか​​と疑問に思っていました(「C」バージョンの作品の作成など)。マルウェアの)。

ここに私の質問:

プログラムが、アセンブリコードにある情報を使用して、自動的に単純化した言語に変換できないのはなぜですか?

最初に書かれたときとまったく同じようには見えないことを理解していますが、読みやすく、フォローしやすい方法で作成し直すことはできませんか?

それは、私が頭を包むことができないものです、ありがとう!

31

簡潔な答え

それは絶対に可能ですが、正確さと読みやすさはまったく別の問題です。 1つの明確化が必要です:リバースエンジニアリングは逆コンパイルではありません。


長い答え

リバースエンジニアリングは一般に、何か(実際には何か)を分解して、それがどのように機能するかを確認するプロセスです。 逆アセンブルは、バイナリ形式のファイルを取り、マシンコードをアセンブリコードに解釈する場合です。 Decompilingは、アセンブリコードをより高いレベルの言語に解釈しています。

あなたの質問は本当に、プログラムを自動コンパイルできないのはなぜですか?そうですね

いくつかの異なる Java Decompilers があります。 Javaアーキテクチャに依存しないため、バイトコードは完全にリバーシブルです。トリッキーになるのは、Cのような言語を逆コンパイルすることです。- Hex Rays は、Cデコンパイラを提供しますが、Cは複雑な言語です。同じタスクを実行するには、10の異なる方法があります。20行で実行できること、3行または10行で実行できることは、言語の解釈です。これにより、Cの逆コンパイルの自動化が困難になります。

もちろん、Cを最も単純な命令に逆コンパイルできます。次に、**(*var1) = 3;または(*bytecode)(param1)のような行を取得します。これらの行は、関数ポインターを呼び出すことができます。さらに悪いことに、これらはまだ解釈であることを覚えておく必要があります。それだけでは強調しきれません。解釈が間違っている場合はどうなりますか?これは逆アセンブルレベルで心配する必要があるものですが、少なくとも1つの命令の5〜6バイトに対して妥当な量の結果があります。次に、関数呼び出しまたはforループを理解するために、15〜20バイトを解釈する必要があります。逆リバースエンジニアリング技術があると、解釈がさらに困難になります。

コンテキストは大きな役割を果たします。関数ポインター、char *ポインター、uint32の違いは何ですか?使用されているコンテキストを除いて、まったく何もありません。コンパイラの最適化では、__fastcallではなく__stdcallを使用する場合があります。つまり、関数のパラメーターの場所を解釈する必要があります。スタック上またはレジスタ内のどちらですか?インライン関数、マクロ、#definesはすべて、より大きなサブルーチンの一部になります。これらのタイプのコンテキストを解釈する実際の方法はありません。

66
RoraΖ

AssemblyからCコードのようなものを自動的に再作成することは可能ですが、逆コンパイラが実行しなければならない推測作業の量は膨大です。

コンパイラは、ソースコードで複雑な変換を行う非常に複雑なものです。最適化、マクロ/プリコンパイラの置換、コードのインライン化、タイプとエラーのチェック、静的リンクなど。デコンパイラは、使用したコンパイラ、設定されたコンパイラフラグ、バージョンを推測(またはデフォルトを選択)する必要があります。コンパイルされたOS、コンパイルされたライブラリなど.

したがって、Cコードを取得してコンパイルし、逆コンパイルすると、結果はnothingのようになります。

そして、それは実行するCコードを生成するためだけのものであり、読みやすさについてはまだ触れていません。変数名、関数名などはコンパイラーによって取り除かれ、生のアドレスに置き換えられるため、通常想像しているような逆コンパイラーは、関数にA()B()C() ...とすべての変数abcは、セマンティクス(つまり、これらが表すもの)を知る方法がないためです。

一番下の行は、アセンブリの経験が少しあれば、逆コンパイルされたコードの読み取りは、生のアセンブリの読み取りよりも実際には難しいと言うでしょう。 (いくつかの例外を除いて:たとえば、Javaは実際には非常にきれいに逆コンパイルされます)。

16
Mike Ounsworth

リバースエンジニアリングを完全に自動化する論文やソフトウェアはまだ見つけていませんが、フォレンジックのように、リバースエンジニアリングの自動化に特に関心のある分野がいくつかあります分析。リバースエンジニアリングの自動化は、(少なくとも現在のところ)リバースエンジニアリングのプロセス全体を完全に自動化することを意図したものではなく、少なくとも一部の手順を実行して、ファイルシステム全体に手順をスケーリングできるようにします。これは、たとえば この記事 で説明されています。

前書き

この記事では、リバースエンジニアリング(リバースエンジニアリングオートメーション)での自動化のニーズの高まりに対処し、研究プロセスへの自動化の導入によって貴重な時間を節約し、情報の検索を支援する方法を説明します。大幅に小規模で実施されます。

また、この記事では、自動化スクリプトの例を紹介し、私のGithubアカウントからアクセスできるようにします。また、この記事にある例以外の例を追加し、プルリクエストを送信して追加できるようにしてください。

リバースエンジニアリングでオートメーションが必要なのはなぜですか?

まず第一に、リバースエンジニアリングオートメーションは調査時間を節約しますが、残りのプロセスに取って代わるものではないことを指摘することが重要だと感じています。

  1. 繰り返しの動作。
  2. プログラムの後の段階で検出される動的コードフラグメント(Crypters、Packers)。
  3. SSDTなどのソフトウェア保護のバイパス。
  4. Ollydbg内で実行されているソフトウェアのメモリの割り当て

この記事では、OlylyDBG-PythonやOllyDBG-Playtimeなどのいくつかのツールについて説明し、次に、オープンソースで here および here でも利用できるいくつかのコードスニペットについて説明します。

2
gaborous