程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# 簡單內存補丁,

C# 簡單內存補丁,

編輯:C#入門知識

C# 簡單內存補丁,


寫在開頭:看了一些視頻教程,感覺OD為什麼別人學個破解那麼容易,我就那麼難了呢,可能是沒有那麼多時間吧。

解釋:個人見解:所謂內存補丁,即:通過修改運行程序的內容,來達到某種目的的操作。修改使用OpenProcess打開,WriteProcessMemory寫入,CloseHandle關閉。部分需要讀取數據判斷使用:ReadProcessMemory

0x1 看教程

  關於有的學習教程,確實要看看視頻才能了解別人的操作,或者很簡單一個東西,如果沒有別人的指導那麼自己操作確實不太容易。

0x2 學習到部分概念

  肯定不可能一味的模仿,做一樣的東西,所以需要學以致用就很關鍵了。於是乎,用vs2013 c++寫了幾行代碼,用於自己測試,用C#寫內存補丁

0x3 網上檢索

  沒有人生而知之,所以網上查詢也是很關鍵的一步,查詢哪些內容呢?就是查詢C#如何寫內存補丁,代碼大同小異不過不一定能用。

0x4 代碼實踐

  網上找到的代碼也是要在實踐中得出能否使用的。所以這一步也是必不可免的。

於是乎有了下面的代碼。需要使用OD找到代碼的位置即和在內存中和代碼的相差位置。

MCF程序  C++ OK方法中

void CMFCTestDlg::OnBnClickedOk()
{
    CString str;
    GetDlgItemText(IDC_EDIT1, str);

    if (str == "test123456789"){
        ::MessageBox(NULL, L"OK", L"提示", 0);
    }
    else{
        ::MessageBox(NULL, L"Fail", L"提示", 0);
    }
}
View Code

C#程序中調用,首先貼一個幫助類,來源網上。當然對其中添加和修改了部分方法。

public abstract class ApiHelper
    {
        [DllImportAttribute("kernel32.dll", EntryPoint = "ReadProcessMemory")]
        public static extern bool ReadProcessMemory
            (
                IntPtr hProcess,
                IntPtr lpBaseAddress,
                IntPtr lpBuffer,
                int nSize,
                IntPtr lpNumberOfBytesRead
            );

        [DllImportAttribute("kernel32.dll", EntryPoint = "OpenProcess")]
        public static extern IntPtr OpenProcess
            (
                int dwDesiredAccess,
                bool bInheritHandle,
                int dwProcessId
            );

        [DllImport("kernel32.dll")]
        private static extern void CloseHandle
            (
                IntPtr hObject
            );

        //寫內存
        [DllImportAttribute("kernel32.dll", EntryPoint = "WriteProcessMemory")]
        public static extern bool WriteProcessMemory
        (
            IntPtr hProcess,
            IntPtr lpBaseAddress,
            int[] lpBuffer,
            int nSize,
            IntPtr lpNumberOfBytesWritten
        );

        //獲取窗體的進程標識ID
        public static int GetPid(string windowTitle)
        {
            int rs = 0;
            Process[] arrayProcess = Process.GetProcesses();
            foreach (Process p in arrayProcess)
            {
                if (p.MainWindowTitle.IndexOf(windowTitle) != -1)
                {
                    rs = p.Id;
                    break;
                }
            }

            return rs;
        }

        //根據進程名獲取PID
        public static int GetPidByProcessName(string processName, ref IntPtr baseAddress)
        {
            Process[] arrayProcess = Process.GetProcessesByName(processName);
            foreach (Process p in arrayProcess)
            {
                baseAddress = p.MainModule.BaseAddress;
                return p.Id;
            }

            return 0;
        }

        //根據進程名獲取PID
        public static int GetPidByProcessName(string processName)
        {
            Process[] arrayProcess = Process.GetProcessesByName(processName);
            foreach (Process p in arrayProcess)
            {
                return p.Id;
            }

            return 0;
        }

        //根據窗體標題查找窗口句柄(支持模糊匹配)
        public static IntPtr FindWindow(string title)
        {
            Process[] ps = Process.GetProcesses();
            foreach (Process p in ps)
            {
                if (p.MainWindowTitle.IndexOf(title) != -1)
                {
                    return p.MainWindowHandle;
                }
            }
            return IntPtr.Zero;
        }

        //讀取內存中的值
        public static int ReadMemoryValue(int baseAddress, string processName)
        {
            try
            {
                byte[] buffer = new byte[2];
                IntPtr byteAddress = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0); //獲取緩沖區地址
                IntPtr hProcess = OpenProcess(0x1F0FFF, false, GetPidByProcessName(processName));
                ReadProcessMemory(hProcess, (IntPtr)baseAddress, byteAddress, buffer.Length, IntPtr.Zero); //將制定內存中的值讀入緩沖區
                CloseHandle(hProcess);
                return Marshal.ReadInt32(byteAddress);
            }
            catch
            {
                return 0;
            }
        }

        //將值寫入指定內存地址中
        public static bool WriteMemoryValue(int baseAddress, string processName, int[] value)
        {
            IntPtr hProcess = OpenProcess(0x1F0FFF, false, GetPidByProcessName(processName)); //0x1F0FFF 最高權限
            bool result = WriteProcessMemory(hProcess, (IntPtr)baseAddress, value, value.Length, IntPtr.Zero);
            CloseHandle(hProcess);

            return result;
        }
    }
View Code

最後是在具體按鈕中的調用了。

private string processName = "MFCTest"; //

        private void button1_Click(object sender, EventArgs e)
        {
            IntPtr startAddress = IntPtr.Zero;
            int pid = ApiHelper.GetPidByProcessName(processName, ref startAddress);
            if (pid == 0)
            {
                MessageBox.Show("哥們啟用之前該運行吧!");
                return;
            }

            int baseAddress = startAddress.ToInt32() + 0x1000;
            int value = ReadMemoryValue(baseAddress);             // 讀取基址(該地址不會改變)
            int address = baseAddress + 0x14F3;                   // 獲取2級地址
            value = ReadMemoryValue(address);
            bool result = WriteMemory(address, new int[] { 144 });
            address = address + 0x1;
            result = WriteMemory(address, new int[] { 144 });

            MessageBox.Show(result ? "成功" : "失敗");
        }


        //讀取制定內存中的值
        public int ReadMemoryValue(int baseAdd)
        {
            return ApiHelper.ReadMemoryValue(baseAdd, processName);
        }

        //將值寫入指定內存中
        public bool WriteMemory(int baseAdd, int[] value)
        {
            return ApiHelper.WriteMemoryValue(baseAdd, processName, value);
        }
View Code

0x5 總結

  只有不斷學習才能知道新的知識,同時在學習中進步。很多不懂的概念其實很簡單。當然前提是你明白以後。

   其中注意一點。

測試代碼下載:WriteProcessMemory的buffer填入一個數組也是可以的。需要計算長度。然後nSize就是,前面的數組作為幾個字節進行使用。

// 重構了些許代碼


        //將值寫入指定內存地址中
        public static bool WriteMemoryValue(int baseAddress, string processName, int[] value, int len)
        {
            IntPtr hProcess = OpenProcess(0x1F0FFF, false, GetPidByProcessName(processName)); //0x1F0FFF 最高權限
            bool result = WriteProcessMemory(hProcess, (IntPtr)baseAddress, value, len, IntPtr.Zero);
            CloseHandle(hProcess);

            return result;
        }

// 144=0x90  表示 nop
bool result = ApiHelper.WriteMemoryValue(address, processName, new int[] { 144 + 144 * 256 }, 2);

 

 WinTestRe.zip

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved