首页
社区
课程
招聘
[原创]一个速度不是很快但是逻辑很简单的内存特征码搜索
2019-5-27 15:47 7046

[原创]一个速度不是很快但是逻辑很简单的内存特征码搜索

2019-5-27 15:47
7046

// ConsoleApplication8.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。

// 很多头文件不需要,你自己看着用吧 我是复制我之前的

#include "pch.h"

#include <Windows.h>

#include <windowsx.h>

#include <process.h>

#include <direct.h>

#include <tchar.h>

#include <stdio.h>

#include <algorithm>

#include <math.h>

#include <Psapi.h>

#include <Tlhelp32.h>

#include <iostream>

#include <vector>

#include <string>

#include <map>

#include <ctime>

#include <thread>


/// 字符转字节

int ctoh(char hex)

{

    if (hex >= '0' && hex <= '9') return hex - '0';

    if (hex >= 'A' && hex <= 'F') return hex - 'A' + 10;

    if (hex >= 'a' && hex <= 'f') return hex - 'a' + 10;

    return 0;

}


/// 十六进制字符串转字节数组

std::vector<BYTE> HexStringToBytes(std::string str)

{

    std::vector<BYTE> Bytes;

    for (SIZE_T i = 0; i < str.size(); i++)

    {

        if (str[i] == ' ')

        {

            continue;

        }

        if (str[i] == '?')

        {

            Bytes.insert(Bytes.end(), '?');

            // 兼容OD模式的特征码

            if (str[i+1] == '?')

                i++;

        }

        else if (str[i] == '*') {

            Bytes.insert(Bytes.end(), '*');

        }

        else {

            Bytes.insert(Bytes.end(), 0x10 * ctoh(str[i]) + ctoh(str[i + 1]));

            i++;

        }

    }

    return Bytes;

}

// 获取进程模块句柄

HMODULE GetProcessModuleHandle(DWORD ProcessId, CONST TCHAR* ModuleName)

{

    HMODULE hMods[1024];

    DWORD cbNeeded;

    TCHAR szModName[MAX_PATH];


    HANDLE ProcessHandle = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);


    if (EnumProcessModulesEx(ProcessHandle, hMods, sizeof(hMods), &cbNeeded, 0x1))

    {

        for (size_t i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)

        {


            GetModuleFileNameEx(ProcessHandle, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR));

            if (_tcscmp(szModName, ModuleName)) {

                return hMods[i];

            }

        }

    }

    CloseHandle(ProcessHandle);

    return NULL;

}


// 读字节数组

std::vector<BYTE> ReadBytes(HANDLE ProcessHandle, DWORD_PTR Address, SIZE_T Size)

{

    std::vector<BYTE> Bytes = {};

    Bytes.resize(Size);

    BYTE* Buffer = new BYTE[Size];

    // HANDLE ProcessHandle = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);

    ReadProcessMemory(ProcessHandle, (LPCVOID)Address, Buffer, Size, NULL);

    for (size_t i = 0; i < Size; i++)

    {

        Bytes[i] = Buffer[i];

    }

    delete[]Buffer;

    // CloseHandle(ProcessHandle);

    return Bytes;

}

// 用来保存模块内存数据

static std::map<CONST TCHAR*, std::map<DWORD_PTR, std::vector<BYTE>>> g_ModuleMemorys;



//256 表示 0x00~0xff 特征码长度不要超过 256

static int maxByteSize = 256;

static int shift[256] = { 0 };

long Sunday(std::vector<byte> T, std::vector<byte> P)

