Heyho ich hab da etwas Feedback für den Autor des Artikels "Windows API" aus dem Wiki (Xalon?) loszuwerden.
Und zwar, zunächst dein Text hat mir sehr weiter geholfen, die Technik ist gut und nachvollziehbar erklärt und ich mag deinen Schreibstil
ABER ich halte deine Implementierung für sehr umständlich, dieses ganze hin und her gespringe und das nicht zerreissen eines Befehls, das geht meiner Meinung nach besser.
Ich habe einfach die originalen ersten 5-Bytes der API gespeichert und mit dem Sprungbefehl überschrieben (egal ob dabei etwas zerrissen wurde), In der angesprungenen Funktion (die statt der API ausgeführt werden soll) schreibe ich dann temporär den originalen Anfang wieder zurück, so dass die API wieder den originalen Zustand hat und ich sie benutzen kann, und am Ende der angesprungen Funktion schreibe ich wieder den Sprungbefehl an den Anfang der API. Es macht so nichts, dass die Befehle zerrissen wurden weil sie ja sowieso nie ausgeführt werden. Tut mir leid, aber das halte ich für eleganter als den originalen Code irgenwo anders auszuführen, was ist zB wenn in den ersten Befehlen der API relative Adressen benutzt werden und du diesen Code jetzt an einer ganz anderen Stelle ausführst? Naja, das war der eine Punkt, ich hoffe du konntest nachvollziehen was ich meine.
Der zweite Punkt, ich bin mir nicht sicher ob das allgemein gültig ist, aber ich habe meinen C++ Code mit Borland 6 geschrieben und bei dem Code den der generiert muss man noch etwas mehr Handarbeit anlegen als du beschrieben hast, Hintergrund ist folgender, ein API Aufruf sieht im Asm Listing so aus:
auf dem Stack liegen also die ganzen Parameter und danach wird beim callen noch die Rücksprungadresse auf den Stack geschrieben. Nach einem API Aufruf (Zeile 5, "bla") sind sowohl die Rücksprungadresse (das sollte klar sein) als auch die gepushten Parameter wieder vom Stack verschwunden. Das ist das allgemeine Verhalten von Windows APIs (zumindest haben meine Forschungen das ergeben),
Wenn ich jetzt den Hook gesetzt habe, die API Adresse gecallt wird, von dort in meine Funktion gesprungen wird, diese abgearbeitet und am Ende mit einem Return beendet wird, dann liegen die gepushten Parameter noch immer auf dem Stack. C++ Funktionen entfernen, anders als API Funktionen, diese nicht wieder automatisch. Zumindest war das bei dem von bcc generierten Code der Fall, wie gesagt ich weiß nicht ob das für alle Compiler/Programmiersprachen gilt.
Der Rücksprung funktioniert zwar wie er soll, aber die aufrufende Funktion erwartet, dass der Stack nach dem API Aufruf aufgeräumt wurde. Das führte dann bei mir zu komischen Fehlern, die nicht sooo leicht zu debuggen waren naja, ich mache das mal an einem Beispiel deutlich:
Wir denken uns eine main Funktion:
und weiterhin sei die API "MessageBoxA" gehookt, wie befinden uns am Anfang der Main Funktion, auf dem Stack (er wächst in meiner Darstellung nach unten) liegt die Rücksprungadresse von irgendeiner Windows Funktion die uns aufgerufen hat (wahrscheinlich CreateProcess oder sowas):
Jetzt wird die (gehookte) API aufgerufen, die Parameter kommen auf den Stack, die Rücksprungadresse kommt auf den Stack, wir befinden uns in der "API" (unserer Funktion, die stattdessen aufgerufen wurde):
Diese Funktion wird abgearbeitet, beendet und springt bei Return zurück in die main Funktion:
Jetzt ist die main Funktion auch fertig, beendet, holt die Rücksprungadresse vom Stack und springt sie an. Was passiert? Sie springt zu &MB_OK, wo höchstwahrscheinlich nichts sinnvolles liegt und es Exceptions hagelt.
Ich hoffe das Beispiel macht klar, was ich meine. Das war auch alles was ich zu sagen hatte.
Ich weiß nicht, inwiefern sowas überhaupt in den Artikel aufgenommen werden sollte, ich weiß nicht ob das eine Eigenart von bcc oder von C++ ist, und es mit anderen Compilern/Programmiersprachen wunderbar funzt, aber ich habe etwas gebraucht um das zu debuggen und hatte einfach Mitteilungsbedürfnis . Schließlich habe ich es über ein kleines Inline Asm Programm, das den Stack aufräumt, lösen können.
Hier kannst du bei Interesse meinen Code finden, die vorkompilierten Binarys in dem Archiv sind noch Debug Binarys, dh. sie sind nur lauffähig wenn auf dem System der Borland Debugger installiert ist. Egal, der Source ist eh interessanter
So das wär's von mir, schönen Tag noch...
//edit, Achja hätte ich ja fast vergessen, da der Abschnitt zum globalen Hooking noch in Arbeit ist, schau dir mal an wie ich das gemacht habe, Windows bietet da einige nette Hilfestellungen an...
Und zwar, zunächst dein Text hat mir sehr weiter geholfen, die Technik ist gut und nachvollziehbar erklärt und ich mag deinen Schreibstil
ABER ich halte deine Implementierung für sehr umständlich, dieses ganze hin und her gespringe und das nicht zerreissen eines Befehls, das geht meiner Meinung nach besser.
Ich habe einfach die originalen ersten 5-Bytes der API gespeichert und mit dem Sprungbefehl überschrieben (egal ob dabei etwas zerrissen wurde), In der angesprungenen Funktion (die statt der API ausgeführt werden soll) schreibe ich dann temporär den originalen Anfang wieder zurück, so dass die API wieder den originalen Zustand hat und ich sie benutzen kann, und am Ende der angesprungen Funktion schreibe ich wieder den Sprungbefehl an den Anfang der API. Es macht so nichts, dass die Befehle zerrissen wurden weil sie ja sowieso nie ausgeführt werden. Tut mir leid, aber das halte ich für eleganter als den originalen Code irgenwo anders auszuführen, was ist zB wenn in den ersten Befehlen der API relative Adressen benutzt werden und du diesen Code jetzt an einer ganz anderen Stelle ausführst? Naja, das war der eine Punkt, ich hoffe du konntest nachvollziehen was ich meine.
Der zweite Punkt, ich bin mir nicht sicher ob das allgemein gültig ist, aber ich habe meinen C++ Code mit Borland 6 geschrieben und bei dem Code den der generiert muss man noch etwas mehr Handarbeit anlegen als du beschrieben hast, Hintergrund ist folgender, ein API Aufruf sieht im Asm Listing so aus:
Code:
push parameter1
push parameter2
[...]
call API_Adresse
bla
Wenn ich jetzt den Hook gesetzt habe, die API Adresse gecallt wird, von dort in meine Funktion gesprungen wird, diese abgearbeitet und am Ende mit einem Return beendet wird, dann liegen die gepushten Parameter noch immer auf dem Stack. C++ Funktionen entfernen, anders als API Funktionen, diese nicht wieder automatisch. Zumindest war das bei dem von bcc generierten Code der Fall, wie gesagt ich weiß nicht ob das für alle Compiler/Programmiersprachen gilt.
Der Rücksprung funktioniert zwar wie er soll, aber die aufrufende Funktion erwartet, dass der Stack nach dem API Aufruf aufgeräumt wurde. Das führte dann bei mir zu komischen Fehlern, die nicht sooo leicht zu debuggen waren naja, ich mache das mal an einem Beispiel deutlich:
Wir denken uns eine main Funktion:
Code:
int main(){
MessageBox(0,"bla","bla",MB_OK);
return 0;
}
und weiterhin sei die API "MessageBoxA" gehookt, wie befinden uns am Anfang der Main Funktion, auf dem Stack (er wächst in meiner Darstellung nach unten) liegt die Rücksprungadresse von irgendeiner Windows Funktion die uns aufgerufen hat (wahrscheinlich CreateProcess oder sowas):
Code:
STACK:
&CreateProcess
Code:
STACK:
&CreateProcess
0
&"bla"
&"bla"
MB_OK
&main
Code:
STACK:
&CreateProcess
0
&"bla"
&"bla"
MB_OK
Ich hoffe das Beispiel macht klar, was ich meine. Das war auch alles was ich zu sagen hatte.
Ich weiß nicht, inwiefern sowas überhaupt in den Artikel aufgenommen werden sollte, ich weiß nicht ob das eine Eigenart von bcc oder von C++ ist, und es mit anderen Compilern/Programmiersprachen wunderbar funzt, aber ich habe etwas gebraucht um das zu debuggen und hatte einfach Mitteilungsbedürfnis . Schließlich habe ich es über ein kleines Inline Asm Programm, das den Stack aufräumt, lösen können.
Hier kannst du bei Interesse meinen Code finden, die vorkompilierten Binarys in dem Archiv sind noch Debug Binarys, dh. sie sind nur lauffähig wenn auf dem System der Borland Debugger installiert ist. Egal, der Source ist eh interessanter
So das wär's von mir, schönen Tag noch...
//edit, Achja hätte ich ja fast vergessen, da der Abschnitt zum globalen Hooking noch in Arbeit ist, schau dir mal an wie ich das gemacht habe, Windows bietet da einige nette Hilfestellungen an...