基于PID通过内核驱动查找进程内存并修改C#进程内变量值的实现方案
基于PID自动定位C#程序内变量内存并内核态改写的实现方案
整体链路完全替代原参考实现中手动输入变量地址的逻辑,核心流程为:通过PID锚定目标进程内核对象→自动遍历进程虚拟内存匹配变量特征→内核态直接完成值替换,全程不需要手动录入硬编码的内存地址。
第一步:通过PID完成目标进程的内核态定位
和参考实现的基础逻辑一致,拿到传入的目标PID后,通过内核API PsLookupProcessByProcessId 拿到对应进程的EPROCESS内核结构体,完成进程身份锚定。这一步的注意点:拿到结构体后必须在操作完成后调用ObDereferenceObject释放引用计数,避免造成内核内存泄漏。
第二步:自动遍历进程内存,替代手动录入地址的环节
这部分是解决“不需要手动输变量地址”的核心改造点,把原示例中由用户层提前算好地址传入驱动的逻辑,改成驱动侧自动扫描匹配:
- 先把当前线程附加到目标进程的地址空间,调用
KeStackAttachProcess完成上下文切换,确保后续内存操作都是针对目标进程的虚拟地址空间,操作完成后再调用KeUnstackDetachProcess切回原上下文。 - 逐块枚举目标进程的所有内存页,通过
MmQueryVirtualMemory获取每块内存的属性,仅处理“提交状态、可读写、非共享映射”的内存块,跳过只读代码段、系统保留页,大幅缩小无效扫描范围。 - 依托你对C#程序的控制权设计扫描匹配规则,完全不需要人工定位地址:
- 提前将x、y定义为静态值类型变量,这类变量会被分配在加载器堆的静态存储区,GC永远不会移动其位置,地址稳定可靠。
- 利用你明确知道x、y初始固定值的优势,设计匹配特征:比如x初始存固定值100(int类型对应4字节序列
0x64 0x00 0x00 0x00),y初始存固定值200(对应4字节序列0xC8 0x00 0x00 0x00);为了避免同值误匹配,可以在变量定义时给每个变量前加固定的4字节标记值,比如x前面加0x12345678,匹配8字节的标记+值序列,准确率接近100%。 - 扫描过程中匹配到符合特征的内存位置,就直接记录为x、y对应的真实内存地址,完全不需要像原来那样用调试器断下程序手动找地址。
第三步:内核态完成自定义值替换
拿到自动匹配到的变量内存地址后,直接复用内核读写API完成值替换:
- 调用
MmCopyVirtualMemory,以当前内核权限,向记录的x、y地址位置写入自定义的目标值。 - 写入完成后释放之前的进程引用,恢复线程上下文,整个流程闭环。
实现注意事项
- 扫描内存读取内容时,一定要用结构化异常(SEH)包裹读取逻辑,避免遇到保护页、guard page时触发内核蓝屏。
- 逐块扫描时穿插短延时(比如每次处理完1个内存块调用
KeDelayExecutionThread停1ms),避免扫描占满CPU导致系统卡顿。 - 如果x、y是托管堆上的实例字段,需要先固定GC句柄再写入,否则GC整理内存时会移动对象位置,导致之前定位的地址失效。
内容的提问来源于stack exchange,提问作者Prabesh Upreti
相关产品推荐
相关产品推荐

