Jump to content
Dr4k3

Afisarea textului de dupa "***"

Recommended Posts

Posted

Da, Windows Passwords... :)

Acest eseu este un supliment la eseul lui The Anonymous referitor la afisarea textului din ferestrele unde apare "***", si contine o descriere detaliata la modul de implementarea a unui astfel de program, la modul de lucru cu mesajele Windows, la modul de schimbare a proprietatilor ferestrelor (pentru incepatori) si, partea cea mai importanta, proiectul in Delphi (cu codul complet!) a programului pe care l-am facut eu in acest scop!!!

Nu sunt sigur, referitor la comentariul lui The Anonymous ca Windows este departe de perfectiune, eu asi spune ca el mai are cite ceva de facut, dar in rest totul este OK, adica: BUGuri exista si "lucreaza" bine, CRASHuri se intimpla si strica multe, BSD (Blue Screen of Death) apar si nu rar, iar Windows isi continua calea pe drumul "ridicarii pretului" :)

Ei, bine. Sa lasam asta pe seama celor de la Microsoft, iar noi sa ne ocupam putintel de "aranjarea lucrurilor" in favoarea noastra.

{Pentru inceput asi dori sa lamuresc citeva notiuni si, din start, asi dori sa spun ca aceste rinduri sunt destinate incepatorilor (acelor care inca nu s-au ocupat de programare in Windows si/sau care nu stiu modul de lucru a Windows).

Un alt lucru important este faptul ca eu lucrez mai mult in Delphi 3 asa ca coduri (exemple) o sa va dau anume in Delphi 3, iar standardizarile de la Microsoft vor fi prezentate in C (cu toate ca nu cred ca va reprezenta o problema traducerea lor in Delphi...).}

{*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

* INITIERE IN PROGRAMARE WINDOWS

*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*}

Pentru cei care au cunostinte mai avansate (adica au Instalat si unInstalat o data Delphi sau Visual C++... glumesc desigur) pot sa le propun sa treaca peste sectiunea de introducere, adica direct la partea mai interesanta :)

In Windows (nu in zadar l-au numit asa, "Ferestre") totul lucreaza pe ferestre. Bine, cu totii stim ca o fereastra este "patratul" cela care apare pe monitor si care are bara de titlu, butoane de control (Close, Maximize, Minimize, Restore) si alte lucruri interesante.

Insa lucrurile stau un pic altfel... Cum credeti ce este butonul Start pe care apasati de sute de ori pe zi, sau ce sunt "toate componentele vizuale a ferestrei active" (cum le numeste The Anonymous)? Toate aceste lucruri sunt fereastre!!! Da, da, anume ferestre. Adica, Microsoft, defineste orice "component vizual" ca o fereastra, iar ferestrele au proprietati, mesaje pe care le primesc.

Deci, in dependenta de clasa din care face parte, fereastra devine ceea ce "vedem" noi. Spre exemplu, daca o fereastra deriva din clasa EDIT in rezultat obtinem un "chenar pentru text" (citeste TextBox), daca o fereastra deriva din clasa BUTTON in rezultat obtinem un "buton".

Un alt lucru care nu trebuie scapat din vedere este asa-numitul handle. Ce reprezinta un handle? Orice fereastra are un identificator (handle) care este reprezentat printr-un numar. Folosind acest handle poate fi accesata direct fereastra dorita (in cazul in care cunoastem acest handle, care de altfel poate fi obtinut folosind functia... stati ca despre asta si este eseul, ca doar nu voi afisa toate cartile in "antet" :)

Cam asta ar fi, in general, cind voi vorbi despre ferestre sa atrageti atentia daca ma refer la o clasa anumita sau la o fereastra "obisnuita", dintre cele cu bara de titlu, etc...

Al doilea lucru interesant sunt mesajele! Modul de lucru a ferestrelor se bazeaza in mare parte pe mesaje. Ce sunt mesajele? Mesajele sunt niste informatii trimise spre ferestre (din orice clasa nu ar deriva ele) pe baza carora ele (ferestrele sau sistema) isi continua activitatea (expresia nu este chiar atragatoare, dar sunt obosit si cinta Cradle of Filth (Leaganul cu "Balegar") asa ca va rog sa nu ma bateti :).

