首页
社区
课程
招聘
[原创]binmay 灵活掩码版,搜索替换工具
发表于: 3天前 171

[原创]binmay 灵活掩码版,搜索替换工具

3天前
171

版本:3 | 许可:GPLv2+ | 平台:Windows

Binmay 是一个轻量级命令行工具,用于在文件或流中搜索二进制字符串,并可选择性地替换为另一个字符串。通过灵活的掩码机制,支持精确到位(bit)的匹配与替换控制。适用于固件修改、二进制补丁、日志清理、注册表分析等场景。

近期,DeepSeek 编程能力增强了,我令其以 资深编程专家角色 经几十次深度优化源码,结果喜人。

原作者:Sean Loaring,Slore
原地址:d1dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6K6L8r3!0J5k6h3I4W2k6g2)9J5c8X3u0A6L8X3#2S2P5b7`.`.

新版本对源码 binmay.c 进行了近乎重写级别的深度优化,在保持原有设计思想的基础上,修复了大量隐性缺陷,大幅提升了健壮性、性能以及可维护性。以下是按维度划分的详尽分析。

优化版从底层修复了原代码的编译错误、内存泄漏、线程安全无关的全局状态污染、不安全文件操作等硬伤,并通过临时文件原子写、智能搜索加速、灵活掩码语法、跨平台二进制模式支持、完整错误恢复链等改进,将一个小巧但粗糙的工具提升到工业生产级质量

Binmay 由 Sean Loaring 原创,Slore 和 Hook 后续改进。
许可证:GNU GPL version 2 或更高版本。

