小子不忘记 发表于 2023-11-16 12:30:55

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


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

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;//定义一个字节变量并开辟指定长度的内存空间
                int 通配符首次位置 = StringToByte(tzm, tzmByte);

                MODULEINFO mMoudleInfo;
                GetModuleInformation(hProcess, hModule, &mMoudleInfo, sizeof(mMoudleInfo));
                DWORDModuleBeginAddr = (DWORD)hModule;//模块开始地址
                DWORDModuleSize =mMoudleInfo.SizeOfImage;//模块大小
                DWORDModuleEndAddr = 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;
                                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, 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, 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;
                for (int i = 0; i < markCodeLen; i++)
                {
                        string tempStr = markCode.substr(i * 2, 2);
                        if (tempStr == "??")
                        {
                                pMarkCode = 0x3F;
                                if (通配符第1次出现的位置 == 0) 通配符第1次出现的位置 = i;
                        }
                        else {
                                pMarkCode = 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 = { 0 };//Sunday算法模板数组赋值,+1防止特征码出现FF时越界
                for (int i = 0; i < 通配符第1次出现的位置; i++) {
                        Shift] = i + 1;
                }

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

页: [1]
查看完整版本: Sunday算法特征码搜索C++ 支持通配符