看流星社区

 找回密码
 注册账号
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
赞助广告位 请点击这里联系站长 QQ20209081
赞助广告位 请点击这里联系站长 QQ20209081
赞助广告位 请点击这里联系站长 QQ20209081
查看: 635|回复: 6

[C/C++源码] C++ sunday算法 极速定位指定进程内存特征码!

[复制链接]

该用户从未签到

发表于 2020-2-11 21:38:35 | 显示全部楼层 |阅读模式
C++ sunday算法 极速定位指定进程内存特征码!


  1. #include <windows.h>
  2. #include <time.h>
  3. #include <iostream>
  4. using namespace std;

  5. /*
  6. findMatchingCode() 参数说明:
  7. 1) hProcess                要打开的进程句柄
  8. 2) markCode                特征码,支持通配符(??),如: 55 8b ec ?? 56 83 ec 20 ?? ?? 08 d9 ee
  9. 3) memBeginAddr                起始搜索地址
  10. 4) memEndAddr                结束搜索地址
  11. 5) retAddr[]                记录找到的地址,传入这个参数前一定要清0,如 DWORD retAddr[32] = {0};  或者 DWORD *retAddr = new DWORD[32]();
  12. 6) deviation                特征码地址离目标地址的偏移距离,上负下正
  13. 7) isCall                是否为找CALL的跳转地址,true 则 retAddr[] 返回的是CALL跳转的地址
  14. 8) isAll                是否查找所有符合的地址,false找到第一个符合的地址后就结束搜索,true继续搜索,直到搜索地址大于结束地址(memEndAddr)
  15. return返回值                找到的地址总数
  16. */
  17. DWORD findMatchingCode(HANDLE hProcess, string markCode, DWORD memBeginAddr, DWORD memEndAddr, DWORD retAddr[], int deviation, bool isCall, bool isAll = false);




  18. DWORD findMatchingCode(HANDLE hProcess, string markCode, DWORD memBeginAddr, DWORD memEndAddr, DWORD retAddr[], int deviation, bool isCall, bool isAll)
  19. {
  20.         //----------------------处理特征码----------------------//
  21.         //去除所有空格
  22.         if (!markCode.empty())
  23.         {
  24.                 int index = 0;
  25.                 while ((index = markCode.find(' ', index)) >= 0)
  26.                 {
  27.                         markCode.erase(index, 1);
  28.                 }
  29.                 index = 0;
  30.                 while (true)
  31.                 {
  32.                         //删掉头部通配符
  33.                         index = markCode.find("??", index);
  34.                         if (index == 0) {
  35.                                 markCode.erase(index, 2);
  36.                         }
  37.                         else {
  38.                                 break;
  39.                         }       
  40.                 }
  41.         }

  42.         //特征码长度不能为单数
  43.         if (markCode.length() % 2 != 0) return 0;

  44.         //特征码长度
  45.         int len = markCode.length() / 2;

  46.         //Sunday算法模板数组的长度
  47.         int nSundayLen = len;

  48.         //将特征码转换成byte型
  49.         BYTE *pMarkCode = new BYTE[len];
  50.         for (int i = 0; i < len; i++)
  51.         {
  52.                 string tempStr = markCode.substr(i*2, 2);
  53.                 if (tempStr == "??") {
  54.                         pMarkCode[i] = 0x3F;
  55.                         if (nSundayLen == len) nSundayLen = i;
  56.                 }                 
  57.                 else{
  58.                         pMarkCode[i] = strtoul(tempStr.c_str(), 0, 16);
  59.                 }       
  60.         }
  61.         //--------------------------end-------------------------//

  62.         //Sunday算法模板数组赋值,+1防止特征码出现FF时越界
  63.         int aSunday[0xFF + 1] = { 0 };
  64.         for (int i = 0; i < nSundayLen; i++){
  65.                 aSunday[pMarkCode[i]] = i + 1;
  66.         }

  67.         //起始地址
  68.         const DWORD dwBeginAddr = memBeginAddr;
  69.         //结束地址
  70.         const DWORD dwEndAddr = memEndAddr;
  71.         //当前读取的内存块地址
  72.         DWORD dwCurAddr = dwBeginAddr;
  73.         //存放内存数据的缓冲区
  74.         BYTE *pMemBuffer = NULL;
  75.         //计算参数retAddr[]数组的长度,该参数传入前一定要清0
  76.         int nArrayLength = 0;
  77.         for (int i = 0; ; i++) {
  78.                 if (*(retAddr + i) != 0) {
  79.                         nArrayLength = i;
  80.                         break;
  81.                 }
  82.         }
  83.         //偏移量
  84.         int nOffset;
  85.         //数组下标:内存、特征码、返回地址
  86.         int i = 0, j = 0, nCount = 0;

  87.         //内存信息
  88.         MEMORY_BASIC_INFORMATION mbi;

  89.         //记录起始搜索时间
  90.         clock_t nBeginTime = clock();

  91.         //扫描内存
  92.         while (dwCurAddr < dwEndAddr)
  93.         {
  94.                 //查询地址空间中内存地址的信息
  95.                 memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION));
  96.                 if (::VirtualQueryEx(hProcess, (LPCVOID)dwCurAddr, &mbi, sizeof(mbi)) == 0) {
  97.                         goto end;
  98.                 }

  99.                 //过滤内存空间, 根据内存的状态和保护属性进行过滤
  100.                 //一般扫描(读写及执行)即可,速度极快,扫不到的话在尝试添加(读写)这一属性
  101.                 if (MEM_COMMIT == mbi.State &&                        //已分配的物理内存
  102.                         //MEM_PRIVATE == mbi.Type ||                //私有内存,不被其他进程共享
  103.                         //MEM_IMAGE == mbi.Type &&
  104.                         //PAGE_READONLY == mbi.Protect ||        //只读
  105.                         //PAGE_EXECUTE_READ == mbi.Protect ||        //读及执行
  106.                         //PAGE_READWRITE == mbi.Protect ||        //读写
  107.                         PAGE_EXECUTE_READWRITE == mbi.Protect)        //读写及执行
  108.                 {
  109.                         //申请动态内存
  110.                         if (pMemBuffer) {
  111.                                 delete[] pMemBuffer;
  112.                                 pMemBuffer = NULL;
  113.                         }
  114.                         pMemBuffer = new BYTE[mbi.RegionSize];
  115.                         //读取进程内存
  116.                         ReadProcessMemory(hProcess, (LPCVOID)dwCurAddr, pMemBuffer, mbi.RegionSize, 0);
  117.                         i = 0;
  118.                         j = 0;
  119.                         while (j < len)
  120.                         {
  121.                         nextAddr:
  122.                                 if (pMemBuffer[i] == pMarkCode[j] || pMarkCode[j] == 0x3F)
  123.                                 {
  124.                                         i++;
  125.                                         j++;
  126.                                 }
  127.                                 else
  128.                                 {
  129.                                         nOffset = i - j + nSundayLen;
  130.                                         //判断偏移量是否大于缓冲区
  131.                                         if (nOffset > mbi.RegionSize - len) break;
  132.                                         //判断 aSunday模板数组 里有没有 内存偏移后的值,有则回溯,否则+1
  133.                                         if (aSunday[pMemBuffer[nOffset]])
  134.                                         {
  135.                                                 i = nOffset - aSunday[pMemBuffer[nOffset]] + 1;
  136.                                                 j = 0;
  137.                                         }
  138.                                         else
  139.                                         {
  140.                                                 i = nOffset + 1;
  141.                                                 j = 0;
  142.                                         }
  143.                                 }
  144.                         }

  145.                         if (j == len)
  146.                         {
  147.                                 //计算找到的目标地址:
  148.                                 //特征码地址 = 当前内存块基址 + i偏移 - 特征码长度
  149.                                 //目标地址 = 特征码地址 + 偏移距离
  150.                                 //CALL(E8)跳转的地址 = E8指令后面的4个字节地址 + 下一条指令地址(也就是目标地址 + 5)
  151.                                 retAddr[nCount] = dwCurAddr + i - len + deviation;
  152.                                 if (isCall) {
  153.                                         DWORD temp;
  154.                                         memcpy(&temp, &pMemBuffer[i - len + deviation + 1], 4);
  155.                                         retAddr[nCount] += 5;
  156.                                         retAddr[nCount] += temp;
  157.                                 }

  158.                                 if (++nCount >= nArrayLength)
  159.                                 {
  160.                                         //传入的数组下标越界就结束搜索
  161.                                         goto end;
  162.                                 }

  163.                                 if (isAll) {                               
  164.                                         i = i - len + 1;
  165.                                         j = 0;
  166.                                         goto nextAddr;
  167.                                 }
  168.                                 else {
  169.                                         goto end;
  170.                                 }
  171.                         }               
  172.                         dwCurAddr += mbi.RegionSize; //取下一块内存地址
  173.                 }
  174.                 else
  175.                 {
  176.                         dwCurAddr += mbi.RegionSize;
  177.                 }
  178.         }


  179. end:
  180.         //计算搜索用时(ms)
  181.         clock_t nEndTime = clock();
  182.         int nUseTime = (nEndTime - nBeginTime);       
  183.         //释放内存
  184.         if (pMemBuffer) {
  185.                 delete[] pMemBuffer;
  186.                 pMemBuffer = NULL;
  187.         }
  188.         delete[] pMarkCode;
  189.         pMarkCode = NULL;
  190.         return nCount;
  191. }

复制代码


注意:一定要根据查询到的内存页大小动态分配内存。千万不要像有些人写的,固定一页大小4096或其他的等等,这样的会存在一种情况,当你的特征码跨2页的时候,你会发现找不到,除非你特殊处理,而且处理起来极为麻烦!

该用户从未签到

发表于 2020-4-11 13:31:22 | 显示全部楼层
请楼主发使用例子 可以吗
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2020-7-4 13:45

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

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