2017-09-21 19 views
0

.C 소스 파일의 어셈블러 목록을 작성했습니다.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는 지금과 같이 : 그리고 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 패턴은 내가 패턴이해야 PRO IDA에서 보았다, 그러나 생성됩니다

.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 세그먼트를 정의하고 거기에 그 재잘을 배치해야합니까? 아니면 데이터 섹션에 있어야합니까? 나는 프로 IDA 내부에서 생성 된 파일을 보았다

ml.exe listing.asm /coff

, 나는 TLS 디렉토리가 모두, 내가 MASM 또는 링커에게 어떻게 생산되지 않았 음을 참조하십시오

나는 이런 식으로 컴파일 디렉토리를 만드시겠습니까?

+0

TLS 디렉토리를 생성하는 링커 또는 어셈블러 옵션을 찾을 수 없습니다. 아마도 가장 빠른 해결 방법은 TLS 구조를 일부 세그먼트 (즉, 섹션)에 배치하고 링커가 심볼 맵을 생성하고 맵 파일을 읽고 스크립트를 실행 파일에 패치하도록 코드하는 것입니다. –

+0

Microsoft C/C++ 컴파일러의 어셈블리 출력을 어셈블 및 사용하지 마십시오. 여기에 해당되는지는 모르겠지만 일반적으로 Microsoft C/C++ 컴파일러에서 생성 된 어셈블리 출력은 불완전하고 올바르지 않습니다. TLS 콜백이라고하는 어셈블리 또는 C++ 함수를 사용 하시겠습니까? –

+0

@RossRidge가 masm을 사용하여 어셈블리에서 tls를 사용하는 방법 – YakibutaRamen

답변

2

Microsoft 링커는 __tls_used (x86 시스템) 또는 _tls_used (비 x86 시스템)을 TLS 디렉토리의 주소로 사용합니다. TLS 디렉토리에는 TLS 콜백의 0으로 종단 된 배열에 대한 포인터가 포함됩니다. 따라서 적절한 TLS 디렉터리를 만들고 이름을 __tls_used/_tls_used으로 지정하면 어셈블리 코드에서 TLS 콜백 함수를 사용할 수 있습니다. 위의 코드는 TLS의 비주얼 C++ 런타임 (CRT) 구현과 호환되지 않기 때문입니다

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 

참고 :

다음은이 방법을 보여줍니다 예제 프로그램입니다. C++ 코드로 작업하려는 경우 CRT가 TLS 디렉토리 및 기타 정보를 제공하도록 할 수 있습니다. .CRT$XL? 섹션에 함수 포인터를 넣으면 ?B에서 Y까지의 문자로 바뀌는 콜백 중 하나를 사용할 수 있습니다. B 문자를 사용하면 CRT TLS 콜백이 호출되기 전에 호출됩니다. D에서 Y까지의 문자를 사용하면 이후에 호출됩니다. 따라서 원하는 코드는 다음과 같습니다.

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