原始代码 优化版本 改进意义
f_malloc 中错误地强制转换为 (struct input*)(未定义结构) 完全移除无意义的转换,使用统一的 xmalloc(void *p) 消除编译错误与未定义行为
未处理 Windows 文本模式可能导致 \n -> \r\n 转换 引入 set_binary_mode(),对 stdin/stdout/stderr 设置 O_BINARY 保证二进制数据在 Windows 下正确读写
自定义 getopt 存在状态机 bug,且返回 -1 非标准 保留自定义 getopt,但修复了错误返回逻辑(统一 return '?'),并增强错误信息 命令行解析更健壮,行为更符合预期
原始代码 优化版本
全局变量泛滥verbosematchespukebufplen 等大量使用全局,资源释放困难 所有配置集中到动态分配的 struct app_config,通过指针传递,main 末尾统一 free
内存泄漏buffered_handlefile_handlemasked_string 等通过 f_malloc 分配后从未释放 实现完备的 *_free 系列函数,main 采用 goto 清理链,无论成功或失败路径均会释放所有已分配资源
缓冲区固定 1024 字节,且 masked_string_setstr 中上游长度检查形同虚设(u: 格式会加倍) 缓冲区扩大至 IO_LEN = 128 * 1024(128KB),大幅减少 I/O 次数;长度检查前置至 process_string_default 内部,防止越界
原始代码 优化版本
多数函数内部直接 exit(1)abort(),无法由调用者优雅恢复,且资源泄露 所有函数返回错误码或 LEN_UNSET,错误层层上传,main 统一处理并跳转清理,确保文件、内存等资源被释放
fwrite 未处理短写(short write) 实现 fwrite_all,循环写入直到全部字节发送完毕,避免大数据量时写不完整
-u/-U 原地更新方式极不安全:直接 rename 原文件为 .org,然后打开原文件名写入。若程序中途崩溃,原文件已消失,数据不可恢复 采用临时文件 + 原子重命名模式:先用 mkstemp(POSIX)或 _mktemp_s(Windows)创建安全临时文件,所有输出写入临时文件,成功后才执行重命名。失败时保留临时文件并给出明确恢复提示。若已备份*.0rg则不覆盖,保留初始版本,零数据丢失风险
掩码长度不一致时仅警告并截断,可能产生非预期结果 严格校验掩码长度与字符串长度必须相等,否则报错退出
空搜索字符串或非法前缀无检查 增加 search->length == 0 检查,非法前缀返回错误
buffered_skip 中偏移量 coffset 可能溢出(原为 int coffset 改为 long long,并在跳过前检查溢出
原始代码 优化版本
masked_string_seek 对每个位置无差别调用 masked_string_match(O(n*m) 的朴素匹配) 引入快速跳跃过滤:在掩码设置后预先计算出前两个非通配字节的位置 first_nonwildsecond_nonwild,以及最后一个非通配字节(可选)。搜索时先检查这三个关键字节是否匹配,不匹配则立即跳过,只有通过快速筛选后才执行完整的逐字节掩码匹配。对于存在大量通配符的掩码(如仅固定首尾字节),性能提升一个数量级
缓冲区大小为 2KB,搜索时滑动窗口小,频繁 I/O 缓冲区提升至 256KB(IO_LEN * 2),单次读入更多数据,大幅减少系统调用和文件读取次数
原始代码 优化版本
掩码只能通过 -S/-R 指定十六进制字节序列(如 00ff),表达能力有限 新增三种掩码语法:
正常模式:保留原有十六进制对,同时支持 ??.. 作为通配符(对应掩码字节 0x00)
忽略列表 !:如 !0,2-4,表示仅忽略指定字节,其余字节必须完全匹配
匹配列表 =:如 =0,2-4,表示仅匹配指定字节,其余字节忽略
并且实现了索引列表的范围(-)和逗号分隔解析,极大提升了二进制补丁的便捷性
无全通配掩码检查,设置一个全为 0x00 的掩码会导致永远匹配但毫无意义 检测掩码是否全部为 0(全通配),并报错拒绝
原始代码 优化版本
DEBUG 宏混在代码中,大量无用原型声明(如 open_outfile)存在 彻底清除冗余代码
函数定义分散,混杂在大量注释括号 {{ }} 中,风格老旧 采用现代 C 风格,static 限制所有内部函数作用域,头文件仅包含必要项,清晰划分“数据结构-前向声明-实现”模块
main 中文件打开、参数解析、搜索、puke 的逻辑纠缠在一起 将参数解析抽离为 parse_args,原地更新逻辑独立处理,main 仅负责流程调度和清理
返回匹配数量使用全局变量 matches 改为 do_search_replace 返回 long long,同时支持 64 位大文件统计
hexdumpline 输出无分隔符,可读性差 格式化输出为空格分隔的十六进制对(printf("%s%02x", i?" ":"", byte)
2026-8-07 更新:优化了编程提示词,提高了代码质量和性能,消灭了一些潜在bug。增加 32bit.exe
2026-7-30 更新:性能、安全提升。防止全通配掩码替换死循环;64位匹配计数,适合处理GB级大文件。
2026-7-09 更新:新增灵活支持掩码 ?? .. 以及 忽略/匹配索引语法。
2026-6-30 发布:binmay2 修复原版所有bug,优化架构,增强性能。

---
MinGW 编译参数:
gcc -march=x86-64-v3 -std=c17 -O2 -pipe -flto -fstack-protector-strong -fstack-clash-protection -fcf-protection=full -fstrict-flex-arrays=3 -D_FORTIFY_SOURCE=3 -Wall -Wextra -Wpedantic -Wconversion -Wimplicit-fallthrough -Wformat=2 -Wtrampolines -Wl,--nxcompat,--dynamicbase,--high-entropy-va,--gc-sections -ffunction-sections -static -s %*

传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!

最后于 2天前 被真难取编辑 ,原因:
上传的附件:
收藏
免费 1
打赏
分享
最新回复 (1)
雪    币: 92
活跃值: (1872)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
注意:
常见 ?? 和 .. 属于Byte级,会忽略256种可能组合,并非高大上。索引列表的价值更大。
十六进制 0~F (16x16种组合) 才是精确匹配bit,须用二进制推导!掩码底层是二进制,0 表示忽略,1 表示匹配。
3天前
0
游客
登录 | 注册 方可回帖
返回