Register for your free account! | Forgot your password?

Go Back   elitepvpers > Coders Den > General Coding
You last visited: Today at 08:27

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



Hooking mit WinAPI über C#

Discussion on Hooking mit WinAPI über C# within the General Coding forum part of the Coders Den category.

Reply
 
Old   #1


 
elite*gold: 1091
Join Date: Jun 2007
Posts: 19,836
Received Thanks: 7,180
Hooking mit WinAPI über C#

Ich hatte in einem meiner Spiele mal die Shoutbox hier in Verbindung mit der epvp Library über DirectX gezeichnet. Dafür habe ich mal mit C# gespielt und mittels der eine Library (DLL) in den Prozess injizieren können.

Ich hatte testweise geplant, eine Art Eingabe zu implementieren die ermöglicht, direkt im Spiel einen Shout zu senden.

Soweit so gut aber irgendwie muss die Eingabe aus dem Spiel ja auch registriert werden, ne? Shift abzufragen ob der Eingabemodus aktiv ist, war kein Problem. GetAsyncKeyState hätte da schon ausgereicht aber ich möchte ja auch die Zeichen der gedrückten Tasten abfangen und mitzeichnen.

Erst hatte ich mit einen Hook in die Hookchain mit dem Typ WH_KEYBOARD_LL eingereiht. Das war kein Problem, ich bekam die entsprechenden Nachrichten (WM_KEYDOWN war relevant) über den Callback und habe tatsächlich auch den Key aus der Nachricht ziehen können, der Ingame gedrückt wurde. Einziger Haken: Enthalten ist der Virtual Key Code, der mir leider nicht viel bringt weil der VK und das eigentliche Zeichen das daraus resultiert 2 verschiedene Paar Schuhe sind.

Gut, erstmal gesucht wie man den VK denn umkonvertieren kann um das Zeichen herauszubekommen. Geht nicht wirklich, weil es keine Unterscheidung zwischen Großbuchstaben und Kleinbuchstaben gibt und Sonderzeichen wohl nicht richtig interpretiert werden (also Tastenkombinationen aus ALT usw.).

Also weiter gesucht und folgende Informationen gefunden:

Quote:
Originally Posted by MSDN
Key strokes are converted into characters by the TranslateMessage function, which we first saw in Module 1. This function examines key-down messages and translates them into characters. For each character that is produced, the TranslateMessage function puts a WM_CHAR or WM_SYSCHAR message on the message queue of the window. The wParam parameter of the message contains the UTF-16 character.
"Super", hatte ich mir gedacht. "Dann wechsel ich einfach den Typ von WH_KEYBOARD_LL auf WH_GETMESSAGE und erhalte mit der selben Callback Signatur einfach alle Nachrichten die so in die Schleife geworfen werden".

Schön wäre es gewesen aber:

Code:
using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                // curModule.ModuleName: Diablo III.exe
                _hHook = SetWindowsHookEx(WH_GETMESSAGE, proc, GetModuleHandle(curModule.ModuleName), 0);
            }
_hHook ist nun plötzlich 0 (NULL), Aufruf zu GetLastError gibt 1428 (0x594) zurück:

Quote:
ERROR_HOOK_NEEDS_HMOD
1428 (0x594)
Cannot set nonlocal hook without a module handle.
Wieso? Ich habe doch hier explizit den Modulnamen angegeben und der ist auch richtig.

Wieder in MSDN nachgeschaut und folgende Informationen erhalten:

Quote:
Originally Posted by MSDN
WH_KEYBOARD_LL Global only
WH_GETMESSAGE Thread or global
Quote:
Originally Posted by MSDN
The global hooks are a shared resource, and installing one affects all applications in the same desktop as the calling thread. All global hook functions must be in libraries. Global hooks should be restricted to special-purpose applications or to use as a development aid during application debugging. Libraries that no longer need a hook should remove its hook procedure.
Hilft mir jetzt aber nicht weiter. Wieso konnte der Hook mit WH_KEYBOARD_LL platziert werden, mit WH_GETMESSAGE aber nicht?

