管理

C# 通过 Windows API 实现进程内存读写操作

Posted on 2026-08-06 00:00  lzhdim  阅读(2393)  评论(0)    收藏  举报

前言

软件开发中,有时我们需要对其他程序的内存进行读取或修改,例如用于游戏调试、系统监控、逆向分析等场景。Windows 提供了一组强大的 API 函数,允许我们实现对其他进程内存的操作。

本文将介绍如何使用 C# 调用 Windows API 实现对目标进程内存的读取与写入,并通过一个完整的示例程序演示其具体应用。

正文

1、基础知识

在开始之前,我们需要了解以下几个关键的 Windows API 函数:

  • OpenProcess:获取目标进程的句柄
  • ReadProcessMemory:读取目标进程的内存数据
  • WriteProcessMemory:向目标进程内存写入数据
  • VirtualAllocEx:在目标进程中分配内存(可选)
  • VirtualFreeEx:释放目标进程中的内存(可选)

这些函数都定义在 kernel32.dll 中,可以通过 DllImport 导入使用。

2、示例目标程序

我们先创建一个简单的 Windows 窗体应用程序作为目标程序。该程序包含一个计数器,每秒递增一次,并显示当前值及其内存地址。

public partialclassForm1 : Form
{
    privateint counter = 100;
    private Thread counterThread;
    privatebool isRunning = false;

    public Form1()
    {
        InitializeComponent();
    }

    private void StartCounter()
    {
        if (isRunning) return;
        isRunning = true;
        counterThread = new Thread(() =>
        {
            while (isRunning)
            {
                this.Invoke((MethodInvoker)delegate
                {
                    unsafe
                    {
                        fixed (int* ptr = &counter)
                        {
                            lblCounter.Text = $"{counter}";
                            txtAddress.Text = $"0x{(IntPtr)ptr:X}";
                        }
                    }
                });
                Thread.Sleep(1000);
                counter++;
            }
        });
        counterThread.IsBackground = true;
        counterThread.Start();
    }

    private void StopCounter()
    {
        isRunning = false;
        if (counterThread != null && counterThread.IsAlive)
        {
            counterThread.Join(1000);
        }
    }

    private void btnStart_Click(object sender, EventArgs e)
    {
        StartCounter();
        btnStart.Enabled = false;
        btnStop.Enabled = true;
    }

    private void btnStop_Click(object sender, EventArgs e)
    {
        StopCounter();
        btnStart.Enabled = true;
        btnStop.Enabled = false;
    }

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        StopCounter();
        base.OnFormClosing(e);
    }
}

 

3、内存修改器程序

下面是一个完整的内存修改器程序,可以读取和修改上面目标程序的计数器值:

public partialclassForm1 : Form
{
    [DllImport("kernel32.dll")]
    public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    [DllImport("kernel32.dll")]
    public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);

    [DllImport("kernel32.dll")]
    public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesWritten);

    privateconstint PROCESS_ALL_ACCESS = 0x1F0FFF;
    private IntPtr processHandle;
    private Process targetProcess;

    public Form1()
    {
        InitializeComponent();
    }

    private void btnRead_Click(object sender, EventArgs e)
    {
        try
        {
            targetProcess = Process.GetProcessesByName(txtProcessName.Text)[0];
            processHandle = OpenProcess(PROCESS_ALL_ACCESS, false, targetProcess.Id);
            IntPtr memoryAddress = (IntPtr)Convert.ToInt64(txtMemoryAddress.Text, 16);
            byte[] buffer = newbyte[4];
            int bytesRead = 0;

            if (ReadProcessMemory(processHandle, memoryAddress, buffer, buffer.Length, ref bytesRead))
            {
                intvalue = BitConverter.ToInt32(buffer, 0);
                lblCurrentValue.Text = value.ToString();
            }
            else
            {
                MessageBox.Show("读取内存失败!");
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show($"发生错误:{ex.Message}");
        }
    }

    private void btnWrite_Click(object sender, EventArgs e)
    {
        try
        {
            if (processHandle == IntPtr.Zero)
            {
                MessageBox.Show("请先读取内存!");
                return;
            }

            IntPtr memoryAddress = (IntPtr)Convert.ToInt64(txtMemoryAddress.Text, 16);
            int newValue = Convert.ToInt32(txtNewValue.Text);
            byte[] buffer = BitConverter.GetBytes(newValue);
            int bytesWritten = 0;

            if (WriteProcessMemory(processHandle, memoryAddress, buffer, buffer.Length, ref bytesWritten))
            {
                MessageBox.Show("写入成功!");
                btnRead_Click(sender, e); // 刷新显示
            }
            else
            {
                MessageBox.Show("写入内存失败!");
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show($"发生错误:{ex.Message}");
        }
    }
}

 

4、使用说明

1、首先运行目标程序(TargetApplication)

2、运行内存修改器(MemoryEditor)

3、使用工具如 Cheat Engine 找到目标程序中 counter 变量的内存地址(本例中直接通过指针获取)

4、在内存修改器中输入进程名和内存地址

5、点击“读取”按钮查看当前值

6、输入新值并点击“写入”按钮修改内存

5、注意事项

1、实际使用时需注意:

确保具有足够的系统权限

注意目标程序的保护机制

内存地址可能动态变化,需要实时更新

2、在 64 位系统上运行时:

需要处理进程权限问题

地址空间差异较大

数据类型大小可能需要调整

总结

通过调用 Windows API,我们可以使用 C# 对其他进程的内存进行读写操作。这种技术广泛应用于程序调试、系统监控、游戏辅助等领域。虽然功能强大,但在实际使用过程中需要注意权限控制、内存地址变化以及目标程序的安全机制等问题。

本文提供了一个完整的示例代码,帮助开发快速理解并实践这一技术。希望对你在学习和项目开发中有所帮助。

 

Copyright © 2000-2022 Lzhdim Technology Software All Rights Reserved