using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using CSharpGuiMemScanner;

namespace CSharpGuiMemScanner
{
    public static class MemoryExploiter
    {

        //Some DLL Imports and bool variables

        public static int totalPatAddresses = 0;
        public static bool isPatternDone = false;
        public static bool isReadDone = false;
        public static bool isWriteDone = false;
        public static bool isByteDone = false;
        public static bool isAOBDone = false;


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

        [DllImport("kernel32.dll")]
        static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress,
            UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);


        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr OpenProcess(
         uint processAccess,
         bool bInheritHandle,
         uint processId);

        [DllImport("kernel32.dll")]
        public static extern bool CloseHandle(int hObject);

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

        [StructLayout(LayoutKind.Sequential)]
        struct MEMORY_BASIC_INFORMATION
        {
            public IntPtr BaseAddress;
            public IntPtr AllocationBase;
            public uint AllocationProtect;
            public IntPtr RegionSize;
            public uint State;
            public uint Protect;
            public uint Type;
        }
        [DllImport("kernel32.dll")]
        static extern int VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, uint dwLength);


        //Actual Memory Manipulation functions start from there

        /*
        I made this ChangProtection as private b/c it will be auto used by these functions below
        So you dont have to do like change protection for specific mem addresses and restoring it 
        again and again......If you want then you can make it public it's upto you
        */

        //I dont necessarily want to include every mem protection constant b/c this one will do the job
        const int PAGE_EXECUTE_READWRITE = 0x40;
        private static uint oldProtection;
        private static uint newProtection;
        private static void ChangeProtection(IntPtr processHandle,long memAddress, UIntPtr bytesToWrite)
        {
            VirtualProtectEx(processHandle, (IntPtr)memAddress, bytesToWrite, PAGE_EXECUTE_READWRITE, out oldProtection);
        }
        private static void RestoreProtection(IntPtr processHandle, long memAddress, UIntPtr bytesToWrite)
        {
            VirtualProtectEx(processHandle, (IntPtr)memAddress, bytesToWrite, oldProtection, out newProtection);
        }


        public static int RPM(long memAddr, string process, uint procesID, bool usingCheckBox = false)
        {
            uint procID = 0;

            if (usingCheckBox)
            {
                procID = procesID;
            }
            else
            {
                Process mproc = Process.GetProcessesByName(process)[0];
                procID = (uint)mproc.Id;
            }
            IntPtr bytes_read = IntPtr.Zero;
            byte[] buffer = new byte[24];

            if (procID > 0)
            {
                IntPtr pHandle = OpenProcess(0xFFFF, false, procID);
                if (pHandle != IntPtr.Zero)
                {
                    ChangeProtection(pHandle, memAddr, (UIntPtr)24); //using 24 as default size you can change it according to you!
                    if (ReadProcessMemory(pHandle, (IntPtr)memAddr, buffer, buffer.Length, out bytes_read))
                    {

                        isReadDone = true;
                        int buff = BitConverter.ToInt32(buffer, 0);
                        RestoreProtection(pHandle, memAddr, (UIntPtr)24);
                        CloseHandle((int)pHandle);
                        return buff;
                    }
                }
            }

            return -1;
        }

        public static string PMAKER(long memAddr, string process,int amount, uint procesID, bool usingCheckBox = false,bool inC = false,bool incComma = false
            , bool incShellCode = false)
        {
            uint procID = 0;
            string returnBuffer = string.Empty;
            if (usingCheckBox)
            {
                procID = procesID;
            }
            else
            {
                Process mproc = Process.GetProcessesByName(process)[0];
                procID = (uint)mproc.Id;
            }
            IntPtr bytes_read = IntPtr.Zero;
            byte[] buffer = new byte[amount];

            if (procID > 0)
            {

                IntPtr pHandle = OpenProcess(0xFFFF, false, procID);
                if (pHandle != IntPtr.Zero)
                {
                    ChangeProtection(pHandle, memAddr, (UIntPtr)amount);
                    if (ReadProcessMemory(pHandle, (IntPtr)memAddr, buffer, buffer.Length, out bytes_read))
                    {
                        isAOBDone = true;

                        for (int i = 0; i < amount; i++)
                        {
                            if (inC)
                            {
                                returnBuffer += "0x" + buffer[i].ToString("X2") + " ";
                            }
                            if (incComma)
                            {
                                if(i+1 == amount)
                                {
                                    returnBuffer += "0x" + buffer[i].ToString("X2");
                                }
                                else
                                {
                                    returnBuffer += "0x" + buffer[i].ToString("X2") + ",";
                                }
                            }
                            if (incShellCode)
                            {
                                returnBuffer += "\\x" + buffer[i].ToString("X2") + "";
                            }
                            if(!inC && !incComma && !incShellCode)
                            {
                                returnBuffer += buffer[i].ToString("X2") + " ";
                            }
                        }

                        RestoreProtection(pHandle, memAddr, (UIntPtr)amount);
                        CloseHandle((int)pHandle);
                        return returnBuffer;
                    }
                }
            }

            return string.Empty;
        }

        public static List<IntPtr> FindPatternInProcess(string proc, byte[] pattern, uint procesID, bool usingCheckBox = false)
        {
            uint procID = 0;
            if (usingCheckBox)
            {
                procID = procesID;
            }
            else
            {
                Process mproc = Process.GetProcessesByName(proc)[0];
                procID = (uint)mproc.Id;
            }
            List<IntPtr> foundAddresses = new List<IntPtr>();

            IntPtr currentAddress = IntPtr.Zero;
            long dataSize = pattern.Length;
            MEMORY_BASIC_INFORMATION memInfo = new MEMORY_BASIC_INFORMATION();
            IntPtr tmpHandle = OpenProcess(0xFFFF, false, procID);

            while (VirtualQueryEx(tmpHandle, currentAddress, out memInfo, (uint)Marshal.SizeOf(memInfo)) == Marshal.SizeOf(memInfo))
            {
                // Check if the memory is accessible
                if (memInfo.State == 0x1000 /* MEM_COMMIT */ && (memInfo.Protect & 0x100 /* PAGE_GUARD */) == 0)
                {
                    byte[] buffer = new byte[memInfo.RegionSize.ToInt64()];
                    IntPtr bytesRead = IntPtr.Zero;

                    if (ReadProcessMemory(tmpHandle, memInfo.BaseAddress, buffer, buffer.Length, out bytesRead))
                    {
                        // Search for the sequence of bytes in the current buffer
                        for (int i = 0; i < memInfo.RegionSize.ToInt64() - dataSize + 1; i++)
                        {
                            bool found = true;
                            for (int j = 0; j < dataSize; j++)
                            {
                                if (pattern[j] != buffer[i + j])
                                {
                                    found = false;
                                    break;
                                }
                            }

                            if (found)
                            {
                                isPatternDone = true;
                                foundAddresses.Add(memInfo.BaseAddress + i);
                            }
                        }
                    }
                }

                // Move to the next memory region
                currentAddress = new IntPtr(currentAddress.ToInt64() + memInfo.RegionSize.ToInt64());

            }
            totalPatAddresses = foundAddresses.Count;
            return foundAddresses;
        }


        public static bool WPM(long memAddr,string process,int val,uint procesID, bool usingCheckBox = false)
        {
            uint procID = 0;

            if (usingCheckBox)
            {
                procID = procesID;
            }
            else
            {
                Process mproc = Process.GetProcessesByName(process)[0];
                procID = (uint)mproc.Id;
            }

            IntPtr bytes_read = IntPtr.Zero;
            byte[] buffer = new byte[24];
            if (procID > 0)
            {
                IntPtr pHandle = OpenProcess(0xFFFF, false, procID);
                if (pHandle != IntPtr.Zero)
                {
                    byte[] tmpBuff = BitConverter.GetBytes(val);
                    ChangeProtection(pHandle, memAddr, (UIntPtr)24);
                    if ( WriteProcessMemory(pHandle, (IntPtr)memAddr, tmpBuff, tmpBuff.Length, out bytes_read))
                    {
                        isWriteDone = true;
                        RestoreProtection(pHandle, memAddr, (UIntPtr)24);
                        CloseHandle((int)pHandle);
                        return true;
                    }
                }
            }

            return false;
        }

        public static bool WBYTE(int memAddr,string process,byte[] buffer, uint procesID, bool usingCheckBox = false)
        {
            uint procID = 0;

            if (usingCheckBox)
            {
                procID = procesID;
            }
            else
            {
                Process mproc = Process.GetProcessesByName(process)[0];
                procID = (uint)mproc.Id;
            }

            IntPtr bytes_read = IntPtr.Zero;
            Process myProcess = Process.GetProcessesByName(process)[0];
            if (procID > 0)
            {
                IntPtr pHandle = OpenProcess(0xFFFF, false, procID);
                if (pHandle != IntPtr.Zero)
                {
                    ChangeProtection(pHandle, memAddr, (UIntPtr)buffer.Length);
                    if (WriteProcessMemory(pHandle, (IntPtr)memAddr, buffer, buffer.Length, out bytes_read))
                    {
                        isByteDone = true;
                        RestoreProtection(pHandle, memAddr, (UIntPtr)buffer.Length);
                        CloseHandle((int)pHandle);
                        return true;
                    }
                }
            }

            return false;



        }
    }

}


    