______

Quote:
Global hooks are not supported in the .NET Framework

Except for the WH_KEYBOARD_LL low-level hook and the WH_MOUSE_LL low-level hook, you cannot implement global hooks in the Microsoft .NET Framework. To install a global hook, a hook must have a native DLL export to inject itself in another process that requires a valid, consistent function to call into. This behavior requires a DLL export. The .NET Framework does not support DLL exports. Managed code has no concept of a consistent value for a function pointer because these function pointers are proxies that are built dynamically.

Low-level hook procedures are called on the thread that installed the hook. Low-level hooks do not require that the hook procedure be implemented in a DLL.


Dann fällt das weg. Gibt's noch andere Möglichkeiten für mein Vorhaben?
Mostey is offline  
Old 03/29/2015, 22:35   #2
 
Dr. Coxxy's Avatar
 
elite*gold: 0
Join Date: Feb 2011
Posts: 1,206
Received Thanks: 736
Dr. Coxxy is offline  
Old 03/30/2015, 08:05   #3


 
elite*gold: 1091
Join Date: Jun 2007
Posts: 19,836
Received Thanks: 7,180
Quote:
Originally Posted by Dr. Coxxy View Post
Schon klar, nur besitze ich eben keine Möglichkeit die Nachrichten abzufangen weil ich nur einen WH_KEYBOARD_LL Hook setzen kann und der nur WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN und WM_SYSKEYUP Nachrichten erhält.
Mostey is offline  
Old 03/30/2015, 18:39   #4
 
Dr. Coxxy's Avatar
 
elite*gold: 0
Join Date: Feb 2011
Posts: 1,206
Received Thanks: 736
edit: sollte mal genauer den firstpost angucken...

btw. - mit c# noch nie was in der richtung gemacht - aber versteh ich richtig, dass du eh schon mit ner dll im zielprozess rumgurkst? - falls ja, solltest du auch einfach z.b. GetMessage direkt hooken können.

edit2:
z.b. so:
Dr. Coxxy is offline  
Thanks
1 User
Old 03/30/2015, 20:17   #5


 
elite*gold: 1091
Join Date: Jun 2007
Posts: 19,836
Received Thanks: 7,180
Quote:
Originally Posted by Dr. Coxxy View Post
btw. - mit c# noch nie was in der richtung gemacht - aber versteh ich richtig, dass du eh schon mit ner dll im zielprozess rumgurkst? - falls ja, solltest du auch einfach z.b. GetMessage direkt hooken können.
Ja, hatte ich als Reserve geplant aber irgendwie ruft der Zielprozess die Funktion nicht auf. Wollte dann mal weiter schauen ob PeekMessage verwendet wird, wurde aber eben auf eine andere Möglichkeit aufmerksam gemacht.

Und zwar ist es wohl doch sehr gut möglich, anhand eines VK und des Keyboard States das entsprechende Zeichen zu bekommen indem man einfach genau das selbe wie TranslateMessage tut: WM_KEYDOWN übersetzen.

Relevant dafür ist:
  • AttachThreadInput
  • ToAscii
  • MapVirtualKey
  • GetKeyboardState

1. In der Hookprozedur mit AttachThreadInput an den UI Thread ranhängen damit man Zugriff auf die gedrückten Tasten bekommt. Zwingend notwendig weil die Hookprozedur nicht im selben Thread läuft
2. Keyboard State (ein Array welches den Status aller Tasten enthält) mittels GetKeyboardState holen
3. Anhand der MapVirtualKey Funktion den Scan Code des VK holen weil dieser von der ToAscii Funktion benötigt wird
4. ToAscii Funktion aufrufen und sowohl VK, Scan Code als auch den Keyboard State übergeben damit entsprechend der gedrückten Tasten das richtige ASCII Zeichen rum kommt.

