• 逆向工程核心原理——第四十五章


    回调函数(TLS)

    若在编程中启用了TLS功能,PE头文件中就会设置一个TLS表(TLS Table)。

    (IMAGE_NT_HEADERS-IMAGE_OPTIONAL_HEADER-IMAGE_DATA_DIRECTORY[9]))

    我们可以看到TLS回调函数的定义:

    启动参数DllHandle为句柄,参数reason为调用函数的原因。

    我们通过一个实验,来准确理解这四种状态。

    TlsTest.exe

    #include <windows.h>
    #include<iostream>
    
    //告知连接器使用TLS
    #pragma comment(linker, "/INCLUDE:__tls_used")
    
    void print_console(char* szMsg)
    {
        HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
        //先于主线程调用执行的TLS回调函数中使用printf可能会发生Runtime Error,可直接调用WriteConsole API
        WriteConsoleA(hStdout, szMsg, strlen(szMsg), NULL, NULL);
    }
    
    void NTAPI TLS_CALLBACK1(PVOID DllHandle, DWORD Reason, PVOID Reserved)
    {
        char szMsg[80] = { 0, };
        wsprintfA(szMsg, "TLS_CALLBACK1() : DllHandle = %X, Reason = %d
    ", DllHandle, Reason);
        print_console(szMsg);
    }
    
    void NTAPI TLS_CALLBACK2(PVOID DllHandle, DWORD Reason, PVOID Reserved)
    {
        char szMsg[80] = { 0, };
        wsprintfA(szMsg, "TLS_CALLBACK2() : DllHandle = %X, Reason = %d
    ", DllHandle, Reason);
        print_console(szMsg);
    }
    /*
        注册TLS函数
        .CRT$XLX的作用
        CRT表示使用C Runtime 机制
        X表示表示名随机
        L表示TLS Callback section
        X也可以换成B~Y任意一个字符
    */
    #pragma data_seg(".CRT$XLX")
    //存储回调函数地址
    PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1, TLS_CALLBACK2, 0 };
    #pragma data_seg()
    
    DWORD WINAPI ThreadProc(LPVOID lParam)
    {
        print_console("ThreadProc() start
    ");
    
        print_console("ThreadProc() end
    ");
    
        return 0;
    }
    
    int main(void)
    {
        HANDLE hThread = NULL;
    
        print_console("main() start
    ");
        //创建子线程
        hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
        //等待子线程结束
        WaitForSingleObject(hThread, 60 * 1000);
        CloseHandle(hThread);
    
        print_console("main() end
    ");
    
        return 0;
    }
    

    运行结果为:

    *注:编译时请选择Debug版本,否则程序只会运行main函数中的内容。

    通过上面实验我们可以发现:

    1.当进程的主程序调用main()前,已注册的TLS回调函数会被调用执行,此时Reason的值为1.

    2.当所有TLS回调函数完成调用后,main()函数开始调用执行,创建用户进程前,TLS会再次被调用,此时Reason为2.

    3.等Threadproc()线程函数执行结束后,TLS会被再次执行,Reason为3。

    4.当main()函数结束时,TLS回再次调用,此时Reason为0.

  • 相关阅读:
    c#命名空间
    MUTC 2 B Meeting point1 二分
    高斯消元模板
    MUTC 2 C Meeting point2 切比雪夫距离orz
    MUTC 2 E Save the dwarfs DP?
    Uva 10859 Placing Lampposts 树形dp
    Uva 11552 Fewest Flops 字符串dp
    Uva 10891 Game of Sum dp博弈
    MUTC 2 D Matrix 并查集
    Uva 1456 Cellular Network 概率dp
  • 原文地址:https://www.cnblogs.com/lex-shoukaku/p/13949033.html
Copyright © 2020-2023  润新知