jtwc 发表于 2022-4-18 10:07

各位老师,网上找了个C++用特征码读取内存地址的代码,咋改才能达到如下的效果呢?

本帖最后由 jtwc 于 2022-4-18 11:23 编辑

各位老师,网上找了个C++用特征码读取内存地址的代码,咋改才能达到如下的效果呢?谢谢了

jtwc 发表于 2022-4-18 10:08

代码如下:
#include <windows.h>
#include <time.h>
#include <iostream>
using namespace std;

//2020.8.9代码更新,修复通配符的小BUG,该BUG会有极低几率搜索错误,现已修复
//2022.4.4代码更新,添加一句代码,修复起始地址的小BUG,该BUG会有小概率搜不到想要的内存

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


DWORD retAddr = { 0 }; //记录特征码对应的地址
//DWORD *retAddr = new DWORD();
int nCount;


DWORD findMatchingCode(HANDLE hProcess, string markCode, DWORD memBeginAddr, DWORD memEndAddr, DWORD retAddr[], int deviation, bool isCall, bool isAll = false);

DWORD findMatchingCode(HANDLE hProcess, string markCode, DWORD memBeginAddr, DWORD memEndAddr, DWORD retAddr[], int deviation, bool isCall, bool isAll)


//DWORD findMatchingCode(HANDLE hProcess, string markCode, DWORD memBeginAddr, DWORD memEndAddr, DWORD retAddr[], int deviation, bool isAll)
{
        //----------------------处理特征码----------------------//
        //去除所有空格
        if (!markCode.empty())
        {
                int index = 0;
                while ((index = markCode.find(' ', index)) >= 0)
                {
                        markCode.erase(index, 1);
                }
                index = 0;
                while (true)
                {
                        //删掉头部通配符
                        index = markCode.find("**", index);
                        if (index == 0) {
                                markCode.erase(index, 2);
                        }
                        else {
                                break;
                        }
                }
        }

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

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

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

        //将特征码转换成byte型
        BYTE *pMarkCode = new BYTE;
        BYTE *pWildcard = new BYTE;
        for (int i = 0; i < len; i++) {
                string tempStr = markCode.substr(i * 2, 2);
                if (tempStr == "**") {
                        pWildcard = 0xFF;
                        if (nSundayLen == len) nSundayLen = i;        //记录第一个通配符的索引,该索引越靠后,效率越高
                }
                else {
                        pWildcard = 0x00;
                }
                pMarkCode = strtoul(tempStr.c_str(), 0, 16);
        }
        //--------------------------end-------------------------//

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

        //起始地址
        const DWORD dwBeginAddr = memBeginAddr;
        //结束地址
        const DWORD dwEndAddr = memEndAddr;
        //当前读取的内存块地址
        DWORD dwCurAddr = dwBeginAddr;
        //存放内存数据的缓冲区
        BYTE *pMemBuffer = NULL;
        //计算参数retAddr[]数组的长度,该参数传入前一定要清0
        int nArrayLength = 0;
        for (int i = 0;; i++) {
                if (*(retAddr + i) != 0) {
                        nArrayLength = i;
                        break;
                }
        }
        //偏移量
        int nOffset;
        //数组下标:内存、特征码、返回地址
        int i = 0, j = 0, nCount = 0;

        //内存信息
        MEMORY_BASIC_INFORMATION mbi;

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

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

                //添加一句代码,修改当前地址到这块内存页的起始地址,编辑于2022.4.4,没有这句会有概率搜不到想要的内存
                dwCurAddr = (DWORD_PTR)mbi.BaseAddress;
                //-----------------------------------------------------//

                //过滤内存空间, 根据内存的状态和保护属性进行过滤
                //一般扫描(读写及执行)即可,速度极快,扫不到的话在尝试添加(读写)这一属性
                if (MEM_COMMIT == mbi.State &&                        //已分配的物理内存
                        //MEM_PRIVATE == mbi.Type ||                //私有内存,不被其他进程共享
                        //MEM_IMAGE == mbi.Type &&
                        //PAGE_READONLY == mbi.Protect ||        //只读
                        //PAGE_EXECUTE_READ == mbi.Protect ||        //读及执行
                        //PAGE_READWRITE == mbi.Protect ||        //读写
                        PAGE_EXECUTE_READWRITE == mbi.Protect)        //读写及执行
                {
                        //申请动态内存
                        if (pMemBuffer) {
                                delete[] pMemBuffer;
                                pMemBuffer = NULL;
                        }
                        pMemBuffer = new BYTE;
                        //读取进程内存
                        ReadProcessMemory(hProcess, (LPCVOID)dwCurAddr, pMemBuffer, mbi.RegionSize, 0);
                        i = 0;
                        j = 0;
                        while (j < len)
                        {
                        nextAddr:
                                if (pMemBuffer == pMarkCode || pWildcard == 0xFF)
                                {
                                        i++;
                                        j++;
                                }
                                else
                                {
                                        nOffset = i - j + nSundayLen;
                                        //判断偏移量是否大于缓冲区
                                        if (nOffset > mbi.RegionSize - len) break;
                                        //判断 aSunday模板数组 里有没有 内存偏移后的值,有则回溯,否则+1
                                        if (aSunday])
                                        {
                                                i = nOffset - aSunday] + 1;
                                                j = 0;
                                        }
                                        else
                                        {
                                                i = nOffset + 1;
                                                j = 0;
                                        }
                                }
                        }

                        if (j == len)
                        {
                                //计算找到的目标地址:
                                //特征码地址 = 当前内存块基址 + i偏移 - 特征码长度
                                //目标地址 = 特征码地址 + 偏移距离
                                //CALL(E8)跳转的地址 = E8指令后面的4个字节地址 + 下一条指令地址(也就是目标地址 + 5)
                                retAddr = dwCurAddr + i - len + deviation;
                                if (isCall) {
                                        DWORD temp;
                                        memcpy(&temp, &pMemBuffer, 4);
                                        retAddr += 5;
                                        retAddr += temp;
                                }

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

                                if (isAll) {
                                        i = i - len + 1;
                                        j = 0;
                                        goto nextAddr;
                                }
                                else {
                                        goto end;
                                }
                        }
                        dwCurAddr += mbi.RegionSize; //取下一块内存地址
                }
                else
                {
                        dwCurAddr += mbi.RegionSize;
                }
        }


