内存特征码暴力搜索算法支持 ?? F? ?F
本帖最后由 wtujoxk 于 2026-7-24 10:30 编辑核心算法来自:https://www.chinapyg.com/thread-155180-1-1.html
SSE2需要硬件支持,但有极个别设备不支持,故做一个纯软运行……
①通过掩码的方式使其支持 前、中、后通配符 及半字节;
②通过循环找到特征码字节序列中的第一个不为'??'的元素后,后续的字节只比较不是'??'的特征字节,优化比较字节数。
#include <iostream>
#include <windows.h>
#include <vector>
#include <Psapi.h>
/// <summary>
/// 内存搜索算法
/// </summary>
/// <param name="startAddress">起始地址</param>
/// <param name="endAddress">结束地址</param>
/// <param name="patternStr">特征码字符串</param>
/// <param name="searchNum">搜索个数,0不限制</param>
/// <returns>搜索到的地地集合</returns>
std::vector<size_t> SearchMemory(size_t startAddress, size_t endAddress, const char*& patternStr, size_t searchNum)
{
std::vector<size_t> resultList = {};
std::string pattern = patternStr;
int index = 0;
while ((index = pattern.find(' ', index)) >= 0) pattern.erase(index, 1); //去除特征码所有空格
size_t len = pattern.length() / 2; //计算特征码长度
size_t nFirstMatch = len;// 跳过头部??,记录第一次匹配的位置半字符或非??,用于优化搜索
BYTE* pMarkCode = new BYTE;// 存储转换后的特征码字节
BYTE* pWildcard = new BYTE;// 存储特征字符串中??、?(??=FF、?=F、非?=0) 通配符
//处理特征码字符串,转换成字节数组
for (size_t i = 0; i < len; i++)
{
std::string tmpStr = pattern.substr(i * 2, 2);
if ("??" == tmpStr) // 是"??"的特征字符
{
tmpStr = "FF";
pWildcard = 0xFF;
}
else// 不是"??"的特征字符
{
if ('?' == tmpStr) // 左半字节为'?'
{
tmpStr = 'F';
pWildcard = (0xF << 4);
}
else if ('?' == tmpStr) // 右半字节为'?'
{
tmpStr = 'F';
pWildcard = 0xF;
}
else
{
pWildcard = 0x0;
}
if (nFirstMatch == len) nFirstMatch = i;
}
pMarkCode = strtoul(tmpStr.c_str(), nullptr, 16);
}
size_t nMemSize = endAddress - startAddress; //计算内存大小
BYTE* pMemBuffer = new BYTE; // 存放内存数据的缓冲区
//memcpy(pMemBuffer, (void*)startAddress, nMemSize);
//跨进程搜索内存,可使用ReadProcessMemory函数,目标进程用参数传入
ReadProcessMemory((HANDLE)-1, (void*)startAddress, pMemBuffer, nMemSize, 0);
//搜索内存,匹配特征码算法
for (size_t m = 0; m <= nMemSize - len; ++m)
{
if ((pMemBuffer | pWildcard) == pMarkCode) //匹配上第一个字节
{
size_t offset = m - nFirstMatch; //记录偏移量
for (size_t n = nFirstMatch; n < len; ++n) //匹配后续字节
{
//后续字节是"??"的通配符,跳过,这句代码可以优化搜索
//后续字节匹配失败退出这次匹配,后续字节匹配成功,继续匹配下一个字节
if ((pWildcard != 0xFF) && ((pMemBuffer | pWildcard) != pMarkCode)) break;
if (n + 1 == len) //匹配成功
{
if ((size_t)pMarkCode != startAddress + offset) // 排除自己
resultList.push_back(startAddress + offset);
if (resultList.size() >= searchNum && searchNum != 0) goto endSearchMemory; //限制搜索数量
}
}
}
}
endSearchMemory:
delete[] pMarkCode; pMarkCode = nullptr;
delete[] pWildcard; pWildcard = nullptr;
delete[] pMemBuffer; pMemBuffer = nullptr;
return resultList;
}
int main()
{
//特征码为:?9 ?? 0? ?? 67
//会处理成:F9 FF 0F FF 67 进行匹配
//通配符为:F0 FF 0F FF 00
const char* pattern = "?9 ?? 0? ?? 67";
// 获取进程模块内存信息
MODULEINFO moduleInfo = { };
GetModuleInformation((HANDLE)-1, GetModuleHandle(L"ntdll.dll"), &moduleInfo, sizeof(moduleInfo));
size_t startAddress = (size_t)moduleInfo.lpBaseOfDll; //模块起始地址
size_t endAddress = startAddress + moduleInfo.SizeOfImage; //模块结束地址
clock_t nBeginTime = clock();
// 调用内存搜索算法
std::vector<size_t> resultList = SearchMemory(startAddress, endAddress, pattern, 0);
printf("共搜到:%d个地址-->搜索时间:%d ms\n", resultList.size(), clock() - nBeginTime);
for (size_t i = 0; i < resultList.size(); ++i)
{
printf("第%d个:%IX\n", i + 1, resultList);
}
system("pause");
return 0;
} 感谢分享 可惜小白不知道如何使用 @wtujoxk
看了楼主发了贴,有一个类似的问题请教下:
https://www.52pojie.cn/thread-1981863-1-1.html
为什么32位的程序搜索前6个字节
bSignature:= $74;
bSignature:= $0E;
bSignature:= $8B;
bSignature:= $D3;
bSignature:= $8B;
bSignature:= $83;
能定位过去。
要是全搜索却定位不过去。。。
于是问题来了,32位的编译过去了。。。那64位的特征码要咋找咋修改程序才能搜索到?
执行程序后“说这不是一个Delphi程序”,明显特征码没有匹配到啊。
Master.lu 发表于 2024-11-19 13:50
可惜小白不知道如何使用
很简单这代码最终不是写给人类的,而是编译器的。
它认它过,就能编译过。
赵本山小品里说的啥? 张嘴,往里送就行了。
所以你得有口锅(编译器),生成(就能测试)吃了。{:lol:}
F9是不是搜索call指令?
感谢分享
页:
[1]