Update dateTimePicker in another process by DTM_SETSYSTEMTIME

1.3k Views Asked by At

I am trying to update the dateTimeController in another application using DTM_SETSYSTEMTIME.

bool retVal = false;
ushort GDT_VALID = 0;

SYSTEMTIME td = new SYSTEMTIME();
td.wYear = 1990;
td.wMonth = 4;
td.wDay = 2;
td.wDayOfWeek = 0;
td.wHour = 0;
td.wMilliseconds = 0;
td.wMinute = 0;
td.wSecond = 0;

int erc = SendMessage(handle, DTM_SETSYSTEMTIME, GDT_VALID, ref td);

Unfortunately the attempt was failed, the picker is not updated, every time return value is zero. Important thing is occasionally the application having the dataTimePicker gives an error message that illegal memory access exception after I execute the SendMessage command.

Can anybody help me to fix this up ?

3

There are 3 best solutions below

0
On BEST ANSWER

Your information is really helpful for me to fix my issue. Following is the code.

private static bool injectMemory(IntPtr windowHandle, byte[] buffer, out IntPtr hndProc, out IntPtr lpAddress)
    {
        hndProc = IntPtr.Zero;
        lpAddress = IntPtr.Zero;
        //open local process object
        Process mainWindowProcess = FindProcess(windowHandle);
        hndProc = OpenProcess(
            (0x2 | 0x8 | 0x10 | 0x20 | 0x400), //create thread, query info, operation 
            //write, and read 
            1,
            (uint)mainWindowProcess.Id);
        if (hndProc == (IntPtr)0)
        {
            Console.WriteLine("Unable to attach process");
            return false;
        }
        //allocate memory for process object
        lpAddress = VirtualAllocEx(hndProc, (IntPtr)null, (uint)buffer.Length,
             AllocationType.Commit | AllocationType.Reserve, MemoryProtection.ExecuteReadWrite);
        if (lpAddress == (IntPtr)0)
        {
            Console.WriteLine("Unable to allocate memory to target proces");
            return false;
        }
        //wite data
        uint wrotelen = 0;
        WriteProcessMemory(hndProc, lpAddress, buffer, (uint)buffer.Length, out wrotelen);
        if (Marshal.GetLastWin32Error() != 0)
        {
            Console.WriteLine("Unable to write memory to process.");
            return false;
        }
        return true;
    }

Method is called by,

        int structMemLen =  Marshal.SizeOf(typeof(SYSTEMTIME));
        byte[] buffer = new byte[structMemLen];
        ushort GDT_VALID = 0;
        SYSTEMTIME sysTime = new SYSTEMTIME();
        //Assign the values as you prefer

        IntPtr dataPtr = Marshal.AllocHGlobal(structMemLen);
        Marshal.StructureToPtr(sysTime, dataPtr, true);
        Marshal.Copy(dataPtr, buffer, 0, structMemLen);
        Marshal.FreeHGlobal(dataPtr);

        IntPtr hndProc = IntPtr.Zero;
        IntPtr lpAddress = IntPtr.Zero;
        injectMemory(mainWindowHandle, buffer, out hndProc, out lpAddress); 
        SendMessage(handle, DTM_SETSYSTEMTIME, (IntPtr)GDT_VALID, lpAddress);
        CloseHandle(hndProc);
0
On

Yes, cannot work. The 4th argument to SendMessage is a pointer to SYSTEMTIME. The pointer value is only valid in your process, not the one that owns the control. Crashing the target app with that pointer value is quite possible. You will need to

  • call OpenProcess() on the target process to obtain its handle
  • call VirtualAllocEx() to allocate memory in the target process
  • call WriteProcessMemory() to copy the SYSTEMTIME value from your process to the target process
  • call SendMessage, using the pointer value you got from VirtualAllocEx
  • call VirtualFreeEx() to release the memory
  • call CloseHandle() to release the process handle.

Lots of things that can go wrong here, starting with UAC stopping you from executing these highly privileged API functions. The function names google well, you should have little trouble finding sample code.

2
On
using System;
using System.Security;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.ConstrainedExecution;

namespace DateTimePicker.Helpers
{
    [Flags]
    public enum ProcessAccessFlags : uint
    {
        All = 0x001F0FFF,
        Terminate = 0x00000001,
        CreateThread = 0x00000002,
        VirtualMemoryOperation = 0x00000008,
        VirtualMemoryRead = 0x00000010,
        VirtualMemoryWrite = 0x00000020,
        DuplicateHandle = 0x00000040,
        CreateProcess = 0x000000080,
        SetQuota = 0x00000100,
        SetInformation = 0x00000200,
        QueryInformation = 0x00000400,
        QueryLimitedInformation = 0x00001000,
        Synchronize = 0x00100000
    }

    [Flags]
    public enum AllocationType : uint
    {
        Commit = 0x1000,
        Reserve = 0x2000,
        Decommit = 0x4000,
        Release = 0x8000,
        Reset = 0x80000,
        Physical = 0x400000,
        TopDown = 0x100000,
        WriteWatch = 0x200000,
        LargePages = 0x20000000
    }

