Iczelion - 24 - Windows Hooks

Tutorial 24: Windows Hooks


Wir werden in diesem Tutorial etwas Windows Hooks lernen. Windows Hooks sind sehr mächtig. Mit ihnen können Sie in anderen Prozessen herumstochern und manchmal ihr Verhalten ändern.
Laden Sie das Beispiel hier herunter.

Theorie:

Windows Hooks können als eins der mächtigsten Features von Windows angesehen werden. Mit ihnen, können Sie auftretente Ereignisse verfolgen, entweder in Ihrem eigenen Prozess oder in anderen Prozessen. Durch "hooking", teilen Sie Windows eine Funktion, Filter-Funktion aich Hook-Prozedur genannt, mit, die jedes Mal, wenn ein Ereigniss, dass Sie interessiert, auftritt, aufgerufen wird. Es gibt davon zwei Arten: lokale und Remote Hooks.
  • Lokale Hooks verfolgen Ereignisse, die in Ihrem eigenen Prozess auftreten.
  • Remote Hooks verfolgen Ereignisse, die in anderen Prozess(en) auftreten. Es gibt zwei Arten von Remote Hooks
    • Thread-spezifisch verfolgt Erigenisse, die in einem bestimmten Thread eines anderen Prozesses auftreten. Kurz gesagt, Sie wollen Ereignisse in bestimmten Threads, bestimmter Prozesse beobachten.
    • System-weit verfolgt alle Ereignisse in allen Threads in allen Prozessen des Systems.
Wenn Sie Hooks installieren, sollten Sie bedenken, dass die System-Performance beeinträchtigt wird. Besonders bei System-weiten Hooks. Da ALLE relevanten Ereignisse an in Ihre Filter-Funktion geleitet werden, könnte sich Ihr System merkbar verlangsamen. Deshalb sollten Sie, wenn Sie system-weite Hooks benutzen, recht umsichtig benutzen und sobald Sie sie nicht mehr benötigen wieder entfernen. Außerdem ist die Gefahr eines Crashs eines anderen Prozesses größer, da Sie sich in andere Prozesse einmischen können und wenn etwas falsch an Ihrer Filter-Funktion ist, kann es den anderen Prozess abstürzen lassen. Dran denken: Macht geht immer mit Verantwortlichkeit zusammen.
Sie müssen verstehen, wie ein Hook arbeitet, bevor Sie ihn effizient nutzen können. Wenn Sie einen Hook erzeugen, erzeugt Windows eine Daten-Struktur im Speicher, die Informationen über den Hook enthält und fügt ihn einer verketteten Liste von vorhandenen Hooks hinzu. Neue Hooks werde vor den allten Hooks eingefügt. Wenn ein Ereignis auftritt und Sie haben einen lokalen Hook installiert, wird sofort die Filterfunktion in Ihrem Prozess aufgerufen. Wenn es allerdings ein Remote Hook ist, muss das System den Code der Hook-Prozedur allerdings in den Adressraum des anderen Prozesses einfügen. Und das System kann das nur machen, wenn sich die Funktion in einer DLL befindet. Deshalb müssen Sie, wenn Sie einen Remote Hook benutzen wollen, Ihre Hook-Prozedur in einer DLL unterbringen. Es gibt zwei Ausnahmen zu dieser Regel: Journal Record und Journal Playback Hooks. Die Hook Prozeduren für diese beiden Hooks müssen sich in dem Thread befinden, der die Hooks installiert. Der Grund dafür ist: beide Hooks handeln mit dem low-Level Abfangen von Hardware Eingabe-Ereignissen. Die Eingabe-Ereignisse müssen in der Reihenfolge aufgezeichnet (recorded)/abgespielt (playback) werden, in der sie auftreten. Wenn der Code dieser beiden Hooks in einer DLL ist, können die Eingabe Ereignisse über verschiedene Threads verteilen und es wird unmöglich die Reihenfolge zu wissen. Die Lösung: die Hook-Prozedur dieser beiden Hooks muss in einem einzelnen Thread sein, d.h. der Thread, der die Hooks installiert.
Es gibt 14 Arten von Hooks:
  • WH_CALLWNDPROC wird aufgerufen wenn SendMessage aufgerufen wird
  • WH_CALLWNDPROCRET wird aufgerufen wenn SendMessage zurückkehrt
  • WH_GETMESSAGE wird aufgerufen wenn GetMessage oder PeekMessage aufgerufen wird
  • WH_KEYBOARD wird aufgerufen wenn GetMessage oder PeekMessage WM_KEYUP oder WM_KEYDOWN aus der Message Queue erhält
  • WH_MOUSE wird aufgerufen, wenn GetMessage oder PeekMessage eine Maus-Nachricht aus der Message Queue erhält
  • WH_HARDWAREwird aufgerufen, wenn GetMessage oder PeekMessage irgend eine Hardware-Nachricht erhält, die nicht von der Tastatur oder Maus kommt.
  • WH_MSGFILTER wird aufgerufen, wenn eine Dialog Box, Menü oder ScrollBar eine Nachricht bearbeitet. Dieser Hook ist lokal. Er ist vor allem für die Objekte, die eine eigene interne Nachrichten-Schleife haben.
  • WH_SYSMSGFILTER das selbe wie WH_MSGFILTER allerdings System-weit
  • WH_JOURNALRECORD wird aufgerufen, wenn Windows eine Nachricht aus der Hardware-Eingabe-Queue erhält.
  • WH_JOURNALPLAYBACK wird aufgerufen, wenn ein Ereigniss von der System-Hardware-Eingabe-Queue angefordert wird.
  • WH_SHELL wird aufgerufen, wenn etwas interessantes an der Shell passiert, so wenn die Task Bar seine Buttons erneut zeichnen muss.
  • WH_CBT wird speziell für computer-based training (CBT) benutzt.
  • WH_FOREGROUNDIDLEwird intern von Windows benutzt. Kaum nutzen für normale Applikationen
  • WH_DEBUG wird benutzt um die Hooking-Prozedur zu debuggen.
