吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1815|回复: 9
收起左侧

[C&C++ 原创] 使用SSE2加速暴力搜索内存特征码(支持模糊匹配)

[复制链接]
wtujoxk 发表于 2023-11-8 15:04
本帖最后由 wtujoxk 于 2023-11-15 12:26 编辑

前言:在学习自写劫持补丁时,遇到搜索内存特征码,于是就有了这代码!!!


支持通配符??,支持一码多匹配,支持x86 x64
效果:
1699426301345.jpg
1699427042662.png

代码:
[C++] 纯文本查看 复制代码
//  核心算法来自看雪论坛[url=https://bbs.kanxue.com/thread-209946.htm]https://bbs.kanxue.com/thread-209946.htm[/url];作者:liuzewei 
//  其余由wtujoxk整理,支持通配符??,支持一码多匹配,支持x86 x64
//  如使用请保留出处

#include <windows.h>
#include <intrin.h>
#include <psapi.h>
#include <string>
#include <vector>
#include <memory>

/*  SSE2PatternFind()特征码搜索
1)  module  需要搜索的模块 HMODULE hModule = GetModuleHandle(L"模块名称");
2)  pattern  搜索特征码,支持通配符?? 格式为:std::string pattern = "55 ?? 77 88 ?? AA BB";
3)  searchNum  搜索个数,0为搜索整个模块,默认为0
4)  deviation  特征码地址离目标地址的偏移距离,上负下正,默认不偏移
    return返回值,找到的地址
    调用 std::vector<ULONGLONG> retList = SSE2PatternFind(hModule, pattern, 10);
*/
std::vector<ULONGLONG> SSE2PatternFind(HMODULE module, std::string pattern, ULONGLONG searchNum = 0, ULONGLONG deviation = 0)
{
    std::vector<ULONGLONG> retList;
    //  "12 34 ?? 78 ?? BC"
    //  去除所有空格
    if (!pattern.empty())
    {
        pattern.erase(std::remove(pattern.begin(), pattern.end(), ' '), pattern.end());
        pattern.erase(0, pattern.find_first_not_of("?"));   
    }
    //  特征码长度不能为单数
    if (pattern.length() % 2 != 0) return retList;
    //  特征码长度
    int len = pattern.length() / 2;
    std::string SigMask = "";
    std::string finalPattern = "";

    //  将特征码转换为目标格式,并将mask做相应的匹配
    for (int i = 0; i < len; i++) {
        std::string tempStr = pattern.substr(i * 2, 2);
        SigMask += (tempStr == "??") ? "?" : "x";
        finalPattern += (tempStr == "??") ? char(0xFF) : char(strtoul(tempStr.c_str(), nullptr, 16));
    }

    //  必须初始化,否则报错
    MODULEINFO moduleInfo = { 0 };
    if (GetModuleInformation(GetCurrentProcess(), module, &moduleInfo, sizeof(moduleInfo)) == 0)
        return retList;
    ULONGLONG VirtualAddress = (ULONGLONG)moduleInfo.lpBaseOfDll;
    ULONGLONG VirtualLength = moduleInfo.SizeOfImage;

   // 常规变量
    PUCHAR MaxAddress = (PUCHAR)(VirtualAddress + VirtualLength);
    PUCHAR BaseAddress;
    PUCHAR CurrAddress;
    PUCHAR CurrPattern;
    PCHAR CurrMask;
    BOOLEAN CurrEqual;
    register UCHAR CurrUChar;

    // SSE 加速相关变量   
    __m128i SigHead = _mm_set1_epi8((CHAR)finalPattern[0]);
    __m128i CurHead, CurComp;
    ULONG MskComp, IdxComp;
    ULONGLONG i, j, nCount = 0;

    //
    //   第一层遍历使用 SSE 将逐字节加速为逐 16 字节每次(最终加速 12 倍获益主要来源与此)
    //
    //   第二层子串匹配不能使用 SSE 加速,原因有四
    //     1. SSE 虽为单指令多数据,但单个指令 CPU 周期比常规指令要高
    //
    //     2. 从概率上来说,子串匹配时第一个字节命中失败与 SSE 一次性对比 16 个字节命中失败在概率上几乎相等
    //
    //     3. 根据实验采用 SSE 优化第二层子串匹配将显著降低最终查找速度
    //
    //     4. 理论上,即使 SSE 单条指令与常规指令具有同样的CPU周期,最高也只能加速 16 倍
    //
    for (i = 0; i <= VirtualLength - 16; i += 16)
    {
        CurHead = _mm_loadu_si128((__m128i*)(VirtualAddress + i));
        CurComp = _mm_cmpeq_epi8(SigHead, CurHead);
        MskComp = _mm_movemask_epi8(CurComp);

        BaseAddress = (PUCHAR)(VirtualAddress + i);
        j = 0;
        while (_BitScanForward(&IdxComp, MskComp))
        {
            CurrAddress = BaseAddress + j + IdxComp;
            CurrPattern = (PUCHAR)finalPattern.c_str();
            CurrMask = (PCHAR)SigMask.c_str();
            for (; CurrAddress <= MaxAddress; CurrAddress++, CurrPattern++, CurrMask++)
            {
                // 因为是暴力搜索整个系统的物理内存,而本函数自身的堆栈区当然也属于整个物理内存的一部分
                // 因此为了避免匹配到参数 SigPattern 本身,对其做了相应过滤操作,如不需要可以自行简化 2 行
                CurrUChar = *CurrPattern;
                // *CurrPattern = CurrUChar + 0x1;
                CurrEqual = (*CurrAddress == CurrUChar);
                // *CurrPattern = CurrUChar;

                if (!CurrEqual) { if (*CurrMask == 'x') break; }
                if (*CurrMask == 0)
                {
                    retList.push_back((ULONGLONG)(BaseAddress + j + IdxComp + deviation));
                    if (++nCount >= searchNum && searchNum != 0) return retList;
                    break;
                }
            }

            ++IdxComp;
            MskComp = MskComp >> IdxComp;
            j += IdxComp;
        }
    }
    return retList;
}


