【问题标题】:TIB Custom StorageTIB 自定义存储
【发布时间】:2013-01-15 16:55:43
【问题描述】:

经过相当多的谷歌搜索和here 的一些提示,我终于设法找到了FS 段的find a layout(Windows 用来存储TIB 数据)。我特别感兴趣的是 PSDK 中提供的ArbitraryUserPointer 成员:

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 文档没有这个子句)。

最后,通过单个__readfsdword(0x14) 直接访问ArbitraryUserPointer 是否安全,或者更喜欢通过线性TIB 地址使用它? (这仍然需要阅读FS)。

【问题讨论】:

    标签: windows low-level memory-segmentation


    【解决方案1】:

    ArbitraryUserPointer 是一个不供一般使用的内部字段。操作系统在内部使用它,如果你覆盖它,你会损坏东西。我承认它的名字很糟糕。

    【讨论】:

    • 嗯,这令人失望,尤其是因为旧的 MSVC 文章已将其标记为应用程序托管。是否有任何文档说明哪些成员是应用程序管理的还是操作系统管理的?我基本上是在寻找隐藏不基于 TLS 的指针的地方
    • TLS 是我能想到的 TEB 中唯一可以让应用程序免费使用的东西。 (如果有其他类似ArbitraryUserPointer 的东西,两个 DLL 将如何协商控制它?)
    • 我根本无法劫持 SEH/堆栈安全令牌? (我可以保证我不会有任何 SEH/安全令牌用于我想要使用它的目的)。除此之外,我想我会坚持使用__declspec(thread) 来获取我的单线程数据...
    • TLS 是支持创建每个线程数据的方式。你没有给出任何不能使用它的理由。
    • 您可以将 TLS 插槽号放在具有众所周知名称的全局变量中。调试器可以读取该变量的值来了解槽号。
    【解决方案2】:

    如果您仍然需要答案,我也遇到了同样的问题并发布了我的问题,类似于您的问题:

    Thread-local storage in kernel mode?

    我需要内核模式驱动程序中的 TLS 等效项。确切地说,我有一个源自某个点的深层函数调用树(例如驱动程序的调度例程),我需要传递上下文信息。

    在我的具体情况下,我不需要持久存储,我只需要一个特定于线程的占位符,用于单个顶级函数调用。因此,我决定使用 TLS 数组中的任意条目进行函数调用,并在完成后 - 恢复其原始值。

    您可以通过以下方式获取 TLS 数组:

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

    顺便说一句,我不知道为什么通常通过阅读fs:[0x18] 的内容来访问 TIB。它只是由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];
    }
    

    【讨论】:

    • 在我问这个问题之前我正在使用它,我的问题是我需要不依赖 TLS 的持久存储,所以现在我使用虚拟 __declspec(thread) vars
    猜你喜欢
    • 1970-01-01
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 2021-10-23
    • 2013-02-17
    • 2013-03-16
    • 2020-06-12
    • 1970-01-01
    相关资源
    最近更新 更多