Nun, da wir etwas Theorie kennen, können wir mit dem installieren/deinstallieren von Hooks weiter machen.
Um einen Hook zu installieren, rufen Sie SetWindowsHookEx auf, was folgende Syntax hat:
SetWindowsHookEx proto HookType:DWORD, pHookProc:DWORD, hInstance:DWORD, ThreadID:DWORD


  • HookType ist einer der oben gelisteten Werte, z.B. WH_MOUSE, WH_KEYBOARD
  • pHookProc ist die Adresse der Hook-Prozedur, die aufgerufen wird, um die Nachrichten für einen speziellen Hook zu bearbeiten. Wenn es sich um einen Remote Hook handelt, muss er sich in einer DLL befinden. Wenn nicht, muss er in einem Prozess sein.
  • hInstance ist das Instanz-Handle der DLL, in der sich die Hook-Prozedur befindet. Wenn es sich um einen lokalen Hook behandelt, muss dieser Wert NULL sein.
  • ThreadID ist die ID des Threads, den der installierende Hook ausspionieren soll. Dieser Parameter ist der jenige, der bestimmt, ob der Hook lokal oder remote ist. Wenn dieser Paramtere NULL ist, wird Windows das als System-weiten Hook interpretieren, der alle Threads im System überwacht. Wenn Sie eine Thread ID eines Threads aus Ihrem eigenen Prozess angeben, ist Hook lokal. Wenn Sie die Thread-ID aus einem anderen Prozess angeben, ist der Hook ein Thread-spezifischer remote. Es gibt zwei Ausnahmen zu dieser Regel: WH_JOURNALRECORD und WH_JOURNALPLAYBACK sind immer lokale System-weite Hooks, die nicht in einer DLL sein müssen. Und WH_SYSMSGFILTER ist immer ein System-weiter Remote Hook. Tatsächlich ist er identisch mit WH_MSGFILTER Hook mit ThreadID==0.
