C# DLL Injecting/Hooking ?

06/02/2012 02:17 ImmuneOne#1
1. Introduction

Injecting libs through C# or whatever programming language is familiar but injecting a C# lib without any use of COM reg or CLR Runtime hosts? How?

Yeah I'm here to explain step-by-step how to do it. Before we rush to the "How to apply a hook?" part, I'm going to explain how the functionality of exporting C# functions works.

2. DLL Exporting

So I could let you all go through the pain of learning how exporting functions works but Robert Giesecke already did for you all; [Only registered and activated users can see links. Click Here To Register...].

So after you downloaded his project template and put it into your "Documents\Visual Studio 20xx\Templates\ProjectTemplates" map without extracting the archive. You should have something that looks like this;
Code:
internal static class UnmanagedExports
{
[DllExport("adddays", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)]
static double AddDays(double dateValue, int days)
{
return DateTime.FromOADate(dateValue).AddDays(days).ToOADate();
}
}
Now let's put the main entry aside for now and let's concetrate on the hooking.

3. C# WinHook

The process memory class; (Functions in reading/writing to/from the memory)
- Create a file named ProcessMemory.cs or whatever you want to call it.
- Make it a [ public static class ].
- Following this Singleton template if you want.
-Following with a DLL Import of VirtualProtect; Changes protection in the virtual address.
Code:
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool VirtualProtect(IntPtr address, uint size, uint newProtect, out uint oldProtect);
-Now for the read/write functions;
Code:
        public static byte[] ReadProcessMemory(IntPtr address, int length)
        {
            var buffer = new byte[length];
            Marshal.Copy(address, buffer, 0, length);
            return buffer;
        }

        public static void WriteProcessMemory(IntPtr address, byte[] buffer)
        {
            uint oldProtect;
            VirtualProtect(address, (uint)buffer.Length, 0x40, out oldProtect);
            Marshal.Copy(buffer, 0, address, buffer.Length);
            VirtualProtect(address, (uint)buffer.Length, oldProtect, out oldProtect);
        }