Cind apasati butonul Start (care este o fereastra, nu uitati) care mesaje credeti ca le primeste el? Eh, sunt foarte multe, dar in linii generale ar fi cam asa (nu o sa folosesc definirea API pentru dinsele, ci doar denumiri conventionale, pentru a intelege esenta): MISCARE_A_CURSORULUI (foarte multe, pentru ca chiar si modificarea coordonatelor cursorului cu 1 pixel genereaza un astfel de mesaj), BUTONUL_DREPT_JOS, BUTONUL_DREPT_SUS. In dependenta de aceste mesaje programul (sistema) poate sa indeplineasca diferite operatii. Spre exemplu, primirea unui mesaj BUNTONUL_DREPT_JOS (WM_LBUTTONDOWN) actioneaza "procedura" de modificare a imaginii butonului (da, da, imaginea de "buton apasat" este modificata anume aici).

Acum sa trecem la modul de trimitere a mesajelor. Orice mesaj trimis la o fereastra (indiferent, iarasi, de clasa ei) are trei componente:

Identificatorul mesajului - reprezinta un nume conventional dat fiecarui mesaj. Este de tipul WM_MESSAGENAME (WindowsMessage_NumeleMesajului). Mai sunt si alte categorii de identificatori, i.e. EM_MESSAGENAME (ExtendedMessage_NumeleMesajului) etc.

wParam - primul parametru (de tip Word) care contine ceva informatii folositoare pentru mesajul dat.

lParam - al doilea parametru (de tip Long) care contine ceva informatii folositoare pentru mesajul dat.

Nota: Citeodata wParam sau lParam nu este folosit, in dependenta de mesaj.

Deci, pina acum avem inchipuire de mesaje, dar dupa cum se pare, ele sunt trimise doar de catre sistema. Corect, dar nu chiar. In Windows API (Application Programming Interface) exista o functie speciala (documentata :) care trimite mesaje la o fereastra.

O sa va dau definirea acestei functii in WIN32 API.

//Cod in C

LRESULT SendMessage(

HWND hwnd, // handle la fereastra destinatie

UINT uMsg, // identificatorul mesajului (WM_MESSAGENAME)

WPARAM wParam, // primul parametru a mesajului

LPARAM lParam // al doilea parametru a mesajului

);

Daca ca parametru hwnd este indicat HWND_BROADCAST atunci mesajul este trimis la toate ferestrele (inclusiv cele ascunse), dar nu la ferestrele copil (citeste Child Windows), adica mesajul va fi receptionat de "chenarele" cu bara de titlu, dar nu de catre butoane, TextBox-uri si alte dracovenii care pot exista si care pot fi numite "elemente vizuale".

Pentru a intelege mai bine toate chestiile aceste, este necesar un exemplu. In primul exemplu va fi explicat cazul cind mesajul este transmis de catre Windows, iar in al doile noi vom transmite mesajul catre o fereastra.

Sa presupunem ca programul nostru are nevoie de a afisa un meniu doar in cazul cind utilizatorul apasa butonul sting al mouse-ului si acest lucru trebuie sa se intimple numai daca butonul sting a fost apasat in coltul drepata-sus a butonului. Din start consideram ca coltul dreapta-sus se socot punctele cu coordonatele, unde: X + 20 <= Lungime_Buton, iar

Y + 20 <= Latime_Buton. Pentru asta la primirea acestui mesaj (WM_LBUTTONDOWN) programul controleaza lParam care in cazul acestui mesaj contine coordonatele. Bitii inferiori ai lui lParam contin coordonatele X, iar bitii superiori coordonatele Y.

Deci, codul in Delphi 3 ar arata cam asa:

{*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

* Puteti incepe copierea aici

*-*-*-*-*-*-*-*-*-*-*-*-*-*-*}

{Deci, Lo(TMessage_Var.lParam) reprezinta coordonatele X,

iar pentru aflarea coodonatelor Y este nevoie de a chema Hi(TMessage_Var.lParam)

Nota: Creatorii de la Borland au anticipat aceste chestii si, in rezultat,

variabila de tip TMessage (tip folosit in functii / proceduri cu mesaje windows)

are deja 4 proprietati suplimentare si anume:

TMessage_Var.lParamLo - echivalent cu Lo(TMessage_Var.lParam)

TMessage_Var.lParamHi - echivalent cu Hi(TMessage_Var.lParam)

TMessage_Var.wParamLo - echivalent cu Lo(TMessage_Var.wParam)

TMessage_Var.wParamHi - echivalent cu Hi(TMessage_Var.wParam)}

if (Lo(TMessage_Var.lParam) + 20 <= Button1.Width) and