Wenn der Aufruf erfolgreich ist, wird das Hook Handle in EAX zurückgegeben. Wenn nicht, wird NULL zurückgegeben. Sie müssen das Hook-Handle fürs spätere Unhooking sichern.
Sie können einen Hook deinstallieren, indem Sie UnhookWindowsHookEx aufrufen, die nur einen Parameter akzeptiert, das Handle des Hooks den Sie deinstallieren wollen. Wenn der Aufruf erfolgreich war, wir ein Wert ungleich 0 in EAX zurückgegeben, ansonsten NULL.
Nun, da Sie wissen, wie man Hooks installiert/deinstalliert, schauen wir uns die Hook-Prozedur an.
Die Hook-Prozedur wir immer aufgerufen, wenn ein Ereigniss auftritt, das mit der Art des Hooks, den Sie installiert haben, verbunden ist. Wenn Sie zum Beispiel einenWH_MOUSE Hook installieren, wird Ihre Hook Prozedur aufgerufen, wenn ein Maus-Ereigniss auftritt. Egal was für Art von Hook Sie installieren, hat die Hook-Prozedur immer folgenden Prototyp:
    HookProc proto nCode:DWORD, wParam:DWORD, lParam:DWORD

    • nCode spezifiziert den Hook Code.
    • wParam und lParam enthalten zusätzlichen Informationen über das Ereigniss
HookProc ist eigentlich ein Platzhalter für den Funktions-Namen. Sie können sie benennen, wie Sie wollen, solange es den obigen Prototypen hat. Die Interpretation von nCode, wParam und lParam ist abhängig von der Art des Hooks den Sie installieren. Genauso wie der Rückgabewert der Hook-Prozedur. Zum Beispiel:
WH_CALLWNDPROC
  • nCode kann lediglich HC_ACTION sein, was bedeutet, dass eine Nachricht an ein Fenster gesendet wurde
  • wParam enthält die Nachricht, die gesendet wurde, wenn nicht gleich 0
  • lParam zeigt auf eine CWPSTRUCT Struktur
  • return value: wird nicht benutzt, 0 wird zurückgegeben
WH_MOUSE
  • nCode kann HC_ACTION oder HC_NOREMOVE sein
  • wParam enthält die Maus-Nachricht
  • lParam zeigt auf eine MOUSEHOOKSTRUCT Struktur
  • return value: 0 wenn die Nachricht bearbeitet werden soll. 1 wenn die Nachricht verworfen werden soll.
Die Schlussfolgerung ist: Sie müssen ihre Win32 API Referenz für Details über die Bedeutung der Parameter und Rückgabewerte des Hooks, den Sie installieren, konsultieren.
Es gibt noch einen kleinen Haken bei der Hook-Prozedur. Wie Sie sich erinnern, werden die Hooks in eine verkettete Liste geschrieben, mit dem zuletzt installierten Hook am Anfang. Wenn ein Ereigniss auftritt, ruft Windows nur den ersten Hook in der Kette auf. Ihre Hook-Prozedur ist dafür verantwortlich den nächsten Hook aus der Kette aufzurufen. Sie brauchen den Hook nicht aufrufen, aber Sie sollten dann wissen, was Sie tun. Meistens ist es besser, die nächste Prozedur aufzurufen, damit andere Hooks das Ereigniss bearbeiten können. Sie können den nächsten Hook aufrufen, indem Sie CallNextHookEx aufrufen, was folgenden Prototypen hat:
CallNextHookEx proto hHook:DWORD, nCode:DWORD, wParam:DWORD, lParam:DWORD
  • hHook ist Ihr eigenes Hook Handle. Die Funktion benutzt dieses Handle, um die verketteten Listen zu durchqueren und sucht die Hook-Prozedur die als nächstes aufgerufen werden soll.
  • nCode, wParam und lParam Sie können einfach diese drei Werte übergeben, die Sie von Windows erhalten für CallNextHookEx.
Eine wichtige Anmwekung über Remote Hooks: die Hook-Prozedur muss sich in einer DLL befinden, welche in andere Prozesse gemapped wird. Wenn Windows eine DLL in andere Prozesse mapped, wird es nicht die Daten-Sektion(en) in die Prozesse mappen. Kurz gesagt, alle Prozesse teilen eine einzige Kopie des Codes, aber sie haben ihre eigene Kopie der DLL Daten-Sektion. Das kann eine große Überraschung für den Unachtsamen sein. Sie denken vielleicht, dass wenn Sie einen Wert in einer Variablen in der Daten-Sektion der DLL speichern, dass dieser Wert von den anderen Prozessen geteilt wird, die die DLL in ihren Address-Raum laden. Das stimmt einfach nicht. In normalen Situationen ist dieses Verhalten wünschenswert, da es die Illusion vorgibt, dass jeder Prozess seine eigene Kopie der DLL hat. Aber nicht wenn es um Windows-Hooks geht. Wir wollen die DLL in jedem Prozess identisch haben, inklusive der Daten. Die Lösung: Sie müssen eine Daten-Sektion als shared markieren. Sie können das machen, indem Sie die Sektions Attribute im Linker-Parameter angeben. Für MASM müssen Sie diesen Parameter benutzen:
/SECTION:<section name>, S
Der Name der initialisierten Daten-Sektion ist .data und der uninitialisierten Daten ist .bss. Wenn Sie zum Beispiel eine DLL assemblieren wollen, die eine Hook-Prozedur enthält und Sie wollen die uninitalisierte Daten-Sektion unter mehreren Prozessen teilen, müssen Sie folgende Zeile benutzen:
link /section:.bss,S /DLL /SUBSYSTEM:WINDOWS ..........
Das S Attribut markiert die Sektion als shared.

