2

ここでかなりのグーグル検索といくつかのヒントを提供した後、最終的にセグメントのレイアウトを見つけることができましたFS(TIBデータを保存するためにウィンドウで使用されます)。特に興味深いのはArbitraryUserPointer、PSDK で提供されているメンバーです。

typedef struct _NT_TIB {
    struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
    PVOID StackBase;
    PVOID StackLimit;
    PVOID SubSystemTib;
    union {
        PVOID FiberData;
        DWORD Version;
    };
    PVOID ArbitraryUserPointer;
    struct _NT_TIB *Self;
} NT_TIB;

この変数を使用することは正確にどのくらい安全ですか (Vista 以降)? x64にはまだ存在しますか?

それに続くのは、この変数へのアクセスです。私は MSVC を使用しているため、__readfsdword&__readgsqword組み込み関数にアクセスできますが、MSDNは何らかの理由でこれらを特権命令としてマークしています。

これらの組み込み関数はカーネル モードでのみ使用でき、ルーチンは組み込み関数としてのみ使用できます。

もちろん、それらはカーネルだけではありませんが、なぜそのようにマークされているのですか?ドキュメントが間違っているだけですか? (私のオフライン VS 2008 ドキュメントにはこの句がありません)。

最後に、ArbitraryUserPointerシングルを介して直接アクセスするのは安全__readfsdword(0x14)ですか、それともリニア TIB アドレスを介して使用することをお勧めしますか? (これはまだ からの読み取りが必要ですFS)。

4

2 に答える 2

4

ArbitraryUserPointer一般的な使用を目的としない内部フィールドです。オペレーティング システムが内部的に使用するため、上書きするとデータが破損します。名前が非常に悪いことは認めます。

于 2012-02-13T17:11:15.920 に答える
0

あなたがまだ答えを求めている場合、私も同じ問題を抱えていて、あなたの質問に似た質問を投稿しました:

カーネルモードでのスレッドローカルストレージ?

カーネル モード ドライバーで TLS に相当するものが必要です。正確には、ある時点 (ドライバーのディスパッチ ルーチンなど) から始まる深い関数呼び出しツリーがあり、コンテキスト情報を渡す必要があります。

私の特定のケースでは、キャッチは、永続的なストレージが必要ないということです。単一のトップレベル関数呼び出しのために、スレッド固有のプレースホルダーが必要なだけです。したがって、関数呼び出しに TLS 配列の任意のエントリを使用し、それが完了したら元の値を復元することにしました。

次の方法で TLS 配列を取得します。

DWORD* get_Tls()
{
    return (DWORD*) (__readfsdword(0x18) + 0xe10);
}

ところで、TIB が通常 の内容を読み取ることによってアクセスされる理由がわかりませんfs:[0x18]fsそれはセレクターによって指されているだけです。しかし、これはすべての MS のコードがそれにアクセスする方法であるため、私もこれを行うことにしました。

次に、任意の TLS インデックス、たとえば 0 を選択します。

const DWORD g_dwMyTlsIndex = 0;

void MyTopLevelFunc()
{
    // prolog
    DWORD dwOrgVal = get_Tls()[g_dwMyTlsIndex];
    get_Tls()[g_dwMyTlsIndex] = dwMyContextValue;

    DoSomething();

    // epilog
    get_Tls()[g_dwMyTlsIndex] = dwOrgVal;
}

void DoSomething()
{
    DWORD dwMyContext = get_Tls()[g_dwMyTlsIndex];
}
于 2012-04-01T11:49:32.317 に答える