Code ist derzeit richtig schlampig und ordentlich aber ist ja eh derzeit nur zum debuggen:

Code:
private IntPtr HookCallback(
            int nCode, IntPtr wParam, IntPtr lParam)
        {

            byte[] ks = new byte[256];

            IntPtr currentHWnd = GetForegroundWindow();
            uint currentProcessID;
            uint currentWindowThreadID = GetWindowThreadProcessId(currentHWnd, out currentProcessID);

            uint thisProgramThreadId = GetCurrentThreadId();

            AttachThreadInput(thisProgramThreadId, currentWindowThreadID, true);


            OnCharEntered("KS:" + GetKeyboardState(ks));
            var vkey = (uint)Marshal.ReadInt32(lParam);
            byte[] ch = new byte[256];
            AttachThreadInput(thisProgramThreadId, currentWindowThreadID, false);


            
            ToAscii(vkey, MapVirtualKey(vkey, MAPVK_VK_TO_VSC), ks, ch, 0);


            OnCharEntered("nCode: " + nCode + " wParam: " + wParam + " lParam: " + lParam + " Map: " + System.Text.Encoding.Default.GetString(ch));
            OnCharEntered("Shift:" + (ks[(int) VirtualKeyStates.VK_SHIFT] & 0x80));
Frag mich jetzt nicht wieso ich TranslateMessage nicht einfach gehooked habe. Das wäre viel zu einfach gewesen.
Mostey is offline  
Old 03/30/2015, 21:32   #6
 
Dr. Coxxy's Avatar
 
elite*gold: 0
Join Date: Feb 2011
Posts: 1,206
Received Thanks: 736
funktioniert da das numpad, € und @ zeichen richtig?
ich hab schonmal was in der richtung gemacht, allerdings mit directinput und da mit paar zeichen probleme gehabt.
Dr. Coxxy is offline  
Old 03/30/2015, 22:06   #7


 
elite*gold: 1091
Join Date: Jun 2007
Posts: 19,836
Received Thanks: 7,180
Quote:
Originally Posted by Dr. Coxxy View Post
funktioniert da das numpad, € und @ zeichen richtig?
ich hab schonmal was in der richtung gemacht, allerdings mit directinput und da mit paar zeichen probleme gehabt.
Habe es eben mal getestet, Numpad funktioniert, @ auch. € wird leider als ? in der Konsole ausgegeben. Liegt womöglich daran, dass das Euro Zeichen nicht im ASCII Zeichensatz enthalten ist. Zumindest nicht in der Standardvariante. Laut ist es das erste Zeichen im extended ASCII Zeichensatz (ISO 8859-1).

Man könnte ja mal weiter rumspielen und zusehen, dass man statt eines ASCII Wertes einfach mal den Unicode Wert herausbekommt. Da wird's sicher Möglichkeiten geben, ich schaue da vielleicht morgen mal.

Ansonsten bin ich mit der derzeitigen Lösung durchaus zufrieden.
Mostey is offline  
Old 04/05/2015, 21:38   #8
 
Master674b's Avatar
 
elite*gold: 0
Join Date: Dec 2012
Posts: 255
Received Thanks: 110
Wieso setzt du nicht einfach einen neuen WndProc und rufst dann daraus den originalen WndProc auf wenn du die Nachricht nicht behandelst. Das ist der Standardweg um Input abzufangen.

Eine neue WndProc setzt du mit SetWindowLongPtr und GWLP_WNDPROC.

Du bekommst dann alle Nachrichten, inklusive WM_CHAR etc.
Master674b is offline  
Old 04/05/2015, 22:41   #9


 
elite*gold: 1091
Join Date: Jun 2007
Posts: 19,836
Received Thanks: 7,180
Quote:
Originally Posted by Master674b View Post
Wieso setzt du nicht einfach einen neuen WndProc und rufst dann daraus den originalen WndProc auf wenn du die Nachricht nicht behandelst. Das ist der Standardweg um Input abzufangen.

Eine neue WndProc setzt du mit SetWindowLongPtr und GWLP_WNDPROC.

Du bekommst dann alle Nachrichten, inklusive WM_CHAR etc.
Ich hatte hier nicht mehr geschrieben, dass ich es tatsächlich so umgesetzt hatte weil die alte Lösung in einem anderen Thread lief und mit meinen bestehenden Hooks ein Problem hatte.

Hatte dann aber keine neue WndProc gesetzt sondern die bestehende des Hauptfensters einfach gehooked.
Mostey is offline  
Reply


Similar Threads Similar Threads
[Help] Winapi/C++
07/08/2011 - C/C++ - 2 Replies
Hallo leute also ich habe mir in letzter zeit oder schon etwas länger c++ Beigebracht. Ich weis nicht ob meine kenntnisse schon ausreichen aber naja ich hab mich mal an Winapi versucht und jetzt mein problem ... kann mir jemand vll erklären was n Handle ist und wenn nicht das gibt es dan vieleicht irgendwelche aufgaben womit ich mir meine c++ kenntnisse verbessern/festigen kann also ich hoffe ihr könnt mir helfen da ich echt ziehmlich interressiert in der Programmierung(Coding) bin. Ich würd...
WinApi Problem
02/17/2011 - General Coding - 12 Replies
Hi, hab keine Ahnung wieso das hier nicht geht. Es lässt sich kompilieren aber es macht nichts, also es erscheint kein Fenster. #define STRICT #include <windows.h> LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); const char szAppName = "Textausgabe im Anwendungsbereich";
WinAPI / AutoIT
02/09/2011 - Last Chaos - 2 Replies
Ich hab ne weile nicht mehr für lc programmiert .. und wollt mal wieder bisl an meinem bots rumspielen .. habe das letzte mal vor!! x trap programmiert ^^ Ich bevorzuge eigentlich AutoIT wegen der tollen pixelsearch und mousemove funktionen ;). Meine Frage .. ist es gar nicht mehr möglich über AutoiT memorys auszulesen selbt mit WINAPI ( windows 7 64 bit ) ? Xtrap meckert bei mir nicht aber er findet auch keinen Prozess ( ich geh davon aus das xtrap blockt ). Habe ich da nen Fehler/etwas...
WinAPI use in C#
06/09/2008 - .NET Languages - 15 Replies
Hi, in Anlehnung an die Topics hier habe ich mich dazu aufgerafft, nen Annotrainer zu schreiben (siehe Attachment). In der Listview werden halt aktive Annoprozesse angezeigt, die man dann anwählen kann um dann mit dem Cheat button Geld zu cheaten. Jedes item in der Listview hat im item.Tag das jeweilige Prozessobject, somit auch die ID. Allerdings komme ich mit den eigentlichen Funktionen OpenProcess, ReadProcessMemory und WirteProcessMemory in C# noch nicht klar. Zwar bekomme ich das...
WinAPI use in C#
05/19/2008 - .NET Languages - 0 Replies
Hi, in Anlehnung an die Topics hier habe ich mich dazu aufgerafft, nen Annotrainer zu schreiben (siehe Attachment). In der Listview werden halt aktive Annoprozesse angezeigt, die man dann anwählen kann um dann mit dem Cheat button Geld zu cheaten. Jedes item in der Listview hat im item.Tag das jeweilige Prozessobject, somit auch die ID. Allerdings komme ich mit den eigentlichen Funktionen OpenProcess, ReadProcessMemory und WirteProcessMemory in C# noch nicht klar. Zwar bekomme ich das...



All times are GMT +1. The time now is 08:28.


Powered by vBulletin®
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2025 elitepvpers All Rights Reserved.