| |
|
|
- Seite 1 - |
|
Frank Abbing | Ein kleines Tool von mir auf API-Hooking Basis. In einer Listbox werden alle Dlls aufgelistest, die gerade von Programmen geladen wurden.
Einfach Exe starten und dann irgendwelche Programme starten. Deren Dlls sollten jetzt gelistet werden und es pieps kurz. Bitte testet mal, ob es noch irgendwo hakt. |
|
|
| |
|
|
|
| |
|
- Seite 4 - |
|
RGH | Frank Abbing
Oooch Roland. Hast aber nicht beachtet, das man im Programm GetProcAdress() pro Funktion nur EINMAL benutzen muss. Zum Speichern der Adresse genügt dann eine simple Variable.
Oooch Frank, hast Du nicht beachtet, daß mein erstes Programm GetProcAdress() auch nur einmal aufruft und das zweite nur dazu dient, den Zeitaufwand zwischen GetProcAdress() und LoadLibrary() zu vergleichen, um festzustellen, wer beim dynamischen Aufruf die Zeit verbrät?
Wenn ich in XProfan das dynamische Linken bevorzuge, dann muß ich die Adresse dann bestimmen, wenn die Funktion das erste Mal verwandt wird. Wenn sie dann an anderer Stelle im Programm wieder verwandt wird, muß ich sie wieder bestimmen oder ich müßte in einer Tabelle nachsehen, ob die bereits bekannt (und auch noch gültig) ist und sie dann verwenden. Das wäre zusätzlicher Verwaltungsaufwand.
Die andere Alternative ist die Umwandlung in einen statischen Aufruf, so wie es der XPSE (und mein obiges Beispiel) macht. Da das bei zeitkritischen Dingen Sinn machen kann, habe ich ja bereits vorgeschlagen, das in die nächste XProfan-Version als Alternative einzubauen. Wie gesagt: beide Varianten haben ihre Vor- und Nachteile.
Gruß Roland |
|
|
| Intel Duo E8400 3,0 GHz / 4 GB RAM / 1000 GB HDD - ATI Radeon HD 4770 512 MB - Windows 7 Home Premium 32Bit - XProfan X4 | 27.03.2007 ▲ |
|
|
|
|
Frank Abbing |
und das zweite nur dazu dient, den Zeitaufwand zwischen GetProcAdress() und LoadLibrary() zu vergleichen, um festzustellen, wer beim dynamischen Aufruf die Zeit verbrät?
Wie schon gesagt - am Thema vorbei.
Es liegt mir fern dir etwas vorschreiben zu wollen und ich mag solche Diskussionen auch gar nicht. Du hast hier eine Möglichkeit die Effizienz von XProfan noch zu steigern. Was du letztendlich daraus machst, und ob und wie du die Kritik deiner User umsetzt, ist deine Sache. |
|
|
| |
|
|
|
| Hallo Roland...
Mal zu deinem Code: Kann es sein, dass du da etwas mogelst? Usedll ist doch ein statischer Aufruf und GetProcAdress - wird das da nicht dynamisch aufgerufen??? |
|
|
| |
|
|
|
| Hallo Frank...
Hast du dir den Quellcode mal angesehen? Ich hab reingesehen... Das hat damit aber rein gar nichts zu tun.
Bin alles andere als ein Experte für ASM. Was mach der Code von GetProcAdress denn genau? Durchsucht der nicht den Table nach der angegebenen Funktion? Lerne gerne was dazu. |
|
|
| |
|
|
|
| Wo liegt der Denkfehler in folgendem Code: KompilierenMarkierenSeparieren $H Windows.ph WindowsHeaderdatei nutzen
Declare hDLL&, Time&, DLL$,LoadLibraryA&,GetProcAddress&,Funktion$,StringAddr&
LET DLL$=Kernel32.DLL
hDLL& = ~LoadLibraryA(@addr(DLL$))
LET Funktion$=GetProcAddress
LET GetProcAddress&=~GetProcAddress(hDLL&, @addr(Funktion$))
LET Funktion$=LoadLibraryA
LET LoadLibraryA&=~GetProcAddress(hDLL&, @addr(Funktion$))
LET DLL$=USER32.DLL
hDLL& = ~LoadLibraryA(@addr(DLL$))
Print Ohne irgendwas: ;
Time& = &GetTickCount
whileLoop 1, 100000
endwhile
print Int(&GetTickCount - Time&)
LET DLL$=$SYSPATH+USER32.DLL
Print LoadLibraryA +DLL$+ :;
StringAddr& = addr(DLL$)
Time& = &GetTickCount
whileLoop 1, 100000
call(LoadLibraryA&,StringAddr&)
endwhile
print Int(&GetTickCount - Time&)
LET DLL$=USER32
Print LoadLibraryA +DLL$+ :;
StringAddr& = addr(DLL$)
Time& = &GetTickCount
whileLoop 1, 100000
call(LoadLibraryA&,StringAddr&)
endwhile
print Int(&GetTickCount - Time&)
Print GetProcAdress ActivateKeyboardLayout: ;
Let Funktion$=ActivateKeyboardLayout
StringAddr& = addr(Funktion$)
Time& = &GetTickCount
whileLoop 1, 100000
call(GetProcAddress&,hDLL&, StringAddr&)
endwhile
print Int(&GetTickCount - Time&)
Print GetProcAdress wvsprintfW: ;
Let Funktion$=wvsprintfW
StringAddr& = addr(Funktion$)
Time& = &GetTickCount
whileLoop 1, 100000
call(GetProcAddress&,hDLL&, StringAddr&)
endwhile
print Int(&GetTickCount - Time&)
waitinput
end
|
|
|
| |
|
|
|
RGH | Andreas Hötker
Was mach der Code von GetProcAdress denn genau? Durchsucht der nicht den Table nach der angegebenen Funktion?
Es ist halt eine API-Funktion, die die absolute Adresse einer Funktion eines geladenen Moduls zurückgibt. Wie sie das macht, entzieht sich meiner Kenntnis. Da Microsoft seine Quellcodes (weitestgehend C und C++ mit ASM-Teilen) nicht veröffentlicht, ist es auch nicht ganz einfach das herauszubekommen. (Außerdem würde das eh nicht weiterhelfen.) Ich vermute aber einfach folgendes: Eine DLL enthält in ihrem Header eine Liste der in ihr exportierten Funktionen mit den Einsprungadressen. Ich nehme daher an, daß GetProcAdress über das Handle der DLL auf diese Liste zugreift.
Gruß Roland |
|
|
| Intel Duo E8400 3,0 GHz / 4 GB RAM / 1000 GB HDD - ATI Radeon HD 4770 512 MB - Windows 7 Home Premium 32Bit - XProfan X4 | 28.03.2007 ▲ |
|
|
|
| |
|
- Seite 5 - |
|
|
RGH | Andreas Hötker
Hallo Roland... Mal zu deinem Code: Kann es sein, dass du da etwas mogelst? Usedll ist doch ein statischer Aufruf und GetProcAdress - wird das da nicht dynamisch aufgerufen???
Nein, ich bin mir nicht bewußt zu mogeln. Aber vielleicht sollten wir mal die Begriffe dynamisch und statisch in diesem Zusammenhang klären:
dynamisch Wenn ich eine DLL dynamisch linke, bedeutet das, daß ich nur dann auf die DLL zugreife, wenn es der gerade ausgeführte Code tatsächlich benötigt. Habe ich z.B. in einem Grafikprogramm eine Lade-Routine für ein exotisches Grafikformat, das eine teure externe DLL benötigt, so kann ich bei dynamischem Zugriff auf die DLL auch ohne DLL mit diesem Programm arbeiten, so lange ich keine Datei dieses Formates laden möchte. Der Programmteil, der diese DLL dynamisch verwendet, wird eben nie aufgerufen. Dieser dynamische Aufruf geschieht, etwas vereinfacht ohne Fehlerbehandlung und Parameterverwaltung, mit folgendem Code: KompilierenMarkierenSeparieren Wobei, wie oben dargelegt, LoadLibrary nur dann die DLL physikalisch von Platte in den Speicher läft, wenn sie noch nicht geladen ist und FreeLibrary nur dann den Speicher der DLL freigibt, wenn der erwähnte Zähler auf 0 geht. Was gegenüber der statischen Variante jedesmal anfällt und den Zeitunterschied ausmacht, ist das GetProcAdress().
statisch Wenn ich eine DLL statisch linke, dann bedeutet das, daß die im Programm benutzten Funktionsadressen nur einmal, und zwr am Anfang des Programmes mit LoadLibrary und GetProcAdress ermittelt werden und im weiteren Verlauf nur noch Calls auf die bekannten Adressen nötig sind. Der Vorteil ist die höhere Geschwindigkeit*, der Nachteil eben, daß das Programm grundsätzlich nicht startet, wenn die DLL fehlt. (Diese ließen sich allerdings durch geschickte Programmierung mehr oder weniger ausgleichen.) Also brauchst Du auch hier, allerdings nur einmal am Anfang des Programmes, LoadLibrary und GetProcAdress. Im Programm erfolgt dann nur noch der Aufruf mit Call (auch hier verkürzt um die Parameterverwaltung): KompilierenMarkierenSeparieren aFunk ist hier die globale Variable, der die Adresse der Funktion beim Programmstart zugewiesen wurde. Da hier GetProcAdress verwandt wurde, ist diese Variante natürlich schneller, was sich bei Programmem mit vielen API-Aufrufen natürlich bermerkbar macht. Diesen Weg geht iF mit XPSE und erreicht daher den Tempozuwachs.
Die meisten Programmiersprachen erlauben beide Varianten der DLL-Bindung, so auch Delphi, in dem XProfan geschrieben ist. So sind bei mir die ODBC-Aufrufe dynamisch gelinkt, das heißt: XProfan startet auch auf Rechnern ohne installierte ODBC-Treiber (Windows 95 kam noch ohne diese Treiber auf den Markt). Die OpenGL-Aufrufe (über die OGL-Funktion) sind statische gelinkt, da es hier a) um Tempo geht und b) alle XProfan-fähigen Windowsversionen OpenGL von Hause aus an Bord haben. Ohne OpenGL würde XProfan nicht starten.
Gruß Roland
* Wieviel das genau ausmacht, hängt natürlich von der jeweiligen API-Funktion ab. Bei aufwändigen API-Funktionen wird der Tempovorteil kaum ins Gewicht fallen, während er bei einfachsten API-Funktionen, die selbst nur solange wie das GetProcAdress brauchen, dann natürlich eine Menge ausmacht! |
|
|
| Intel Duo E8400 3,0 GHz / 4 GB RAM / 1000 GB HDD - ATI Radeon HD 4770 512 MB - Windows 7 Home Premium 32Bit - XProfan X4 | 28.03.2007 ▲ |
|
|
|
|
| Hallo Roland - noch mal zum mogeln...
Wir hatten das schon mal: Ist es bei den Profanfunktionen (hier usedll) nicht so, das dort die Adresse bereits beim Aufrufen des Programmes ermittelt wird?
~GetProcAdress dürfte aber GetProcAdress erst beim Aufruf der Funktion aufrufen - ist das richtig? Verschaffst du damit Usedll (hier LoadLibraryA - darum geht es ja ) nicht einen ungerechten Vorteil?
Müssten nicht beide Funktionen über Call aufgerufen werden, um überhaupt erst einmal gleiche Voraussetzungen zu schaffen?
Die Frage Was mach GetProcAdress genau? war an Frank gerichtet, der sich ja die Funktion angesehen hat - trotzdem danke!
@Frank: Das, wo geladene Module gespeichert werden, stinkt für mich nach einer LDR_DATA_TABLE_ENTRY Struktur, also einer doppelt verlinkten Liste, wie ich sie von MIster Root und Fu her kenne. Innerhalb einer solchen Struktur wird auch der Loadcount gespeicheit - da ist nicht viel Speicher zu scannen. Die API GetProcAdress wird wohl den Exporttable einer DLL scannen, und da können locker 1000 verschiedene Funktionen drin stehen - aber darüber wirst du mich wohl noch genau aufklären (will ich jedenfalls hoffen). |
|
|
| |
|
|
|
Frank Abbing |
Die API GetProcAdress wird wohl den Exporttable einer DLL scannen, und da können locker 1000 verschiedene Funktionen drin stehen - aber darüber wirst du mich wohl noch genau aufklären (will ich jedenfalls hoffen).
Ich versuchs. Hab natürlich auch nur den disassemblierten Quellcode vorliegen, dort ist es nicht so einfach zu erkennen, welche Tabellen wie wo vorliegen. Zuersteinmal wird geprüft, ob im Parameter die twain_32.dll gemeint ist. Wenn ja, wird schonmal ein anderes Verfahren angewendet. Ansonsten wird erstmal API der NT.Dll aufgerufen. Stringvergleiche/umwandlungen (A/W) und sowas. Dann wird Heap-Speicher angefordert und danach in den verschiedenen Systemdirectories nachgesehen, ob die Dll überhaupt vorliegt, und in welcher Version. Und wieder zurück zur NT.Dll, wo wohl der eigentliche Test weitergeht. Dort hab ich auch nachgesehen. Es geht da tief ins System hinein, mit Aufruf von allerhand (undokumentierten) Lowlevel-APIs mit vielen Zugriffen auf Speicher und Directories. Scheint eine echte Schatzkiste zu sein, diese Dll. Alles in Allem also nix eben mal Handle hochzählen... |
|
|
| |
|
|
|
| Was da sonst noch passiert, hat aber nichts mit Speicher nach Handles scannen zu tun, das geht sehr schnell, da es sich dort um eine LDR_DATA_TABLES_ENTRY Struktur handelt, die doppelt verlinkt ist. U.a. wird da in LoadLibraryA der Pfad der DLL überprüft - USER32 / USER32.dll / $SYSPATH+/USER32.dll verweisen ja auf die gleiche DLL, und die DLL soll da nicht nochmals geladen werden. Hast du dir mal mal meinen Quelltext-Test angesehen? Das sieht es schon ganz anders aus, mit dem Ergebnis, als Rolands Test. Mache ich da irgendwelche gedanklichen Fehler???
Ich glaube, Roland verschafft da in seinem Code LoadLibraryA einen ungerechten Vorteil. |
|
|
| |
|
|
|
RGH | Andreas Hötker
Hallo Roland - noch mal zum mogeln...
Ah, jetzt verstehe ich, was Du meinst! Ja, da hast Du vermutlich recht. Das hatte ich übersehen. SORRY!
So müßte getestet werden: KompilierenMarkierenSeparieren ... und dann brauchen sie beide ungefähr gleich lang. Da war ich wohl im Irrtum.
Wie dem auch sei: Beim statischen Linken braucht man beide nur beim Start und nachher nicht mehr, so dass dadurch der Tempogewinn erzielt wird.
Gruß Roland (hat schon Ideen, das statische Linken in XProfan 11 komfortabler zu gestalten) |
|
|
| Intel Duo E8400 3,0 GHz / 4 GB RAM / 1000 GB HDD - ATI Radeon HD 4770 512 MB - Windows 7 Home Premium 32Bit - XProfan X4 | 28.03.2007 ▲ |
|
|
|
|
Frank Abbing |
... und dann brauchen sie beide ungefähr gleich lang. Da war ich wohl im Irrtum.
Wie dem auch sei: Beim statischen Linken braucht man beide nur beim Start und nachher nicht mehr, so dass dadurch der Tempogewinn erzielt wird.
Gruß Roland (hat schon Ideen, das statische Linken in XProfan 11 komfortabler zu gestalten)
Na das hört man ja gerne. Das das Ganze doch noch einen Sinn gehabt. |
|
|
| |
|
|