如何用C#程序查找并替换编译EXE中的指定十六进制值
在C#中实现十六进制值的查找与替换(针对多文件修补场景)
我明白你现在的痛点——要批量处理8个文件的十六进制修补,相同的待替换十六进制值但每个文件里的偏移量不一样,却卡在了关键的查找环节。咱们一步步来搞定这个问题,核心思路是把十六进制字符串转换成字节数组,然后在文件的字节流里精准定位这些字节的位置,最后完成替换。
关键步骤拆解
- 十六进制转字节数组:因为文件本质是字节流,咱们需要把要查找/替换的十六进制字符串转换成对应的字节数组,才能和文件内容匹配。
- 实现字节数组查找方法:.NET没有直接提供查找字节数组所有出现位置的API,所以咱们得自己写一个方法,能找出目标字节数组在源字节数组里的所有偏移量。
- 批量处理文件:循环遍历你的8个文件,依次完成读文件→查找→替换→写回的操作。
完整代码示例
using System; using System.Collections.Generic; using System.IO; using System.Linq; class HexPatcher { static void Main(string[] args) { // 配置参数:要查找的十六进制值、要替换成的十六进制值、目标文件列表 string searchHex = "A1B2C3D4"; // 替换成你实际要找的十六进制字符串 string replaceHex = "E5F67890"; // 替换成你实际要替换的十六进制字符串 string[] targetFiles = new[] { "file1.exe", "file2.dll", "file3.bin", /* 剩下的5个文件路径 */ }; // 转成字节数组 byte[] searchBytes = HexStringToByteArray(searchHex); byte[] replaceBytes = HexStringToByteArray(replaceHex); // 批量处理每个文件 foreach (string filePath in targetFiles) { if (!File.Exists(filePath)) { Console.WriteLine($"警告:文件 {filePath} 不存在,跳过"); continue; } try { // 读取文件所有字节 byte[] fileBytes = File.ReadAllBytes(filePath); // 查找所有匹配的偏移量 List<int> matchOffsets = FindAllOccurrences(fileBytes, searchBytes); if (matchOffsets.Count == 0) { Console.WriteLine($"文件 {filePath} 中未找到目标十六进制值,跳过"); continue; } // 执行替换(如果有多个匹配,这里会替换所有;如果只需要替换特定偏移,可筛选matchOffsets) foreach (int offset in matchOffsets) { Array.Copy(replaceBytes, 0, fileBytes, offset, replaceBytes.Length); } // 写回文件(建议先备份原文件!) File.WriteAllBytes(filePath, fileBytes); Console.WriteLine($"文件 {filePath} 修补完成,共替换 {matchOffsets.Count} 处"); } catch (Exception ex) { Console.WriteLine($"处理文件 {filePath} 时出错:{ex.Message}"); } } Console.WriteLine("批量修补操作完成"); } // 十六进制字符串转字节数组的工具方法 private static byte[] HexStringToByteArray(string hex) { // 去掉可能的空格 hex = hex.Replace(" ", ""); if (hex.Length % 2 != 0) { throw new ArgumentException("十六进制字符串长度必须是偶数"); } return Enumerable.Range(0, hex.Length) .Where(x => x % 2 == 0) .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) .ToArray(); } // 在源字节数组中查找目标字节数组的所有出现位置 private static List<int> FindAllOccurrences(byte[] source, byte[] target) { List<int> offsets = new List<int>(); if (target.Length == 0 || source.Length < target.Length) { return offsets; } for (int i = 0; i <= source.Length - target.Length; i++) { bool match = true; for (int j = 0; j < target.Length; j++) { if (source[i + j] != target[j]) { match = false; break; } } if (match) { offsets.Add(i); // 如果不需要查找重叠匹配,可以在这里加上 i += target.Length - 1; } } return offsets; } }
注意事项
- 备份原文件:在执行替换前,一定要先备份你的目标文件,避免操作失误导致文件损坏。
- 重叠匹配处理:如果你的目标十六进制值存在重叠匹配的可能(比如查找"AAAA",源数组里有"AAAAAA"),可以根据需求修改
FindAllOccurrences方法里的循环逻辑(注释里的代码)。 - 权限问题:如果修补的是系统文件或受保护的应用程序,可能需要以管理员权限运行你的C#程序。
- 编码与字节序:确保你要查找的十六进制值的字节序和文件里的实际字节序一致(比如大端/小端),如果不一致需要调整转换逻辑。
内容的提问来源于stack exchange,提问作者Kontorted
相关产品推荐
相关产品推荐

