原创 《游戏修改器DIY之三》——用C#读写游戏进程内存收藏

新一篇: 《CRectTrackerCS在C#中的使用》 | 旧一篇: 发布 VC知识库1-50期合订本

《游戏修改器DIY之三》
——用C#读写游戏进程内存

天津 赵春生

相关下载


    这是《游戏修改器DIY》系列的第三篇,通过前两篇拙作相信大家对游戏修改器的制作有了初步的了解,前两篇使用的编程工具是“Microsoft Visual C++ 6.0”,而这次将使用“Microsoft Visual C# 2005 Express Edition”。在C#中使用API可不像在C/C++那么简单,因为对我来说,C#还很陌生……

    本篇不再赘述游戏修改器的原理了,如果对此不了解的朋友可先看看我写的前两篇拙作或其他相关资料。


一:在C#中使用API。

    首先要导入一个namespace,以便简化后面的代码输入:

using System.Runtime.InteropServices;


    其次要使用DllImport引入API函数,如:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
    
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);


    现在就可以使用了,如:

MessageBox(new IntPtr(0), "Hello World!""Hello Dialog"0);


    为了使用方便,我制作了一个简单的类:

 

    class ProcessMemoryWorkApi
{
    
//HANDLE OpenProcess(
    
//    DWORD dwDesiredAccess,// access flag
    
//    BOOL bInheritHandle, // handle inheritance flag
    
//    DWORD dwProcessId  // process identifier
    
//    );
    [DllImport("kernel32.dll")]
    
public static extern
        IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId);

    
//BOOL CloseHandle(
    
//    HANDLE hObject  // handle to object to close
    
//    );
    [DllImport("kernel32.dll")]
    
public static extern
        Int32 CloseHandle(IntPtr hObject);

    
//BOOL WriteProcessMemory(
    
//    HANDLE hProcess, // handle to process whose memory is written to
    
//    LPVOID lpBaseAddress, // address to start writing to
    
//    LPVOID lpBuffer, // pointer to buffer to write data to
    
//    DWORD nSize, // number of bytes to write
    
//    LPDWORD lpNumberOfBytesWritten  // actual number of bytes written
    
//    );
    [DllImport("kernel32.dll")]
    
public static extern
        Int32 WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, 
uint[] lpBuffer, UInt32 nSize, IntPtr lpNumberOfBytesWritten);

    
//BOOL ReadProcessMemory(
    
//    HANDLE hProcess, // handle of the process whose memory is read
    
//    LPCVOID lpBaseAddress, // address to start reading
    
//    LPVOID lpBuffer, // address of buffer to place read data
    
//    DWORD nSize, // number of bytes to read
    
//    LPDWORD lpNumberOfBytesRead  // address of number of bytes read
    
//    );
    [DllImport("kernel32.dll")]
    
public static extern
        Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, 
uint[] lpBuffer, UInt32 nSize, IntPtr lpNumberOfBytesRead);
}



二:用C#制作游戏修改器。

    游戏是大家熟悉的“三维弹球”,这是WinXP自带的一款游戏,目的是修改她的分数,选这个游戏的原因是因为大家都能很容易地得到她,而且修改起来也很方便:取0x1025040中的值,然后与0x52相加,即可得到存放游戏分数的地址。

    单击“Go”按钮,可显示当前分数,并将分数改为:“999600000”(图1),关键代码如下:

 

private void button_go_Click(object sender, EventArgs e)
        
{
            IntPtr PinballHandle;
            IntPtr PinballScoreAddressPointer 
= (IntPtr)0x1025040;  //内存0x1025040中的值+0x52->PinballScoreAddress
            uint[] PinballScoreAddress = new uint[1];               //游戏分数的内存地址
            uint[] PinballScoreWrite = new uint[] 0x3B94AF80 };   //将分数改为:999600000
            uint[] PinballScoreRead = new uint[1];                  //用来存放当前分数

            
//"3D Pinball"在“Windows 任务管理器”中显示为"PINBALL.EXE",但作为
            
