飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 955|回复: 6

[C/C++] 内存特征码暴力搜索算法支持 ?? F? ?F

  [复制链接]
  • TA的每日心情
    奋斗
    2024-10-21 16:09
  • 签到天数: 93 天

    [LV.6]常住居民II

    发表于 2024-11-17 15:23:19 | 显示全部楼层 |阅读模式

    核心算法来自:https://www.chinapyg.com/thread-155180-1-1.html
    SSE2需要硬件支持,但有极个别设备不支持,故做一个纯软运行……



    ①通过掩码的方式使其支持 前、中、后通配符 及半字节;

    ②通过循环找到特征码字节序列中的第一个不为'??'的元素后,后续的字节只比较不是'??'的特征字节,优化比较字节数。




    [C++] 纯文本查看 复制代码
    #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<ULONG_PTR> SearchMemory(ULONG_PTR startAddress, ULONG_PTR endAddress, const char*& patternStr, ULONG_PTR searchNum)
    {
    	std::vector<ULONG_PTR> resultList;
    	std::string pattern = patternStr;
    	int index = 0;
    	while ((index = pattern.find(' ', index)) >= 0) pattern.erase(index, 1); //去除特征码所有空格
    	ULONG_PTR len = pattern.length() / 2; //计算特征码长度
    	ULONG_PTR nFirstMatch = len;  // 跳过头部??,记录第一次匹配的位置半字符或非??,用于优化搜索
    	BYTE* pMarkCode = new BYTE[len];  // 存储转换后的特征码字节
    	BYTE* pWildcard = new BYTE[len];  // 存储特征字符串中??、?(??=FF、?=F、非?=0) 通配符
    
    	//处理特征码字符串,转换成字节数组
    	for (ULONG_PTR i = 0; i < len; i++)
    	{
    		std::string tmpStr = pattern.substr(i * 2, 2);
    		if ("??" == tmpStr) // 是"??"的特征字符
    		{
    			tmpStr = "FF";
    			pWildcard[i] = 0xFF;
    		}
    		else  // 不是"??"的特征字符
    		{
    			if ('?' == tmpStr[0]) // 左半字节为'?'
    			{
    				tmpStr[0] = 'F';
    				pWildcard[i] = (0xF << 4);
    			}
    			else if ('?' == tmpStr[1]) // 右半字节为'?'
    			{
    				tmpStr[1] = 'F';
    				pWildcard[i] = 0xF;
    			}
    			else
    			{
    				pWildcard[i] = 0x0;
    			}
    			if (nFirstMatch == len)	nFirstMatch = i;
    		}
    
    		pMarkCode[i] = strtoul(tmpStr.c_str(), nullptr, 16);
    	}
    
    	ULONG_PTR nMemSize = endAddress - startAddress; //计算内存大小
    	BYTE* pMemBuffer = new BYTE[nMemSize]; // 存放内存数据的缓冲区
    	//memcpy(pMemBuffer, (void*)startAddress, nMemSize);
    	//跨进程搜索内存,可使用ReadProcessMemory函数,目标进程用参数传入
    	ReadProcessMemory((HANDLE)-1, (void*)startAddress, pMemBuffer, nMemSize, 0);
    
    	//搜索内存,匹配特征码算法
    	for (ULONG_PTR m = 0; m < nMemSize; ++m)
    	{
    		if (!((pMemBuffer[m] | pWildcard[nFirstMatch]) ^ pMarkCode[nFirstMatch])) //匹配上第一个字节
    		{
    			ULONG_PTR offset = m - nFirstMatch; //记录偏移量
    			for (ULONG_PTR n = nFirstMatch; n < len; ++n) //匹配后续字节
    			{
    				if (offset > nMemSize - len) break; //超出内存范围
    				if (pWildcard[n] != 0xFF)  //后续字节是"??"的通配符,跳过,这句代码可以优化搜索
    					if ((pMemBuffer[offset + n] | pWildcard[n]) ^ pMarkCode[n]) break; //匹配失败
    				if (n + 1 == len) //匹配成功
    				{
    					if ((ULONG_PTR)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));
    	ULONG_PTR startAddress = (ULONG_PTR)moduleInfo.lpBaseOfDll; //模块起始地址
    	ULONG_PTR endAddress = startAddress + moduleInfo.SizeOfImage; //模块结束地址
    
    	clock_t nBeginTime = clock();
    	// 调用内存搜索算法
    	std::vector<ULONG_PTR> resultList = SearchMemory(startAddress, endAddress, pattern, 0);
    	printf("共搜到:%d个地址-->搜索时间:%d ms\n", resultList.size(), clock() - nBeginTime);
    
    	for (ULONG_PTR i = 0; i < resultList.size(); ++i)
    	{
    		printf("第%d个:%IX\n", i + 1, resultList[i]);
    	}
    	system("pause");
    	return 0;
    }

    评分

    参与人数 3威望 +3 飘云币 +3 收起 理由
    wgz001 + 1 + 1 感谢发布原创作品,PYG有你更精彩!
    wangwei628 + 1 + 1 PYG有你更精彩!
    飞天 + 1 + 1 PYG有你更精彩!

    查看全部评分

    本帖被以下淘专辑推荐:

    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2022-10-31 16:13
  • 签到天数: 103 天

    [LV.6]常住居民II

    发表于 2024-11-17 19:01:07 | 显示全部楼层
    感谢分享                     
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 01:28
  • 签到天数: 2060 天

    [LV.Master]伴坛终老

    发表于 2024-11-19 13:50:01 | 显示全部楼层
    可惜小白不知道如何使用

    点评

    很简单这代码最终不是写给人类的,而是编译器的。 它认它过,就能编译过。 赵本山小品里说的啥? 张嘴,往里送就行了。 所以你得有口锅(编译器),生成(就能测试)吃了。  详情 回复 发表于 2024-11-21 17:06
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2024-12-4 16:27
  • 签到天数: 644 天

    [LV.9]以坛为家II

    发表于 2024-11-21 16:53:53 | 显示全部楼层
    @wtujoxk
    看了楼主发了贴,有一个类似的问题请教下:
    https://www.52pojie.cn/thread-1981863-1-1.html

    为什么32位的程序搜索前6个字节
       
        bSignature[0]:= $74;
        bSignature[1]:= $0E;
        bSignature[2]:= $8B;
        bSignature[3]:= $D3;
        bSignature[4]:= $8B;
        bSignature[5]:= $83;

    能定位过去。
    要是全搜索却定位不过去。。。
    于是问题来了,32位的编译过去了。。。那64位的特征码要咋找咋修改程序才能搜索到?
    执行程序后“说这不是一个Delphi程序”,明显特征码没有匹配到啊。
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2024-12-4 16:27
  • 签到天数: 644 天

    [LV.9]以坛为家II

    发表于 2024-11-21 17:06:37 | 显示全部楼层
    Master.lu 发表于 2024-11-19 13:50
    可惜小白不知道如何使用

    很简单这代码最终不是写给人类的,而是编译器的。

    它认它过,就能编译过。
    赵本山小品里说的啥? 张嘴,往里送就行了。
    所以你得有口锅(编译器),生成(就能测试)吃了。
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2024-12-4 16:27
  • 签到天数: 644 天

    [LV.9]以坛为家II

    发表于 2024-11-21 17:09:38 | 显示全部楼层
    F9是不是搜索call指令?
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2024-12-14 13:07
  • 签到天数: 118 天

    [LV.6]常住居民II

    发表于 2024-11-24 12:03:51 | 显示全部楼层
    感谢分享  

    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表