zoukankan      html  css  js  c++  java
  • 线程本地存储tls

    1.动态tls介绍

    windows为每个进程分配一组线程本地存储的标记. 至少有64个标记,如果程序使用超过了64个将动态增长.

    这些标记有2种状态: free和inuse. 所有标记的状态对该进程中所有线程都是可见的.

    程序中每个线程会对应每个标记一个slot,这个slot是个lpvoid的值

    程序通过调用DWORD TlsAlloc(void) 来获取一个free状态的索引,并遍历该进程所有线程对其slot赋值为0,然后每个线程就可以通过

    这个标记值(该标记的索引dword),来对自己的slot赋值,索引是每个线程可见的,但是每个线程自己的slot是只有自己可见的,这个slot就可以

    理解为线程本地存储.

    每个线程可以通过下面的函数对自己的slot赋值:

    BOOL
    WINAPI
    TlsSetValue(
    _In_ DWORD dwTlsIndex,  //标记的索引值
    _In_opt_ LPVOID lpTlsValue  //给slot赋的值
    )

    或者获取slot的值:

    LPVOID    //返回slot的值
    WINAPI
    TlsGetValue(
    _In_ DWORD dwTlsIndex   //标记的索引值
    )

    所以一般用slot来存储指针

    前面说过,标记对所有线程可见,如果有任何线程通过下面函数来释放标记,那么所有线程的对应于该标记的slot值将不可用

    BOOL
    WINAPI
    TlsFree(
    _In_ DWORD dwTlsIndex //标记的索引值
    )

    2.测试代码

    DWORD threadProc(LPVOID param)
    {
        DWORD index = *(DWORD*)param;
        printf("tls1 [%d] value is %s
    ", index, (char*)TlsGetValue(index));
        TlsSetValue(index, "thread");
        printf("tls2 [%d] value is %s
    ", index, (char*)TlsGetValue(index));
        return 0;
    }
    int main()
    {
        DWORD index;
        index=TlsAlloc();
        TlsSetValue(index, "tls");
        printf("main1 tls value is %s
    ", (char*)TlsGetValue(index));
        CreateThread(0, 0, (LPTHREAD_START_ROUTINE)threadProc, &index, 0, 0);
        Sleep(100);
        printf("main2 tls value is %s
    ", (char*)TlsGetValue(index));
        DWORD ret = TlsFree(index);
        system("pause");
        return 0;
    }

    执行结果:

    main1 tls value is tls
    tls1 [1] value is (null)
    tls2 [1] value is thread
    main2 tls value is tls
    请按任意键继续. . .

    3.tls回调函数及静态TLS

    tls回调函数会在线程创建和销毁时执行,因此可以用于反调试和软件加密解密

    使用链接指令:#pragma comment(linker,"/include:__tls_used") 开启tls节

    通过#pragma data_seg(".CRT$XLX")将回调函数填入tls节区中

    #pragma data_seg(".CRT$XLX")
    PIMAGE_TLS_CALLBACK callbacks[] = { callback1 ,callback2 ,0 };
    #pragma data_seg()

    回调函数原型:

    void NTAPI callback1(PVOID hmodule, DWORD reason, PVOID reserved);

  • 相关阅读:
    通过java代码获取jvm信息和系统信息
    java cp与java jar的区别
    vue下实现WebRTC
    MANIFEST.MF文件详解
    element 前端排序 与 后端排序
    JAVA获取CPUID、主板序列号、硬盘序列号、MAC地址(自己验证过)
    PHP常用代码大全
    程序员从初级到中级10个秘诀
    移动平台还有哪些创业机会
    程序员招聘:如何识别真正的程序员
  • 原文地址:https://www.cnblogs.com/freesec/p/6571674.html
Copyright © 2011-2022 走看看