调用代码:
[C++] 纯文本查看 复制代码
#include <iostream>
#include <windows.h>
#include <shlwapi.h>
#include <Psapi.h>
#include "SSE2PatternFind.h"


using namespace std;

int main()
{
    HMODULE hModule = GetModuleHandle(L"ntdll.dll");
    string pattern = "78 ?? 48 8D ?? ?? 50";

    clock_t begin = clock();
    vector<ULONGLONG> retList = SSE2PatternFind(hModule, pattern);
    cout << "SSE搜索用时:" << clock() - begin << " ms" << endl;
    for (int i = 0; i < retList.size(); i++)
        cout << "特征码:"+ pattern + " 第" << i + 1 << "个--->结果: " << (void*)retList[i] << endl;

    system("pause");
    return 0;
}


注:此代码搜索内存不连续和映射不完整的模块会抛锚 ,有能力的自己完善!

免费评分

参与人数 4吾爱币 +10 热心值 +4 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
lkmmn5801585 + 1 + 1 用心讨论,共获提升!
topzhp + 1 + 1 我很赞同!
max2012 + 1 + 1 我很赞同!

查看全部评分

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

yiting8 发表于 2023-11-8 15:32
用CE可以吗?
DoraemonPocket 发表于 2023-11-8 15:36
fjqisba 发表于 2023-11-8 16:42
 楼主| wtujoxk 发表于 2023-11-8 17:14
本帖最后由 wtujoxk 于 2023-11-8 17:16 编辑
fjqisba 发表于 2023-11-8 16:42
https://github.com/fjqisba/FastBinSearch,我也写了一份,楼主可以对比看看

写这个之前,在看雪看过你的,非常好,也测试了这两种,但是这种方式更快一些,这两种在内存不连续和映射不完整的时候,都有抛锚的时候!比如在搜索32位的kernel32.dll模块时,必抛锚!!!
janken 发表于 2023-11-8 17:49
学习了,之前一直不知道内存搜索是怎么执行的。
wasm2023 发表于 2023-11-8 18:35
fjqisba 发表于 2023-11-8 16:42
https://github.com/fjqisba/FastBinSearch,我也写了一份,楼主可以对比看看

大佬的dart助手啥时候更新呦
Elaineliu 发表于 2023-11-8 22:37
本帖最后由 Elaineliu 于 2023-11-8 22:50 编辑

https://github.com/ReClassNET/ReClass.NET
https://github.com/cheat-engine/cheat-engine

这俩挺好的



https://github.com/1aa82e/crysearch
666888tzq 发表于 2023-11-9 12:46
感谢分享,不错。
kicktj 发表于 2024-3-13 18:39
这个不能跨进程的吧,到 CurrEqual = (*CurrAddress == CurrUChar); 这里就报错了,*CurrAddress 读不出值

我只是把 if (GetModuleInformation(GetCurrentProcess(), module, &moduleInfo, sizeof(moduleInfo)) == 0)
改成 if (GetModuleInformation(OpenProcess(PROCESS_ALL_ACCESS, false, 8596), module, &moduleInfo, sizeof(moduleInfo)) == 0) 而已
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

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

GMT+8, 2024-5-3 06:31

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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