寫在開頭:看了一些視頻教程,感覺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