(Hi(TMessage_Var.lParam) + 20 <= Button1.Height) then ShowCoolMenu;

Daca avem nevoie de niste taste apasate concomitent sau alti parametri suplimentari, controlam valoarea lui wParam care in cazul de fata va contine niste chei, adica: a fost sau nu apasat CTRL in momentul transmiterii mesajului, etc...

Nota: In practica proprie am intilnit multe cazuri cind trebuia de efectuat un control a unei variabile, variabila care poate fi ca suma a doua si/sau mai multe constante si am intilnit multi care aveau probleme cu acest lucru (nici eu nu am facut exceptie... la inceput :). Spre exemplu:

Sa presupunem ca avem variabila SR de tip TSearchRec (tip folosit la functiile FindFirst si FindNext, functii de cautare a fisierelor in Delphi). Aceasta variabila are mai multe proprietati, printre care si proprietatea Attr: Integer (care reprezinta atributele elementului gasit). Ea (Attr) este o suma a constantelor faDirectory, faArchive, faHidden etc.; in cazul in care elementul gasit este de tip DOSAR, ASCUNS si SISTEM (faDirectory, faHidden si faSysFile) - Attr va contine valoarea: faDirectory($00000010) + faHidden($00000002) + faSysFile($00000004) = $00000016 (adica 22 in limba muritorilor de rind :) Acum, problema: daca cunoastem ca dorim sa controlam este sau nu elementul gasit dosar, nu putem sa comparam SR.Attr>=faDirectory pentru ca SR.Attr ar putea sa fie mai mare sau egal cu faDirectory fara ca sa-l contina si anume:

faSysFile($0000000b)+faHidden($00000002)>=faDirectory($00000010) dar nu-l contine!!!

Deci, pentru a fi sigur de faptul ca elementul nostru este anume dosar, se foloseste un asa procedeu:

if SR.Attr and faDirectory <> 0 then DoYourJob;

Nota s-a primit cam mare, dar cred ca cei care aveau nevoie de ceva lamuriri in aceasta directie au primit informatia necesara.

Spre ce "bat" eu acum... Mai sus (daca va amintiti) vorbeam despre controlul altor parametri suplimentari folosind wParam. Deci, in cazul in care doreati sa controlati daca la apasarea butonului drept al mouse-ului mai era apasata si tasta CTRL o sa trebuiasca sa scriti un asa cod:

{*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

* Puteti incepe copierea aici

*-*-*-*-*-*-*-*-*-*-*-*-*-*-*}

if TMessage_Var.wParam and MK_CONTROL then DoSomething;

//sau combinarea a celor doua coduri prezentate...

//observati ca de data asta am folosit proprietatile xxxLo si xxxHi

if (TMessage_Var.lParamLo + 20 <= Button1.Width) and

(TMessage_Var.lParamHi + 20 <= Button1.Height) then

if TMessage_Var.wParam and MK_CONTROL then DoSomethingElse;

A fost un exemplu destul de lung as spune... Foarte pe scurt o sa va dau un exemplu de trimitere a unui mesaj spre o fereastra (nu uitati, indiferent de clasa!). Pentru asta se foloseste functia SendMessage (despre care am discutat mai sus).

{*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

* Puteti incepe copierea aici

*-*-*-*-*-*-*-*-*-*-*-*-*-*-*}

Var PWText: array[1..255] of Char;

begin

//Trimitem un mesaj spre fereastra WHandle si anumem mesajul WM_GETTEXT

// (mesaj ce va returna in PWText textul din fereastra data).

SendMessage(WHandle, WM_GETTEXT, SizeOf(PWText), DWord(@PWText));

//Am folosit special acest mesaj pentru ca este unul din acele mesaje pe care le vom folosi

//in elaborarea programului nostru de mai departe.

end;

Un moment la care asi dori sa ma opresc indeosebi, ar fi "pasarea" parametrilor catre aceasta functie. Daca examinati definirea functiei SendMessage in WIN32 API veti observa ca ultimii doi parametri (wParam si lParam) sunt de tipul WPARAM si, respectiv, LPARAM. Un alt lucru important este ca aceste doua tipuri nu sunt altceva decit niste valori intregi... adica se aseamana la ceva numere intregi (0, 1, 2... N). Din alt punct de vedere, wParam pentru mesajul WM_GETTEXT trebuie sa contina lungimea buffer-ului in care se va copia textul obtinut din fereastra. Lungime reprezinta ceva valori intregi: totul este OK. lParam are insa o alta menire pentru acest mesaj si anume: el trebuie sa reprezinte un pointer la o variabila care va contine textul copiat din fereastra. Pentru asta am folosit aceasta implementare: DWord(@PWText).

