2017-09-21 97 views
0

我已經生成了我的.C源文件的彙編列表。而在C源代碼我已經實現TLS是這樣的:MASM無法識別我的TLS回調

char *msg = "callback"; 
void NTAPI tls_callback(PVOID DllHandle, DWORD dwReason, PVOID lpVd) 
{ 
    MessageBoxA(0,msg,msg,0); 

} 

#ifdef _WIN64 
#pragma comment (linker, "/INCLUDE:_tls_used") 
#pragma comment (linker, "/INCLUDE:tls_callback_func") 
#else 
#pragma comment (linker, "/INCLUDE:__tls_used") 
#pragma comment (linker, "/INCLUDE:_tls_callback_func") 
#endif 

#ifdef _WIN64 
#pragma const_seg(".CRT$XLF") 
EXTERN_C const 
#else 
#pragma data_seg(".CRT$XLF") 
EXTERN_C 
#endif 
PIMAGE_TLS_CALLBACK tls_callback_func = tls_callback; 
#ifdef _WIN64 
#pragma const_seg() 
#else 
#pragma data_seg() 
#endif 

__declspec(thread) char *tlsData = "tls static data"; 

我公司生產的這款C文件的彙編列表,和TLS現在這個樣子:

PUBLIC [email protected] 
PUBLIC _tls_callback_func 
PUBLIC _tlsData 

_TLS SEGMENT 
_tlsData 
    DB 00H 
    DB 00H 
    DB 00H 
    DB 00H 
    DB 00H 
    DB 40H 
    DB 30H 
    DB 80H 
_TLS ENDS 
CRT$XLF SEGMENT 
_tls_callback_func DD FLAT:[email protected] 
CRT$XLF ENDS 


_TEXT SEGMENT 
_DllHandle$ = 8      ; size = 4 
_dwReason$ = 12      ; size = 4 
_lpVd$ = 16      ; size = 4 
[email protected] PROC     ; COMDAT 

    push ebp 
    mov ebp, esp 

    mov edx, DWORD PTR _msg 

    push 0 
    push edx 
    push edx 
    push 0 
    call DWORD PTR [email protected] 
; Line 34 
    pop ebp 
    ret 12     ; 0000000cH 
[email protected] ENDP 
_TEXT ENDS 

我不明白的是,然而TLS模式產生的,我在IDA擡頭PRO模式應該是:

.rdata:004921A8 __tls_used  dd offset __tls_start 
.rdata:004921AC TlsEnd_ptr  dd offset __tls_end 
.rdata:004921B0 TlsIndex_ptr dd offset __tls_index 
.rdata:004921B4 TlsCallbacks_ptr dd offset _tls_callback_func 
.rdata:004921B8 TlsSizeOfZeroFill dd 0 
.rdata:004921BC TlsCharacteristics dd 100000h 

那麼,我需要定義一個新的TLS段,並把這些行話在那裏?或者它應該在數據部分?

我編譯它是這樣的:

ml.exe listing.asm /coff

我已經看過了內部國際開發協會專業生產文件,我看到TLS目錄並沒有產生可言,我怎麼告訴MASM或其鏈接製作目錄?

+0

我無法找到鏈接器或彙編程序生成TLS目錄的任何選項。可能最快的解決方法是將TLS結構放在某個段(即段)中,讓鏈接器生成一個符號映射並編寫一個腳本來讀取映射文件並修補可執行文件。 –

+0

千萬不要嘗試裝配和使用Microsoft C/C++編譯器的彙編輸出。我不知道這是否是這種情況,但通常由Microsoft C/C++編譯器生成的程序集輸出不完整且不正確。你的目標是擁有一個稱爲TLS回調的程序集或C++函數嗎? –

+0

@RossRidge從程序集中使用tls使用masm – YakibutaRamen

回答

2

Microsoft鏈接器使用符號__tls_used(在x86系統上)或_tls_used(在非x86系統上)作爲TLS目錄的地址。 TLS目錄包含一個指向零終止的TLS回調數組的指針。因此,通過創建合適的TLS目錄併爲其命名__tls_used/_tls_used,您可以在彙編代碼中使用TLS回調函數。

下面是一個例子程序演示此:

PUBLIC __tls_used 
    PUBLIC start 

    EXTERN [email protected]:DWORD, [email protected]:DWORD, [email protected]:DWORD 

_BSS SEGMENT PUBLIC DWORD FLAT 
tls_index DD ? 
_BSS ENDS 

_RDATA SEGMENT PUBLIC PARA FLAT ALIAS('.rdata') READ 

__tls_used: 
    DD OFFSET tls_start 
    DD OFFSET tls_end 
    DD OFFSET tls_index 
    DD OFFSET tls_callbacks 
    DD tls_bss_end - tls_end 
    DD 0 ; chracterstics 

tls_callbacks: 
    DD OFFSET tls_callback 
    DD 0 

main_msg: 
    DB "Main entry called.", 13, 10 
main_msg_len = $ - main_msg 

_RDATA ENDS 

_DATA SEGMENT PUBLIC FLAT 
tls_cb_msg: 
    DB "TLS callback called. Reason: 0", 13, 10 
tls_cb_msg_len = $ - tls_cb_msg 
_DATA ENDS 


_TLS SEGMENT PUBLIC DWORD FLAT ALIAS('.tls') 
tls_start: 
    ; put initialized TLS variable definitions here 
tls_end: 
    ; put uninitialized TLS variable definitions here 
tls_bss_end: 
_TLS ENDS 

_TEXT SEGMENT PUBLIC PARA 'CODE' FLAT 
    ASSUME DS:FLAT 

tls_callback: 
    mov eax, [esp + 8] 
    add BYTE PTR [tls_cb_msg + tls_cb_msg_len - 3], al 

    push -11 ; nStdHandle 
    call [[email protected]] 

    push 0 ; lpOverlapped 
    push 0 ; lpNumberOfBytesWritten 
    pushd tls_cb_msg_len ; nNumberOfBytesToWrite 
    push tls_cb_msg ; lpBuffer 
    push eax ; hFile 
    call [[email protected]] 
    ret 12 

start: 
    push -11 ; nStdHandle 
    call [[email protected]] 

    push 0 ; lpOverlapped 
    push 0 ; lpNumberOfBytesWritten 
    pushd main_msg_len ; nNumberOfBytesToWrite 
    push main_msg ; lpBuffer 
    push eax ; hFile 
    call [[email protected]] 

    push 0 ; uExitCode 
    call [[email protected]] 
    int 3 

_TEXT ENDS 

    END start 

注意,上面的碼不與Visual C++運行時(CRT)實現TLS的兼容。如果您打算使用C++代碼,那麼您需要讓CRT提供TLS目錄和其他信息。您可以通過將指針指向.CRT$XL?部分中的功能指針,使用BY之間的一個字母替換問號?,從而指示您使用其中一個回調。使用字母B將導致它在調用CRT TLS回調之前被調用。使用從DY的信函將在後面調用。所以你想要的代碼會是這樣的:

_CRT SEGMENT PUBLIC DWORD ALIAS('.CRT$XLD') 
    DD OFFSET my_tls_callback 
_CRT ENDS