Twindows Internals (RO) despre Windows, software si alte lucruri de care ne mai lovim

1Apr/068

Nici macar Bill Gates

Circula intr-o vreme pe messenger un mesaj de genul urmator:

"Incredibil! Incearca sa creezi un folder con pe desktop si ai sa vezi ca nu se poate. Nici macar Bill Gates nu a putut explica fenomenul. Trimite mai departe si altora sa se minuneze si ei".

O parte din voi probabil ati primit deja acest mesaj si cunoasteti explicatia, subiectul fiind discutat deja prin mai multe locuri, inclusiv aici.

Vom incerca aici sa explicam care e motivul exact pentru care nu merge operatia respectiva si probabil ca astfel veti putea spune ca sunteti mai tari decat Bill Gates. :)

Pregatirea terenului

Folosim Windows Debugger pentru experimentele noastre. Pornim un command prompt (din care vom incerca sa cream directorul cu pricina), deschidem debugger-ul si apoi ne atasam cu el (din meniu optiunea File->Attach to a process) la procesul respectiv (cmd.exe). Punem un breakpoint pe functia NtCreateFile pentru a intercepta apelul ei:

0:000> bp NtCreateFile

"¦dupa care dam drumul executiei:

0:001> g

Cine-i responsabil?

Mergem in command prompt si dam comanda "md c:\con". Sa vedem cum arata stiva atunci cand este apelat NtCreateFile:

0:000> kb
ChildEBP RetAddr Args to Child
0013f504 7c81ea04 0013f584 00100001 0013f544 ntdll!NtCreateFile
0013f57c 4ad0b31d 00158678 00000000 00158678 kernel32!CreateDirectoryW+0xfd
0013f7a8 4ad0b239 00158678 00158518 00153a6e cmd!MdWork+0x84
0013fc58 4ad0b2a7 001597d0 4ad0b2b5 00000008 cmd!LoopThroughArgs+0x239
0013fc6c 4ad05aa2 00158518 00000000 00158518 cmd!eMkdir+0x17
0013fe9c 4ad013eb 00158518 00158518 00000002 cmd!FindFixAndRun+0x1f5
0013fee0 4ad0bbba 00000000 00000001 00000000 cmd!Dispatch+0x137
0013ff44 4ad05164 00000001 000341a8 000329b8 cmd!main+0x216
0013ffc0 7c816d4f 00fbd6c4 7c90e1fe 7ffd8000 cmd!mainCRTStartup+0x125
0013fff0 00000000 4ad05056 00000000 78746341 kernel32!BaseProcessStart+0x23

Aflam ce cale a primit, examinand al treilea parametru (primul evidentiat cu rosu mai sus):

0:000> dt _OBJECT_ATTRIBUTES 0013f544
+0x000 Length : 0x18
+0x004 RootDirectory : (null)
+0x008 ObjectName : 0x0013f570 _UNICODE_STRING "\??\con"
+0x00c Attributes : 0x40
+0x010 SecurityDescriptor : (null)
+0x014 SecurityQualityOfService : (null)

Analizand stiva vedem ca NtCreateFile a fost apelat de catre CreateDirectory. Primul parametru dat lui CreateDirectory este calea catre directorul ce trebuie creat. Examinam continutul acestuia pentru a vedea calea primita.

0:000> db 00158678
00158678 63 00 3a 00 5c 00 63 00-6f 00 6e 00 00 00 00 00 c.:.\.c.o.n.....
00158688 00 00 00 00 00 00 00 00-02 00 05 00 00 00 00 00 ................

Observam ca este chiar cea din linia de comanda ("c:\con"). Incercam sa cream un director ce nu are un nume rezervat de device, cum este de exemplu "c:\blog" (pentru mai multe detalii despre denumirea fisierelor cititi aici).

Sa vedem ce nume primeste NtCreateFile in cazul comenzii "md c:\blog":

0:000> kb
ChildEBP RetAddr Args to Child
0013f504 7c81ea04 0013f584 00100001 0013f544 ntdll!NtCreateFile
0013f57c 4ad0b31d 00159a88 00000000 00159a88 kernel32!CreateDirectoryW+0xfd
0013f7a8 4ad0b239 00159a88 00159b18 00158688 cmd!MdWork+0x84

