Can I Intercept and Change a Parameter of a Function?

Sep 9, 2010 at 12:53 PM

Hi!

I'm evaluating EasyHook and built my first project that hooks GetSystemInfo(SYSTEM_INFO pSystemInfo) from kernell32.dll, but I need to change the value of the pSystemInfo passed as parameter.

1) The original application calls GetSystemInfo;

2) I intercept that, the original application waits;

3) I change the value of pSystemInfo and return;

4) The original application receives the parameter after I changed it.

Is it possible?

I Ask because its possible with madshi for Delphi but I would like to use EasyHook.

Thank you!

Bruno

Sep 10, 2010 at 3:10 AM

Yes, it is possible.

Sep 10, 2010 at 9:58 PM

Can you say me how?

My application code:

using System;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Text;
using System.IO;
using EasyHook;

namespace HkSysInfo
{
    public class HkSysInfoInterface : MarshalByRefObject
    {
        public void IsInstalled(Int32 InClientPID)
        {
            Console.WriteLine("HkSysInfo has been installed in target {0}.\r\n", InClientPID);
        }

        public void OnGetSystemInfo(Int32 InClientPID, String[] InProcs)
        {
            for (int i = 0; i < InProcs.Length; i++)
            {
                Console.WriteLine(InProcs[i]);
            }
        }

        /*public void OnGetSystemInfo()
        {
            Console.WriteLine("GetSystemInfo() called");
        }*/

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

        public void Ping()
        {
        }
    }
    

    class Program
    {
        static String ChannelName = null;

        static void Main(string[] args)
        {
            Int32 TargetPID = 0;

            if ((args.Length != 1) || !Int32.TryParse(args[0], out TargetPID))
            {
                Console.WriteLine();
                Console.WriteLine("Usage: HkSysInfo %PID%");
                Console.WriteLine();

                return;
            }

            try
            {
                Config.Register(
                    "HkSysInfo application.",
                    "HkSysInfo.exe",
                    "SysInfoInject.dll");

                RemoteHooking.IpcCreateServer<HkSysInfoInterface>(ref ChannelName, WellKnownObjectMode.SingleCall);
                
                RemoteHooking.Inject(
                    TargetPID,
                    "SysInfoInject.dll",
                    "",
                    ChannelName);
                
                Console.ReadLine();
            }
            catch (Exception ExtInfo)
            {
                Console.WriteLine("There was an error while connecting to target:\r\n{0}", ExtInfo.ToString());
            }
        }
    }
}

My library code:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using EasyHook;

namespace SysInfoInject
{
    public class Main : EasyHook.IEntryPoint
    {
        HkSysInfo.HkSysInfoInterface Interface;
        LocalHook GetSystemInfoHook;
        Stack<String> Queue = new Stack<String>();

        public Main(
            RemoteHooking.IContext InContext,
            String InChannelName)
        {
            // connect to host...
            Interface = RemoteHooking.IpcConnectClient<HkSysInfo.HkSysInfoInterface>(InChannelName);

            Interface.Ping();
        }

        public void Run(
            RemoteHooking.IContext InContext,
            String InChannelName)
        {
            // install hook...
            try
            {

                GetSystemInfoHook = LocalHook.Create(
                    LocalHook.GetProcAddress("kernel32.dll", "GetSystemInfo"),
                    new DGetSystemInfo(GetSystemInfo_Hooked),
                    this);

                GetSystemInfoHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
            }
            catch (Exception ExtInfo)
            {
                Interface.ReportException(ExtInfo);

                return;
            }

            Interface.IsInstalled(RemoteHooking.GetCurrentProcessId());

            RemoteHooking.WakeUpProcess();

            Queue.Clear();

            // 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.OnGetSystemInfo(RemoteHooking.GetCurrentProcessId(), Package);                        
                    }
                    else
                        Interface.Ping();
                }
            }
            catch
            {
                // Ping() will raise an exception if host is unreachable
            }
        }


        [StructLayout(LayoutKind.Sequential)]
        public struct SYSTEM_INFO
        {
            public uint dwOemId;
            public uint dwPageSize;
            public uint lpMinimumApplicationAddress;
            public uint lpMaximumApplicationAddress;
            public uint dwActiveProcessorMask;
            public uint dwNumberOfProcessors;
            public uint dwProcessorType;
            public uint dwAllocationGranularity;
            public uint dwProcessorLevel;
            public uint dwProcessorRevision;
        }

        [DllImport("User32.dll")]
        public static extern int MessageBox(int h, string m, string c, int type);
        
        [UnmanagedFunctionPointer(CallingConvention.StdCall,
            CharSet = CharSet.Unicode,
            SetLastError = true)]
        delegate void DGetSystemInfo(
            [In] ref SYSTEM_INFO pSI);

        // just use a P-Invoke implementation to get native API access from C# (this step is not necessary for C++.NET)
        [DllImport("kernel32.dll",
            CharSet = CharSet.Unicode,
            SetLastError = true,
            CallingConvention = CallingConvention.StdCall)]
        static extern void GetSystemInfo(
            [In] ref SYSTEM_INFO pSI);

        // this is where we are intercepting all file accesses!
        static void GetSystemInfo_Hooked(
            [In] ref SYSTEM_INFO pSysInfo)
        {
            //MessageBox(0, "API Message Box", "API Demo", 0); Only test
            
            try
            {
                Main This = (Main)HookRuntimeInfo.Callback;

                lock (This.Queue)
                {
                    This.Queue.Push("[" + RemoteHooking.GetCurrentProcessId() + ":" +
                        RemoteHooking.GetCurrentThreadId() + "]: \"" + pSysInfo.dwNumberOfProcessors + " processadores\"");                    
                }
            }
            catch
            {
            }


// *************** Here I change the value of number of processors, i want a program that calls GetSystemInfo() 
// to receive 1 processor instead of the real number of processors of the computer. Is it possible? How?
            pSysInfo.dwNumberOfProcessors = 1;
// ****************************************************** //            

            // call original API...
            GetSystemInfo(
                ref pSysInfo);

            //return pSysInfo;
        }
    }
}

See my comment in the library code about the number of processors. Is it possible? How?

For the test, I did a little external program that calls GetSystemInfo() and display the result every second. And then I pass the PID to HkSysInfo.exe.

Thanks!

Bruno

Sep 13, 2010 at 1:30 AM

Try move the assignment after the original call.

            GetSystemInfo(ref pSysInfo);
           pSysInfo.dwNumberOfProcessors = 1;

Sep 13, 2010 at 12:36 PM

Thank you! It works!