2013-02-07 15 views
5

私は.text win32プロセスのセグメントダンプを作成するアプリケーションを持っています。次に、コードを基本ブロックに分割します。基本ブロックは、常に次々と実行される命令のセットです(ジャンプは常にそのような基本ブロックの最後の命令です)。ここでは例を示します:逆アセンブルされたCコードを関数に分割する方法は?

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の機能を検出するには?

答えて

6

だろう関数にブロックをグループ化するための最も簡単なアルゴリズム:

  1. ノートすべてのアドレス、あなたがしているようなアドレスの後の最初のブロックがretで終わる場合call some_address指示
  2. で作られて呼び出すに関数で完了した場合はelse
  3. ブロック内のジャンプを別のブロックに従ってください。実行可能なすべての実行パス(条件付きジャンプについては、パスが2つに分割されていることを覚えておいてください) retで終了しました。

    1. 呼び出しの数がメモリから関数ポインタを読むことによって、間接的に行うことができます:あなたのプログラム自体が

    問題無限ループを入力することで、ハングしないようにするには、ループを整理ジャンプを認識する必要があります、例えばあなたはcall [some_address]代わり

  4. call some_addressのいくつかの間接呼び出しを組み合わせてシミュレーションすることができる計算アドレスに代わり、直ちにret
  5. call some_address続いcall some_addressjump some_addressを有していてもよく返す前に他の関数を呼び出す
  6. 機能を行うことができる必要があるだろうpush some_address + ret OR push some_address + jmp some_other_address
  7. 一部の機能は、(例えば、それらが異なるエントリポイントを持っていますが、一つ以上の出口点が同じである)、その末尾にコードを共有することがあり

あなたは関数は、最も一般的なプロローグ命令シーケンスを探して開始場所を決定するためにいくつかのヒューリスティックを使用してもよい。

再び
push ebp 
mov ebp, esp 

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

コンパイラ(例えば、MSVC++)は、関数間のスペースをint 3命令で埋めることもでき、今後の関数の開始のヒントとしても役立ちます。

さまざまな呼び出し規約を区別するために、シンボルを表示するのが最も簡単です(もちろん、それがある場合)。 MSVC++ generates different name prefixes and suffixes, e.g.

  • _function - CDECL
  • _functionの@数 - 関数@数@
  • をSTDCALL - fastcall

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

3

enterの存在を使用して、関数の先頭を示すことができます(certain code which sets up a frame)。

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

後で、retへの呼び出しの前に反対のコード(またはleave)を見つけることができます:

mov esp, ebp 
pop ebp 

また、ローカル変数を識別するために、ローカルスタック領域のバイト数を使用することができます。

Identifying thiscall, fastcallなどは、初期位置を使用するcallの直前のコードの分析と、使用/消去されたレジスタの評価を行います。

1

windasmやollydbgのようなソフトウェアを見てください。 callおよびret操作は、関数呼び出しを示します。しかし、コードは順番に実行されず、ジャンプはどこにでも行えます。 call dword ptr [edx]はedxレジスタに依存するため、実行時のデバッグを行わない限り、どこに行くのかわからなくなります。

ファストコール機能を認識するには、パラメータの受け渡し方法を確認する必要があります。 Fastcallは最初の2つのポインタサイズのパラメータをedxとecxレジスタに入れます。ここでstdcallはそれらをスタックにプッシュします。説明はthis articleを参照してください。

関連する問題