IntPtr lpBaseAddress,
[In, Out] byte[] buffer,
UInt32 size,
out IntPtr lpNumberOfBytesRead
);
[DllImport(\"kernel32.dll\")] public static extern Int32 CloseHandle(
IntPtr hObject
);
如果你想知道在c++和c#之间有关类型转换的更多信息,我建议你从msdn.microsoft.com站点搜索此话题:“Marshaling Data with Platform Invoke”。 基本上, 如果你把逻辑上是正确的程序搁在那儿, 它便能运行, 但有时还需要一点点的调整。
在声明了这些函数之后,我要做的是用一个简单的类把它们包装起来,并使用这个类。我把声明放在一个叫做ProcessMemoryReaderApi的类中,这样做更有条有理。主要的实用类称为ProcessMemoryReade。这个类有一个ReadProcess属性,它源于System.Diagnostics.Process类型,用于存放你要读取其内存的进程。类中有一个方法,用来以读模式打开进程。
public void OpenProcess()
{
m_hProcess = ProcessMemoryReaderApi.OpenProcess(
ProcessMemoryReaderApi.PROCESS_VM_READ, 1,
(uint)m_ReadProcess.Id);
}
PROCESS_VM_READ 常量告诉系统以读模式打开进程, 而m_ReadProcess.Id 声明了我要打开的是什么进程。
在该类中最重要的是一个方法,它从进程中读取内存:
public byte[] ReadProcessMemory(IntPtr MemoryAddress, uint bytesToRead,
out int bytesReaded)
{
byte[] buffer = new byte[bytesToRead];
IntPtr ptrBytesReaded;
ProcessMemoryReaderApi.ReadProcessMemory(m_hProcess,MemoryAddress,buffer,
bytesToRead,out ptrBytesReaded);
bytesReaded = ptrBytesReaded.ToInt32();
return buffer;
}
这个函数以所请求的大小声明一个字节数组,并使用API读取内存。就这么简单!
最后,下面这个方法关闭了进程。
public void CloseHandle()
{
int iRetValue;
iRetValue = ProcessMemoryReaderApi.CloseHandle(m_hProcess);
if (iRetValue == 0)
throw new Exception(\"CloseHandle failed\");
}
第三步 – 使用类
现在轮到了有趣的部分。使用这个类就是为了读取“扫雷”的内存并揭开布雷图。要使用类,需要先对其进行初始化:
ProcessMemoryReaderLib.ProcessMemoryReader pReader
= new ProcessMemoryReaderLib.ProcessMemoryReader();
接着,必须设置你想要读取其内存的进程。以下是如何获得“扫雷”进程的例子,这个进程一旦被装入,就被设置为ReadProcess属性:
System.Diagnostics.Process[] myProcesses
; = System.Diagnostics.Process.GetProcessesByName(\"winmine\");
pReader.ReadProcess = myProcesses[0];
我们现在需要做的是:打开进程,读取内存,并在完成后关闭它。下面还是有关操作的例子,它读取代表布雷图宽度的地址。
pReader.OpenProcess();
int iWidth;
byte[] memory;
memory = pReader.ReadProcessMemory((IntPtr)0x1005334,1,out bytesReaded);
iWidth = memory[0];
pReader.CloseHandle();
简单吧!
在结论部分,我列出了显示布雷图的完整代码。别忘了,我要访问的所有内存位置就是在本文第一部分中所找到位置。
// 布雷图的资料管理器
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));
ProcessMemoryReaderLib.ProcessMemoryReader pReader
= new ProcessMemoryReaderLib.ProcessMemoryReader();
System.Diagnostics.Process[] myProcesses
= System.Diagnostics.Process.GetProcessesByName(\"winmine\");
// 获得“扫雷”进程的第一个实列
if (myProcesses.Length == 0)
{
MessageBox.Show(\"No MineSweeper process found!\");
return;
}
pReader.ReadProcess = myProcesses[0];
// 以读内存模式打开进程
pReader.OpenProcess();
int bytesReaded;
int iWidth, iHeight, iMines;
int iIsMine;
int iCellAddress;
byte[] memory;
memory = pReader.ReadProcessMemory((IntPtr)0x1005334,1,out bytesReaded);
iWidth = memory[0];
txtWidth.Text = iWidth.ToString();
memory = pReader.ReadProcessMemory((IntPtr)0x1005338,1,out bytesReaded);
iHeight = memory[0];
txtHeight.Text = iHeight.ToString();
memory = pReader.ReadProcessMemory((IntPtr)0x1005330,1,out bytesReaded);
iMines = memory[0];
txtMines.Text = iMines.ToString();
// 删除以前的按钮数组
this.Controls.Clear();
this.Controls.AddRange(MainControls);
// 创建一个按钮数组, 用于画出布雷图的每一格
ButtonArray = new System.Windows.Forms.Button[iWidth,iHeight];
int x,y;
for (y=0 ; y<iHeight ; y++)
for (x=0 ; x<iWidth ; x++)
{
ButtonArray[x,y] = new System.Windows.Forms.Button();
ButtonArray[x,y].Location = new System.Drawing.Point(20 + x*16, 70 + y*16);
ButtonArray[x,y].Name = \"\";
ButtonArray[x,y].Size = new System.Drawing.Size(16,16);
iCellAddress = (0x1005340) + (32 * (y+1)) + (x+1);
memory = pReader.ReadProcessMemory((IntPtr)iCellAddress,1,out bytesReaded);
iIsMine = memory[0];
if (iIsMine == 0x8f)//如果有雷,则画出地雷位图
ButtonArray[x,y].Image = ((System.Drawing.Bitmap)
(resources.GetObject(\"button1.Image\")));
this.Controls.Add(ButtonArray[x,y]);
}
// 关闭进程句柄
pReader.CloseHandle();
就是这些,希望你能学到新的东西。