{

    int n = T.size();

    int m = P.size();


   

    // 默认值,移动m+1位 256 表示 0x00~0xff

    for (int i = 0; i < maxByteSize; i++) {

        shift[i] = m + 1;

    }

    // 模式串P中每个字母出现的最后的下标

    // 所对应的主串参与匹配的最末位字符的下一位字符移动到该位,所需要的移动位数

    for (int i = 0; i < m; i++) {

        shift[P[i]] = m - i;

    }

    // 模式串开始位置在主串的哪里

    int s = 0;

    // 模式串已经匹配到的位置

    int j;

    while (s <= n - m) {

        j = 0;

        while (P[j] == '*' || P[j] == '?' || T[s + j] == P[j]) {

            j++;

            // 匹配成功

            if (j >= m) {

                return s;

            }

        }

        // 找到主串中当前跟模式串匹配的最末字符的下一个字符

        // 在模式串中出现最后的位置

        // 所需要从(模式串末尾+1)移动到该位置的步数

        s += shift[T[s + m]];

    }

    return -1;

}


DWORD_PTR FindFeatureCode(DWORD ProcessId, CONST TCHAR* ModuleName, std::string FeatureCodeString)

{

    DWORD_PTR Address = 0;

    DWORD_PTR BeginAddress = 0;

    DWORD_PTR EndAddress = 0;

    HANDLE ProcessHandle = NULL;

    MODULEINFO ModuleInfo;

    MEMORY_BASIC_INFORMATION mbi;

    std::map<DWORD_PTR, std::vector<BYTE>> Memorys;

    std::map<DWORD_PTR, std::vector<BYTE>>::iterator it;


    std::vector<BYTE> FeatureCode = HexStringToBytes(FeatureCodeString);


    // 这里获取模块内存信息 

    if (g_ModuleMemorys.find(ModuleName) == g_ModuleMemorys.end())

    {

        //printf("%s\n", "123456");

        ProcessHandle = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);


        GetModuleInformation(ProcessHandle, GetProcessModuleHandle(ProcessId, ModuleName), &ModuleInfo, sizeof(ModuleInfo));


        BeginAddress = (DWORD_PTR)ModuleInfo.lpBaseOfDll;

        EndAddress = (DWORD_PTR)ModuleInfo.lpBaseOfDll + ModuleInfo.SizeOfImage;


        while (BeginAddress <= EndAddress)

        {

            ::VirtualQueryEx(ProcessHandle, (LPCVOID)BeginAddress, &mbi, sizeof(mbi));


            if (mbi.Protect != 1 && mbi.Protect != 16 && mbi.Protect != 512 && mbi.RegionSize > 1)

            {


                g_ModuleMemorys[ModuleName].insert(std::pair<DWORD_PTR, std::vector<BYTE>>(BeginAddress, ReadBytes(ProcessHandle, BeginAddress, mbi.RegionSize)));

            }


            BeginAddress += mbi.RegionSize;

        }

        CloseHandle(ProcessHandle);

    }


    Memorys = g_ModuleMemorys[ModuleName];


    it = Memorys.begin();


    while (it != Memorys.end())

    {

        long offset = Sunday(it->second, FeatureCode);

        if (offset >= 0)

        {

            Address = it->first + offset;

            goto _exit;

        }

        it++;

    }

    // 暴力匹配

    //SIZE_T i = 0;

    //SIZE_T j = 0;

    //// 这个就是匹配的逻辑了

    //while (it != Memorys.end())

    //{

    //    i = it->second.size();

    //    while (i--) {

    //        j = FeatureCode.size();

    //        while (j--) {

    //            if (j == 0)

    //            {

    //                Address = it->first + i;

    //                goto _exit;

    //            }

    //            else if (FeatureCode[j] != it->second[i + j] && FeatureCode[j] != '?' && FeatureCode[j] != '*') {

    //                break;

    //            }

    //        }


    //    }


    //    it++;

    //}

_exit:

    return Address;

}


int main(int argc, char const* argv[])

