2017-09-21 70 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