end:
        //计算搜索用时(ms)
        clock_t nEndTime = clock();
        int nUseTime = (nEndTime - nBeginTime);
        //释放内存
        if (pMemBuffer) {
                delete[] pMemBuffer;
                pMemBuffer = NULL;
        }
        delete[] pMarkCode;
        pMarkCode = NULL;
        delete[] pWildcard;
        pWildcard = NULL;

        return nCount;
}


int main()
{
        HWND hWnd;
        hWnd = FindWindow(NULL, "Plants vs. Zombies GOTY ");

        DWORD PID;
        GetWindowThreadProcessId(hWnd, &PID);

        HANDLE lsProcess;
        lsProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
       

        cout << findMatchingCode(lsProcess, " 96 00 00 00 14 00 00 00 D4 3B ", 0x400000, 0x7FFFFFFF, retAddr, 0, 0, true) << endl;

        cout << retAddr << endl;//内存地址

        system("pause");
        return 0;
}

小小随 发表于 2022-4-18 10:25

#include <string>
#include <algorithm>
#include <array>
#include <immintrin.h>

static constexpr char charhexset[] = "0123456789ABCDEFabcdef";
typedef unsigned int                u32;
#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
typedef long long               s96;
typedef unsigned long long      u96;
#else
typedef int                     s96;
typedef unsigned int            u96;
#endif
static bool StringReplace(std::string& source, const std::string& delimiters, const std::string& dispose = "", const std::size_t offset = 1)
{
    if (source.empty())
    {
      return false;
    }

    if (delimiters.empty())
    {
      return true;
    }

    for (std::string::size_type pos = source.find(delimiters); pos != std::string::npos; pos = source.find(delimiters))
    {
      if (source.replace(pos, offset, dispose).size())
      {
            continue;
      }
      return false;
    }

    return true;
}

static bool Hexadec2xdigit(const std::string& data, std::string& buffer, std::size_t offset)
{
    if (data.empty())
    {
      return false;
    }

    for (std::size_t i = 0; i < data.size(); i += offset)
    {
      if (std::isxdigit(data))
      {
            buffer += static_cast<char>(std::stoul(data.substr(i, offset), nullptr, 16));
      }
      else
      {
            buffer += 'X';
      }
    }

    return true;
}

static bool Hexadec2xdigitEx(const std::string& data, std::string& buffer, u32 checkxdigit = 0, u32 transform = 1)
{
    if (data.empty())
    {
      return false;
    }

    std::string masks(data);
    {
      // 去掉 0x 去掉 空格
      if (StringReplace(masks, "0x") && StringReplace(masks, " "))
      {
            // 大小写转换
            if (masks.end() == (1 == transform ? std::transform(masks.begin(), masks.end(), masks.begin(), [] (unsigned char ch) { return toupper(ch); }) : std::transform(masks.begin(), masks.end(), masks.begin(), [] (unsigned char ch) { return tolower(ch); })))
            {
                // 检查是否是完整的十六进制数
                if (checkxdigit)
                {
                  if (std::string::npos != masks.find_first_not_of(charhexset))
                  {
                        return false;
                  }
                }

                return Hexadec2xdigit(static_cast<const std::string&>(masks), buffer, 2);
            }
      }
    }

    return false;
}