0:000> dt _OBJECT_ATTRIBUTES 0013f544
+0x000 Length : 0x18
+0x004 RootDirectory : (null)
+0x008 ObjectName : 0x0013f570 _UNICODE_STRING "\??\c:\blog"
+0x00c Attributes : 0x40
+0x010 SecurityDescriptor : (null)
+0x014 SecurityQualityOfService : (null)

Observam prefixarea cu "\??", asa cum am discutat in articolul anterior. Sa vedem ce cale a primit CreateDirectory:

0:000> db 00159a88
00159a88 63 00 3a 00 5c 00 62 00-6c 00 6f 00 67 00 00 00 c.:.\.b.l.o.g...
00159a98 00 00 00 00 00 00 00 00-0d 00 05 00 00 00 00 00 ................

Concluzia micului nostru experiment este ca parametrul din linia de comanda ajunge nealterat la functia CreateDirectory, in interiorul careia el se transforma din "c:\con" in "\??\con". Asa cum stim deja, \?? este directorul ce contine numele device-urilor MS-DOS, deci lui NtCreateFile i se va cere crearea obiectului "\??\con", nu a directorului "c:\con" asa cum am cerut din linia de comanda.

Pentru a vedea exact cine transforma "c:\con" in "\??\con", sa examinam primele instructiuni ale functiei CreateDirectory:

0:000> u kernel32!CreateDirectoryW L10
kernel32!CreateDirectoryW:
7c81e968 8bff mov edi,edi
7c81e96a 55 push ebp
7c81e96b 8bec mov ebp,esp
7c81e96d 83ec38 sub esp,0x38
7c81e970 56 push esi
7c81e971 57 push edi
7c81e972 8b7d08 mov edi,[ebp+0x8]
7c81e975 8d45e0 lea eax,[ebp-0x20]
7c81e978 50 push eax
7c81e979 33f6 xor esi,esi
7c81e97b 56 push esi
7c81e97c 8d45f4 lea eax,[ebp-0xc]
7c81e97f 50 push eax
7c81e980 57 push edi
7c81e981 ff153c11807c call dword ptr [kernel32!_imp__RtlDosPathNameToNtPathName_U (7c80113c)]
7c81e987 84c0 test al,al

Observam un apel catre functia RtlDosPathNameToNtPathName. Stim deja ca, inainte de a fi apelat NtCreateFile, calea trebuie convertita in format nativ, deci banuim ca aceasta conversie este realizata de RtlDosPathNameToNtPathName. Pentru a ne convinge de acest lucru, punem un breakpoint la revenirea din apelul sau:

0:000> bp 7c81e987

Primul parametru al functiei de conversie reprezinta calea ce trebuie convertita, iar al doilea variabila in care se va retine calea dupa conversie. In momentul in care executia ajunge la breakpoint-ul nostru, analizam continutul celor doi.

Mai intai calea ce trebuie convertita (primul parametru):

0:000> db edi L10
00158678 63 00 3a 00 5c 00 63 00-6f 00 6e 00 00 00 00 00 c.:.\.c.o.n.....

"¦apoi si calea dupa conversie (al doilea parametru):

0:000> dt _UNICODE_STRING ebp-0xc
"\??\con"
+0x000 Length : 0xe
+0x002 MaximumLength : 0x21a
+0x004 Buffer : 0x001520a0 "\??\con"

Suspiciunea ne este acum confirmata. RtlDosPathNameToNtPathName este responsabila pentru conversie. In interiorul ei se verifica daca numele din cale este un nume de device MS-DOS rezervat (ex. "con") si se inlocuieste cu calea catre device-ul MS-DOS.

Si totusi, de ce nu merge?

Poate sunteti curiosi de ce nu a reusit crearea lui "\??\con" (rezultat prin conversia lui "c:\con"). In momentul in care breakpoint-ul pentru NtCreateFile este atins, lasam apelul sa se execute pana la intoarcerea in CreateDirectory:

0:000> gu
eax=c0000034 ebx=00000000 ecx=0013f504 edx=7c90eb94 esi=00000000 edi=00158600
eip=7c81ea04 esp=0013f538 ebp=0013f57c iopl=0 nv up ei pl zr na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
kernel32!CreateDirectoryW+0xfd:
7c81ea04 8bd8 mov ebx,eax