    [Flags]
    public enum MemoryProtection : uint
    {
        Execute = 0x10,
        ExecuteRead = 0x20,
        ExecuteReadWrite = 0x40,
        ExecuteWriteCopy = 0x80,
        NoAccess = 0x01,
        ReadOnly = 0x02,
        ReadWrite = 0x04,
        WriteCopy = 0x08,
        GuardModifierflag = 0x100,
        NoCacheModifierflag = 0x200,
        WriteCombineModifierflag = 0x400
    }

    public class DateTimePickerNativeMethods
    {
        private const int DTM_GETSYSTEMTIME = 0x1001;
        private const int DTM_SETSYSTEMTIME = 0x1002;

        public static DateTime GetDateTime(IntPtr hwnd)
        {
            var hProcess = TryOpenProcess(hwnd);
            var typeSize = Marshal.SizeOf(typeof(SYSTEMTIME));

            var hMem = VirtualAllocEx(hProcess, IntPtr.Zero, (uint)typeSize, (uint)(AllocationType.Commit | AllocationType.Reserve), (uint)MemoryProtection.ReadWrite);
            var lResult = NativeMethods.SendMessage(hwnd, DTM_GETSYSTEMTIME, IntPtr.Zero, hMem);
            var address = Marshal.AllocHGlobal(typeSize);
            if (ReadProcessMemory(hProcess, hMem, address, typeSize, out IntPtr lpNumberOfBytesRead) == false)
            {
                throw new Exception();
            }

            var systemtime = (SYSTEMTIME)Marshal.PtrToStructure(address, typeof(SYSTEMTIME));

            Marshal.FreeHGlobal(address);
            VirtualFreeEx(hProcess, hMem, typeSize, AllocationType.Decommit | AllocationType.Release);
            CloseHandle(hProcess);

            return new DateTime(systemtime.Year, systemtime.Month, systemtime.Day, systemtime.Hour, systemtime.Minute, systemtime.Second);
        }

        public static void SetDateTime(IntPtr hwnd, DateTime dateTime)
        {
            var typeSize = Marshal.SizeOf(typeof(SYSTEMTIME));
            var buffer = new byte[typeSize];

            var data = Marshal.AllocHGlobal(typeSize);
            Marshal.StructureToPtr(new SYSTEMTIME(dateTime), data, true);
            Marshal.Copy(data, buffer, 0, typeSize);
            Marshal.FreeHGlobal(data);

            CreateMemory(hwnd, buffer, out IntPtr hwndProc, out IntPtr lpAddress);
            NativeMethods.SendMessage(hwnd, DTM_SETSYSTEMTIME, IntPtr.Zero, lpAddress);
            CloseHandle(hwndProc);
        }

        private static void CreateMemory(IntPtr windowHandle, byte[] buffer, out IntPtr hwndProc, out IntPtr lpAddress)
        {
            hwndProc = TryOpenProcess(windowHandle);
            lpAddress = TryGetLParamAddress(hwndProc, buffer.Length);
            TryWriteProcessMemory(hwndProc, lpAddress, buffer);
        }        

        private static IntPtr TryOpenProcess(IntPtr hwnd)
        {
            var process = FindProcess(hwnd);
            var hwndProcess = OpenProcess(process, ProcessAccessFlags.All);
            if (hwndProcess == IntPtr.Zero)
            {
                throw new Exception("failed to open process");
            }
            return hwndProcess;
        }

        private static IntPtr TryGetLParamAddress(IntPtr hwndProc, int length)
        {
            var lpAddress = VirtualAllocEx(
                hwndProc,
                (IntPtr)null,
                (uint)length,
                (uint)(AllocationType.Commit | AllocationType.Reserve),
                (uint)MemoryProtection.ExecuteReadWrite)
                ;

            if (lpAddress == IntPtr.Zero)
            {
                throw new Exception();
            }

            return lpAddress;
        }

        private static void TryWriteProcessMemory(IntPtr hwndProc, IntPtr lpAddress, byte[] buffer)
        {
            WriteProcessMemory(hwndProc, lpAddress, buffer, buffer.Length, out IntPtr wrotelen);
            if (Marshal.GetLastWin32Error() != 0)
            {
                throw new Exception();
            }
        }

        private static Process FindProcess(IntPtr windowHandle)
        {
            var automationElement = System.Windows.Automation.AutomationElement.FromHandle(windowHandle);
            var process = Process.GetProcessById(automationElement.Current.ProcessId);
            return process;
        }

        #region Win32 methods
        [DllImport("kernel32.dll", SetLastError = true)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool CloseHandle(IntPtr hObject);

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

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

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, uint processId);
        public static IntPtr OpenProcess(Process proc, ProcessAccessFlags flags)
        {
            return OpenProcess((uint)flags, false, (uint)proc.Id);
        }

        [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
        public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, AllocationType dwFreeType);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead);
        #endregion
    }
}