Sunday算法特征码搜索C++(支持通配符)

感谢论坛sunday算法和特征码搜索的参考,在原来基础上增加功能进行了少许的修改。

主要参考了以下2位大神的代码:

 C++ sunday算法,极速定位指定进程内存特征码!_独爱秋季的博客-CSDN博客

Sunday算法实现内存快速搜索特征码(支持带问号)_吾无法无天的博客-CSDN博客



 DWORD aobScan(HANDLE hProcess, HMODULE hModule, string 特征码,int CallOffset=0,DWORD* outCallAddre=0,int BaseAddreOffset=0, DWORD* outBaseAddr=0)
	{//进程PID,模块句柄,特征码,CallOffset:找call偏移-上负下正,BaseAddreOffset:找基址偏移;偏移是从特征码地址算起
		string tzm = DeletStringPace(特征码);//删除特征码所有空格
		int tzmLen = tzm.length() / 2;//特征码长度
		if (tzm.length() % 2 != 0)/*特征码长度不能为单数*/ return 0;
		byte* tzmByte = new byte[tzmLen];//定义一个字节变量并开辟指定长度的内存空间
		int 通配符首次位置 = StringToByte(tzm, tzmByte);

		MODULEINFO mMoudleInfo;
		GetModuleInformation(hProcess, hModule, &mMoudleInfo, sizeof(mMoudleInfo));
		DWORD  ModuleBeginAddr = (DWORD)hModule;//模块开始地址
		DWORD  ModuleSize =mMoudleInfo.SizeOfImage;//模块大小
		DWORD  ModuleEndAddr = ModuleBeginAddr + ModuleSize;//模块结束地址

		BYTE *pMemBuffer = NULL;//存放读取的内存数据的缓冲区		
		MEMORY_BASIC_INFORMATION mbi;//内存信息
		clock_t nBeginTime = clock();//记录起始搜索时间

		while (ModuleBeginAddr < ModuleEndAddr)//结束条件
		{//开始扫描内存
			memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION));//查询地址空间中内存地址的信息
			if (VirtualQueryEx(hProcess, (LPCVOID)ModuleBeginAddr, &mbi, sizeof(mbi)) == 0)break;;
			
			if (MEM_COMMIT == mbi.State && PAGE_READWRITE == mbi.Protect || PAGE_EXECUTE_READWRITE == mbi.Protect)
			{//过滤内存空间, 根据内存的状态和保护属性进行过滤
				if (pMemBuffer) {// 申请动态内存
					delete[] pMemBuffer; pMemBuffer = NULL;
				}
				pMemBuffer = new BYTE[mbi.RegionSize];
				if (!ReadProcessMemory(hProcess, (LPCVOID)ModuleBeginAddr, pMemBuffer, mbi.RegionSize, 0))continue;
				UINT deviation = SundayCmp(pMemBuffer, mbi.RegionSize, tzmByte, tzmLen, 通配符首次位置);
				if (-1 != deviation)//deviation是偏移
				{//-1为没有找到 
					clock_t nEndTime = clock();//记录结束时间
					printf(" %x  用时:%d 毫秒\r\n", ModuleBeginAddr + deviation, nEndTime - nBeginTime);
					if (0!=CallOffset)
					{//如果是找call
						DWORD temp; 
						memcpy(&temp, &pMemBuffer[deviation  + CallOffset + 1], 4);//拷贝出对应地址上的机器码,复制4个字节
						printf(" 返回call: %X  用时:%d 毫秒\r\n", ModuleBeginAddr + deviation+ CallOffset + temp +5, nEndTime - nBeginTime);
						*outCallAddre= ModuleBeginAddr + deviation + CallOffset + temp +5;//下一条指令地址(也就是目标地址 + 5)
					}
					if (0!=BaseAddreOffset)
					{//如果是找基址
						DWORD temp;
						memcpy(outBaseAddr, &pMemBuffer[deviation + BaseAddreOffset], 4);//拷贝出对应地址上的机器码,复制4个字节
						printf(" 返回基址: %X \r\n", outBaseAddr);//
					}
					return ModuleBeginAddr + deviation;//返回特征码地址
				}
			}
			ModuleBeginAddr += mbi.RegionSize; //取下一块内存地址
		}
		return -1;//没找到返回
	}


 int StringToByte(string &markCode,byte* pMarkCode)
	{//带通配符的string字符串转byte字节数组
		int markCodeLen = markCode.length() / 2;
		int 通配符第1次出现的位置 = 0;
		//pMarkCode = new BYTE[markCodeLen];
		for (int i = 0; i < markCodeLen; i++)
		{
			string tempStr = markCode.substr(i * 2, 2);
			if (tempStr == "??")
			{
				pMarkCode[i] = 0x3F;
				if (通配符第1次出现的位置 == 0) 通配符第1次出现的位置 = i;
			}
			else {
				pMarkCode[i] = strtoul(tempStr.c_str(), 0, 16);
			}
		}
		return 通配符第1次出现的位置;
	}



 int SundayCmp(byte* dest, int destLen, byte* pattern, int patternLen, int 通配符第1次出现的位置)
	{
		int nOffset = 0;//偏移量
		int i = 0, j = 0, nCount = 0;//数组下标:内存、特征码、返回地址

		int Shift[0xFF + 1] = { 0 };//Sunday算法模板数组赋值,+1防止特征码出现FF时越界
		for (int i = 0; i < 通配符第1次出现的位置; i++) {
			Shift[pattern[i]] = i + 1;
		}

		while (j < patternLen)
		{//以特征码长度进行循环
			if (dest[i] == pattern[j] || pattern[j] == 0x3F)//0x3F代表通配符
			{//如果相等
				i++; j++;
			}
			else
			{
				nOffset = i - j + 通配符第1次出现的位置;
				if (nOffset > destLen - patternLen)/*判断偏移量是否大于缓冲区*/ break;
				if (Shift[dest[nOffset]])
				{//判断 Shift模板数组 里有没有 内存偏移后的值,有则回溯,否则+1
					i = nOffset - Shift[dest[nOffset]] + 1;
					j = 0;
				}
				else
				{
					i = nOffset + 1;
					j = 0;
				}
			}
		}
		if (j == patternLen)
		{//计算找到的目标地址://特征码地址 = 当前内存块基址 + i偏移 - 特征码长度
			return  i - patternLen;
		}
		return -1;
	}

实例:Sunday算法特征码搜索极速定位基址和call地址C++(支持通配符)-C/C++文档类资源-CSDN文库

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值