zoukankan      html  css  js  c++  java
  • 逆向工程核心原理——第四十五章

    回调函数(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.

  • 相关阅读:
    放大图 带回弹效果
    用recyclerview实现对话(通过接口实现)
    java 问号表达式
    recyclerview的使用
    我遇到的报错信息整理
    横竖屏切换
    NOIP 2017提高组自测 奶酪
    小蝌蚪找妈妈 牛客
    牛客练习赛50 C tokitsukaze and Soldier
    洛谷P1630 求和
  • 原文地址:https://www.cnblogs.com/lex-shoukaku/p/13949033.html
Copyright © 2011-2022 走看看