5

.textwin32プロセスのセグメントダンプを作成するアプリケーションがあります。次に、コードを基本ブロックに分割します。基本ブロックは、常に次々に実行される一連の命令です(ジャンプは常にそのような基本ブロックの最後の命令です)。次に例を示します。

Basic block 1
    mov ecx, dword ptr [ecx]
    test ecx, ecx
    je 00401013h

Basic block 2
    mov eax, dword ptr [ecx]
    call dword ptr [eax+08h]

Basic block 3
    test eax, eax
    je 0040100Ah

Basic block 4
    mov edx, dword ptr [eax]
    push 00000001h
    mov ecx, eax
    call dword ptr [edx]

Basic block 5
    ret 000008h

ここで、そのような基本ブロックを関数にグループ化したいと思います。たとえば、どの基本ブロックが関数を形成するかを言います。アルゴリズムは何ですか?1つの関数内に多くのret命令がある可能性があることを覚えておく必要があります。機能を検出する方法はfast_call

4

3 に答える 3

6

ブロックを関数にグループ化するための最も単純なアルゴリズムは次のようになります。

  1. 呼び出し先のすべてのアドレスに注意してcall some_addressください。
  2. そのようなアドレスの後の最初のブロックが で終わるret場合、関数は終了です。
  3. ブロック内のジャンプを別のブロックなどにたどり、可能なすべての実行パスをたどり(それぞれがパスを2つに分割する条件付きジャンプについて思い出してください)、すべてのパスがret. 無限ループに入ってプログラム自体がハングしないように、ループを構成するジャンプを認識する必要があります。

問題:

  1. メモリから関数ポインタを読み取ることにより、多くの呼び出しを間接的に行うことができますcall [some_address]call some_address
  2. 計算されたアドレスに対していくつかの間接的な呼び出しを行うことができます
  3. 戻る前に他の関数を呼び出す関数は、すぐに続くjump some_addressのではなく、call some_addressret
  4. call some_addresspush some_address+ retOR push some_address+の組み合わせでシミュレートできますjmp some_other_address
  5. 一部の関数は、最後にコードを共有する場合があります (たとえば、エントリ ポイントは異なりますが、1 つ以上の出口ポイントは同じです)。

最も一般的なプロローグ命令シーケンスを探すことで、関数がどこから始まるかを判断するためにヒューリスティックを使用できます。

push ebp
mov ebp, esp

繰り返しますが、関数がフレーム ポインターを抑制してコンパイルされている場合、これは機能しない可能性があります (つまり、スタック上のパラメーターにアクセスするesp代わりに使用する可能性があります)。ebp

コンパイラ (MSVC++ など) は、関数間スペースにint 3命令を埋め込むこともできます。これも、次の関数開始のヒントとして役立ちます。

さまざまな呼び出し規約の違いについては、シンボルを見るのがおそらく最も簡単です (もちろん、シンボルがある場合)。MSVC++ は、さまざまな名前のプレフィックスとサフィックスを生成します。たとえば、次のようになります。

  • _関数 - cdecl
  • _function@number - stdcall
  • @function@number - 高速呼び出し

シンボルからこの情報を抽出できない場合は、コードを分析して、パラメーターが関数にどのように渡されるか、および関数またはその呼び出し元がそれらをスタックから削除するかどうかを確認する必要があります。

于 2013-02-07T16:53:59.937 に答える
3

の存在を使用してenter、関数の開始、またはフレームを設定する特定のコードを示すことができます。

push ebp
mov  ebp, esp
sub  esp, (bytes for "local" stack space)

leave後で、呼び出しの前に反対のコード (または) が見つかりますret

mov esp, ebp
pop ebp

ローカル スタック スペースのバイト数を使用して、ローカル変数を識別することもできます。

、 などを識別するthiscallにはfastcallcall、初期位置を使用する の直前のコードの分析と、使用/クリーンアップされたレジスタの評価が必要です。

于 2013-02-07T16:30:27.663 に答える
1

windasmやollydbgのようなソフトウェアを見てください。callandret演算は、関数呼び出しを示します。ただし、コードは順番に実行されず、ジャンプはあちこちで行うことができます。 call dword ptr [edx]edxレジスタに依存するため、ランタイムデバッグを行わない限り、どこに行くのかを知ることはできません。

fastcall関数を認識するには、パラメーターがどのように渡されるかを確認する必要があります。Fastcallは、最初の2つのポインターサイズのパラメーターをedxおよびecxレジスターに配置し、stdcallはそれらをスタックにプッシュします。説明については、この記事を参照してください。

于 2013-02-07T16:39:27.280 に答える