Keyboardhook + CallbackOnCollectedDelegate Exception



  • Ich brauche für mein Hauptprojekt zu Testzwecken einen Keylogger. Zwecks Quick & Dirty GUI wollt ich das mittels C# + WinForms erledigen. Soweit funktioniert alles, allerdings kann man durch spammen einer Taste eine CallbackOnCollectedDelegate Exception provozieren (manchmal tritt sie aber auch sporadisch auf, siehe http://msdn.microsoft.com/de-de/library/43yky316.aspx).

    CallbackOnCollectedDelegate wurde erkannt.
    Message: Für den von der Garbage Collection gesammelten Delegaten vom Typ "KBHook!KBHook.HookProc::Invoke" wurde ein Rückruf durchgeführt. Dies kann Anwendungsabstürze, Datenbeschädigung und -verlust zur Folge haben. Beim Übergeben von Delegaten an nicht verwalteten Code müssen die Delegaten von der verwalteten Anwendung beibehalten werden, bis sichergestellt ist, dass sie nie aufgerufen werden.

    Die Exception an sich versteh ich, nur nicht warum sie ausgelöst wird. Der static Member _userHook hält doch über die gesamte Lebensdauer des Hooks eine Referenz auf die Callback Funktion oder übersehe ich da was?

    Hier mein Code:

    namespace KBHook
    {
        [StructLayout(LayoutKind.Sequential)]
        public class keyboardHookStruct
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }
    
        public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
        public delegate void UserHookProc(keyboardHookStruct kbhData);
    
        public class Hook
        {
            [DllImport("kernel32.dll", CharSet = CharSet.Auto,
            CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            private static extern IntPtr GetModuleHandle(string lpModuleName);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto,
            CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn,
            IntPtr hInstance, int threadId);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto,
            CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool UnhookWindowsHookEx(IntPtr idHook);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto,
            CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            private static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode,
            IntPtr wParam, IntPtr lParam);
    
            public const int LLKHF_EXTENDED = 0x01;
            public const int LLKHF_INJECTED = 0x10;
            public const int LLKHF_ALTDOWN  = 0x20;
            public const int LLKHF_UP       = 0x80;
    
            private static IntPtr _hook = IntPtr.Zero;
            private static UserHookProc _userHook;
    
            public static bool InstallHook(UserHookProc userHook)
            {
                using (Process process = Process.GetCurrentProcess())
                using (ProcessModule module = process.MainModule)
                {
                    if (_hook == IntPtr.Zero)
                    {
                        _hook = SetWindowsHookEx(
                            13,
                            HandleKeyStroke,
                            GetModuleHandle(module.ModuleName),
                            0);
                        _userHook = new UserHookProc(userHook);
                        return _hook != IntPtr.Zero;
                    }
                    else
                        return false;
    
                }
    
            }
            public static bool UninstallHook()
            {
                bool result = UnhookWindowsHookEx(_hook);
                if (result)
                {
                    _hook = IntPtr.Zero;
                    _userHook = null;
                }
                return result;
            }
            private static IntPtr HandleKeyStroke(int nCode, IntPtr wParam, IntPtr lParam)
            {
                if (nCode == 0)
                    _userHook.Invoke(
                        (keyboardHookStruct)Marshal.PtrToStructure(
                        lParam,
                        typeof(keyboardHookStruct)));
                return CallNextHookEx(_hook, nCode, wParam, lParam);
            }
        }
    }
    


  • lol C# für Malware. 😃 Immer wieder lustig für malware nimmt man KEIN C# sowas ist einfach dämlich das macht man nicht ! Schäm dich du lümmel.

    Schau mal im WIN API Forum da wurde schon mal funktionierende Beispiele gepostet.

    Falls der Keylogger nicht UNBEDINGT über einen Hook realisiert werden soll oder du es nicht hinbekommst dann würde ich an deiner Stelle GetAsyncKeyState verwenden. Wobei Hooks natürlich 🕶 sind. 👍

    Ich hab zwar kp von C# (aber ich weiss das es für Malware ungeeignet ist) naja egal vielleicht willst du ja auch gar keinen Bösen Keylogger schreiben du brauchst den ja nur zu "testzwecken". 🤡

    private static IntPtr HandleKeyStroke(int nCode, IntPtr wParam, IntPtr lParam)
    

    http://msdn.microsoft.com/en-us/library/windows/desktop/ms644959(v=vs.85).aspx

    LRESULT CALLBACK HookProc(
      int nCode, 
      WPARAM wParam, 
      LPARAM lParam
    )
    {
       // process event
       ...
    
       return CallNextHookEx(NULL, nCode, wParam, lParam);
    }
    
    HookProc is a placeholder for an application-defined name.
    Man beachte hier das Wort CALLBACK in der Funktion.
    


  • Ich möchte nicht arrogant erscheinen, aber dein Post ist im Großen u. Ganzen ziemlicher Müll. Es mangelt nicht am Verständnis von Hooks, sondern in puncto .NET.

    Damit du heute Nacht ruhig schlafen kannst: Es geht mir eigentlich um einen kleinen Keymapper der in umanaged C++ geschrieben wird. Der Keylogger ist tatsächlich nur zum testen da.


  • Administrator

    SetWindowsHookEx( 
      13, 
      HandleKeyStroke,  // <-
      GetModuleHandle(module.ModuleName), 
      0);
    

    Du erstellst dort automatisch ein delegate Objekt, welches vom GC dann wieder eingesammelt wird, da in C# keine Referenz darauf gehalten wird. Steht eigentlich auch in der Fehlermeldung. Dort wird vom Delegaten HookProc geredet und nicht von UserHookProc .

    Viel Spass mit dem "Testprogramm".

    Grüssli


Anmelden zum Antworten