I'm a first traveler coding in WinApi, Hooks, COM objects. Then, I made a dll to inject (EasyHook) this in the target SIEMENS Step7 process and modify the software code at runtime:

Maybe I want some opinion about this kind of practices, hooking, injection, file system driver, kernel hook, modify .exe vtable before init, interprocess-communication, etc.

This code gets the `DataSource` from a Grid GUI(COM Object) when the user do a determined "Force" action through menu.

    using EasyHook;
    using Octtos.S7ussapx.Injected.COM.Interfaces;
    using Octtos.S7ussapx.Injected.Step7.COM.Interfaces;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading;
    
    namespace Octtos.S7ussapx.Injected
    {
        public class Main : IEntryPoint
        {
            private ClientCallbackHandler _callbackHandler;
    
            [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
            unsafe delegate int IDispatchInvokeDelegate(IntPtr pthis, int dispIdMember, ref Guid riid, uint lcid, ushort wFlags,
                ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, void* ppvResult,
                ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] pArgErr);
    
            #region CoGetClassObject ole32.dll
    
            private LocalHook _coGetClassObjectHook;
    
            private LocalHook _S7StatusOCXIClassFacttoryCreateInstanceHook;
            private LocalHook _S7VarServer50IClassFacttoryCreateInstanceHook2;
    
            private bool _s7StatusOCXCOMHookCreated = false;
            private bool _s7VarServer50COMHookCreated = false;
    
            private IntPtr _S7StatusOCXIClassFacttoryCreateInstanceMethodPtr;
            private IntPtr _S7VarServer50IClassFacttoryCreateInstanceMethodPtr;
    
            private delegate uint CoGetClassObjectDelegate(ref Guid rclsid, int dwClsContext, IntPtr pServerInfo, ref Guid riid, out IntPtr ppv);
    
            [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
            private delegate int IClassFactoryCreateInstanceDelegate(IntPtr pThis, IntPtr pUnkOuter, ref Guid riid, out IntPtr ppv);
    
            private static unsafe uint CoGetClassObject_Hook(ref Guid clsid, int dwClsContext, IntPtr pServerInfo, ref Guid iid, out IntPtr ppv)
            {
                var me = (Main)HookRuntimeInfo.Callback;
                var classObjectInstance = CoGetClassObject(ref clsid, dwClsContext, pServerInfo, ref iid);
    
                ppv = Marshal.GetIUnknownForObject(classObjectInstance);
    
                var iclassFactory = classObjectInstance as IClassFactory;
    
                if (!me._s7StatusOCXCOMHookCreated)
                { 
                    if (iclassFactory != null && clsid == typeof(IS7StatusOcx).GUID)
                    {
                        var method = typeof(IClassFactory).GetMethod("CreateInstance");
                        var methodVTableIdx = Marshal.GetComSlotForMethodInfo(method);
    
                        int** comVTable = *(int***)ppv.ToPointer();
                        int* hMethod = comVTable[methodVTableIdx];
                        me._S7StatusOCXIClassFacttoryCreateInstanceMethodPtr = new IntPtr(hMethod);
    
                        me._S7StatusOCXIClassFacttoryCreateInstanceHook = LocalHook.Create(me._S7StatusOCXIClassFacttoryCreateInstanceMethodPtr, new IClassFactoryCreateInstanceDelegate(S7StatusOCXCreateInstance_Hook), me);
                        me._S7StatusOCXIClassFacttoryCreateInstanceHook.ThreadACL.SetExclusiveACL(new int[0]);
    
                        me._s7StatusOCXCOMHookCreated = true;
                    }
                }
    
                if (!me._s7VarServer50COMHookCreated)
                {
                    if (iclassFactory != null && clsid == typeof(IS7VarServer50).GUID)
                    {
                        var method = typeof(IClassFactory).GetMethod("CreateInstance");
                        var methodVTableIdx = Marshal.GetComSlotForMethodInfo(method);
    
                        int** comVTable = *(int***)ppv.ToPointer();
                        int* hMethod = comVTable[methodVTableIdx];
                        me._S7VarServer50IClassFacttoryCreateInstanceMethodPtr = new IntPtr(hMethod);
    
                        me._S7VarServer50IClassFacttoryCreateInstanceHook2 = LocalHook.Create(me._S7VarServer50IClassFacttoryCreateInstanceMethodPtr, new IClassFactoryCreateInstanceDelegate(S7VarServer50CreateInstance_Hook), me);
                        me._S7VarServer50IClassFacttoryCreateInstanceHook2.ThreadACL.SetExclusiveACL(new int[0]);
    
                        me._s7VarServer50COMHookCreated = true;
                    }
                }
    
                Marshal.ReleaseComObject(classObjectInstance);
    
                return 0;
            }
    
            #endregion
    
            #region S7StatusOCX IClassFactory.Create ole32.dll
    
            private IS7StatusOcxDispatch _currentInstance;
    
            [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
            private delegate int IClassFactoryCreateInstanceDelegate2(IntPtr pThis, IntPtr pUnkOuter, ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object obj);
    
            private static unsafe int S7StatusOCXCreateInstance_Hook(IntPtr pThis, IntPtr pUnkOuter, ref Guid riid, out IntPtr ppv)
            {
                var me = (Main)HookRuntimeInfo.Callback;
    
                var baseMethod = (IClassFactoryCreateInstanceDelegate2)Marshal.GetDelegateForFunctionPointer(me._S7StatusOCXIClassFacttoryCreateInstanceMethodPtr, typeof(IClassFactoryCreateInstanceDelegate2));
    
                object objInstance;
                var hr = baseMethod(pThis, pUnkOuter, ref riid, out objInstance);
    
                me._currentInstance = (IS7StatusOcxDispatch)objInstance;
    
                var ppv2 = Marshal.GetIUnknownForObject(objInstance);
    
                Marshal.QueryInterface(ppv2, ref riid, out ppv);
    
                return hr;
            }
    
            #endregion
    
            #region S7VarServer50 IClassFactory.Create ole32.dll
    
            private LocalHook _s7VarServer5IDispatchHook;
    
            private IntPtr _s7VarServer50IDispatchInvokeMethodPtr;
    
            private bool _S7VarServer50CreateInstanceHookCreated = false;
    
            private IDictionary<IntPtr, IS7StatusOcxDispatch> _s7StatusOCXDispatchInstances = new Dictionary<IntPtr, IS7StatusOcxDispatch>();
    
            private static unsafe int S7VarServer50CreateInstance_Hook(IntPtr pThis, IntPtr pUnkOuter, ref Guid riid, out IntPtr ppv)
            {
                var me = (Main)HookRuntimeInfo.Callback;
    
                var baseMethod = (IClassFactoryCreateInstanceDelegate2)Marshal.GetDelegateForFunctionPointer(me._S7VarServer50IClassFacttoryCreateInstanceMethodPtr, typeof(IClassFactoryCreateInstanceDelegate2));
    
                object objInstance;
                var hr = baseMethod(pThis, pUnkOuter, ref riid, out objInstance);
    
                var ppv2 = Marshal.GetIUnknownForObject(objInstance);
    
                Marshal.QueryInterface(ppv2, ref riid, out ppv);
    
                if (objInstance is IS7VarServer50Dispatch)
                {
                    Guid iidIDispatch = typeof(IDispatch).GUID;
                    IntPtr ppv3;
                    Marshal.QueryInterface(ppv2, ref iidIDispatch, out ppv3);
    
                    if (me._s7StatusOCXDispatchInstances.ContainsKey(ppv3))
                    {
                        me._s7StatusOCXDispatchInstances[ppv3] = me._currentInstance;
                    }
                    else { 
                        me._s7StatusOCXDispatchInstances.Add(ppv3, me._currentInstance);
                    }
    
                    me._currentInstance = null;
                    
    
                    if (!me._S7VarServer50CreateInstanceHookCreated)
                    {
                        var methodVTableIdx = Marshal.GetComSlotForMethodInfo(typeof(IDispatch).GetMethod("Invoke"));
    
                        int** comVTable = *(int***)ppv3.ToPointer();
                        int* hMethod = comVTable[methodVTableIdx];
                        me._s7VarServer50IDispatchInvokeMethodPtr = new IntPtr(hMethod);
    
                        me._s7VarServer5IDispatchHook = LocalHook.Create(me._s7VarServer50IDispatchInvokeMethodPtr, new IDispatchInvokeDelegate(S7VarServer50IDispatch_Invoke_Hook), me);
                        me._s7VarServer5IDispatchHook.ThreadACL.SetExclusiveACL(new int[0]);
    
                        me._S7VarServer50CreateInstanceHookCreated = true;
                    }
                }
    
                return hr;
            }
    
            //Por que esse IDispatch tem IntPtr pThis como primeiro parâmetro? Se na DOC o primeiro parâmetro dessa função é o dispIdMember?!
            //http://msdn.microsoft.com/en-us/library/aa912367.aspx
            unsafe static int S7VarServer50IDispatch_Invoke_Hook(IntPtr pthis, int dispIdMember, ref Guid riid, uint lcid, ushort wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, void* ppvResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] pArgErr)
            {
                var me = (Main)HookRuntimeInfo.Callback;
    
                switch (dispIdMember)
                {
                    case 14:
                        me._callbackHandler.WriteLine("CreateForceJob() called");
                        break;
                    case 15:
                        me._callbackHandler.WriteLine("StartForceJob() called");
    
                        IS7StatusOcxDispatch instance;
                        
                        if (me._s7StatusOCXDispatchInstances.TryGetValue(pthis, out instance))
                        {
                            string varList;
                            instance.GetVariableList(out varList, false);
    
                            var bytes = Encoding.Unicode.GetBytes(varList);
                            var str = Encoding.Default.GetString(bytes);
                            me._callbackHandler.WriteLine(str);
                        }
                        else
                        {
                            me._callbackHandler.WriteLine("ERROR!!! Tentou pegar uma instancia que não existia. Por que essa instância não existe?");
                        }
    
                        break;
                    default:
                        break;
                }
    
                var baseMethod = (IDispatchInvokeDelegate)Marshal.GetDelegateForFunctionPointer(me._s7VarServer50IDispatchInvokeMethodPtr, typeof(IDispatchInvokeDelegate));
                return baseMethod(pthis, dispIdMember, ref riid, lcid, wFlags, ref pDispParams, ppvResult, ref pExcepInfo, pArgErr);
            }
    
            #endregion
    
            public Main(RemoteHooking.IContext ctx, string channelId)
            {
                _callbackHandler = RemoteHooking.IpcConnectClient<ClientCallbackHandler>(channelId);
            }
    
            public unsafe void Run(RemoteHooking.IContext ctx, string arg1)
            {
                try
                {
                    _coGetClassObjectHook = LocalHook.Create(LocalHook.GetProcAddress("ole32.dll", "CoGetClassObject"),
                        new CoGetClassObjectDelegate(CoGetClassObject_Hook), this);
                    _coGetClassObjectHook.ThreadACL.SetExclusiveACL(new int[0]);
    
                    RemoteHooking.WakeUpProcess();
                    _callbackHandler.InjectStart();
    
                    while (true)
                    {
                        _callbackHandler.SetIsAlive(true);
                        Thread.Sleep(TimeSpan.FromSeconds(2));
                    }
                }
                catch (Exception ex)
                {
                    throw;
                }
            }
    
            [DllImport("ole32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
            [return: MarshalAs(UnmanagedType.Interface)]
            private static extern object CoGetClassObject(ref Guid rclsid, int dwClsContext, IntPtr pServerInfo, ref Guid riid);
        }
    }