ええ、はい、方法はありますが、あなたはそれを気に入らないでしょう。(どうやら、私はこのような免責事項が必要です。それ以外の点では完全に役立つコメントが、非常に知識が豊富であるが、それほど寛容ではない「シニア」SOメンバーによって反対票を投じられるのを防ぐためです。)
参考:以下の説明は、Delphi5が最新で最高だったときに実際に書いたコードの概要です。それ以来、そのコードは新しいDelphiバージョン(現在はDelphi 2010まで)に移植され、引き続き機能します。
手始めに、クラスはVMTとそれに付随する関数(およびコンパイラのバージョンと設定によっては、いくつかのtype-info)の組み合わせにすぎないことを知っておく必要があります。ご存知かもしれませんが、TClassタイプで識別されるクラスは、そのクラスのVMTのメモリアドレスへのポインタにすぎません。言い換えると、クラスのVMTのアドレスがわかっている場合は、それもTClassポインターです。
その知識をしっかりと頭に入れておけば、実行可能メモリを実際にスキャンして、アドレステストごとにVMTのように見えるかどうかをテストできます。VMTのように見えるすべてのアドレスをリストに追加すると、実行可能ファイルに含まれるすべてのクラスの完全な概要が得られます。(実際には、これにより、ユニットの実装セクションでのみ宣言されたクラス、およびバイナリとして配布されているコンポーネントとライブラリからリンクされたクラスにアクセスすることもできます!)
確かに、一部のアドレスは有効なVMTのように見えますが、実際にはランダムな他のデータ(またはコード)であるというリスクがあります-しかし、私が思いついたテストでは、これはまだ私には起こりませんでした(約6年このコードを10を超えるアクティブに保守されているアプリケーションで実行する)。
だからここにあなたがしなければならないチェックがあります(この正確な順序で!):
- アドレスはTObjectのアドレスと同じですか?もしそうなら、このアドレスはVMTであり、これで完了です。
- TClass(address).ClassInfo;を読み取ります。割り当てられている場合:
- それはコードセグメント内にあるはずです(いいえ、それについては詳しく説明しません-グーグルで検索してください)
- このClassInfoの最後のバイト(SizeOf(TTypeInfo)+ SizeOf(TTypeData)を追加することによって決定される)も、そのコードセグメント内にある必要があります
- このClassInfo(タイプPTypeInfo)では、KindフィールドをtkClassに設定する必要があります
- このClassInfoでGetTypeDataを呼び出すと、PTypeDataが生成されます
- これも有効なコードセグメントに含まれる必要があります
- 最後のバイト(SizeOf(TTypeData)を追加することで決定)もそのコードセグメント内にある必要があります
- このTypeDataのうち、ClassTypeフィールドはテスト対象のアドレスと同じである必要があります。
- 次に、オフセットvmtSelfPtrでVMTを読み取り、これによってアドレスがテストされるかどうかをテストします(それ自体を指す必要があります)
- vmtClassNameを読み取り、それが有効なクラス名を指しているかどうかを確認します(ポインターが有効なセグメントに存在することを再度確認し、文字列の長さが許容可能であり、IsValidIdentがTrueを返す必要があることを確認します)
- vmtParentを読む-有効なコードセグメントにも含まれる必要があります
- TClassにキャストし、ClassParentを読み取ります。これも有効なコードセグメントに含まれるはずです。
- vmtInstanceSizeを読み取ります。これは、> =TObject.InstanceSizeおよび<=MAX_INSTANCE_SIZE(自分で決定)である必要があります。
- ClassParentからvmtInstanceSizeを読み取ります。また、> = TObject.InstanceSizeおよび<=以前に読み取ったインスタンスサイズである必要があります(親クラスが子クラスより大きくなることはありません)
- オプションで、インデックス0以降のすべてのVMTエントリが有効なコードポインタであるかどうかを確認できます(ただし、VMTのエントリ数を決定するのは少し問題があります...これを示すインジケータはありません)。
- ClassParentを使用してこれらのチェックを繰り返します。(これは上記のTObjectテストに到達するか、惨めに失敗するはずです!)
これらのチェックがすべて当てはまる場合、テストアドレスは有効なVMTであり(私に関する限り)、リストに追加できます。
これをすべて実装して頑張ってください。これを正しく行うのに約1週間かかりました。
それがあなたのためにどのようにうまくいくか教えてください。乾杯!