{*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

* SFIRSIT DE INITIERE IN PROGRAMARE WINDOWS

*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*}

{*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

* PARTEA INTERESANTA :)

*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*}

Inapoi la partea introductiva :) .

The Anonymous a folosit o metoda destul de buna pentru a afisa "parolele ascunse" (cind pronunt aceasta combinatie imi vine sa rid, pentru ca nu-i vorba de afisarea lor din PWL sau alte locuri "ascunse" ci doar afisarea dintr-o fereastra...:), deci, pentru a afisa parolele ascunse in Windows. Intr-adevar trimitind un mesaj EM_SETPASSWORDCHAR la o fereastra derivata din clasa EDIT putem obtine rezultatul dorit. Dar cum sa facem sa ajungem la fereastra dorita (cu toate ca daca trimitem un mesaj la o fereastra, iar ea nu il intelege... pur si simplu il ignora, dupa cum a mentionat si The Anonymous)?Si chiar daca am gasit-o: ce facem cu mesajul acesta, ca doar mai are si niste parametri (wParam, lParam)? Ei bine s-o luam de la capat...

Pentru inceput, gasirea ferestrelor.

Pentru a gasi ferestrele active in momentul executiei programului vom folosi o functie API (iarasi :) si anume:

//Cod in C

BOOL EnumWindows(

WNDENUMPROC lpEnumFunc, // adresa functiei callback

LPARAM lParam // o valoare definita de programul nostru

);

Primul parametru al functiei va reprezenta adresa functiei callback a programului nostru, iar al doilea parametru reprezinta ceva date de care putem avea nevoie la executia functiei noastre callback.

Nota: O functie callback in API reprezinta o functie construita de programul nostru (adica de noi :) care are ca parametri parametrii necesari functiei originale API si returneaza un tip de date specificat de functia originala API. Cu alte cuvinte, daca avem functia API DoSomethingAPI(SOMETYPE sometp, LPARAM lParam), unde sometp reprezinta adresa unei functii, iar functia ceea trebuie sa fie de tipul BOOL CallBackSomething(PARAM_1 param1, PARAM_2 param2), inseamna ca noi trebuie sa construim o asa functie in program, de acest tip, cu acesti parametri, iar cind chemam DoSomethingAPI vom utiliza ceva de tipul:

//Cod in Delphi

DoSomethingAPI(@CallBackSomething, lParam);

Aceasta functie enumera ferestrele toplevel (acele cu bara de titlu...) si paseaza handle-ul ferestrei la functia noastra callback. Enumerarea ferestrelor continua pina cind sunt "epuizate" toate ferestrele sau pina cind functia noastra callback returneaza valoarea FALSE.

Functia callback pentru EnumWindows se defineste astfel:

//Cod in C

BOOL CALLBACK EnumWindowsProc(

HWND hwnd, // handle-ul ferestrei gasite

LPARAM lParam // o valoare definita de programul nostru

);

Ei bine, aceasta functie poate sa intreprinda actiuni pe care le dorim noi si in plus mai are si handle-uri la ferestrele enumerate de EnumWindows. Cum o putem utiliza noi?! In cazul cind avem handle-urile ferestrelor toplevel putem sa cautam prin ele ferestre derivate din clasa EDIT (adica "elemente vizuale TextBox" :) care au proprietatea ES_PASSWORD (citeste "Extended Style Password")! Pentru asta ne vom folosi de inca una din functiile API si anume:

//Cod in C

BOOL EnumChildWindows(

HWND hWndParent, // handle-ul ferestrei "parinte", adica a ferestrei care contine fereastra data

WNDENUMPROC lpEnumFunc, // adresa functiei callback

LPARAM lParam // o valoare definita de programul nostru

);

Si, evident, mai avem nevoie si de o functie callback pentru aceasta functie API:

//Cod in C

BOOL CALLBACK EnumChildProc(

HWND hwnd, // handle-ul ferestrei gasite

LPARAM lParam // o valoare definita de programul nostru

);

Deci, algoritmul de cautare a ferestrelor derivate din EDIT cu proprietatea ES_PASSWORD este cam asa:

Enumera ferestrele toplevel

Enumera ferestrele child.

Controleaza daca printre ferestrele child exista ferestre cu proprietate ES_PASSWORD.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...