寫在開頭:看了一些視頻教程,感覺OD為什麼別人學個破解那麼容易,我就那麼難了呢,可能是沒有那麼多時間吧。
解釋:個人見解:所謂內存補丁,即:通過修改運行程序的內容,來達到某種目的的操作。修改使用OpenProcess打開,WriteProcessMemory寫入,CloseHandle關閉。部分需要讀取數據判斷使用:ReadProcessMemory
關於有的學習教程,確實要看看視頻才能了解別人的操作,或者很簡單一個東西,如果沒有別人的指導那麼自己操作確實不太容易。
肯定不可能一味的模仿,做一樣的東西,所以需要學以致用就很關鍵了。於是乎,用vs2013 c++寫了幾行代碼,用於自己測試,用C#寫內存補丁
沒有人生而知之,所以網上查詢也是很關鍵的一步,查詢哪些內容呢?就是查詢C#如何寫內存補丁,代碼大同小異不過不一定能用。
網上找到的代碼也是要在實踐中得出能否使用的。所以這一步也是必不可免的。
於是乎有了下面的代碼。需要使用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
只有不斷學習才能知道新的知識,同時在學習中進步。很多不懂的概念其實很簡單。當然前提是你明白以後。
其中注意一點。
測試代碼下載: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