Laden...

Globale Hooks mit c# (nichtnur lowlevel)

Erstellt von Floste vor 14 Jahren Letzter Beitrag vor 14 Jahren 10.787 Views
Floste Themenstarter:in
1.130 Beiträge seit 2007
vor 14 Jahren
Globale Hooks mit c# (nichtnur lowlevel)

Beschreibung:

Eine Bootstrapper-dll, die eine c#-dll nachlädt und die Hookproc-Aufrufe daran weiterleitet.

Die zu ladende Dll muss eine Klasse namens "Hook", die in keinem namespace ist und die Funktionen "public static int Init(string empty)","public static int GetHookProc(string empty)" und "public static int Run(string empty)" enthält enthalten:


using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class Hook
{
    [STAThread]
    public static int Init(string empty)
    {
        return 0;
    }

    public delegate int HookProcDelegate(int code, IntPtr wParam, IntPtr lParam);

    [STAThread]
    public static int GetHookProc(string empty)
    {
        HookProcDelegate del = new HookProcDelegate(HookProc);
        
        GCHandle.Alloc(del, GCHandleType.Normal);//Edit

        IntPtr result = Marshal.GetFunctionPointerForDelegate(del);
        return (int)result;
    }

    [DllImport("user32.dll")]
    static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

    static unsafe int HookProc(int code, IntPtr wParam, IntPtr lParam)
    {
        MSG* pmsg = (MSG*)lParam;
        //Hook-Code
        return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
    }

    public static int Run(string empty)
    {
        return 0;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct MSG
    {
        public IntPtr hwnd;
        public UInt32 message;
        public IntPtr wParam;
        public IntPtr lParam;
        public UInt32 time;
        public POINT pt;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

        public POINT(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }

        public static implicit operator System.Drawing.Point(POINT p)
        {
            return new System.Drawing.Point(p.X, p.Y);
        }

        public static implicit operator POINT(System.Drawing.Point p)
        {
            return new POINT(p.X, p.Y);
        }
    }
}

Hook erstellen (die c#dll "inject.dll" mit der Hook-klasse und die loaderDll.dll müssen sich im gleichen Ordner befinden):


[DllImport("kernel32.dll",EntryPoint="LoadLibraryW")]
        static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPWStr)]string str);

        [DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]
        public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr SetWindowsHookEx(HookType hook, IntPtr callback,
        IntPtr hMod, int dwThreadId);

        [DllImport("user32.dll")]
        static extern bool UnhookWindowsHookEx(IntPtr hhk);

        public enum HookType : int
        {
            WH_JOURNALRECORD = 0,
            WH_JOURNALPLAYBACK = 1,
            WH_KEYBOARD = 2,
            WH_GETMESSAGE = 3,
            WH_CALLWNDPROC = 4,
            WH_CBT = 5,
            WH_SYSMSGFILTER = 6,
            WH_MOUSE = 7,
            WH_HARDWARE = 8,
            WH_DEBUG = 9,
            WH_SHELL = 10,
            WH_FOREGROUNDIDLE = 11,
            WH_CALLWNDPROCRET = 12,
            WH_KEYBOARD_LL = 13,
            WH_MOUSE_LL = 14
        }

       
        IntPtr hHook=IntPtr.Zero;
        IntPtr hDll = LoadLibrary("LoaderDll.dll");
        if(hDll==IntPtr.Zero)throw new Exception("LoaderDll.dll nicht gefunden");
        IntPtr hookProc = GetProcAddress(hDll, "?Proc@@YGJHIJ@Z");
        hHook = SetWindowsHookEx(HookType.WH_GETMESSAGE, hookProc, hDll, 0);
        ...
        //zurückkehern zu Application.Run()
        ....
        UnhookWindowsHookEx(hHook);
        

Schlagwörter: Globaler Hook Hoocproc Keyboard

[EDIT] 2 bugs behoben und etwas aufgeräumt:

  1. GC.KeepAlive durch GCHandle .Alloc ersetzt: führte zum zufälligen Abstürtzen belibiger Programme mit gui.
  2. Für x86 statt Anycpu compiliert: führte zu Fehlfunktionen auf x64

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Floste Themenstarter:in
1.130 Beiträge seit 2007
vor 14 Jahren

([Edit] die binarys sind jetzt in den Unterordnern .\Release\ und .\Injecter\bin\Release){orange}

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Floste Themenstarter:in
1.130 Beiträge seit 2007
vor 14 Jahren

Wenn man in einen bestimmten Prozess eine c#-Assebmbly einschleusen will, ohne gleich einen systemeiten hook zu setzen geht es mir der Bibliothek auch. (Die Assembly muss auch eine Klasse namens Hook enthalten, die hookproc wird allerdings nie aufgerufen, sondern nur "init" und "run"):


        unsafe private static void InjectCore(uint processId)
        {
            IntPtr hKernel32 = Kernel32.LoadLibrary("kernel32.dll");
            IntPtr loadLibraryProc = Kernel32.GetProcAddress(hKernel32, "LoadLibraryW");
            IntPtr hprocess = Kernel32.OpenProcess(Kernel32.ProcessAccessFlags.CreateThread | Kernel32.ProcessAccessFlags.Synchronize |
                Kernel32.ProcessAccessFlags.VMWrite | Kernel32.ProcessAccessFlags.VMOperation | Kernel32.ProcessAccessFlags.VMRead
            , false, processId);

            IntPtr foreigenMemory = IntPtr.Zero;
            {
                string paramstr = Program.GetLocalPath() + "LoaderDll.dll\0";
                byte[] bytes = Encoding.Unicode.GetBytes(paramstr);
                foreigenMemory = Kernel32.VirtualAllocEx(hprocess, IntPtr.Zero, (uint)bytes.Length,
                    Kernel32.AllocationType.RESERVE | Kernel32.AllocationType.COMMIT, Kernel32.MemoryProtection.EXECUTE_READWRITE);
                int written = 0;
                Kernel32.WriteProcessMemory(hprocess, foreigenMemory, bytes, (uint)bytes.Length, out written);
            }
            uint id = 0;
            Kernel32.CreateRemoteThread(hprocess, IntPtr.Zero, 0, loadLibraryProc, foreigenMemory, 0, &id);
            Kernel32.CloseHandle(hprocess);
        }

