Einzelnen Beitrag anzeigen

Olli
(Gast)

n/a Beiträge
 
#21

Re: AV bei LookupAccountSidW

  Alt 9. Aug 2007, 02:18
Hier mal etwas menschenlesbarer
Code:
.text:7C924CE1 ; int __stdcall RtlCopyUnicodeString(PUNICODE_STRING DestinationString,PUNICODE_STRING SourceString)
.text:7C924CE1                 public _RtlCopyUnicodeString@8
.text:7C924CE1 _RtlCopyUnicodeString@8 proc near      ; CODE XREF: RtlConvertSidToUnicodeString(x,x,x)+158p
.text:7C924CE1                                         ; LdrLoadAlternateResourceModule(x,x)+34A22p ...
.text:7C924CE1
.text:7C924CE1 DestinationString= dword ptr 8
.text:7C924CE1 SourceString   = dword ptr 0Ch
.text:7C924CE1
.text:7C924CE1 ; FUNCTION CHUNK AT .text:7C934947 SIZE 00000014 BYTES
.text:7C924CE1
.text:7C924CE1                 mov    edi, edi
.text:7C924CE3                 push   ebp
.text:7C924CE4                 mov    ebp, esp
.text:7C924CE6                 mov    eax, [ebp+SourceString]
.text:7C924CE9                 test   eax, eax       ; Test pointer
.text:7C924CEB                jz     BailOut01
.text:7C924CF1                 mov    edx, [ebp+DestinationString]
.text:7C924CF4 ; CX = DestinationString.MaximumLength
[color=blue].text:7C924CF4                 mov    cx, [edx+UNICODE_STRING.MaximumLength][/color]
.text:7C924CF8                 push   ebx
.text:7C924CF9                 push   esi
.text:7C924CFA ; ESI = SourceString.Buffer
.text:7C924CFA                mov    esi, [eax+UNICODE_STRING.Buffer]
.text:7C924CFD ; EAX = SourceString.Length
.text:7C924CFD                movzx  eax, [eax+UNICODE_STRING.Length]
.text:7C924D00 ; if(AX > CX) ...
.text:7C924D00                 cmp    ax, cx         ; Does it fit?
.text:7C924D03                 push   edi
[color=red].text:7C924D04                 mov    edi, [edx+UNICODE_STRING.Buffer][/color]
.text:7C924D07                 mov    [ebp+DestinationString], edi ; "Misuse" the stack location ;)
.text:7C924D0A                ja     TruncateToMaxLength
.text:7C924D10
.text:7C924D10 BackFromTruncate:                      ; CODE XREF: RtlCopyUnicodeString(x,x)+FC69j
.text:7C924D10                 mov    ecx, eax       ; EAX contains number of bytes
.text:7C924D12                 mov    ebx, ecx       ; Save for later (ECX gets decremented)
.text:7C924D14                 shr    ecx, 2          ; Divide by sizeof(DWORD)
.text:7C924D17 ; Now store either the Length of SourceString or MaxLength
.text:7C924D17 ; of DestinationString into DestinationString.Length
[color=darkgreen].text:7C924D17                 mov    [edx+UNICODE_STRING.Length], ax[/color]
[color=red].text:7C924D1A                rep movsd              ; Copy DWORD-wise into buffer @EDI[/color]
.text:7C924D1C                mov    ecx, ebx       ; Restore size in Bytes into ECX
.text:7C924D1E                and    ecx, 3          ; Remainder from SHR
.text:7C924D21                 rep movsb              ; Copy remaining Bytes (byte-wise)
.text:7C924D23                 mov    cx, [edx+UNICODE_STRING.Length]
.text:7C924D26                 cmp    cx, [edx+UNICODE_STRING.MaximumLength]
.text:7C924D2A                pop    edi            ; Restore from 7C924D03
.text:7C924D2B                pop    esi            ; Restore from 7C924CF9
.text:7C924D2C                pop    ebx            ; Restore from 7C924CF8
.text:7C924D2D                jnb    short ExitThis
.text:7C924D2F ; Zero-terminate DestinationString only if we have
.text:7C924D2F ; enough space. Otherwise get out.
.text:7C924D2F                mov    ecx, [ebp+DestinationString]
.text:7C924D32                 shr    eax, 1          ; Divide by 2 (== sizeof WCHAR)
.text:7C924D34                 and    word ptr [ecx+eax*2], 0 ; Zero-terminate
.text:7C924D39
.text:7C924D39 ExitThis:                              ; CODE XREF: RtlCopyUnicodeString(x,x)+4Cj
.text:7C924D39                                         ; RtlCopyUnicodeString(x,x)+FC75j
.text:7C924D39                 pop    ebp
.text:7C924D3A                retn   8
.text:7C924D3A _RtlCopyUnicodeString@8 endp
An 7C924D1A wird EDI gesetzt also der Zielpuffer. Die Stackposition des übergebenen Parameters wird dazu temporär "mißbraucht", nicht wundern, das ist normal (macht der Compiler).

Ich bitte festzuhalten, daß in der blau markierten Zeile bei dem 2ten Aufruf von Dezi's Testprogramm bereits einmal von Adresse 2 (nil+2) gelesen wird (formal PUNICODE_STRING(p)^.MaximumLength, also 2 Bytes/1 Word). In der ersten roten Zeile wird von Adresse 4 (nil+4) gelesen (formal PUNICODE_STRING(p)^.Buffer, also 4 Bytes/1 DWORD).

Und jetzt kommt der wunde Punkt. Wieso knallt's in der zweiten roten Zeile und nicht bereits in der Zeile davor (grün), wo ja bereits an 0 (nil) geschrieben wird (formal PUNICODE_STRING(p)^.Length, also 2 Bytes)? Könnte was mit Speicheralignment zu tun haben, vielleicht ist aber einfach die Beobachtung von Dezi falsch oder falsch interpretiert?!

Da (p == nil), folgt:

PUNICODE_STRING(nil)^.Length := Irgendwas; ... das kann man in Delphi, soweit ich mich entsinne, auch exakt so ausdrücken und kompilieren!!!

Das würde in jeder Hinsicht knallen. Am Anfang der Funktion wird auch nur SourceString überprüft, jedoch nicht DestinationString - was theoretisch bereits in Bailout01 schiefgehen sollte!

Code:
.text:7C93494F BailOut01:                             ; CODE XREF: RtlCopyUnicodeString(x,x)+Aj
.text:7C93494F                mov    eax, [ebp+DestinationString]
[color=red].text:7C934952                 and    [eax+UNICODE_STRING.Length], 0[/color]
.text:7C934956                 jmp    ExitThis
.text:7C934956 ; END OF FUNCTION CHUNK FOR _RtlCopyUnicodeString@8
Eine Übergabe von nil für beide Parameter sollte also genauso zum Absturz führen, da hier wiederum an Adresse 0 (nil) geschrieben wird (rote Zeile, zwei Bytes, entsrpricht der grünen Zeile von oben).
  Mit Zitat antworten Zitat