Beispiel:

Es gibt zwei Module: eins ist das Hauptprogramm, das den GUI Teil mach und das andere ist die DLL die den Hook de/installiert.
;--------------------------------------------- Das ist der Source Code des Haupt-Programms -------------------------------------- .386 .model flat,stdcall option casemap:none include \masm32\include\windows.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc include mousehook.inc includelib mousehook.lib includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib wsprintfA proto C :DWORD,:DWORD,:VARARG wsprintf TEXTEQU .const IDD_MAINDLG equ 101 IDC_CLASSNAME equ 1000 IDC_HANDLE equ 1001 IDC_WNDPROC equ 1002 IDC_HOOK equ 1004 IDC_EXIT equ 1005 WM_MOUSEHOOK equ WM_USER+6 DlgFunc PROTO :DWORD,:DWORD,:DWORD,:DWORD .data HookFlag dd FALSE HookText db "&Hook",0 UnhookText db "&Unhook",0 template db "%lx",0 .data? hInstance dd ? hHook dd ? .code start: invoke GetModuleHandle,NULL mov hInstance,eax invoke DialogBoxParam,hInstance,IDD_MAINDLG,NULL,addr DlgFunc,NULL invoke ExitProcess,NULL DlgFunc proc hDlg:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD LOCAL hLib:DWORD LOCAL buffer[128]:byte LOCAL buffer1[128]:byte LOCAL rect:RECT .if uMsg==WM_CLOSE .if HookFlag==TRUE invoke UninstallHook .endif invoke EndDialog,hDlg,NULL .elseif uMsg==WM_INITDIALOG invoke GetWindowRect,hDlg,addr rect invoke SetWindowPos, hDlg, HWND_TOPMOST, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW .elseif uMsg==WM_MOUSEHOOK invoke GetDlgItemText,hDlg,IDC_HANDLE,addr buffer1,128 invoke wsprintf,addr buffer,addr template,wParam invoke lstrcmpi,addr buffer,addr buffer1 .if eax!=0 invoke SetDlgItemText,hDlg,IDC_HANDLE,addr buffer .endif invoke GetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer1,128 invoke GetClassName,wParam,addr buffer,128 invoke lstrcmpi,addr buffer,addr buffer1 .if eax!=0 invoke SetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer .endif invoke GetDlgItemText,hDlg,IDC_WNDPROC,addr buffer1,128 invoke GetClassLong,wParam,GCL_WNDPROC invoke wsprintf,addr buffer,addr template,eax invoke lstrcmpi,addr buffer,addr buffer1 .if eax!=0 invoke SetDlgItemText,hDlg,IDC_WNDPROC,addr buffer .endif .elseif uMsg==WM_COMMAND .if lParam!=0 mov eax,wParam mov edx,eax shr edx,16 .if dx==BN_CLICKED .if ax==IDC_EXIT invoke SendMessage,hDlg,WM_CLOSE,0,0 .else .if HookFlag==FALSE invoke InstallHook,hDlg .if eax!=NULL mov HookFlag,TRUE invoke SetDlgItemText,hDlg,IDC_HOOK,addr UnhookText .endif .else invoke UninstallHook invoke SetDlgItemText,hDlg,IDC_HOOK,addr HookText mov HookFlag,FALSE invoke SetDlgItemText,hDlg,IDC_CLASSNAME,NULL invoke SetDlgItemText,hDlg,IDC_HANDLE,NULL invoke SetDlgItemText,hDlg,IDC_WNDPROC,NULL .endif .endif .endif .endif .else mov eax,FALSE ret .endif mov eax,TRUE ret DlgFunc endp end start ;----------------------------------------------------- Das ist der Source Code der DLL -------------------------------------- .386 .model flat,stdcall option casemap:none include \masm32\include\windows.inc include \masm32\include\kernel32.inc includelib \masm32\lib\kernel32.lib include \masm32\include\user32.inc includelib \masm32\lib\user32.lib .const WM_MOUSEHOOK equ WM_USER+6 .data hInstance dd 0 .data? hHook dd ? hWnd dd ? .code DllEntry proc hInst:HINSTANCE, reason:DWORD, reserved1:DWORD .if reason==DLL_PROCESS_ATTACH push hInst pop hInstance .endif mov eax,TRUE ret DllEntry Endp MouseProc proc nCode:DWORD,wParam:DWORD,lParam:DWORD invoke CallNextHookEx,hHook,nCode,wParam,lParam mov edx,lParam assume edx:PTR MOUSEHOOKSTRUCT invoke WindowFromPoint,[edx].pt.x,[edx].pt.y invoke PostMessage,hWnd,WM_MOUSEHOOK,eax,0 assume edx:nothing xor eax,eax ret MouseProc endp InstallHook proc hwnd:DWORD push hwnd pop hWnd invoke SetWindowsHookEx,WH_MOUSE,addr MouseProc,hInstance,NULL mov hHook,eax ret InstallHook endp UninstallHook proc invoke UnhookWindowsHookEx,hHook ret UninstallHook endp End DllEntry ;---------------------------------------------- Das ist das Makefile der DLL ---------------------------------------------- NAME=mousehook $(NAME).dll: $(NAME).obj Link /SECTION:.bss,S /DLL /DEF:$(NAME).def /SUBSYSTEM:WINDOWS /LIBPATH:c:\masm\lib $(NAME).obj $(NAME).obj: $(NAME).asm ml /c /coff /Cp $(NAME).asm



