2017-09-21 5 views
0

Ich habe eine Assembler-Liste meiner .C-Quelldatei erstellt. Und in der C-Quelle habe ich tls wie folgt umgesetzt:MASM erkennt meinen TLS-Rückruf nicht

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"; 

I Assembler-Liste dieser C-Datei erstellt haben, und tls sehen nun wie folgt aus:

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 

Ich sehe nicht, dass die tls Muster wird jedoch erzeugt, i in IDA nachgeschlagen PRO sollte das Muster sein:

.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 

Also brauche ich ein neues tls Segment zu definieren und jene Rüttler in dort platzieren? Oder sollte es im Datenbereich sein?

ich kompilieren Sie es wie folgt aus:

ml.exe listing.asm /coff

Ich habe pro produzierte Datei in ida nachgeschlagen, und ich sehe, dass tls Verzeichnis nicht produziert wurde, wie kann ich feststellen, masm oder dessen Linker Verzeichnis erstellen?

+0

Ich kann keine Optionen für den Linker oder den Assembler finden, um das TLS-Verzeichnis zu generieren. Die schnellste Problemumgehung besteht wahrscheinlich darin, die TLS-Struktur in einem Segment (d. H. Abschnitt) abzulegen, den Linker eine Symbolzuordnung generieren zu lassen und ein Skript zu schreiben, das die Zuordnungsdatei liest und die ausführbare Datei patcht. –

+0

Versuchen Sie nie, die Assembly-Ausgabe des Microsoft C/C++ - Compilers zu assemblieren und zu verwenden. Ich weiß nicht, ob das hier der Fall ist, aber im Allgemeinen ist die vom Microsoft C/C++ - Compiler erzeugte Assembly-Ausgabe unvollständig und falsch. Ist Ihr Ziel eine Assembly oder C++ - Funktion, die als TLS-Callback aufgerufen wird? –

+0

@RossRidge zu verwenden Tls aus Assembly mit Masm – YakibutaRamen

Antwort

2

Der Microsoft-Linker verwendet das Symbol __tls_used (auf x86-Systemen) oder _tls_used (auf Nicht-x86-Systemen) als die Adresse des TLS-Verzeichnisses. Das TLS-Verzeichnis enthält einen Zeiger auf ein mit Null abgeschlossenes Array von TLS-Rückrufen. Wenn Sie also ein geeignetes TLS-Verzeichnis erstellen und ihm den Namen __tls_used/_tls_used geben, können Sie eine TLS-Callback-Funktion im Assemblercode verwenden.

Hier ist ein Beispielprogramm, das dies zeigt:

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 

Beachten Sie, dass obiger Code nicht kompatibel mit der Visual C++ Runtime (CRT) Implementierung von TLS ist. Wenn Sie planen, mit C++ - Code zu arbeiten, möchten Sie, dass der CRT das TLS-Verzeichnis und andere Informationen bereitstellt. Sie können ihm mitteilen, dass er einen Ihrer Rückrufe verwenden soll, indem Sie einen Zeiger auf die Funktion im Bereich .CRT$XL? setzen, in dem das Fragezeichen ? durch einen Buchstaben von B zu Y ersetzt wird. Wenn der Buchstabe B verwendet wird, wird er aufgerufen, bevor der CRT TLS-Rückruf aufgerufen wird. Mit einem Brief von D bis Y wird es danach aufgerufen. Der Code, den Sie möchten, wäre etwa:

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