前一段时间在linux上简单试了一下TLS,今天在windows平台上再看看TLS,但是今天不去观察TLS在代码中实际的效果,我只要查看生成的PE程序中TLS的状态。如下,先写一段非常简单的代码:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <stdlib.h> #include <stdio.h> int main() { __declspec (thread) static int tlsFlag = 1; printf("win tls test\n"); getchar(); } |
这里面什么都没有做,只是定义了一个变量,然后build,通过CFF查看生成的exe中的section信息:
明显可以看到,这里多了一个.tls的段,如果注释掉这一句“__declspec (thread) static int tlsFlag = 1;”呢,再build观察一下:
这里需要注意测试源文件是.c文件,如果改成.cpp后缀,直接编译上面的源码生成的结果和第二张图一模一样,都是没有.tls项,此处不太理解,why!不过我的目的不是去分析PE格式,而是要生成一个带有TLS段的exe程序,仅此而已,所以就简单了,在csdn上看到一位学习PE格式的大婶,里面提到了怎么使用TLS(稍后给出网站),所以我们简单的修改一下代码,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <stdlib.h> #include <stdio.h> #include <windows.h> #pragma comment(linker,"/INCLUDE:__tls_used") int main() { __declspec (thread) static int tlsFlag = 1; //TlsAlloc(); printf("win tls test\n"); getchar(); } |
其实只添加了一句“#pragma comment(linker,"/INCLUDE:__tls_used")”,然后再build看一下exe的信息:
很完美,section里面有.tls段,而且有TLS Directory了,这就是我要的最终exe格式,但是只有这一点还不太够用,还需要验证一下tls的工作,此处直接使用上面大婶的代码,里面有原帖的地址:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
//http://blog.csdn.net/bugmeout/article/details/45605497 // tls_test.cpp : 定义控制台应用程序的入口点。 // #include <windows.h> #include <stdio.h> #include <tchar.h> #pragma comment(linker,"/INCLUDE:__tls_used") void NTAPI tls_callback1(LPVOID dllhhanle,DWORD reason,PVOID Reserved) { printf("Tls_callback1 :dllhandle=%x,reason=%d\n",dllhhanle,reason); } void NTAPI tls_callback2(LPVOID dllhhanle,DWORD reason,PVOID Reserved) { printf("Tls_callback2 :dllhandle=%x,reason=%d\n",dllhhanle,reason); } #pragma data_seg(".CRT$XLX") PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[]={tls_callback1,tls_callback2,0}; //end with 0 #pragma data_seg() DWORD WINAPI ThreadProc(LPVOID lpParam) { printf("ThreadProc() Start\n"); printf("ThreadProc() end\n"); return 0; } int _tmain(int argc, _TCHAR* argv[]) { HANDLE hThread = NULL; printf("Main Start\n"); hThread = CreateThread(NULL,0,ThreadProc,NULL,0,NULL); WaitForSingleObject(hThread,60*1000); CloseHandle(hThread); printf("Main end\n"); return 0; } |
基本上没有动太多的脑子,因为我的需求只是验证一下带有TLS的程序在某些情况下能不能工作而已,所以直接从网上看了看资料,就直接拿过来代码用了。既然已经用了,索性将msdn给出的示例代码也转移一份,以备将来查看,这份代码只是描述了tls的正常使用,没有涉及到和PE里面对应的代码段关系,所以只是作为TLS使用参考还可以,不是本次需要的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
//https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms686991(v=vs.85).aspx #include <stdio.h> #define THREADCOUNT 4 DWORD dwTlsIndex; VOID ErrorExit(LPSTR); VOID CommonFunc(VOID) { LPVOID lpvData; // Retrieve a data pointer for the current thread. lpvData = TlsGetValue(dwTlsIndex); if ((lpvData == 0) && (GetLastError() != ERROR_SUCCESS)) ErrorExit("TlsGetValue error"); // Use the data stored for the current thread. printf("common: thread %d: lpvData=%lx\n", GetCurrentThreadId(), lpvData); Sleep(5000); } DWORD WINAPI ThreadFunc(VOID) { LPVOID lpvData; // Initialize the TLS index for this thread. lpvData = (LPVOID) LocalAlloc(LPTR, 256); if (! TlsSetValue(dwTlsIndex, lpvData)) ErrorExit("TlsSetValue error"); printf("thread %d: lpvData=%lx\n", GetCurrentThreadId(), lpvData); CommonFunc(); // Release the dynamic memory before the thread returns. lpvData = TlsGetValue(dwTlsIndex); if (lpvData != 0) LocalFree((HLOCAL) lpvData); return 0; } int main(VOID) { DWORD IDThread; HANDLE hThread[THREADCOUNT]; int i; // Allocate a TLS index. if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) ErrorExit("TlsAlloc failed"); // Create multiple threads. for (i = 0; i < THREADCOUNT; i++) { hThread[i] = CreateThread(NULL, // default security attributes 0, // use default stack size (LPTHREAD_START_ROUTINE) ThreadFunc, // thread function NULL, // no thread function argument 0, // use default creation flags &IDThread); // returns thread identifier // Check the return value for success. if (hThread[i] == NULL) ErrorExit("CreateThread error\n"); } for (i = 0; i < THREADCOUNT; i++) WaitForSingleObject(hThread[i], INFINITE); TlsFree(dwTlsIndex); return 0; } VOID ErrorExit (LPSTR lpszMessage) { fprintf(stderr, "%s\n", lpszMessage); ExitProcess(0); } |