吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1144|回复: 8
收起左侧

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

[复制链接]
jtwc 发表于 2022-4-18 10:07
本帖最后由 jtwc 于 2022-4-18 11:23 编辑

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

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 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[32] = {0};  或者 DWORD *retAddr = new DWORD[32]();
6) deviation                特征码地址离目标地址的偏移距离,上负下正
7) isCall                是否为找CALL的跳转地址,true 则 retAddr[] 返回的是CALL跳转的地址
8) isAll                是否查找所有符合的地址,false找到第一个符合的地址后就结束搜索,true继续搜索,直到搜索地址大于结束地址(memEndAddr)
return返回值                找到的地址总数
搜不到内存可能是保护属性没有选对
*/


  DWORD retAddr[32] = { 0 }; //记录特征码对应的地址
//DWORD *retAddr = new DWORD[32]();
  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[len];
        BYTE *pWildcard = new BYTE[len];
        for (int i = 0; i < len; i++) {
                string tempStr = markCode.substr(i * 2, 2);
                if (tempStr == "**") {
                        pWildcard[i] = 0xFF;
                        if (nSundayLen == len) nSundayLen = i;        //记录第一个通配符的索引,该索引越靠后,效率越高
                }
                else {
                        pWildcard[i] = 0x00;
                }
                pMarkCode[i] = strtoul(tempStr.c_str(), 0, 16);
        }
        //--------------------------end-------------------------//

        //Sunday算法模板数组赋值,+1防止特征码出现FF时越界
        int aSunday[0xFF + 1] = { 0 };
        for (int i = 0; i < nSundayLen; i++) {
                aSunday[pMarkCode[i]] = 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[mbi.RegionSize];
                        //读取进程内存
                        ReadProcessMemory(hProcess, (LPCVOID)dwCurAddr, pMemBuffer, mbi.RegionSize, 0);
                        i = 0;
                        j = 0;
                        while (j < len)
                        {
                        nextAddr:
                                if (pMemBuffer[i] == pMarkCode[j] || pWildcard[j] == 0xFF)
                                {
                                        i++;
                                        j++;
                                }
                                else
                                {
                                        nOffset = i - j + nSundayLen;
                                        //判断偏移量是否大于缓冲区
                                        if (nOffset > mbi.RegionSize - len) break;
                                        //判断 aSunday模板数组 里有没有 内存偏移后的值,有则回溯,否则+1
                                        if (aSunday[pMemBuffer[nOffset]])
                                        {
                                                i = nOffset - aSunday[pMemBuffer[nOffset]] + 1;
                                                j = 0;
                                        }
                                        else
                                        {
                                                i = nOffset + 1;
                                                j = 0;
                                        }
                                }
                        }

                        if (j == len)
                        {
                                //计算找到的目标地址:
                                //特征码地址 = 当前内存块基址 + i偏移 - 特征码长度
                                //目标地址 = 特征码地址 + 偏移距离
                                //CALL(E8)跳转的地址 = E8指令后面的4个字节地址 + 下一条指令地址(也就是目标地址 + 5)
                                retAddr[nCount] = dwCurAddr + i - len + deviation;
                                if (isCall) {
                                        DWORD temp;
                                        memcpy(&temp, &pMemBuffer[i - len + deviation + 1], 4);
                                        retAddr[nCount] += 5;
                                        retAddr[nCount] += 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
[C++] 纯文本查看 复制代码
#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[i]))
        {
            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 [pos, i] = 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 [masks, i, n, pos] = 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)[j])
            {
                masks[i] |= static_cast<std::size_t>(1) << j;
            }
        }

        for (auto [store, j] = 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[i]) == masks[i])
            {
                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
[mw_shl_code=cpp,true]#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
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 14:32

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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