5

ollydbg で次の数行のアセンブリを見つけました。

MOV ECX,DWORD PTR DS:[xxxxxxxx] ; xxxxxxxx is an address
MOV EDX,DWORD PTR DS:[ECX]
MOV EAX,DWORD PTR DS:[EDX+116]
CALL EAX

誰かステップスルーして、ここで何が起きているのか教えてくれませんか?

4

4 に答える 4

6

これは、構造体に格納された関数ポインターの呼び出しです。

この最初の行は、 address に格納されているポインターを取得しますDS:xxxxxxxx。角括弧は、Cと同様にアドレスの逆参照*を示します。メモリからの値がポインタとして使用されようとしています。それはレジスターに入れられecxます。

MOV ECX,DWORD PTR DS:[xxxxxxxx] ; xxxxxxxx is an address

2 行目は、上記で取得したポインターを逆参照します。その値 fromecxは、逆参照されるアドレスとして使用されるようになりました。メモリ内で見つかった値は別のポインターです。この 2 番目のポインターは、edxレジスターに配置されます。

MOV EDX,DWORD PTR DS:[ECX]

3 行目もメモリを逆参照します。今回は、上記で取得したポインタから 0x116 バイトずれたアドレスにアクセスが発生します。これは 4 で割り切れないため、この関数ポインターは C++ vtable からのものではないようです。メモリから取得した値は、今度はレジスタに格納されますeax

MOV EAX,DWORD PTR DS:[EDX+116]

最後に、 が指す関数eaxが実行されます。これは、関数ポインタを介して関数を呼び出すだけです。関数は引数を取りませんが、回答の改訂について質問がありPUSHます。このスニペットに先行する指示はありますか? それらは関数の引数になります。クエスチョン マークは、この関数が値を返す可能性があることを示しています。

CALL EAX

全体として、コード スニペットは、プラグイン ライブラリから OllyDbg への拡張関数の呼び出しのように見えます。OllyDbg ABIstructは、いくつかの関数ポインターを含むさまざまな を指定します。関数ポインターの配列もありますが、保持されたポインターに到達するための二重の間接参照 (偶数倍でアライメントされていないオフセットも) があるため、これは関数ポインターの配列または C++ ではなく、そうでedxはないと思います。structクラスの vtable。

つまり、関数ポインタを含むxxxxxxxxへのポインタへのポインタです。struct

OllyDbg ソース ファイル PlugIn.h には、いくつかの候補struct定義があります。次に例を示します。

typedef struct t_sorted {              // Descriptor of sorted table
  char           name[MAX_PATH];       // Name of table, as appears in error
  int            n;                    // Actual number of entries
  int            nmax;                 // Maximal number of entries
  int            selected;             // Index of selected entry or -1
  ulong          seladdr;              // Base address of selected entry
  int            itemsize;             // Size of single entry
  ulong          version;              // Unique version of table
  void           *data;                // Entries, sorted by address
  SORTFUNC       *sortfunc;            // Function which sorts data or NULL
  DESTFUNC       *destfunc;            // Destructor function or NULL
  int            sort;                 // Sorting criterium (column)
  int            sorted;               // Whether indexes are sorted
  int            *index;               // Indexes, sorted by criterium
  int            suppresserr;          // Suppress multiple overflow errors
} t_sorted;

これらの例は許可されており、asm スニペットは関数ポインターのポインターをNULLチェックしません。NULLしたがって、DRAWFUNCfromt_tableまたはSPECFUNCof である必要がありt_dumpます。

ヘッダー ファイルを含む小さなプロジェクトを作成し、 と を使用printf()offsetof()て、それらのいずれかが 0x116 のオフセットにあるかどうかを判断できます。

そうでなければ、OllyDbg の内部はこのスタイルで書かれていると思います。そのため、OllyDbg 内でさまざまな目的に使用されるプライベートstructな定義 (Plugin.h ファイルで公開されていない) が存在する可能性があります。


付け加えておきたいのですが、OllyDbg のソースが利用できないのは残念だと思います。そこに含まれる静的にリンクされた逆アセンブラは、ある種の ?GPL ライセンスの下にあるという印象を受けましたが、OllyDbg のソースを入手することができませんでした。

于 2010-08-10T20:34:47.657 に答える
2

アドレス xxxxxxx から 32 ビットの数値を取得し、ECX レジスタに入れます。次に、この値をアドレスとして使用し、値を読み取って EDX レジスタに入れ、最後にこの数値に 116 を加えて、そのアドレスの値を EAX に読み取ります。次に、現在 EAX に保持されているアドレスでコードの実行を開始します。そのコードが戻りオペコードに遭遇すると、call 命令の後に実行が続行されます。

これはかなり基本的な組み立てです。あなたがデバッガーでやっているのと、割り当ての期限がいつなのか不思議に思います;-)

于 2010-08-10T20:31:51.140 に答える
0

コンパイラが MSVC であるというコメントを考えると、それが仮想メソッド呼び出しであると 99% 確信しています。

MOV ECX,DWORD PTR DS:[xxxxxxxx]

クラス インスタンスへのポインタは、グローバル変数から ECX にロードされます。(注: デフォルトの __thiscall 呼び出し規約では、ECX を使用してインスタンス ポインター (別名thisポインター) を渡します)。

MOV EDX,DWORD PTR DS:[ECX]

vftable (仮想関数テーブル) ポインターは通常、クラス レイアウトの最初の項目です。ここで、ポインタが EDX にロードされます。

MOV EAX,DWORD PTR DS:[EDX+116]

テーブルのオフセット 116 (0x74) にあるメソッド ポインターが EAX に読み込まれます。各ポインターは 4 バイトであるため、これはクラスの 30 番目の仮想メソッド (116/4 + 1) です。

CALL EAX

メソッドが呼び出されます。

元の C++ では、次のようになります。

g_pObject1->method30();

仮想メソッドを含む MSVC の C++ クラスの実装について詳しくは、こちらの記事を参照してください。

于 2010-08-25T22:27:21.790 に答える
0

私が ASM (1997) をやってからしばらく経ちましたが、それでも私は i386 ASM しかやっていませんでした。

残念ながら、これらの 4 行のコードではあまりわかりません。ほとんどの場合、CPU レジスタにデータをロードして関数を呼び出すだけです。

具体的には、データまたはポインターがそのアドレスから CX レジスターにロードされているようです。次に、その値が CX から DX にコピーされます。したがって、DX にある CX のポインターの値があります。次に、DX の値に 116 のオフセットを加えた値が AX レジスタ (アキュムレータ?) にコピーされます。

次に、AX にコピーされたそのアドレスにある関数が実行されます。

于 2010-08-10T20:30:25.123 に答える