Analyse:

Das Beispiel wird eine Dialog Box mit drei Edit Steuerelementen anzeigen, die mit dem Klassen-Namen, Fenster-Handle und der Adresses der Fenster-Prozedur, die zu dem Fenster gehört, über dem der Mauszeiger ist, anzeigt. Es gibt zwei Buttons, Hook und Exit, wenn Sie den Hook Button klicken, hooked das Programm die Maus-Eingabe und der Button Text ändert sich zu Unhook. Wenn Sie den Maus-Zeiger über ein Fenster bewegen, werden die Informationen über das Fenster, in dem Hauptfenster des Beispiels angezeigt. Wenn Sie den Unhook Button klicken, entfernt das Programm den Maus-Hook wieder.
Das Hauptprogramm benutzt eine Dialog Box als Haupt-Fenster. Es definiert eine eigene Nachricht, WM_MOUSEHOOK, welche zwischen dem Haupt-Programm und der Hook-DLL gesendet wird. Wenn das Programm diese Nachricht erhält, enthält wParam das Handle des Fensters, über das sich der Mauszeiger befindet. Natürlich ist das eine willkürliche Lösung. Ich habe mich entschlossen, das Handle in wParam zu übergeben, nur der Einfachheit halber. Sie können Ihre eigene Methode der Kommunikation zwischen Haupt-Programm und Hook-DLL benutzen.
.if HookFlag==FALSE invoke InstallHook,hDlg .if eax!=NULL mov HookFlag,TRUE invoke SetDlgItemText,hDlg,IDC_HOOK,addr UnhookText .endif


Das Programm enthält ein Flag, HookFlag, um den Status des Hooks zu überwachen. Wenn es FALSE ist, ist der Hook nicht installiert und TRUE wenn der Hook installiert ist.
Wenn der Benutzer den Hook Button drückt, überprüft das Programm, ob der Hook schon installiert ist. Wenn nicht, wird die InstallHook Funktion in der Hook DLL aufgerufen, um ihn zu installieren. Beachten Sie, dass wir das Handle des Haupt-Dialogs als Parameter der Funktion übergeben, so dass die Hook DLL die WM_MOUSEHOOK Nachrichten an das richtige Fenster, dh. an unser eigenes sendet.
Wenn das Programm geladen ist, wird auch die Hook DLL geladen. Eigentlich werden DLLs immer unverzüglich geladen, nachdem das Programm im Speicher ist. Die DLL Einstiegspunkt-Funktion wird ausgeführt, bevor der erste Befehl des Programms ausgeführt wird. So, dass wenn das Programm ausgeführt wird, die DLL(s) schon initialisiert ist/sind. Wir haben folgenden Code in der Einstiegs-Funktion der Hook DLL:
.if reason==DLL_PROCESS_ATTACH push hInst pop hInstance .endif


