I wrote this in VB and converted it to C# on an online converter. Haven't tested it yet.

 
Main Code

Code:
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Runtime.InteropServices;


public class WinApi
{
    [DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
    #region "Windows(R) Functions"
    public static extern void GetSystemInfo(ref SystemInfo lpSystemInfo);
    [DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
    public static extern bool CloseHandle(IntPtr hObject);
    [DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
    public static extern IntPtr OpenProcess(UInt32 dwDesiredAcess, bool bInheritHandle, Int32 dwProcessId);
    [DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
    public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, Int32 iSize, ref int lpNumberOfBytesRead);
    [DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
    public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpbaseAddress, byte[] lpBuffer, Int32 nSize, ref Int32 dwNumberOfBytesWritten);
    [DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]

    public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, UInt32 dwNewProtect, ref UInt32 dwOldProtect);
    [DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
    public static extern UInt32 VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, ref MemoryBasicInformation lpMemoryBasicInformation, Int32 dwLength);

    #endregion
    #region "Structs"

    public struct SystemInfo
    {
        public Int16 wProcessorArchitecture;
        public Int16 wReserved;
        public Int32 dwPageSize;
        public IntPtr lpMinimumApplicationAddress;
        public IntPtr lpMaximumApplicationAddress;
        public Int32 dwActiveProcessorMask;
        public Int32 dwNumberOfProcessors;
        public Int32 dwProcessorType;
        public Int32 dwAllocationGranularity;
        public Int16 wProcessorLevel;
        public Int16 wProcessorRevision;
    }
    public struct MemoryBasicInformation
    {
        public IntPtr BaseAddress;
        public IntPtr AllocationBase;
        public UInt32 AllocationProtect;
        public IntPtr RegionSize;
        public UInt32 State;
        public UInt32 Protect;
        public UInt32 AllocationType;
    }

    #endregion
    #region "Enums"

    public enum MemoryAllocationProtection : UInt32
    {
        PAGE_NOACCESS = 0x1,
        PAGE_READONLY = 0x2,
        PAGE_READWRITE = 0x4,
        PAGE_WRITECOPY = 0x8,
        PAGE_EXECUTE = 0x10,
        PAGE_EXECUTE_READ = 0x20,
        PAGE_EXECUTE_READWRITE = 0x40,
        PAGE_EXECUTE_WRITECOPY = 0x80,
        PAGE_GUARD = 0x100,
        PAGE_NOCACHE = 0x200,
        PAGE_WRITECOMBINE = 0x400
    }
    public enum MemoryAllocationType : UInt32
    {
        MEM_IMAGE = 0x1000000,
        MEM_MAPPED = 0x40000,
        MEM_PRIVATE = 0x20000
    }
    public enum MemoryAllocationState : UInt32
    {
        COMMIT = 0x1000,
        RESERVE = 0x2000,
        DECOMMIT = 0x4000,
        RELEASE = 0x8000,
        RESET = 0x80000,
        PHYSICAL = 0x400000,
        TOP_DOWN = 0x100000,
        WRITE_WATCH = 0x200000,
        LARGE_PAGES = 0x20000000
    }
    public enum ProcessAccess : UInt32
    {
        //'Function descriptions taken from msdn.com
        /// <summary>
        /// Required to terminate a process using TerminateProcess.
        /// </summary>
        PROCESS_TERMINATE = 0x1,
        /// <summary>
        /// Required to create a thread.
        /// </summary>
        PROCESS_CREATE_THREAD = 0x2,
        /// <summary>
        /// Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory).
        /// </summary>
        PROCESS_VM_OPERATION = 0x8,
        /// <summary>
        /// Required to read memory in a process using ReadProcessMemory.
        /// </summary>
        PROCESS_VM_READ = 0x10,
        /// <summary>
        /// Required to write to memory in a process using WriteProcessMemory.
        /// </summary>
        PROCESS_VM_WRITE = 0x20,
        /// <summary>
        /// Required to duplicate a handle using DuplicateHandle.
        /// </summary>
        PROCESS_DUP_HANDLE = 0x40,
        /// <summary>
        /// Required to create a process.
        /// </summary>
        PROCESS_CREATE_PROCESS = 0x80,
        /// <summary>
        /// 	Required to set memory limits using SetProcessWorkingSetSize.
        /// </summary>
        PROCESS_SET_QUOTA = 0x100,
        /// <summary>
        /// 	Required to set certain information about a process, such as its priority class (see SetPriorityClass).
        /// </summary>
        PROCESS_SET_INFORMATION = 0x200,
        /// <summary>
        /// Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken).
        /// </summary>
        PROCESS_QUERY_INFORMATION = 0x400,
        /// <summary>
        /// Required to suspend or resume a process.
        /// </summary>
        PROCESS_SUSPEND_RESUME = 0x800,
        /// <summary>
        /// Required to retrieve certain information about a process (see GetExitCodeProcess, GetPriorityClass, IsProcessInJob, QueryFullProcessImageName). A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted PROCESS_QUERY_LIMITED_INFORMATION. Windows Server 2003 and Windows XP:  This access right is not supported.
        /// </summary>
        PROCESS_QUERY_LIMITED_INFORMATION = 0x1000,
        /// <summary>
        /// Required to wait for the process to terminate using the wait functions.
        /// </summary>
        PROCESS_SYNCHRONIZE = 0x100000
    }

    #endregion
}
public class MemoryManager : IDisposable
{
    #region "Private"
    private bool _isAttached = false;
    private Int32 _targetProcessId = 0;
    //'
    private IntPtr _targetProcessHandle = IntPtr.Zero;
    private IntPtr _mainModuleBase = IntPtr.Zero;
    private WinApi.SystemInfo _systemInfo;

    private Int32 _mbiSize = 0;
    public MemoryManager()
    {

        WinApi.GetSystemInfo(ref _systemInfo);
        _mbiSize = System.Runtime.InteropServices.Marshal.SizeOf(new WinApi.MemoryBasicInformation());
    }
    #endregion

    public bool AttachToProcess(Int32 processId)
    {
        if (_isAttached)
        {
            return false;
        }
        else
        {
            foreach (Process proc in Process.GetProcesses())
            {
                if (proc.Id == processId)
                {
                    _targetProcessHandle = WinApi.OpenProcess(WinApi.ProcessAccess.PROCESS_VM_WRITE | WinApi.ProcessAccess.PROCESS_VM_READ | WinApi.ProcessAccess.PROCESS_VM_OPERATION | WinApi.ProcessAccess.PROCESS_QUERY_INFORMATION, false, processId);

                    if (_targetProcessHandle == IntPtr.Zero)
                    {
                        return false;

                    }
                    else
                    {
                        _isAttached = true;
                        _targetProcessId = processId;
                        _mainModuleBase = proc.MainModule.BaseAddress;
                        return true;
                    }
                }
            }

            MessageBox.Show("MemoryManager::AttachToProcess() Process Id not found: " + processId.ToString());
            return false;
        }
    }

    public void DetachFromProcess()
    {
        if (_isAttached)
        {
            if (_targetProcessHandle != IntPtr.Zero)
            {
                WinApi.CloseHandle(_targetProcessHandle);
            }
            _isAttached = false;
            _targetProcessId = 0;
            _targetProcessHandle = IntPtr.Zero;
        }
    }
    public bool IsAttached
    {
        get { return _isAttached; }
    }
    public IntPtr MainModuleBase
    {
        get { return _mainModuleBase; }
    }
    #region "Read"
    public byte ReadByte(IntPtr addr)
    {
        byte[] _byte = new byte[1];
        if (_isAttached)
            WinApi.ReadProcessMemory(_targetProcessHandle, addr, _byte, 1, ref new Int32());
        return _byte(0);
    }
    public Int16 ReadInt16(IntPtr addr)
    {
        byte[] _bytes = new byte[2];
        if (_isAttached)
            WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 2, ref new Int32());
        return BitConverter.ToInt16(_bytes, 0);
    }
    public Int32 ReadInt32(IntPtr addr)
    {
        byte[] _bytes = new byte[4];
        if (_isAttached)
            WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 4, ref new Int32());
        return BitConverter.ToInt32(_bytes, 0);
    }
    public Int64 ReadInt64(IntPtr addr)
    {
        byte[] _bytes = new byte[8];
        if (_isAttached)
            WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 8, ref new Int32());
        return BitConverter.ToInt64(_bytes, 0);
    }
    public UInt16 ReadUInt16(IntPtr addr)
    {
        byte[] _bytes = new byte[2];
        if (_isAttached)
            WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 2, ref new Int32());
        return BitConverter.ToUInt16(_bytes, 0);
    }
    public UInt32 ReadUInt32(IntPtr addr)
    {
        byte[] _bytes = new byte[4];
        if (_isAttached)
            WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 4, ref new Int32());
        return BitConverter.ToUInt32(_bytes, 0);
    }
    public UInt64 ReadUInt64(IntPtr addr)
    {
        byte[] _bytes = new byte[8];
        if (_isAttached)
            WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 8, ref new Int32());
        return BitConverter.ToUInt64(_bytes, 0);
    }
    public float ReadFloat(IntPtr addr)
    {
        byte[] _bytes = new byte[4];
        if (_isAttached)
            WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 4, ref new Int32());
        return BitConverter.ToSingle(_bytes, 0);
    }
    public double ReadDouble(IntPtr addr)
    {
        byte[] _bytes = new byte[8];
        if (_isAttached)
            WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, 8, ref new Int32());
        return BitConverter.ToDouble(_bytes, 0);
    }
    /// <summary>
    /// Reads an Ascii string from the target process's ram.
    /// </summary>
    /// <param name="addr">Beginning address of the string.</param>
    /// <param name="maxLength">Max length of string if unknown. Must be > 0</param>
    public string ReadAsciiString(IntPtr addr, Int32 maxLength)
    {
        if (!(_isAttached && (maxLength > 0)))
        {
            return string.Empty;

        }
        byte[] _bytes = new byte[maxLength];
        Int32 _bytesRead = 0;
        if (WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, maxLength, ref _bytesRead))
        {
            return System.Text.Encoding.ASCII.GetString(_bytes, 0, _bytesRead);
        }
        else
        {
            return string.Empty;
            //'rpm failed
        }
    }
    public byte[] ReadBytes(IntPtr address, int Length = 4)
    {
        byte[] lpBuffer = new byte[((Length - 1) + 1)];
        WinApi.ReadProcessMemory(_targetProcessHandle, address, lpBuffer, Length, ref 0);
        return lpBuffer;
    }
    /// <summary>
    /// Read a Unicode string from the target process's ram.
    /// </summary>
    /// <param name="addr">Beginning address of the string.</param>
    /// <param name="maxLength">Max length of string if unknown. Must be > 0</param>
    public string ReadUnicodeString(IntPtr addr, Int32 maxLength)
    {
        if (!(_isAttached && (maxLength > 0)))
        {
            return string.Empty;
            //' fail. not attached to any process (or maxLength = 0).
        }
        maxLength = maxLength * 2;
        //' 2  bytes per character. TODO: "Unicode" ?
        byte[] _bytes = new byte[maxLength];
        Int32 _bytesRead = 0;
        if (WinApi.ReadProcessMemory(_targetProcessHandle, addr, _bytes, _bytes.Length, ref _bytesRead))
        {
            return System.Text.Encoding.Unicode.GetString(_bytes, 0, _bytesRead);
        }
        else
        {
            return string.Empty;
            //' rpm failed.
        }
    }
    /// <summary>
    /// Reads an array of bytes from the target process's ram into a pre-declared buffer.
    /// </summary>
    /// <param name="byteBuff">Must be large enough, will not be re-sized!</param>
    /// <param name="size">Number of bytes to read.</param>
    /// <param name="actualBytesRead">Byref. Returns the actual number of bytes read.</param>
    public bool ReadBytes(IntPtr addr, ref byte[] byteBuff, Int32 size, ref Int32 actualBytesRead)
    {
        return WinApi.ReadProcessMemory(_targetProcessHandle, addr, byteBuff, size, ref actualBytesRead);
    }
    #endregion
    #region "Write"
    public bool WriteByte(IntPtr addr, byte aByte)
    {
        byte[] _bts = { aByte };
        //' Awkward. Winapi function is declared as array() instead of as IntPtr
        return WinApi.WriteProcessMemory(_targetProcessHandle, addr, _bts, 1, ref new Int32());
    }
    public bool WriteInt16(IntPtr addr, Int16 data)
    {
        return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 2, ref new Int32());
    }
    public bool WriteUInt16(IntPtr addr, UInt16 data)
    {
        return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 2, ref new Int32());
    }
    public bool WriteInt32(IntPtr addr, Int32 data)
    {
        return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 4, ref new Int32());
    }
    public bool WriteInt64(IntPtr addr, Int64 data)
    {
        return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 8, ref new Int32());
    }
    public bool WriteUInt64(IntPtr addr, UInt64 data)
    {
        return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 8, ref new Int32());
    }
    public bool WriteFloat(IntPtr addr, float data)
    {
        return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 4, ref new Int32());
    }
    public bool WriteDouble(IntPtr addr, double data)
    {
        return WinApi.WriteProcessMemory(_targetProcessHandle, addr, BitConverter.GetBytes(data), 8, ref new Int32());
    }
    public bool WriteAsciiString(IntPtr addr, string str, ref Int32 actualBytesWritten)
    {
        byte[] _bytes = System.Text.Encoding.ASCII.GetBytes(str);
        return WinApi.WriteProcessMemory(_targetProcessHandle, addr, _bytes, _bytes.Length, ref actualBytesWritten);
    }
    public bool WriteUnicodeString(IntPtr addr, string str, ref Int32 actualBytesWritten)
    {
        byte[] _bytes = System.Text.Encoding.Unicode.GetBytes(str);
        return WinApi.WriteProcessMemory(_targetProcessHandle, addr, _bytes, _bytes.Length, ref actualBytesWritten);
    }
    public bool WriteBytes(IntPtr addr, byte[] bytes)
    {
        dynamic byteCount = bytes.Count();
        return WinApi.WriteProcessMemory(_targetProcessHandle, addr, bytes, bytes.Length, ref byteCount);
    }
    public void WriteNOP(IntPtr address, long Length = 0)
    {
        long num = (Length - 1);
        long i = 0;
        while ((i <= num))
        {
            WriteByte((address + Convert.ToInt32(i)), 0x90);
            i = (i + 1);
        }
    }
    #endregion
    #region "Hack"
    public WinApi.MemoryBasicInformation[] GetMemRegions()
    {
        List<WinApi.MemoryBasicInformation> _rtnBlocks = new List<WinApi.MemoryBasicInformation>();
        Int64 _curBase = _systemInfo.lpMinimumApplicationAddress.ToInt64;
        WinApi.MemoryBasicInformation _curMbi = default(WinApi.MemoryBasicInformation);

        try
        {
            do
            {
                if (WinApi.VirtualQueryEx(_targetProcessHandle, new IntPtr(_curBase), ref _curMbi, _mbiSize) == 0)
                {
                    break; // TODO: might not be correct. Was : Exit Do
                }
                if (_curMbi.State == WinApi.MemoryAllocationState.COMMIT)
                {
                    _rtnBlocks.Add(_curMbi);
                }
                _curBase += _curMbi.RegionSize.ToInt64;
            } while (_curBase < _systemInfo.lpMaximumApplicationAddress.ToInt64);
        }
        catch (Exception ex)
        {
            MessageBox.Show("MemoryManager::GetMemRegions() Threw an Exception. Please give this message to tech support -->" + Environment.NewLine + "Current memory region info:" + Environment.NewLine + ".baseAddress: 0x" + _curMbi.BaseAddress.ToString("X") + Environment.NewLine + ".size: " + _curMbi.RegionSize.ToString() + " bytes" + Environment.NewLine + ".protect: " + _curMbi.Protect + Environment.NewLine + ".type: " + _curMbi.AllocationType + Environment.NewLine + "state: " + _curMbi.State + Environment.NewLine + Environment.NewLine + "System error message (also important): " + Environment.NewLine + ex.Message + Environment.NewLine + "Thank you. ");
        }

        return _rtnBlocks.ToArray();
    }
    #endregion

    #region "IDisposable Support"
    private bool disposedValue;
    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposedValue)
        {
            if (disposing)
            {
                DetachFromProcess();
            }
        }
        this.disposedValue = true;
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    #endregion

}


Capabilities:
ReadByte
ReadInt16
ReadInt32
ReadInt64
ReadUInt16
ReadUInt32
ReadUInt64
ReadFloat
ReadDouble
ReadAsciiString
ReadBytes
ReadUnicodeString
WriteByte
WriteBytes
WriteInt16
WriteUInt16
WriteInt32
WriteUInt32
WriteInt64
WriteUInt64
WriteFloat
WriteDouble
WriteAsciiString
WriteUnicodeString
WriteNOP



Someone released a similar memory class but I can't remember who it was. If it was you, reply and I'll add you to credits. I rewrote almost all of it though.

 
Usage

Code:
// Instantiate the class
public MemoryManager memMgr = new MemoryManager();

// Attach to process
public void Main() {
     memMgr.AttachToProcess(procID);

     // Get the process base address
     long baseAddress = memMgr.MainModuleBase;
}

// Then of course all of the functions

memMgr.WriteFloat(address, valueToWrite);
memMgr.ReadFloat(address);


Please +thanks and +rep.