public class Kernel32
    {
        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
           uint dwProcessId);

        [Flags]
        public enum ProcessAccessFlags : uint
        {
            All = 0x001F0FFF,
            Terminate = 0x00000001,
            CreateThread = 0x00000002,
            VMOperation = 0x00000008,
            VMRead = 0x00000010,
            VMWrite = 0x00000020,
            DupHandle = 0x00000040,
            SetInformation = 0x00000200,
            QueryInformation = 0x00000400,
            Synchronize = 0x00100000
        }

        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr hObject);

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetCurrentProcess();

        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle,
           uint dwThreadId);

        [DllImport("kernel32.dll")]
        public static extern bool TerminateThread(IntPtr hThread, uint dwExitCode);

        [Flags]
        public enum ThreadAccess : int
        {
            TERMINATE = (0x0001),
            SUSPEND_RESUME = (0x0002),
            GET_CONTEXT = (0x0008),
            SET_CONTEXT = (0x0010),
            SET_INFORMATION = (0x0020),
            QUERY_INFORMATION = (0x0040),
            SET_THREAD_TOKEN = (0x0080),
            IMPERSONATE = (0x0100),
            DIRECT_IMPERSONATION = (0x0200)
        }

        [DllImport("kernel32.dll")]
        public static extern uint SuspendThread(IntPtr hThread);

        [DllImport("kernel32.dll")]
        public static extern uint ResumeThread(IntPtr hThread);

        [DllImport("kernel32.dll")]
        public static unsafe extern IntPtr CreateRemoteThread(IntPtr hProcess,
           IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, uint* lpThreadId);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
           byte[] lpBuffer, uint nSize, out int lpNumberOfBytesWritten);


        [Flags()]
        public enum AllocationType : uint
        {
            COMMIT = 0x1000,
            RESERVE = 0x2000,
            RESET = 0x80000,
            LARGE_PAGES = 0x20000000,
            PHYSICAL = 0x400000,
            TOP_DOWN = 0x100000,
            WRITE_WATCH = 0x200000
        }

        [Flags()]
        public enum MemoryProtection : uint
        {
            EXECUTE = 0x10,
            EXECUTE_READ = 0x20,
            EXECUTE_READWRITE = 0x40,
            EXECUTE_WRITECOPY = 0x80,
            NOACCESS = 0x01,
            READONLY = 0x02,
            READWRITE = 0x04,
            WRITECOPY = 0x08,
            GUARD_Modifierflag = 0x100,
            NOCACHE_Modifierflag = 0x200,
            WRITECOMBINE_Modifierflag = 0x400
        }

        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
           uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr LoadLibrary(String InPath);

        [DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
        public static extern IntPtr GetProcAddress(IntPtr InModule, String InProcName);
    }

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!

Floste Themenstarter:in
1.130 Beiträge seit 2007
vor 14 Jahren
Anmerkungen

1.Wenn man ein Programm mit dem Debugger startet, wird es mit anderen Benutzerrechten ausgeführt, als normale Programme. Deshalb funktioniert der Code nicht, solange man mit dem Debugger startet. Uac kann ebenfalls ein Problem darstellen, sofern das Programm mit geringeren Rechten als andere des selben Benutzers gestartet wird.

  1. Die Bootstrapperdll ist nicht für x64 geeignet. Deshalb muss man seine c#-Exe für x86 compilieren. Die direkte dll-injektion von x86 in x64-Prozesse (und umgekehrt) scheitert. Globale hooks funktionieren auf x64 aus irgebndeinem Grund nicht. Wahrscheinlich wurden sie aus Sicherheitsgründen vom m$ deaktiviert..

Wenn jemand Inetresse an einer x64-dll hat, kann er sich bei mir melden. Es muss aber um beide Systeme zu unterstützen ein Prozess pro System gestartet werden. Also müssten ein Prozess für x64 und einer für x86 parallel laufen.

  1. Ich habe die Runtimeversion des 2.0er Frameworks hardcoded einprogrammiert. Injezierte dlls dürfen also nur die Frameworkversionen von 2.0 bis 3.x verwenden, da diese auf der selben Runtimeversion beruhen. Um das zu umgehen kann man selbstverständlich die Runtimeversion im Code ändern und die c++ -Dll neu Compilieren.

  2. Nicht die alte ver verwenden

  3. Bestimmte Programme mögen es nicht besonders, wenn man dlls injeziert: In seltensten Fällen Av-Software b.z.w firewalls (Das sie anschlagen ist aber die absolute Ausnahme, solange man nur Programme des lokalen Benutzers und keine Systemdienste manipuliert) und bestimmte Onlinespiele (Insbesondere gewisse MMORPGS) haben was dagegen.

Projekte:Jade, HttpSaver
Zum Rechtschreiben gibts doch schon die Politiker. Aber die bauen auch nur mist!