csharp/AgentRev/CoD-FoV-Changers/src/Ghosts_fov_changer/Ghosts_fov_changer/MemoryMod.cs

MemoryMod.cs
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

namespace MemoryMod
{
    clast MemoryMod
    {
        const int READ = 0x10; // PROCESS_VM_READ
        const int WRITE = 0x28; // PROCESS_VM_OPERATION | PROCESS_VM_WRITE
        // Above values are explained at http://msdn.microsoft.com/library/windows/desktop/ms684880.aspx

        uint pFoV;

        byte[] cVar = Encoding.ASCII.GetBytes("cg_fov\0"); // C-style (null-terminated) string; in this example, I will show you how to locate that string


        // Here are the DLLImports

        [DllImport("kernel32.dll", EntryPoint = "OpenProcess")] // kernel32.dll contains Win32 API functions; it is roughly equivalent to "windows.h" in C / C++
        public static extern uint OpenProcess(uint accessRights, bool inheritHandle, uint procID);

        [DllImport("kernel32.dll", EntryPoint = "CloseHandle")]
        public static extern bool CloseHandle(uint procHandle);

        [DllImport("kernel32.dll", EntryPoint = "ReadProcessMemory")]
        public static extern bool ReadProcessMemory(uint procHandle, uint address, byte[] buffer, uint size, ref uint bytesRead);

        [DllImport("kernel32.dll", EntryPoint = "WriteProcessMemory")]
        public static extern bool WriteProcessMemory(uint procHandle, uint address, byte[] buffer, uint size);

        [DllImport("msvcrt.dll", EntryPoint = "memcmp")] // msvcrt.dll contains contains common C and C++ libraries; "memcmp" is located in the "string.h" C library
        public unsafe static extern int memcmp(byte* haystack, byte[] needle, int length); // All DLLImported functions with array parameters can receive them as an array or a pointer;
                                                                                           // To use pointers, the function must be declared "unsafe"

        public unsafe bool SearchMemory() // Any function that deals with pointers in any shape or form must be declared "unsafe"
        {
            bool isFound = false;

            Process[] procs = Process.GetProcessesByName("iw5mp"); // ".exe" must be omitted

            if (procs.Length != 0)
            {
                uint procID = (uint)procs[0].Id;
                uint procHandle = OpenProcess(READ, false, procID);

                if (procHandle != 0)
                {
                    uint bytesRead = 0;

                    uint start = 0x00400000; // For applications compiled with Visual Studio, as in the case of MW3, the main module always begins at 0x400000
                    uint end = 0x01000000;

                    uint buffSize = 0x1000; // (4096 bytes) This buffer size is optimal, since when combined with the bytesRead value, 
                                            // it permits skipping over empty memory areas, which are always 4096 bytes at minimum

                    byte[] buffer = new byte[buffSize];

                    for (uint i = start; i < end; i += buffSize)
                    {
                        ReadProcessMemory(procHandle, i, buffer, i, ref bytesRead); // The "ref" is because the method writes the value directly to the variable;
                                                                                    // It is not needed for the buffer, since C# arrays are references themselves

                        if (bytesRead == buffSize) // We check if the buffer has been fully filled; if it isn't, it means that this area of the memory contains no data
				        {
                            fixed (byte* pBuffer = buffer) // We declare the pointer, which can only be used within this scope
                            {
                                for (uint j = 0; j < buffSize; i += 4) // The "4" is because values are always stored in the memory at an offset 
                                                                       // with the last digit being a multiple of 4 (32-bit offsets)
                                {
                                    if (memcmp(pBuffer + i, cVar, cVar.Length) == 0) // memcmp returns 0 if memory values are equal, it's not a mistake;
                                                                                     // The "+i" is the whole reason behind the use of a pointer here,
                                                                                     // it allows direct offsets without having to manipulate the array
                                    {
                                        pFoV = i + j;
                                        isFound = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }

                    CloseHandle(procHandle);
                }
            }

            return isFound;
        }


        public void WriteFloat(uint ptr, float val)
        {
            if (ptr != 0)
            {
                Process[] procs = Process.GetProcessesByName("iw5mp");

                if (procs.Length != 0)
                {
                    uint procID = (uint)procs[0].Id;
                    uint procHandle = OpenProcess(WRITE, false, procID);

                    if (procHandle != 0)
                    {
                        WriteProcessMemory(procHandle, ptr, BitConverter.GetBytes(val), sizeof(float));
                        CloseHandle(procHandle);
                    }
                }
            }
        }
    }
}