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

前言

软件开发中,有时我们需要对其他程序的内存进行读取或修改,例如用于游戏调试、系统监控、逆向分析等场景。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 = newbyte4;

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

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

相关推荐
-银雾鸢尾-1 小时前
C#中的预处理指令
开发语言·c#
Livia要学习1 小时前
Python面向对象三大特性:封装、继承、多态
开发语言·python
dalong101 小时前
Savitzky-Golay 的C# 实现
开发语言·kotlin·c#
猿长大人2 小时前
C# | Autofac 新手指南:从零理解依赖注入与组件装配
c#·.net·di·依赖注入
show4332 小时前
多格式导出怎么做?2026免费小程序TXT/SRT实践
开发语言·小程序·c#
岁岁养乐多2 小时前
LangChain4j 工厂模式
java·开发语言
小小龙学IT2 小时前
Day 28 项目调试与优化 —— 给聊天室做一次“全面体检“
c语言·开发语言
hy.z_7772 小时前
【C++】9. Vector
开发语言·c++
开开心心就好2 小时前
免费压缩软件WinRAR无弹窗、广告干扰
java·开发语言·前端·数据库·python·excel·winrar