{

    clock_t startTime, endTime;

    startTime = clock();//计时开始


    // 特征码字符串格式随意  这里是拿网易的有道词典测试的

    ULONG address = 0;



    address = FindFeatureCode(13232, L"YoudaoDict.exe", "3E A0 ?? ?? ?? ?? 3E AC 3E B0 ?? B4 ?? B8 ?? ?? ?? ?? 3E C4 3E C8 3E CC ?? D0 3E D4 ?? D8 3E DC 3E E0 ?? E4 ?? E8 ?? ?? ?? ??  ");

    

    printf("address %x\n", address);



    endTime = clock();//计时结束

    printf("运行时间: %f/s\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);

    system("pause");

    //MSG msg;

    //while (GetMessage(&msg, NULL, 0, 0))

    //{

    //    //翻译消息

    //    TranslateMessage(&msg);

    //    //分发消息

    //    DispatchMessage(&msg);

    //}

    //return 0;

}



[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2020-5-8 10:58 被aas102400编辑 ,原因:
收藏
点赞3
打赏
分享
最新回复 (16)
雪    币: 1042
活跃值: (455)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Rookietp 2019-5-27 20:00
2
0
代码看的很舒服,先收藏一波.用得上的时候再来.
最后于 2019-5-27 20:00 被Rookietp编辑 ,原因:
雪    币: 6124
活跃值: (4056)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
黑洛 1 2019-5-27 20:38
3
0
我感觉你的代码很怪,stl库和原指针混用,说不出变扭的感觉。和逻辑、效率关系不大,单纯觉得这样写代码会对自己和别人造成一定的困扰。
雪    币: 12059
活跃值: (15389)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
pureGavin 2 2019-5-27 20:42
4
0
mark,楼主辛苦了
雪    币: 200
活跃值: (540)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
aas102400 2019-5-28 09:17
5
0
黑洛 我感觉你的代码很怪,stl库和原指针混用,说不出变扭的感觉。和逻辑、效率关系不大,单纯觉得这样写代码会对自己和别人造成一定的困扰。
我自己都是瞎学的  不懂啥子规范 
雪    币: 200
活跃值: (540)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
aas102400 2019-5-28 09:35
6
0
aas102400 我自己都是瞎学的 不懂啥子规范 [em_12]
我自己百度找 那种要么是不能用 要么就是又臭又长
雪    币: 7
活跃值: (939)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
网络游侠 2019-5-28 10:06
7
0
黑洛 我感觉你的代码很怪,stl库和原指针混用,说不出变扭的感觉。和逻辑、效率关系不大,单纯觉得这样写代码会对自己和别人造成一定的困扰。
这代码不算别扭吧,可读性还行。
雪    币: 200
活跃值: (540)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
aas102400 2019-5-28 10:37
8
0
网络游侠 这代码不算别扭吧,可读性还行。
取内存那个可以单独写一个函数 我懒的弄了就整一块去了
雪    币: 17
活跃值: (278)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
叁毛 1 2019-5-28 16:14
9
0
AC自动机,多模匹配,只需要匹配一次
雪    币: 6124
活跃值: (4056)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
黑洛 1 2019-5-28 17:07
10
0
aas102400 我自己都是瞎学的 不懂啥子规范 [em_12]
可读性没啥问题 ,就是混用不太好
雪    币: 200
活跃值: (540)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
aas102400 2019-6-3 17:10
12
0
黑洛 可读性没啥问题 ,就是混用不太好
为啥这样不好啊
雪    币: 6124
活跃值: (4056)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
黑洛 1 2019-6-3 17:50
13
0
aas102400 为啥这样不好啊
不是一个语言的写法混用感觉很奇怪,然后虽然你用c语言的写法写,但是最后还是会被编译为C++
雪    币: 200
活跃值: (540)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
aas102400 2019-6-4 17:16
14
0

语法啥的,开心就好呀
雪    币: 194
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
MrNv 2019-6-8 20:05
15
0
大佬这个支持64位吗
雪    币: 200
活跃值: (540)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
aas102400 2019-6-10 11:45
16
0
MrNv 大佬这个支持64位吗
支持
雪    币: 419
活跃值: (96)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
smallsina 2022-5-26 15:34
17
0
mark 666
游客
登录 | 注册 方可回帖
返回