Linux下C#读取其他进程内存结果异常的问题排查
嘿,我来帮你捋捋这个问题,你遇到的情况在Linux下用C#读其他进程内存时真的挺常见的,咱们一步步拆解排查:
先看几个核心问题点
1. 你代码里的Seek参数大概率有问题
你贴的代码里fs.Seek(address, ...)没写完,正确的写法应该是fs.Seek(address, SeekOrigin.Begin),要是这里填错了起始位置(比如写成了Current或者End),那你定位的内存地址完全是错的,读出来的自然是垃圾数据,这是最可能的直接原因。
2. 读取长度和数据解析要对应上
GDB里你用的是*(uint64_t*)0x1234ABCD,也就是读8字节的64位无符号整数,但你调用自己的ReadMemory时,有没有把length参数设成8?要是你传了别的数值(比如1或者4),那读出来的字节数组肯定没法解析成正确的指针值。另外,读出来的字节数组要转成ulong类型才能和GDB的结果对比——Linux是小端字节序,直接用BitConverter.ToUInt64(buffer, 0)转换就对了,别直接把字节数组当字符串拼,那肯定出乱子。
3. 权限是绕不开的坎
GDB能读对,大概率是你用了sudo或者GDB本身有ptrace权限,但你的C#程序要是没以足够权限运行(比如普通用户身份),读取/proc/{pid}/mem时会拿到无效数据或者零填充的内容。试试用sudo dotnet run启动你的程序,再看结果。
4. 先确认目标地址的有效性
你可以先去读/proc/{pid}/maps文件,找一找0x1234ABCD这个地址在不在进程的有效内存映射里,还要看对应的映射段是不是有r--p(可读)的权限。要是这个地址根本没被映射到物理内存,读出来的肯定是垃圾。
给你调整后的参考代码
我把你没写完的部分补全,还加了一些错误检查:
public static byte[] ReadMemory(int pid, long address, int length) { try { string memPath = $"/proc/{pid}/mem"; Console.WriteLine($"Reading memory from: {memPath}"); using (FileStream fs = new FileStream(memPath, FileMode.Open, FileAccess.Read)) { byte[] buffer = new byte[length]; // 必须用SeekOrigin.Begin定位到目标虚拟地址 fs.Seek(address, SeekOrigin.Begin); int actualRead = fs.Read(buffer, 0, length); // 检查实际读取的字节数,避免返回不完整的无效数据 if (actualRead != length) { Console.WriteLine($"Warning: Only read {actualRead} bytes (requested {length})"); Array.Resize(ref buffer, actualRead); } return buffer; } } catch (Exception ex) { Console.WriteLine($"Error reading memory: {ex.Message}"); return null; } }
调用的时候要注意传对参数,还要做正确的类型转换:
// 替换成你的目标进程PID和地址 int targetPid = 1234; long targetAddr = 0x1234ABCD; // 读8字节对应uint64_t byte[] memBytes = ReadMemory(targetPid, targetAddr, 8); if (memBytes != null && memBytes.Length == 8) { ulong pointerValue = BitConverter.ToUInt64(memBytes, 0); Console.WriteLine($"读取到的指针值: 0x{pointerValue:X8}"); }
最后再试几个排查步骤
- 先确认你的C#程序以root权限运行
- 核对
ReadMemory的length参数是8 - 检查
/proc/{pid}/maps确认目标地址的有效性
备注:内容来源于stack exchange,提问作者ThePrime