//GetProcessesByName的参数使用时并不能包含扩展名".EXE"。
            System.Diagnostics.Process[] PinballProcessID
                
= System.Diagnostics.Process.GetProcessesByName("PINBALL"); //根据进程名获取进程ID

            
if (PinballProcessID.Length != 0)
            
{
                PinballHandle 
= ProcessMemoryWorkApi.OpenProcess(0x1F0FFF0, (UInt32)PinballProcessID[0].Id);  //PROCESS_ALL_ACCESS=0x1F0FFF
                ProcessMemoryWorkApi.ReadProcessMemory(PinballHandle, PinballScoreAddressPointer, PinballScoreAddress, 4, (IntPtr)0);//通过指针得到PinballScoreAddress
                PinballScoreAddress[0= PinballScoreAddress[0+ 0x52//PinballScoreAddress+0x52才是游戏分数的内存地址
                ProcessMemoryWorkApi.ReadProcessMemory(PinballHandle, (IntPtr)PinballScoreAddress[0], PinballScoreRead, 4, (IntPtr)0);      //当前游戏分数
                MessageBox.Show("当前分数为: " + PinballScoreRead[0].ToString() + " " + "分数即将被修改成: 999600000""ProcessMemoryWork_Demo");
                ProcessMemoryWorkApi.WriteProcessMemory(PinballHandle, (IntPtr)PinballScoreAddress[
0], PinballScoreWrite, 4, (IntPtr)0);    //修改游戏分数
                ProcessMemoryWorkApi.CloseHandle(PinballHandle);
            }

            
else
                MessageBox.Show(
""3D Pinball" 还没有运行吧?""ProcessMemoryWork_Demo");

        }


三:相关提示。

    刚刚接触C#不久,对OOP也一知半解,写此文只为抛砖引玉,谢谢!

    本程序代码测试环境:
    WinXP (Professional SP2)
    Microsoft Visual Studio 2005 (Installed Edition: C# Express)
    Version 8.0.50727.762  (SP.050727-7600)
    Microsoft .NET Framework
    Version 2.0.50727

    《游戏修改器DIY》/《游戏修改器DIY之二》可通过搜索引擎或访问我的Blog获得。

    Blog:
    http://timw.yeah.net
    http://timw.126.com

20:35 2007-04-27


 

发表于 @ 2007年04月29日 15:19:00|评论(loading...)|收藏

新一篇: 《CRectTrackerCS在C#中的使用》 | 旧一篇: 发布 VC知识库1-50期合订本

评论

#jianglinjun 发表于2007-07-26 04:38:33  IP: 211.158.106.*
请问 0x1025040和0x52 这个是怎么来的...
2007-07-28 10:08:09作者回复
都是是用OD跟踪出来的.都是定值.
#Prince_vegeta 发表于2007-07-28 10:08:57  IP: 125.36.237.*
都是是用OD跟踪出来的.都是定值.
#jiangc 发表于2007-11-11 10:47:18  IP: 61.186.154.*
用内存编辑器可以找到么?
2007-11-13 10:32:30作者回复
内存编辑器恐怕操作起来有些困难,还是用游戏修改器找关键地址,然后跟踪该地址找到关键点比较妥当。
#33 发表于2008-01-21 02:01:42  IP: 218.27.69.*
我把你的程序的内存地址改了一下,因为我要改的游戏的内存地址不是动态的。然后注释了 PinballScoreAddress[0] = PinballScoreAddress[0] + 0x52; //
进程名也改了。但是无论如何都得不到那个内存地址的值。。总是0。弹球就好使。不知道为啥。
#Vegeta 发表于2008-01-26 18:26:18  IP: 221.238.142.*
一定要确保你读取的地址是正确的:用游戏修改软件找到的地址一定要正确。然后再尝试。
#mlx574 发表于2008-08-01 14:04:01  IP: 125.66.79.*
能不能用编程的方法得到这个基址?
2008-08-01 22:13:55作者回复
那么做就成了通用游戏修改器了。
发表评论  


登录
Csdn Blog version 3.1a
Copyright © 赵春生