- I suppose you quite understand it and are tired of the instructions now (that if you're actually following the tutorial and not just scrolling to the end because there is no download file:rolleyes:). I don't feel like posting them anymore so now just add an interface named IDetourHook;
Code:
    [ComVisible(true)] 
    [Guid("00000000-0000-0000-0000-000000000001"),
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IDetourHook
    {
        /// <summary>
        /// If the hook has been installed yet.
        /// </summary>
        bool IsInstalled { get; }
        /// <summary>
        /// Invoke original hooked function.
        /// </summary>
        /// <param name="args"></param>
        /// <returns>Original object returned by hooked func.</returns>
        object InvokeOriginal(params object[] args);
        /// <summary>
        /// Instal hook.
        /// </summary>
        /// <returns>Succession of installation</returns>
        bool Install();
        /// <summary>
        /// Remove hook.
        /// </summary>
        /// <returns>Succession of uninstalling</returns>
        bool Uninstall();
    }
-Followed by the DetourHook Class.
Code:
    public class DetourHook
        : IDetourHook
    {
        #region Variables

        protected readonly IntPtr HookPtr;
        protected readonly byte[] newBytes;
        protected readonly byte[] originalBytes;
        protected readonly IntPtr TargetPtr;
        protected readonly Delegate TargetFunc;
        /// <summary>
        /// Gets a value indicating whether the hook is installed.
        /// </summary>
        public bool IsInstalled { get; private set; } 

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes the variables.
        /// </summary>
        /// <param name="target"></param>
        /// <param name="hook"></param>
        public DetourHook(Delegate TargetFunc, Delegate HookFunc)
        {
            this.TargetPtr = Marshal.GetFunctionPointerForDelegate(TargetFunc);
            this.TargetFunc = TargetFunc;
            this.HookPtr = Marshal.GetFunctionPointerForDelegate(HookFunc);

            originalBytes = new byte[6];
            Marshal.Copy(TargetPtr, originalBytes, 0, 6);

            var hookPointerBytes = BitConverter.GetBytes(HookPtr.ToInt32());
            newBytes = new byte[] { 0x68, hookPointerBytes[0], hookPointerBytes[1], hookPointerBytes[2], hookPointerBytes[3], 0xC3 };
        }

        #endregion

        #region Functions
        
        //for documentation check the interface.

        public object InvokeOriginal(params object[] args)
        {
            Uninstall();
            var returnValue = TargetFunc.DynamicInvoke(args);//ret
            Install();
            return returnValue;//ret
        }

        public bool Install()
        {
            ProcessMemory.WriteProcessMemory(TargetPtr, newBytes);
            IsInstalled = true;
            return true;
        }

        public bool Uninstall()
        {
            ProcessMemory.WriteProcessMemory(TargetPtr, originalBytes);
            IsInstalled = false;
            return true;
        }

        #endregion
    }
4. Completion and Finalization

-Sample hook class;
Code:
   public static class SampleHookClass
   {
       public static readonly IntPtr SendPacketAddress = (IntPtr)0x6BFD0C;
       public static readonly IntPtr RecvPacketAddress = (IntPtr)0x6C05E8;

       [UnmanagedFunctionPointer(CallingConvention.ThisCall, SetLastError = true)]
       public delegate int NetworkFunction(IntPtr self, IntPtr pckt, ushort len);//credits to IAmHawtness for correcting me

       public static readonly NetworkFunction originalSendfunc = (NetworkFunction)Marshal.GetDelegateForFunctionPointer(SendPacketAddress, typeof(NetworkFunction));
       public static readonly NetworkFunction originalRecvfunc = (NetworkFunction)Marshal.GetDelegateForFunctionPointer(RecvPacketAddress, typeof(NetworkFunction));

       public static void InitHooks()
       {
           var mySendFunc = new NetworkFunction(MySendFunction);
           var myRecvFunc = new NetworkFunction(MyRecvFunction);

           //Add hooks.
           WinHookManager.This.InitHook(originalSendfunc, mySendFunc, "Conquer::SendPacket");
           WinHookManager.This.InitHook(originalRecvfunc, myRecvFunc, "Conquer::RecvPacket");
           //Install hooks.
           WinHookManager.This.Install("Conquer::SendPacket");
           WinHookManager.This.Install("Conquer::RecvPacket");
       }

       private static int MySendFunction(IntPtr self, IntPtr pckt, ushort len)
       {
           //Do something here.
           return (int)WinHookManager.This.InvokeOriginal("Conquer::SendPacket", new object[] { self, pckt, len });
       }

       private static int MyRecvFunction(IntPtr self, IntPtr pckt, ushort len)
       {
           //Do something here.
           return (int)WinHookManager.This.InvokeOriginal("Conquer::RecvPacket", new object[] { self, pckt, len });
       }
   }
-Sample main entry;
Code:
    internal static class UnmanagedExports
    {
        [DllExport("dll_main", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)]
        static void main()
        {
            SampleHookClass.InitHooks();//Initializes&installs all specified hooks.
        }
    }
-Injecting the .DLL if not known (usage of the Syringe.dll); [Only registered and activated users can see links. Click Here To Register...]
Code:
            Process proc;
            proc= Process.GetProcessesByName("proc")[0];
            //or create the proc yourself.
            
            Injector injector = new Injector(proc);
            injector.InjectLibrary("libname.dll");
            injector.CallExport("libname.dll", "dll_main");

            Console.ReadKey();
            injector.EjectLibrary("libname.dll");
            injector.Dispose();
-Released from the UG.
06/02/2012 09:07 .Kinshi#2
I love how when "advanced" things like this get posted on Epvp, no ones replies because everyone is like "wtf!?".
Thanks anyway buddy, great job.
06/02/2012 15:47 pro4never#3
Quote:
Originally Posted by .Kinshi View Post
I love how when "advanced" things like this get posted on Epvp, no ones replies because everyone is like "wtf!?".
Thanks anyway buddy, great job.
That and a significant percentage of those who would either understand or use such information already read this post in the UG ages ago :P

Still, very useful information and hopefully people will take note.
06/02/2012 16:49 KraHen#4
Any idea why am I crashing my client while I`m returning the original receive function? For send it works flawlessly. Am I missing something here?
06/02/2012 16:55 IAmHawtness#5
Quote:
Originally Posted by KraHen View Post
Any idea why am I crashing my client while I`m returning the original receive function? For send it works flawlessly. Am I missing something here?
What's the address you're using for the "RecvPacketFunction"?
06/02/2012 16:58 KraHen#6
0x6C9833
06/02/2012 17:20 IAmHawtness#7
Quote:
Originally Posted by KraHen View Post
0x6C9833
Yeah, that's the one I use for my hooking, but that address is in the middle of a function that does something along the lines of:
check if packet was received -> if yes, decrypt packet -> process packet.

You have to find the "ProcessPacket" function instead, I'm not actually sure where it is since I haven't used it in a long time, but it should be somewhere further down after the "test eax, eax" at 0x6C9833
06/02/2012 17:22 KraHen#8
Ohh I get it, so this was the recv loop actually. Thanks.
06/02/2012 21:44 IAmHawtness#9
Quote:
Originally Posted by KraHen View Post
Ohh I get it, so this was the recv loop actually. Thanks.
Just out of curiosity, have you found the actual "ProcessMessage" (or whatever you call it) function and got it working yet?
06/03/2012 03:02 ImmuneOne#10
Quote:
Originally Posted by pro4never View Post
That and a significant percentage of those who would either understand or use such information already read this post in the UG ages ago :P

Still, very useful information and hopefully people will take note.
I released it in UG a week ago. This information has no more value being in UG or not.
06/04/2012 05:57 KraHen#11
Quote:
Originally Posted by IAmHawtness View Post
Just out of curiosity, have you found the actual "ProcessMessage" (or whatever you call it) function and got it working yet?
You`re gonna laugh but I found it easier to hook the loop instead. Hurray for lazy me!
06/04/2012 12:13 IAmHawtness#12
Quote:
Originally Posted by KraHen View Post
You`re gonna laugh but I found it easier to hook the loop instead. Hurray for lazy me!
Hahaha yeah, how exactly are you hooking it then?
06/04/2012 17:03 koko20#13
Adress Patch 5587 + i want update it for patch 5611 to work zU.Conquer.exe.50 8B 4B 14 E8 ? ? ? ? 85 C0....RecvLoop....74 0C FF 75 0C 57 E8 ? ? ? ?....SendFunc....8B 40 08 8B 0D ? ? ? ? 33 C6....SendThisPt
06/04/2012 20:04 phize#14
Quote:
Originally Posted by koko20 View Post
Adress Patch 5587 + i want update it for patch 5611 to work zU.Conquer.exe.50 8B 4B 14 E8 ? ? ? ? 85 C0....RecvLoop....74 0C FF 75 0C 57 E8 ? ? ? ?....SendFunc....8B 40 08 8B 0D ? ? ? ? 33 C6....SendThisPt
Looks like those are string references from my packet monitor. Good luck on updating it.
10/05/2013 19:27 Fehmt#15
Sorry for bumping the topic, but I cant find "WinHookManager" class. Even google can't find it