MASM 无法识别我的 TLS 回调
MASM doesn't recognize my TLS callback
我已经生成了我的 .C
源文件的汇编程序列表。在 C 源代码中,我已经实现了这样的 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 _tls_callback@12
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:_tls_callback@12
CRT$XLF ENDS
_TEXT SEGMENT
_DllHandle$ = 8 ; size = 4
_dwReason$ = 12 ; size = 4
_lpVd$ = 16 ; size = 4
_tls_callback@12 PROC ; COMDAT
push ebp
mov ebp, esp
mov edx, DWORD PTR _msg
push 0
push edx
push edx
push 0
call DWORD PTR __imp__MessageBoxA@16
; Line 34
pop ebp
ret 12 ; 0000000cH
_tls_callback@12 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
我在 ida pro 中查找了生成的文件,我发现根本没有生成 tls 目录,我如何告诉 masm 或其链接器生成目录?
Microsoft 链接器使用符号 __tls_used
(在 x86 系统上)或 _tls_used
(在非 x86 系统上)作为 TLS 目录的地址。 TLS 目录包含指向 TLS 回调的零终止数组的指针。因此,通过创建合适的 TLS 目录并将其命名为 __tls_used
/_tls_used
,您可以在汇编代码中拥有 TLS 回调函数。
下面是一个演示这个的示例程序:
PUBLIC __tls_used
PUBLIC start
EXTERN __imp__GetStdHandle@4:DWORD, __imp__WriteFile@20:DWORD, __imp__ExitProcess@4: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 [__imp__GetStdHandle@4]
push 0 ; lpOverlapped
push 0 ; lpNumberOfBytesWritten
pushd tls_cb_msg_len ; nNumberOfBytesToWrite
push tls_cb_msg ; lpBuffer
push eax ; hFile
call [__imp__WriteFile@20]
ret 12
start:
push -11 ; nStdHandle
call [__imp__GetStdHandle@4]
push 0 ; lpOverlapped
push 0 ; lpNumberOfBytesWritten
pushd main_msg_len ; nNumberOfBytesToWrite
push main_msg ; lpBuffer
push eax ; hFile
call [__imp__WriteFile@20]
push 0 ; uExitCode
call [__imp__ExitProcess@4]
int 3
_TEXT ENDS
END start
请注意,以上代码与 TLS 的 Visual C++ 运行时 (CRT) 实现不兼容。如果您计划使用 C++ 代码,那么您会希望让 CRT 提供 TLS 目录和其他信息。您可以通过在 .CRT$XL?
部分放置一个指向函数的指针来告诉它使用您的回调之一,其中问号 ?
被从 B
到 [=19= 的字母替换].使用字母 B
将导致在调用 CRT TLS 回调之前调用它。使用从 D
到 Y
的字母将在之后调用它。所以你想要的代码应该是这样的:
_CRT SEGMENT PUBLIC DWORD ALIAS('.CRT$XLD')
DD OFFSET my_tls_callback
_CRT ENDS
我已经生成了我的 .C
源文件的汇编程序列表。在 C 源代码中,我已经实现了这样的 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 _tls_callback@12
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:_tls_callback@12
CRT$XLF ENDS
_TEXT SEGMENT
_DllHandle$ = 8 ; size = 4
_dwReason$ = 12 ; size = 4
_lpVd$ = 16 ; size = 4
_tls_callback@12 PROC ; COMDAT
push ebp
mov ebp, esp
mov edx, DWORD PTR _msg
push 0
push edx
push edx
push 0
call DWORD PTR __imp__MessageBoxA@16
; Line 34
pop ebp
ret 12 ; 0000000cH
_tls_callback@12 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
我在 ida pro 中查找了生成的文件,我发现根本没有生成 tls 目录,我如何告诉 masm 或其链接器生成目录?
Microsoft 链接器使用符号 __tls_used
(在 x86 系统上)或 _tls_used
(在非 x86 系统上)作为 TLS 目录的地址。 TLS 目录包含指向 TLS 回调的零终止数组的指针。因此,通过创建合适的 TLS 目录并将其命名为 __tls_used
/_tls_used
,您可以在汇编代码中拥有 TLS 回调函数。
下面是一个演示这个的示例程序:
PUBLIC __tls_used
PUBLIC start
EXTERN __imp__GetStdHandle@4:DWORD, __imp__WriteFile@20:DWORD, __imp__ExitProcess@4: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 [__imp__GetStdHandle@4]
push 0 ; lpOverlapped
push 0 ; lpNumberOfBytesWritten
pushd tls_cb_msg_len ; nNumberOfBytesToWrite
push tls_cb_msg ; lpBuffer
push eax ; hFile
call [__imp__WriteFile@20]
ret 12
start:
push -11 ; nStdHandle
call [__imp__GetStdHandle@4]
push 0 ; lpOverlapped
push 0 ; lpNumberOfBytesWritten
pushd main_msg_len ; nNumberOfBytesToWrite
push main_msg ; lpBuffer
push eax ; hFile
call [__imp__WriteFile@20]
push 0 ; uExitCode
call [__imp__ExitProcess@4]
int 3
_TEXT ENDS
END start
请注意,以上代码与 TLS 的 Visual C++ 运行时 (CRT) 实现不兼容。如果您计划使用 C++ 代码,那么您会希望让 CRT 提供 TLS 目录和其他信息。您可以通过在 .CRT$XL?
部分放置一个指向函数的指针来告诉它使用您的回调之一,其中问号 ?
被从 B
到 [=19= 的字母替换].使用字母 B
将导致在调用 CRT TLS 回调之前调用它。使用从 D
到 Y
的字母将在之后调用它。所以你想要的代码应该是这样的:
_CRT SEGMENT PUBLIC DWORD ALIAS('.CRT$XLD')
DD OFFSET my_tls_callback
_CRT ENDS