Hooking ExtTextOut. 64bit dll and 32 bit dll progrlem.

Aug 15, 2014 at 5:42 PM
Ok. Im trying to hook notepad only to learn how to use the library. Im developing in a x64 OS using visual studio C# express.

Here is my code for the dll:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows;
using System.Diagnostics;
using EasyHook;
 
namespace FileMonInject
{
    public class Main : EasyHook.IEntryPoint
    {
        DivisionManager.DivisionInterface Interface;
        LocalHook ExtTextOutHook;
        Stack<String> Queue = new Stack<String>();
 
        public Main(
            RemoteHooking.IContext InContext,
            String InChannelName)
        {
            Debug.WriteLine("inject");
            // connect to host...
            Interface = RemoteHooking.IpcConnectClient<DivisionManager.DivisionInterface>(InChannelName);
 
            Interface.Ping();
        }
 
        public void Run(
            RemoteHooking.IContext InContext,
            String InChannelName)
        {
            Debug.WriteLine("inject");
            // install hook...
            try
            {
 
                ExtTextOutHook = LocalHook.Create(
                    LocalHook.GetProcAddress("gdi32.dll", "ExtTextOutW"),
                    new DExtTextOut(ExtTextOut_Hooked), this);
 
                ExtTextOutHook.ThreadACL.SetExclusiveACL(new Int32[] { 0});
            }
            catch (Exception ExtInfo)
            {
                Interface.ReportException(ExtInfo);
 
                return;
            }
 
            Interface.IsInstalled(RemoteHooking.GetCurrentProcessId());
 
            RemoteHooking.WakeUpProcess();
 
            // wait for host process termination...
            try
            {
                while (true)
                {
                    Thread.Sleep(500);
 
                    // transmit newly monitored file accesses...
                    if (Queue.Count > 0)
                    {
                        String[] Package = null;
 
                        lock (Queue)
                        {
                            Package = Queue.ToArray();
 
                            Queue.Clear();
                        }                      
                        Interface.OnCreatFile(RemoteHooking.GetCurrentProcessId(), Package);
                    }
                    else
                        Interface.Ping();
                }
            }
            catch
            {
                // Ping() will raise an exception if host is unreachable
            }
        }
 
        [Serializable, StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
 
            public RECT(int left_, int top_, int right_, int bottom_)
            {
                Left = left_;
                Top = top_;
                Right = right_;
                Bottom = bottom_;
            }
 
            public int Height { get { return Bottom - Top; } }
            public int Width { get { return Right - Left; } }
 
        }
    
        [UnmanagedFunctionPointer(CallingConvention.StdCall,
            CharSet = CharSet.Unicode,
            SetLastError = true)]
        delegate bool DExtTextOut(
            IntPtr hdc,
            int X,
            int Y,
            uint fuOptions,
            [In] ref RECT lprc,
            [MarshalAs(UnmanagedType.LPWStr)] string lpString,
            uint cbCount,
            [In] IntPtr lpDx); 
 
        // just use a P-Invoke implementation to get native API access from C# (this step is not necessary for C++.NET)
        [DllImport("gdi32.dll",
            CharSet = CharSet.Unicode,
            SetLastError = true,
            CallingConvention = CallingConvention.StdCall)]
        static extern bool ExtTextOutW(
            IntPtr hdc,
            int X,
            int Y,
            uint fuOptions,
            [In] ref RECT lprc,
            string lpString,        
                          
            uint cbCount,                                        
            [In] IntPtr lpDx); 
      
 
        // this is where we are intercepting all file accesses!
        static bool ExtTextOut_Hooked(
            IntPtr hdc,            
            int X,            
            int Y,            
            uint fuOptions,            
            [In] ref RECT lprc,
            [MarshalAs(UnmanagedType.LPWStr)] string lpString,            
 
            uint cbCount,            
            [In] IntPtr lpDx) 
          
        {
            
            try
            {
                Main This = (Main)HookRuntimeInfo.Callback;
                lock (This.Queue)
                {                  
                    This.Queue.Push("[" + RemoteHooking.GetCurrentProcessId() + ":" + RemoteHooking.GetCurrentThreadId() + "]: \"" + lpString + "\"");                  
                }
            }
            catch
            {
                Debug.WriteLine("OOoops");
            }
 
            // call original API...
            return ExtTextOutW(
                hdc,                  
                X,                  
                Y,                  
                fuOptions,                  
                ref lprc,                  
                lpString,                  
                cbCount,                  
                lpDx); 
        }
    }
}
This is the program that inject the dll:
using System;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Diagnostics;
using EasyHook;
using System.Threading;
using System.Runtime.InteropServices;

namespace DivisionManager
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        static String ChannelName = null;
        public MainWindow()
        {
            Debug.WriteLine("OOoops");
            Int32 TargetPID = 0;
            InitializeComponent();
            try
            {
                Debug.WriteLine("OOoops");
                Config.Register("A Division like demo application", "DivisionManager.exe", "DivisionInject.dll");
                Debug.WriteLine("OOoops");
                RemoteHooking.IpcCreateServer<DivisionInterface>(ref ChannelName, WellKnownObjectMode.SingleCall);
                Process[] ProcList = Process.GetProcesses();
                String FileName;
                Int32 Id;
                for (int i = 0; i < ProcList.Length; i++)
                {
                    Process Proc = ProcList[i];
                    FileName = Proc.ProcessName;
                    Id = Proc.Id;
                    if (FileName == "notepad")
                        TargetPID = Id;
                }
                Debug.WriteLine("OOoop2s");
                RemoteHooking.Inject(TargetPID, "DivisionInject.dll", "DivisionInject.dll", ChannelName);
                Debug.WriteLine("OOoops3");

                              
            }

            catch (Exception ExtInfo)
            {
                
                Console.WriteLine("There was an error while connecting " +
                                  "to target:\r\n{0}", ExtInfo.ToString());
            }
        }
    }

    public class DivisionInterface : MarshalByRefObject
    {
        public void IsInstalled(Int32 InClientPID)
        {
            Debug.WriteLine("Division has been installed in target {0}.\r\n", InClientPID);
        }

        public void OnCreatFile(Int32 InClientPID, String[] InFileNames)
        {
            for (int i = 0; i < InFileNames.Length; i++)
            {
                Debug.WriteLine(InFileNames[i]);
            }
        }

        public void ReportException(Exception InInfo)
        {
            Debug.WriteLine("The target process has reported an error:\r\n" + InInfo.ToString());
        }

        public void Ping()
        {
        }
    }
}
The problem is that
RemoteHooking.Inject(TargetPID, "DivisionInject.dll", "DivisionInject.dll", ChannelName);

Is throwing an exception:
A first chance exception of type 'System.ArgumentException' occurred in EasyHook.dll
There was an error while connecting to target:
System.ArgumentException: STATUS_INVALID_PARAMETER_5: The given 64-Bit library does not exist! (Code: 2)

Im compiling both projects using AnyCpu. So i thought that DivisionInject.dll was supposed to load as a 32-bit or 64bit at runtime, depending on the system.

What im doing wrong here?

Thanks.
Coordinator
Aug 16, 2014 at 9:41 AM
My first guess is try providing the full path to the assembly. It will be running within the context of the target application and won't know where it is.