第九章:線程局部存儲
PEB,在NT中,該結構可以從進程空間的FS:[0x30]處找到,PEB描述的信息主要包括:進程狀態、進程堆、PE映像信息等,其中Ldr記錄了進程加載進內存的所有模塊的基地址。
TLS技術:
動態線程局部存儲技術、靜態線程局部存儲技術
OS動態申請通過四個API,靜態則通過預先在PE文件中聲明數據存儲空間。
TlsAlloc函數一旦得到一個可用的索引值后,還會遍歷進程中的每個線程,并將對應的TLS存儲槽全部清0,再返回。
TlsSetValue/TlsGetValue為了速度沒有參數驗證的錯誤檢查,可以傳不是TlsAlloc返回的值作為參數。
TLS存儲槽實際對應于TEB中TlsSlot字段,用戶可以直接操作此字段
靜態線程局部存儲預先將變量定義在PE文件內部,一般使用.tls節存儲,在Visual C++中只要如下聲明
_declspec (thread) int tlsFlag = 1;
靜態線程局部存儲只有用于靜態加載,靜態連接到該DLL的其他DLL也要確保不被動態加載。
//動態TLS實例.386.model flat,stdcalloption casemap:noneinclude windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.libMAX_THREAD_COUNT equ 4;數據段.data
hTlsIndex dd ?
dwThreadID dd ?
hThreadID dd MAX_THREAD_COUNT dup(0)dwCount dd ?szBuffer db 500 dup(0)
szOut1 db '線程%d終止,用時:%d毫秒。',0
szErr1 db '讀取TLS槽數據時失敗!',0
szErr2 db '寫入TLS槽數據時失敗!',0;代碼段.code;----------
; 初始化
;----------
_initTime proc local @dwStartpushad;獲得當前時間,;將線程的創建時間與線程對象相關聯invoke GetTickCountmov @dwStart,eaxinvoke TlsSetValue,hTlsIndex,@dwStart.if eax==0invoke MessageBox,NULL,addr szErr2,\NULL,MB_OK.endifpopadret
_initTime endp;----------
; 獲取用時
;----------
_getLostTime proc local @dwTemppushad;獲得當前時間,;返回當前時間和線程創建時間的差值invoke GetTickCountmov @dwTemp,eaxinvoke TlsGetValue,hTlsIndex.if eax==0invoke MessageBox,NULL,addr szErr2,\NULL,MB_OK.endifsub @dwTemp,eaxpopadmov eax,@dwTempret
_getLostTime endp;----------
; 線程函數
;----------
_tFun proc uses ebx ecx edx esi edi,lParamlocal @dwCountlocal @tIDpushadinvoke _initTime;模擬耗時操作mov @dwCount,1000*10000mov ecx,@dwCount.while ecx>0dec @dwCountdec ecx.endw invoke GetCurrentThreadIdmov @tID,eaxinvoke _getLostTimeinvoke wsprintf,addr szBuffer,\addr szOut1,@tID,eaxinvoke MessageBox,NULL,addr szBuffer,\NULL,MB_OKpopadret
_tFun endpstart:;通過在進程位數組中申請一個索引,;初始化線程運行時間記錄系統invoke TlsAllocmov hTlsIndex,eaxmov dwCount,MAX_THREAD_COUNTmov edi,offset hThreadID.while dwCount>0invoke CreateThread,NULL,0,\offset _tFun,NULL,\NULL,addr dwThreadIDmov dword ptr [edi],eaxadd edi,4dec dwCount.endw;等待結束線程mov dwCount,MAX_THREAD_COUNTmov edi,offset hThreadID.while dwCount>0mov eax,dword ptr [edi]mov dwThreadID,eaxpush ediinvoke WaitForSingleObject,eax,\INFINITEinvoke CloseHandle,dwThreadIDpop ediadd edi,4dec dwCount.endw;通過釋放線程局部存儲索引,;釋放時間記錄系統占用的資源invoke TlsFree,hTlsIndexend start
?
//靜態TLS實例.386.model flat,stdcalloption casemap:noneinclude windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib.dataszText db 'HelloWorldPE',0,0,0,0 ; 構造IMAGE_TLS_DIRECTORYTLS_DIR dd offset Tls1dd offset Tls2dd offset Tls3dd offset TlsCallBackdd 0dd 0
Tls1 dd 0
Tls2 dd 0
Tls3 dd 0
TlsCallBack dd offset TLSdd 0dd 0.data?TLSCalled db ? ;重進標志.codestart:invoke ExitProcess,NULLRET; 以下代碼將會在.code之前執行一次
TLS:; 變量TLSCalled是一個防重進標志。正常情況下該部分代碼; 會被執行兩次,但使用了該標識后,該代碼只在開始運行前; 執行一次cmp byte ptr [TLSCalled],1je @exitmov byte ptr [TLSCalled],1invoke MessageBox,NULL,addr szText,NULL,MB_OK@exit:RETend start
靜態TLS實例生成的exe需要手動修改下數據目錄表
根據 .data節???? 800文件偏移地址?? 3000內存偏移,szText占10字節
所有TLS數據目錄起始RVA修改為3010,大小為一個TLS數據目錄大小。能170文件偏移位置修改為10 30 00 00 18 00...
總結
以上是生活随笔為你收集整理的PE学习(九)第九章:TLS 动态TLS与静态TLS的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。