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

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

相关推荐
web守墓人1 小时前
【goed/ui】自定义组件设计思想篇
linux·windows·ui·golang
2601_966949652 小时前
只拿到股票代码还不够:量化程序到底还需要哪些标的信息?——从数据建模开始理解股票元数据
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
m0_734571762 小时前
深入理解5g <十八>传输块tbsize的计算
开发语言·5g
He BianGu4 小时前
【WPF-VisionMaster】机器视觉通用平台V5.0版本发行说明
opencv·c#·wpf·halcon·机器视觉·visionmaster
tang_04274 小时前
【Hi.Ltd 专题】第9期:Interop 配置互操作(JSON/INI/XML/YAML/注册表/扫码)
经验分享·c#·hi.ltd系列
RAN11426760084 小时前
1.3第一个程序的介绍
开发语言·qt
blue_ice .4 小时前
Verilog DDS 数字信号发生器:DAC 输出模拟波形与 ADC 回采观测
开发语言·单片机·嵌入式硬件·fpga开发
2601_962364974 小时前
红外活体模组,Windows 设备安全身份入口解析
windows·安全·电脑
远翔调光芯片^138287988725 小时前
ECP5702能芯科技PD取电芯片在市场上的优势有哪些?
开发语言·人工智能·单片机·嵌入式硬件·智能家居
易点云徐源5 小时前
(已解决)Photoshop 2020 点击“选择主体”闪退:不用重装,1 个配置切回旧算法解决
windows·photoshop