static bool SearchPattern(const unsigned char* pos, const std::string& chars)
{
    for (std::string::const_iterator xdigit = chars.cbegin(); xdigit != chars.cend(); ++xdigit, ++pos)
    {
      if (*pos != static_cast<const unsigned char>(*xdigit) &&   // no match
            'X' != static_cast<const unsigned char>(*xdigit))      // filter out arbitrary characters
      {
            return false;
      }
      else
      {
            // hit character
            continue;
      }
    }

    return true;
}

static bool SearchPattern(const void* start,                  // start address
                        const void* end,                      // end address
                        const std::string& keyword,         // characteristic code
                        std::size_t index,                  // take out the serial number
                        void*& address)                     // return to address
{
    if (keyword.empty())
    {
      return false;
    }

    if (start != end && static_cast<const unsigned char*>(end) > static_cast<const unsigned char*>(start) && static_cast<std::size_t>(static_cast<const unsigned char*>(end) - static_cast<const unsigned char*>(start)) > keyword.size())
    {
      std::string chars;
      {
            if (Hexadec2xdigitEx(keyword, chars, 0))
            {
                for (auto = std::make_tuple(static_cast<const unsigned char*>(start), static_cast<std::size_t>(0)); pos <= end; ++pos)
                {
                  if (SearchPattern(pos, chars))
                  {
                        if (++i != index)
                        {
                            continue;
                        }
                        else
                        {
                            address = const_cast<void*>(reinterpret_cast<const void*>(pos));
                        }

                        return true;
                  }
                }
            }
      }
    }

    return false;
}

static bool SearchPattern(const u96 start, const u96 end, const std::string& keyword, std::size_t index, void*& address)
{
    return SearchPattern(reinterpret_cast<const void*>(start), reinterpret_cast<const void*>(end), keyword, index, address);
}

static bool SearchPatternEx(const void* start, const void* end, const std::string& chars, std::size_t index, std::size_t count, void*& address)
{
    for (auto = std::make_tuple(std::array<std::size_t, 32>{}, static_cast<std::size_t>(0), static_cast<std::size_t>(0), static_cast<const unsigned char*>(start)); i < count; ++i)
    {
      for (std::size_t j = 0; j < 16 && n < chars.size(); ++j, ++n)
      {
            if ('X' != static_cast<const char*>(chars.c_str() + i * 16))
            {
                masks |= static_cast<std::size_t>(1) << j;
            }
      }

      for (auto = std::make_tuple(_mm_loadu_si128(reinterpret_cast<const __m128i *>(chars.c_str() + i * 16)), static_cast<std::size_t>(0)); pos <= end; _mm_prefetch(reinterpret_cast<const char*>(++pos + 64), _MM_HINT_NTA))
      {
            if (static_cast<std::size_t>(static_cast<std::size_t>(_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(pos + i * 16)), store))) & masks) == masks)
            {
                if (n < chars.size())
                {
                  break;
                }

                if (++j != index)
                {
                  continue;
                }
                else
                {
                  address = const_cast<void*>(reinterpret_cast<const void*>(pos));
                }

                return true;
            }
      }
    }

    return false;
}

static bool SearchPatternEx(const void* start, const void* end, const std::string& keyword, std::size_t index, void*& address)
{
    if (keyword.empty())
    {
      return false;
    }

    if (start != end && static_cast<const unsigned char*>(end) > static_cast<const unsigned char*>(start) && static_cast<std::size_t>(static_cast<const unsigned char*>(end) - static_cast<const unsigned char*>(start)) > keyword.size())
    {
      std::string chars;
      {
            if (Hexadec2xdigitEx(keyword, chars, 0))
            {
                return SearchPatternEx(start, end, chars, index, static_cast<std::size_t>((((chars.size()) + (16 - 1)) & ~(16 - 1)) >> 4), address);
            }
      }
    }

    return false;
}

static bool SearchPatternEx(const u96 start, const u96 end, const std::string& keyword, std::size_t index, void*& address)
{
    return SearchPatternEx(reinterpret_cast<const void*>(start), reinterpret_cast<const void*>(end), keyword, index, address);
}

jtwc 发表于 2022-4-18 10:29

小小随 发表于 2022-4-18 10:25
#include
#include
#include


老师,谢谢了,这个特征码,支持通配符(**)吗?

jtwc 发表于 2022-4-18 10:36

laodan 发表于 2022-4-18 10:30
你看下这个:https://www.52pojie.cn/thread-1180359-1-1.html

老师,谢谢了,这个支持“??”,不支持(**),而且程序容易崩溃

metoo2 发表于 2022-4-18 10:50

特征码是地址?

jtwc 发表于 2022-4-18 10:57

metoo2 发表于 2022-4-18 10:50
特征码是地址?

老师,不是

小小随 发表于 2022-4-18 12:23

jtwc 发表于 2022-4-18 10:29
老师,谢谢了,这个特征码,支持通配符(**)吗?

支持 格式为 AA BB ?? DD ?? FF
页: [1]
查看完整版本: 各位老师,网上找了个C++用特征码读取内存地址的代码,咋改才能达到如下的效果呢?