Aceasta este o scurtă trecere în revistă a modului de creare a unei biblioteci de import care poate fi utilizată împreună cu MASM. Vă sugerez să știți deja ceva despre bibliotecile de import, adică știi că este așa și așa mai departe. Voi face un efort pentru a genera biblioteci de import compatibile cu MASM.
Formatul bibliotecilor interpretului MASM
MASM și Visual C ++ pot folosi aceleași biblioteci de import, ceea ce este foarte convenabil. Importarea bibliotecii Mikrosoft folosește o varietate de formate COFF, care diferă de formatul OMF utilizat de TASM. Din acest motiv, TASM nu poate folosi bibliotecile MASM'ovskie importe și invers. Nu voi intra în detaliile construcției acestor biblioteci. Este suficient să spunem că fiecare bibliotecă de import Microsoft conține informații despre funcții din anumite DLL-uri. Această informație include numele funcțiilor și dimensiunea totală a parametrilor parcurși funcțiilor. Dacă navigați cu kernel32.lib utilizând un hex editor, veți găsi următoarele:
Numele funcțiilor au un prefix "-". Numărul următor @ reprezintă dimensiunea totală a parametrilor acestei funcții în octeți. ExitProcess acceptă doar un singur parametru dword, deci acest număr este egal cu 4. De ce sunt incluse informații despre dimensiunea parametrilor? Aceste informații sunt utilizate de MASM pentru a verifica corectitudinea parametrilor de funcții specificați, atunci când se numește folosind cuvântul cheie "invoca". Dacă pur și simplu împingeți parametrii pe stivă cu instrucțiunea "împingeți" și executați funcția cu instrucțiunea "apel", MASM nu va verifica corectitudinea parametrilor. Acest avantaj face imposibilă crearea unei biblioteci de import MASM din DLL, deoarece DLL-ul nu conține informații exacte despre dimensiunea parametrilor parcurși funcției.
Crearea bibliotecilor importului MASM din DLL
Dacă sunteți gata să utilizați funcțiile cu "push" și "call", puteți crea o bibliotecă de import din orice DLL cu următoarele.- Utilizați dumpbin.exe, care vine cu Visual C ++ pentru a obține numele funcțiilor DLL care urmează să fie expuse.
Asta e tot. Ai blah.lib, pe care îl poți folosi cu MASM, până când trebuie să folosești 'invoke'.
Crearea bibliotecilor de biblioteci invocate
Sunt unul dintre cei care sunt foarte reticenți în a folosi abordarea de mai sus. Utilizați invoca gorado este mai convenabil. Acesta este unul dintre motivele pentru care prefer MASM TASM'u. Dar așa cum sa spus mai devreme, este aproape imposibil să creați o bibliotecă invocabilă a importului utilizând aceeași procedură descrisă mai sus. De exemplu, puteți decide că dacă modificați numele funcțiilor într-un fișier .def pentru a include "@xx" acolo, biblioteca de import poate funcționa așa cum ar trebui. Crede-mă. Nu va funcționa.
Cea mai ușoară modalitate de a crea o bibliotecă de importuri accesibile invocării este utilizarea MASM în sine. Dacă creați un DLL, atunci descoperiți că împreună cu el aveți biblioteca de import, care va fi complet invocabilă! Strategia noastră este după cum urmează:- Obținem informații despre numele funcțiilor și dimensiunea generală a parametrilor.
- Creăm codul sursă DLL, care va include aceste funcții cu numărul și dimensiunea corectă a argumentelor.
- Creăm fișierul de definiție a modulului, în care expunem funcțiile corespunzătoare.
- Asamblați codul sursă asm ca proiect DLL.
Asta e tot. Veți primi o bibliotecă MASM complet funcțională. Pașii de mai sus merită o explicație mai detaliată.
Obținerea numelor funcțiilor și mărimea totală a parametrilor
Aceasta este cea mai dificilă parte a procesului. Dacă aveți doar un DLL, veți avea un inconvenient obositor. Mai jos sunt descrise mai multe metode, pe care le puteți utiliza, deși niciuna dintre ele nu oferă o garanție de 100%.- Utilizați dezasamblarea interactivă (IDA) pentru a dezasambla DLL-ul. Cu ajutorul acestui instrument minunat puteți obține dimensiunea completă a parametrilor acceptați de funcție. Cu toate acestea, aceasta nu este cea mai bună cale. IDA este un dezasamblator consumator, dar uneori numai o persoană poate decide ce este. Va trebui să gândiți și să dezvoltați întreaga listă.
- Urmăriți valoarea indicelui în stivă înainte și după apelarea tuturor funcțiilor din DLL. Metoda este după cum urmează:
- Obțineți adresele funcțiilor utilizând GetProcAddress.
- Apelați fiecare funcție fără a trimite parametrii prin stivă. Rețineți valoarea esp înainte de apel.
- Când funcția returnează un control, comparați valoarea esp după apel cu ceea ce a fost înainte de apel. Motivul este următorul: atunci când trece parametrii în formatul stdcall, funcția își asumă responsabilitatea pentru menținerea echilibrului secular. Diferența dintre valorile esp și dimensiunea parametrilor așteptați de funcție.
- Din păcate, această metodă nu este impecabilă. Este posibil să nu reușească în următoarele situații.
- Dacă funcțiile din DLL folosesc celălalt parametru de trecere a parametrilor, altele decât stdcall sau pascal.
- Dacă funcția nu reușește să elibereze coșul, de exemplu, dacă apare o excepție.
- Dacă funcțiile care ne interesează servesc ceva periculos, de exemplu, pentru formatarea șurubului (Upasi Lord!)
- Examinați programele existente care utilizează DLL-ul corect. Puteți depana / dezasambla aceste programe pentru a vedea numărul și mărimea parametrilor parcurși funcțiilor din DLL. Cu toate acestea, dacă există funcții în DLL care nu sunt utilizate în niciunul dintre programele disponibile pentru dvs., această metodă nu va funcționa.
Crearea unei surse DLL, care va conține toate aceste funcții
După ce obțineți numele funcțiilor și mărimea parametrilor lor, cea mai tragică va fi în urmă. Va trebui să creați o funcție DLL și să scrieți aceleași nume ca în DLL. De exemplu, există o singură funcție în DLL, GetSomeLine, care obține parametrii de 16 octeți. În sursă, completați următoarele rânduri:
Puteți să întrebați ce este? Procedură, în care nu există o singură instrucțiune? Biblioteca de import nu conține nicio informație despre ce ar trebui să facă funcția. Singurul său scop este de a furniza informații despre numele funcțiilor și parametrii acestora. Prin urmare, nu trebuie să punem instrucțiuni în procedură - necompletate. Totuși, vom șterge DLL-ul inutil după montaj. Tot ce vrem este să amestecăm informațiile despre codul sursă cu privire la numele funcțiilor și mărimea parametrilor, astfel încât MASM să genereze biblioteca importului. Dimensiunea fiecărui parametru individual nu este importantă. Pentru informațiile dvs., MASM tratează întotdeauna fiecare parametru ca DWORD, indiferent de modificatorul de dimensiune pe care l-ați setat. De exemplu, putem face acest lucru:
Și MASM va crea în bibliotecă importul '_GetSomeLine @ 16'.
Crearea fișierului de definiție a modulului
Acesta este un proces simplu. Veți avea nevoie de acest fișier, că MASM ar putea genera un DLL și o bibliotecă de import. Fișierul șablon pentru definiția modulului este după cum urmează:
Trebuie să specificați numele DLL-ului, care va fi identic cu numele bibliotecii de import, apoi introduceți numele funcțiilor după comanda EXPORTS, un nume de funcție pe fiecare linie. Salvați fișierul și veți obține fișierul de lucru al definiției modulului.
Asamblarea codului sursă ca proiect DLL
Ultimul pas este cel mai simplu. Veți avea nevoie de ml.exe și link.exe.
Și veți primi o bibliotecă de bibliotecă invocată.
Expunerea uscată de mai sus poate să nu fie pe deplin înțeleasă. Cred în învățarea prin acțiune. Așa că am făcut un exemplu. care demonstrează cele de mai sus. Fișierele incluse în exemplu sunt:- Codul sursă din asamblare, care conține toate funcțiile din kernel32.dll (documentat).
- Fișier definiție fișier.
- Un fișier batch, pe care îl puteți utiliza pentru a compila biblioteca de import.
Compilați exemplul, veți obține kernel32.lib, pe care îl puteți utiliza în loc de cel furnizat de Microsoft.
Dacă doriți să adăugați / eliminați funcții de la / către o anumită bibliotecă de import, puteți utiliza două utilitare simple scrise de mine. De exemplu, dacă doriți să adăugați funcții nedocumentate la kernel32.lib, aceste programe vă vor fi utile.
Extrage nume și mărimi corespunzătoare din orice bibliotecă de import. Porniți-l și va procesa toate bibliotecile care se află în același director. Fișierele de ieșire vor avea .icz. Conținutul lor va arăta astfel:
Dacă doriți să adăugați o funcție, trebuie doar să introduceți un nume nou (prin adăugarea de caractere "_") și dimensiunea totală a parametrilor. Dacă funcția este exponentiată printr-o ordinală, atunci numele trebuie setat la @xx. "xx" va fi ordinală. Rețineți că acest utilitar simplu nu verifică numele pentru repetare, deoarece în unele biblioteci de import pot fi repetate numele.
Acest utilitar acceptă fișierele generate de Lib2Def și creează o bibliotecă de import de la acestea. Acesta va procesa toate fișierele cu extensia .icz. Pentru informațiile dvs., analizează liniile fișierului .icz și creează .asm și .def din ele. Apoi se numește ml.exe și link.exe astfel încât să genereze biblioteca de import. .obj fișiere. asm. exp și .dll sunt eliminate și rămâne doar .lib. Dacă acest utilitar nu poate genera fișierul .lib, verificați dacă există linii repetate în fișierul .icz: acesta este cel mai des întâlnit caz.