std::search最适合内存中特征字节序列查找,因其专为子序列匹配设计;需避免std::string存储二进制数据,优先用std::vector或内存映射,并返回文件偏移而非裸指针。
用
在内存块中找特征字节序列
直接用标准库比手写二分搜索更合适——因为你要找的是「连续字节模式」,不是已排序数组里的单个值。二分搜索(
等)只适用于有序比较,而特征码匹配是子序列查找,属于暴力/Boyer-Moore 类问题。
实操建议:
立即学习
“
C++免费学习笔记(深入)
”;
是最轻量、无依赖的方案,接受两个迭代器范围:主数据(如
)和待查模式(如
)
确保传入的模式不为空,否则
行为未定义;加一句
如果数据来自文件映射或
,可直接用裸指针构造迭代器:
注意:
是朴素 O(n×m) 算法,对几 MB 内存+几十字节模式完全够用;若模式常驻且长度 ≥ 8,可考虑
(C++17),但需额外存储 searcher 对象
处理带通配符的特征码(如
)
标准算法不支持通配。必须自己遍历比对,核心是跳过
或
标记位。
实操建议:
立即学习
“
C++免费学习笔记(深入)
”;
把模式存成
,其中
表示通配;或用
,
表示忽略该字节
比对循环里用
判断每一位
别用字符串解析
在运行时——这应是构建工具阶段做的事;写个简单脚本(Python/Perl)预处理文本特征码为 C++ 字面量数组,避免运行时 hex 解析开销
通配会显著降低缓存友好性,尽量控制通配位置(比如只允许尾部 1–2 字节通配),避免全模式都带
从文件读取二进制并搜索,避开
的 null 截断陷阱
用
存原始字节是危险的:它把
当结束符,
和
都可能出错;尤其特征码常含
。
C知道
CSDN推出的一款AI技术问答工具
下载
实操建议:
立即学习
“
C++免费学习笔记(深入)
”;
一律用
装载文件内容:
打开文件必须用
,否则 Windows 下
会被悄悄转成
,破坏字节一致性
大文件(>100MB)别全读进内存;改用
(Linux/macOS)或
(Windows),然后对映射区域调用
如果只能流式处理(如网络响应体),则用滑动窗口 + KMP 备份失败函数,但多数逆向定位场景是离线文件,全映射更简单可靠
跨平台地址计算与偏移输出:别直接返回指针
搜索结果是内存地址(
),但用户真正需要的是“在文件中的第几个字节”,即基于文件起始的偏移量。
实操建议:
立即学习
“
C++免费学习笔记(深入)
”;
不要返回裸指针,而是返回
偏移(
),这样可序列化、可日志、可做算术
如果用了内存映射,记得映射起始地址 ≠ 文件起始地址(有对齐填充),要用
换算成真实文件偏移
输出时用
,
适配
宽度,比硬写
或
更安全
多个命中?用
收集,别只返回第一个——特征码重复很常见(比如编译器生成的多个相同 prologue)
真正麻烦的从来不是“找到”,而是“确认这个匹配是否语义正确”:同一段字节在不同编译器/优化等级下可能对应不同逻辑。所以偏移只是起点,后面还得结合反汇编上下文人工验证。
std::searchstd::lower_boundstd::searchstd::vector::iterator std::arraystd::searchif (pattern.empty()) return end(data);const uint8_t*std::search(ptr, ptr + size, pat_begin, pat_end)std::searchstd::boyer_moore_searcher0x90 0x?? 0x31 0xc00xff0x??std::vector> std::nulloptstd::pairsecond == falseif (!pattern[i].has_value() || data[off + i] == pattern[i].value())"90 ?? 31 c0"??std::stringstd::string\x00.data().size()0x00std::vectorfile.read(reinterpret_cast(buf.data()), buf.size()); std::ios::binary\r\n\nmmapCreateFileMappingstd::searchuint8_t*size_tresult_ptr - data_ptrmmap_addr + offset_in_mappingprintf("found at offset 0x%zx\n", offset);%zxsize_t%llu%xstd::vector