Der Code speichert nur das Instanz-Handle der Hook-DLL in einer globalen Variablen names hInstance um sie innerhalb der InstallHook-Funktion zu benutzen. Da die DLL Einstiegs-Funktion aufgerufen wird, bevor andere Funktionen der DLL aufgerufen werden, ist hInstance immer gültig. Wir speichern hInstance in der .data Sektion, so dass dieser Wert für jeden Prozess gespeichert wird. Da, wenn der Maus-Cursor über ein anderes Fenster schwebt, die Hook-DLL in den Prozess gemapped wird. Stellen Sie sich vor, dass da schon eine DLL ist, die die zu ladende Hook DLL Adresse beschäftigt, würde die Hook DLL in eine andere Adresse gemapped werden. Der Wert von hInstance würde beim laden der neuen Adresse erneuert werden. Wenn der Benutzer den Unhook Button klickt und dann den Hook Button, wird SetWindowsHookEx erneut aufgerufen. Diesmal würde es die neue Lade Adresse als das Instanz-Handle benutzen, welches falsch ist, da im Beispiel-Prozess die Hook DLL Lade Adresse sich nicht geändert hat. Der Hook ist ein lokaler, wenn Sie nur die Maus-Ereignisse, die in ihrem Fenster passieren hooken können. Kaum wünschenswert.
InstallHook proc hwnd:DWORD push hwnd pop hWnd invoke SetWindowsHookEx,WH_MOUSE,addr MouseProc,hInstance,NULL mov hHook,eax ret InstallHook endp


Die InstallHook Funktion selbst hingegen ist sehr einfach. Sie sichert das Fenster-Handle, das als ihr Parameter übergeben wurde, in einer globalen Variable namens hWnd für späteren Gebrauch. Dann ruft sie SetWindowsHookEx auf, um den Maus-Hook zu installieren. Der Rückgabewert von SetWindowsHookEx wird in einer globalen Variable namens hHook gespeichert, um sie mit UnhookWindowsHookEx zu benutzen.
Nachdem SetWindowsHookEx aufgerufen wurde, ist der Maus-Hook funktionsfähig. Wann immer auch ein Maus-Ereigniss im System auftritt, wird MouseProc (Ihre Hook Prozedur) aufgerufen.
MouseProc proc nCode:DWORD,wParam:DWORD,lParam:DWORD invoke CallNextHookEx,hHook,nCode,wParam,lParam mov edx,lParam assume edx:PTR MOUSEHOOKSTRUCT invoke WindowFromPoint,[edx].pt.x,[edx].pt.y invoke PostMessage,hWnd,WM_MOUSEHOOK,eax,0 assume edx:nothing xor eax,eax ret MouseProc endp