...si vedem ce eroare intoarce:

0:000> !error @eax
Error code: (NTSTATUS) 0xc0000034 (3221225524) - Object Name not found.

Asa cum am discutat in articolul despre accesarea unui fisier, Object Manager-ul trebuie sa localizeze obiectul indicat de cale, dar dupa eroarea intoarsa vedem ca localizarea a esuat.

Dar un director cu numele "con" se poate crea

Daca incercam crearea directorului prin comanda "md \\?\c:\con" vom vedea ca directorul este creat. De ce reuseste? Pentru ca atunci cand RtlDosPathNameToNtPathName primeste calea de convertit "\\?\c:\con", observa ca este deja in formatul nativ (adica este o cale pe care Object Manager-ul o poate analiza) si iese din functie cu succes fara a mai face verificarea respectiva.

Am vazut aici motivele exacte ale "isteriei con", asa cum o numea Tibi. Ca de obicei, comentariile si intrebarile sunt asteptate mai jos.

VN:F [1.9.3_1094]
Rating: 5.0/5 (1 vote cast)
VN:F [1.9.3_1094]
Rating: 0 (from 0 votes)
Nici macar Bill Gates, 5.0 out of 5 based on 1 rating

Most Commented Posts

Filed under: Internals Leave a comment
Comments (8) Trackbacks (0)
  1. Bonus points pentru utilizarea WinDbg si extra bonus points pentru cititorii care pricep ce inseamna comenzile :)

    VN:F [1.9.3_1094]
    Rating: 0.0/5 (0 votes cast)
    VN:F [1.9.3_1094]
    Rating: 0 (from 0 votes)
  2. Excelent… imi plac cel mai mult articolele tehnice de pe studentclub, cred ca de asta e aici situl! Tineti-o tot asa si curand ajungeti din urma The Old New Thing! :P

    VN:F [1.9.3_1094]
    Rating: 0.0/5 (0 votes cast)
    VN:F [1.9.3_1094]
    Rating: 0 (from 0 votes)
  3. super! e valabil si daca incercati sa creati ‘aux’

    VN:F [1.9.3_1094]
    Rating: 0.0/5 (0 votes cast)
    VN:F [1.9.3_1094]
    Rating: 0 (from 0 votes)
  4. si acum cum se sterge? :P … just kiding!

    F_U_L_G_A@yahoo.co.uk

    VN:F [1.9.3_1094]
    Rating: 0.0/5 (0 votes cast)
    VN:F [1.9.3_1094]
    Rating: 0 (from 0 votes)
  5. de ce merge “md \\?\c:\con” si nu cu “md \??\c:\con” ?

    VN:F [1.9.3_1094]
    Rating: 0.0/5 (0 votes cast)
    VN:F [1.9.3_1094]
    Rating: 0 (from 0 votes)
  6. pentru cei ce nu-ntelege uit-acia cum se sterge : ” rd \\?\c:\con “

    VN:F [1.9.3_1094]
    Rating: 0.0/5 (0 votes cast)
    VN:F [1.9.3_1094]
    Rating: 0 (from 0 votes)
  7. Eu reusesc dar cu o mica chichitza….

    Creaza un nou folder, dai rename dupa care tine apasat ALT-ul in timp ce scrii de la numpad-uri 0160 (iti va disparea “Nw folder”); dai drumul la ALT si scrii “con”…Enter si gata…Va salut, bafta!

    VN:F [1.9.3_1094]
    Rating: 0.0/5 (0 votes cast)
    VN:F [1.9.3_1094]
    Rating: 0 (from 0 votes)
  8. Dragos, tu creezi un director cu un alt nume . Acest 0160 este un ASCI code prin care scrii un caracter “blank” si prin urmare ur ai creeat un /[BLANK]CON/ .

    Ps. incearca sa faci un dir numai cu acest nume si vei avea impresia ca ai creat un director fara nume :) )
    New Folder // Alt+0160 // OK

    VA:F [1.9.3_1094]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.3_1094]
    Rating: 0 (from 0 votes)

Leave a comment


No trackbacks yet.