3

x86 では、呼び出し後にスタックにプッシュされるアドレスは、呼び出し命令の後の場所を指します。この命令は、x86 マシンでは可変長にすることができます。どの種類の呼び出しが使用されたかを検出する方法はありますか?

たとえば、間接呼び出し *(%eax) は FF 10 ですが、これは直接呼び出し 0x10FF10FF の一部である可能性もあります。いえ

12: ff 10                   call   *(%eax)
14: e8 fb 10 ff 10          call   10ff1114 <main+0x10ff1114>

たとえば、FF 10 が見つかった場合、E8 の 3 バイト前にあるかどうかを確認します。これで十分でしょうか? 私が考えていなかった他の隠されたトラップは何ですか?

4

2 に答える 2

3

いつもより少し情報量が多いので、少し無理が​​少なくなります。しかし、追加情報があってもそれが不可能であることを正確に示します。

追加情報は、ジャンプした場所とリターンアドレスを知ることから得られます。差が戻りアドレスの直前の dword と一致しない場合、それは直接呼び出しではありません。したがって、逆方向のデコードをいじる必要なく、比較的簡単に見つけることができます (これは一般的には不可能であり、運と経験則、およびそれを打ち負かすために特別に作成されていないコードのみであり、その場合でもジャンプが発生する可能性があります)。どこからでも、どこからでも)。

ただし、コードは次のようになります。

  push returnaddr
  mov eax, calladdr
  jmp eax ;or whatever way you like, showing a silly jump through reg for no reason
  ...
  call calladdr
returnaddr:

とにかく、検出できない方法で一致します。

したがって、それが間違いなく直接呼び出し以外のものであったかどうかを確認することしかできません。特定の方法が使用されたことを確実に知ることはできませんcall calladdr。上記のスニペットの を置き換えて、任意のパターンのように見せることは明らかに可能です。

于 2012-10-12T20:59:30.823 に答える
2

基本的に、できません。また、呼び出しを実行したことと、スタックにアドレスをプッシュしてからジャンプを実行したことの違いもわかりません。経験に基づいて推測することはできますが、完全な命令トレース (記録) を作成する何らかのエミュレーターで実際にコードを実行したことがない限り、悪意のあるコードにだまされる可能性は常にあります。

于 2012-10-12T20:32:33.493 に答える