Als erstes wird CallNextHookEx aufgerufen, um anderen Hooks die Chance zu geben, Maus-Ereignisse zu bearbeiten. Danach wird die WindowFromPoint Funktion aufgerufen um das Handle des Fensters an den angegebenen Bildschirm-Koordinaten zu ermitteln. Beachten Sie, dass wir die POINT Struktur in der MOUSEHOOKSTRUCT Struktur benutzen, auf die lParam, als aktuelle Muas-Koordinaten, zeigt. Danch senden wir das Fenster-Handle zum Hauptprogramm via PostMessage mit der WM_MOUSEHOOK Nachricht. An was Sie denken sollten: Sie sollten nicht SendeMessage innerhalb einer Hook-Prozedur benutzen, da es einen Nachricht Deadlock erzeugen kann. PostMessage wird dafür benötigt. Die MOUSEHOOKSTRUCT Struktur ist wie folgt definiert:
MOUSEHOOKSTRUCT STRUCT DWORD pt POINT hwnd DWORD ? wHitTestCode DWORD ? dwExtraInfo DWORD ? MOUSEHOOKSTRUCT ENDS



  • pt sind die aktuellen Bildschirm Koordinaten des Maus-Cursor
  • hwnd ist das Handle des Fensters, dass die Maus-Nachrichten empfängt. Es ist normalerweise das Fenster unter dem Maus-Cursor, aber nicht immer. Wenn ein Fenster SetCapture aufruft, wird die Maus-Eingabe zu diesem Fenster statt dessen umgeleitet. Aus diesem Grund benutze ich das hwnd Elemente dieser Struktur nicht, sondern rufe statt dessen WindowFromPoint auf.
  • wHitTestCode spezifiziert den Hit-Test Wert. Der Hit-Test Wert gibt mehr Informationen über die aktuelle Maus-Cursor-Position. Es spezifiziert, auf welchem Teil des Fensters der Maus-Cursor ist. Für eine komplette Liste, schauen Sie in Ihrer Win32 API unter WM_NCHITTEST Nachricht nach.
  • dwExtraInfo enthält zusätliche Informationen die mit der Nachricht verbunden sind. Normalerweise wird dieser Wert gesetzt indem mouse_event aufgerufen wird und ermittelt durch einen GetMessageExtraInfo Aufruf.
Wenn das Haupt-Fenster ein WM_MOUSEHOOK Nachricht erhält, benutzt es das Fenster Handle in wParam um Information über das Fenster zu erhalten.
.elseif uMsg==WM_MOUSEHOOK invoke GetDlgItemText,hDlg,IDC_HANDLE,addr buffer1,128 invoke wsprintf,addr buffer,addr template,wParam invoke lstrcmpi,addr buffer,addr buffer1 .if eax!=0 invoke SetDlgItemText,hDlg,IDC_HANDLE,addr buffer .endif invoke GetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer1,128 invoke GetClassName,wParam,addr buffer,128 invoke lstrcmpi,addr buffer,addr buffer1 .if eax!=0 invoke SetDlgItemText,hDlg,IDC_CLASSNAME,addr buffer .endif invoke GetDlgItemText,hDlg,IDC_WNDPROC,addr buffer1,128 invoke GetClassLong,wParam,GCL_WNDPROC invoke wsprintf,addr buffer,addr template,eax invoke lstrcmpi,addr buffer,addr buffer1 .if eax!=0 invoke SetDlgItemText,hDlg,IDC_WNDPROC,addr buffer .endif


Um Flackern zu vermeiden, überprüfen wir, ob der Text im Edit Steuerelement mit dem identisch ist, den wir schreiben wollen. Falls ja, überspringen wir den Text.
Wir ermitteln den Klassen-Namen, indem wir GetClassName aufrufen, die Adresse der Fenster-Prozedur indem wir GetClassLong mit GCL_WNDPROC aufrufen und formatieren sie dann in Strings und zeigen sie im vorgesehenen Edit Steuerelement an.
invoke UninstallHook invoke SetDlgItemText,hDlg,IDC_HOOK,addr HookText mov HookFlag,FALSE invoke SetDlgItemText,hDlg,IDC_CLASSNAME,NULL invoke SetDlgItemText,hDlg,IDC_HANDLE,NULL invoke SetDlgItemText,hDlg,IDC_WNDPROC,NULL


Wenn der Benutzer den Unhook Button klickt, ruft das Programm die UninstallHook Funktion in der Hook DLL auf. UninstallHook ruft nur UnhookWindowsHookEx auf. Danach ändern wir den Text des Buttons zurück auf "Hook", HookFlag auf FALSE und löschen den Inhalt der Edit Steurelemente.
Beachten Sie den Linker Parameter im Makefile.
Link /SECTION:.bss,S /DLL /DEF:$(NAME).def /SUBSYSTEM:WINDOWS


Die .bss Sektion wird als Shared-Sektion (geteilte Sektion) angegeben, damit alle Prozesse die selbe uninitialisierte Daten-Sektion der Hook-DLL benutzen. Ohne diesen Parameter wird Ihre Hook-DLL nicht korrekt arbeiten.

Deutsche Übersetzung: Joachim Rohde
Die original Win32Asm-Tutorials stammen von Iczelion's Win32 Assembly HomePage