admin 发表于 2022-12-28 16:22:12

游戏安全-用特征码定位基址偏移

BytesToHexStr.h
BytesToHexStr.cpp
HexStrToBytes.h
HexStrToBytes.cpp
CFind_Offset.h
CFind_Offset.cpp
CFind_Offset_GetBaseOfffset.cpp
CFind_Offset_MatchSearch.cpp
//以下是调用例子
基址偏移.h
OFFSET_所有对象数组.cpp
定位所有基址偏移.cpp
//main.cpp是入口函数所在
main.cpp
//BytesToHexStr.h
#pragma once
#include <stdio.h>
#include <string.h>
#include <Windows.h>
char* ByteToHexChar(unsigned char c);
void BytesToHexStr(INchar *pBytes,IN SIZE_T nSize,OUTchar*pOutBufHexStr,IN SIZE_T nBufSize);
//BytesToHexStr.cpp
#include <windows.h>
#include "BytesToHexStr.h"

char* ByteToHexChar(unsigned char c)
{
        static char szRet={0}; //FF 0F 00 1A 11
        unsigned char szhigh=c/16;
        unsigned char szlow=c-szhigh*0x10;
        if (szhigh>=0&&szhigh<=9)
        {
                szRet='0'+szhigh; //30+9//'9'
        }else
        {
                //10..15
                szRet='A'+szhigh-10;
        }

        if (szlow>=0&&szlow<=9)
        {
                szRet='0'+szlow; //30+9//'9'
        }else if (szlow>=10&&szlow<=15)
        {

                //10..15
                szRet='A'+szlow-10;
        }
        return (char*) szRet;
}

void BytesToHexStr(INchar *pBytes,IN SIZE_T nSize,OUTchar*pOutBufHexStr,IN SIZE_T nBufSize)
{
        DWORD n=0;
        if (nBufSize/3<nSize)
        {
                n=nBufSize/3;
        }else
        {
                n=nSize;
        }
        pOutBufHexStr='\0';
        for (UINT32 i=0;i<n;i++)
        {
                strcat_s(pOutBufHexStr,nBufSize, ByteToHexChar(pBytes));
                strcat_s(pOutBufHexStr,nBufSize,","); //×Ö½Ú·Ö¸ô·û
        }
        strcat_s(pOutBufHexStr,nBufSize,"\0"); //½áÊø·û
        return ;
}
//HexStrToBytes.h
#pragma once
#include <stdio.h>
#include <string.h>
#include <Windows.h>
//1、szHexStr 为待转换字16进制字串
//2、szBytesbuf 是存放转换后的数据
//3、nBufSize是szBytesbuf缓冲区的大小
//4、返回成功转换的字节数量

SIZE_T HexStrToBytes(const char*szHexStr, OUT BYTE*szBytesbuf, SIZE_T nBufSize);
//带分隔符
SIZE_T HexStrToBytesNew(const char*szHexStr, OUT BYTE*szBytesbuf, SIZE_T nBufSize);
SIZE_T HexStrToBytesEx(IN const char*szHexStr, OUT BYTE*szBytesbuf, SIZE_T nBufSize, OUT BYTE*szStar);




//HexStrToBytes.cpp
#include <windows.h>
#include "HexStrToBytes.h"
#include <stdio.h>
#include <string>
using namespace std;
                                                       
unsigned char charToByte(char c)
{
//0..9
//a..f
//A..F
        unsigned char cret=0;
        if (c>='0'&&c<='9')
        {
                cret=c-'0';//'1'
        }else         if (c>='a'&&c<='f')
        {
                cret=c-'a'+10;//'1'
        }else   if (c>='A'&&c<='F')
        {
                cret=c-'A'+10;//'1'
        }

        return cret;
}

//1、szHexStr 为待转换字16进制字串
//2、szBytesbuf 是存放转换后的数据
//3、nBufSize是szBytesbuf缓冲区的大小


SIZE_T HexStrToBytes(const char*szHexStr,OUT BYTE*szBytesbuf,SIZE_T nBufSize)
{
        int dwHexLen=(int)strlen(szHexStr);
        unsigned char OneByte=0;
        int j=0;
        int nBytes=0;
        for (int i=0;i<=dwHexLen;i++)
        {
               
               //判断,分隔符
               if (i&&i%2==0)
               {
                       nBytes++;
                       szBytesbuf=OneByte;
                       //检测缓冲是否溢出
                       if (j>=nBufSize)
                       {
                               //溢出了 返回
                               break;
                       }
                       OneByte=0;//初始化 以备下一字节的转换
               }
               {
                          OneByte=OneByte*16+charToByte(szHexStr);
               }
        }

        if(nBytes>68) {MessageBoxA(0,"特征码过长","警示",1);};
        return nBytes;
};

//带分隔符
SIZE_T HexStrToBytesNew(const char*szHexStr,OUT BYTE*szBytesbuf,SIZE_T nBufSize)
{
        int dwHexLen=(int)strlen(szHexStr);
        unsigned char OneByte=0;
        int j=0;
        int nBytes=0;
        for (int i=0;i<=dwHexLen;i++)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
        {
               
               //判断,分隔符
               if (szHexStr==','||szHexStr=='\0')
               {
                       nBytes++;
                       szBytesbuf=OneByte;
                       //检测缓冲是否溢出
                       if (j>=nBufSize)
                       {
                               //溢出了 返回
                               break;
                       }
                       OneByte=0;//初始化 以备下一字节的转换
               }else
               {
                          OneByte=OneByte*16+charToByte(szHexStr);
               }
        }
        return nBytes;
};

bool 是通配符(BYTE c)
{        //自己定义通配符 可以是所有的非数字符号
        bool flag = false;
        if (c == '*'||c == '?')
        {
                flag = true;
        }
        else if (c == '?')//全角状态的问号
        {
                flag = true;
        }
        return flag;
}

bool 是数字(IN BYTE c,OUT BYTE &num)
{
boolflag = false;
//0..9
//a..f
//A..F
        //unsigned char cret = 0;
        if (c >= '0'&&c <= '9')
        {
                num = c - '0';//'1'
                flag = true;
        }
        else         if (c >= 'a'&&c <= 'f')
        {
                num = c - 'a' + 10;//'1'
                flag = true;
        }
        else   if (c >= 'A'&&c <= 'F')
        {
                num = c - 'A' + 10;//'1'
                flag = true;
        }
        return flag;
}

bool 是分隔符(BYTE c)
{
        bool flag = false;
        if (c == ',' || c == ' ')
        {
                flag = true;
        }
        else if (c == ';')   
        {
                flag = true;
        }
        return flag;
       
}

//str是待处理的字符串
//to_replaced 是被替换的字符串
//newchars是新的字符串
string& replace_str(string& str, const string& to_replaced, const string& newchars)   
{
      for(string::size_type pos(0); pos != string::npos; pos += newchars.length())   
      {
          pos = str.find(to_replaced,pos);
          if(pos!=string::npos)   
             str.replace(pos,to_replaced.length(),newchars);   
          else
            break;
      }   
      return   str;   
}

//带分隔符,通配符处理
SIZE_T HexStrToBytesEx(IN const char*szHexStr, OUT BYTE*szBytesbuf, SIZE_T nBufSize,OUT BYTE*szStar)
{
        char tmpstr = { 0 };
        strcpy_s(tmpstr, szHexStr );
        //printf("szHexStr=%s\r\n", szHexStr);
        int dwHexLen = (int)strlen(szHexStr);
        {
//替换所有0x前缀0X
//替换所有分隔符
//不是数字的全当通配符

                //所有小写字母转大写
                for (int i = 0; i <= dwHexLen; i++)
                {
                        if (tmpstr >= 'a'&&tmpstr <= 'z')
                        {
                                //转大写
                                tmpstr = tmpstr + 'A' - 'a'; //'a'>'A'                   'A' - 'a'=-32
                        }
                }
                std::string newHexStr = tmpstr;//这里不直接赋值为szHexStr,是为防止缓冲区重叠
                //替换所有0x前缀0X
                replace_str(newHexStr, "0X", "");//小写的0x已经在上边被转换
                //替换所有分隔符
                replace_str(newHexStr, ",", "");//中文逗号
                replace_str(newHexStr, ",", "");//英文逗号
                replace_str(newHexStr, " ", "");//英文逗号
                replace_str(newHexStr, "\t", "");//英文逗号
                strcpy_s(tmpstr, newHexStr.c_str());
        }

        unsigned char OneByte = 0;
        int j = 0;
        int nBytes = 0;
        BYTE num=0;
        dwHexLen =(int) strlen(tmpstr);
        for (int i = 0; i <= dwHexLen; i++)
        {

        //2个字符一组处理
        //        if (是数字(tmpstr,num))       
                if (i&&i % 2 == 0)
                {        //i=2,4,6,8,10 偶数才会走到这里
                //        printf("[%03d]=%02X <%03d>\r\n",j, OneByte, OneByte);
                        nBytes++;
                        szBytesbuf = OneByte;
                       
                        //检测缓冲是否溢出
                        if (j >= nBufSize|| tmpstr=='\0')
                        {
                                //遇到字符口中结束 或者 溢出了返回
                                break;
                        }
                        OneByte = 0;//初始化 以备下一字节的转换
                }

                {          //i=0,1,2,3,4,5,6
                        bool flag=是数字(tmpstr, num);       // 1A,3F
                        if (flag)
                        {
                                OneByte = OneByte * 16 + num;// charToByte(tmpstr);
                        }else
                        {
                                //不是数字 全当通配符处理了 ** ?? ??
                                //通配符 也必须是成对出现 否则格式就是错误的
                                if (tmpstr != tmpstr)
                                {
                                        char buf;
                                        sprintf_s(buf, "szHexStr=%s,tmpstr=%s通配符未成对出现", szHexStr, tmpstr);
                                        MessageBoxA(0, buf, "ERROR HexStrToBytesEx", 0);
                                }
                                //printf("[%03d]=<%c,%c>\r\n", j, tmpstr, tmpstr);
                               
                                szStar = 1;           //保存通配符位置

                                i = i + 1; //一次性跳过一对通配符 需要的是i=i+2 这里加1是因为for循环那里还有个i++

                        }
                       
                }

        }
        //printf("\r\n");
        return nBytes;
};

//CFind_Offset.h
#pragma once

#include <stdio.h>
#include <windows.h>
#include <psapi.h>
#include <tchar.h>
char* GetBjTime(IN OUT char*buf, size_t nBufSize);
typedef class _CFind_Offset
{
public:

static         HWNDGetHwnd();//获取目标窗口句柄
static        DWORD GetPID(); //获取目标PID
static        HANDLE GetProcessHandle();//获取目标进程句柄
staticUINT_PTR GetExeBase();//获取目标进程主模块基址
staticBOOLGetExeData(OUT PBYTE &pbuf,OUT size_t &nReadSize);
staticBOOLFindOffset(IN BYTE* buf, IN size_t bufSize, IN BYTE* 特征码, IN BYTE 特征码长度, OUT DWORD &nOffset);
staticINT_PTRGetBaseOfffset(IN INT_PTR 指令地址,IN INT_PTR 指令长度,IN INT_PTR 指令前缀长度);

staticINT_PTRGetBaseOfffset(const char*特征码, INT_PTR 特征码偏移, BYTE 指令长度, BYTE 指令前缀长度);
staticINT_PTRGetBaseOfffsetEx(IN const char*特征码, ININT_PTR 特征码偏移, INBYTE 指令长度, INBYTE 指令前缀长度);
staticINT_PTRMatchSearch(IN const char*特征码带通配符, ININT_PTR 特征码偏移, INBYTE 指令长度, INBYTE 指令前缀长度);       //

staticINT_PTRMatchSearch(IN const char *变量名,
        IN const char*特征码带通配符,
        ININT_PTR 特征码偏移,
        INBYTE 指令长度,
        INBYTE 指令前缀长度);       // CFind_Offset
staticvoid printfCmdAndFile(const char*buf);

}CFind_Offset;


//CFind_Offset.cpp

#include "CFind_Offset.h"

//buf 是目标进程的代码数据
//bufSize 代码段数据的大小
//特征码
//特征码长度
//nOffset返回找到的偏移       =目标进程特征地址-目标进程主模块地址
staticchar tmpbuf = { 0 };//根据文件大小设置本地的缓冲区 100MB

BOOLCFind_Offset::FindOffset(IN BYTE* buf, IN size_t bufSize,IN BYTE* 特征码,IN BYTE 特征码长度,OUT DWORD &nOffset)
{
                   for (size_t i=0;i<bufSize- 特征码长度;i++)
                   {
                           if (memcmp(buf + i, 特征码, 特征码长度) == 0)        //内存比较
                           {
                                   nOffset =(DWORD)i;
                                   return TRUE;
                                   break;
                           }
                   }
                   return FALSE;
};

INT_PTRCFind_Offset::GetBaseOfffset(IN INT_PTR 指令地址, IN INT_PTR 指令长度, IN INT_PTR 指令前缀长度)
{
        INT_PTR p1 = 指令地址/*Mir4G.exe*/ + 指令前缀长度;
        if ((p1+4) > sizeof(tmpbuf))
        {
                MessageBoxA(NULL, "错误的参数", "ERROR", 0);
                return 0;
        }
        else
        {
                //000000013F59223D   | 48 8B 0D EC D8 9A 05   | mov rcx,qword ptr ds:| Mir4G.exe+5E0FB30//13F130000+        5E0FB30
                //$-2C         | 48 8B 0D EC D8 9A 05   | mov rcx,qword ptr ds:| Mir4G.exe+5E0FB30                  mov rcx qword ptr[????]           EC D8 9A 05 //059AD8EC

                INT_PTR 偏移 = *(DWORD*)(tmpbuf+p1);
                //目标地址=指令地址+指令长度+偏移          
                //144F3FB30=000000013F59223D+7+059AD8EC                  
                //13F130000+        5E0FB30        = 13F130000+46223D+7+059AD8EC              //EXE基址=13F130000
                // exe基址+        5E0FB30        = exe基址+46223D+7+059AD8EC
                // exe基址+        5E0FB30        = exe基址+指令地址+7+059AD8EC
                // exe基址+        5E0FB30        = exe基址+指令地址+指令长度+偏移

                // 5E0FB30= 指令地址+指令长度+偏移

                INT_PTR 目标地址 = 指令地址 + 指令长度 + 偏移;
               
                return 目标地址;
        }
       
};
//只读取一次
BOOLCFind_Offset::GetExeData(OUT PBYTE &pbuf, OUT size_t &nReadSize)
{
       
        staticsize_t nsize = 0;       //用于保存实际读取的字节大小

        if (nsize)
        {
                nReadSize = nsize;
                pbuf = (PBYTE)tmpbuf;
                return TRUE;
        }
        //顺利的情况下 以下代码只会执行一次
        HANDLE hp = GetProcessHandle();          //获取目标进程句柄权限
        UINT_PTR exebase = GetExeBase(); //获取目标进程的 主模块基址
        BOOL br=ReadProcessMemory(hp, (PVOID)exebase, tmpbuf, sizeof(tmpbuf), &nsize);
        if (br == FALSE)
        {
                printf("hp=%p ErrorGetLastError()=%d line=%d\r\n", hp, GetLastError(),__LINE__);
                getchar();
        }
        else
        {
                nReadSize = nsize;
                pbuf =(BYTE*) tmpbuf;
               
        }

        return br;
};

HWNDCFind_Offset::GetHwnd()
{
        HWND h = FindWindowA("UnrealWindow", NULL); //"UnrealWindow"// "Mir4G" "Mir4G"
        if (h)
        {
                return h;
        }
        else
        {
                printf("Error line=%d FindWindowA ret NULL 游戏未打开 \r\n", __LINE__);
                getchar();
        }
        return 0;
};
DWORD CFind_Offset::GetPID()
{
        HWND h = GetHwnd();
        DWORD pid = 0;
        GetWindowThreadProcessId(h, &pid);

        return pid;
};

HANDLE CFind_Offset::GetProcessHandle()
{
        DWORD pid = GetPID();
        static HANDLE hp = OpenProcess(PROCESS_ALL_ACCESS, false, pid);//如失败,返回值为空,可调用GetLastError获得错误代码。
        if (hp==NULL )
        {
                printf("Error line=%d OpenProcess ret NULL GetLastError()=%d \r\n", __LINE__, GetLastError());
                getchar();
        }
        return hp;
};

UINT_PTR CFind_Offset::GetExeBase()
{
        //return(UINT_PTR) GetModuleHandleA(NULL);//代码已经注入到目标进程空间
        static        UINT_PTR exeBase64 = NULL;
        HMODULE hMods; //20*sizeof(HMODULE ) //160
        DWORD cbNeeded;
        unsigned int i;
        HANDLE 进程句柄 = GetProcessHandle();
        if (exeBase64) return exeBase64;
        // Get a list of all the modules in this process.
        BOOL br = EnumProcessModules(进程句柄, hMods, sizeof(hMods), &cbNeeded);
        if (br)
        {
                UINT32 模块数量 = cbNeeded / sizeof(HMODULE);
                for (i = 0; i < 模块数量; i++)
                {
                        TCHAR szModName = { 0 };
                  DWORD iret=        GetModuleFileNameEx(进程句柄, hMods, szModName, sizeof(szModName) / sizeof(TCHAR));
                       
                        // Get the full path to the module's file.
                        //printf("i=[%d],szModName=%s hMods[%d]=%p>>>\r\n",i, szModName,i,hMods);
                        if (iret)
                        {
                                //如果是 .exe模块 直接返回基址
                                if (strstr(szModName, ".exe")) //*.bin *.dat //Mir4G.exe
                                {
                                        exeBase64 = (UINT_PTR)hMods; //hMods
                                        printf("//主模块Mir4G.exe地址=%llXi=%d\r\n", exeBase64, i);
                                }
       
                        }
                }
        }
        else
        {
                /*
        〖0〗-操作成功完成。
  〖1〗-功能错误。
  〖2〗-系统找不到指定的文件。
  〖3〗-系统找不到指定的路径。
  〖4〗-系统无法打开文件。
  〖5〗-拒绝访问。
  〖6〗-句柄无效。
                */
                printf("Error EnumProcessModules line=%dGetLastError=%d 进程句柄=%p", __LINE__,GetLastError(), 进程句柄);
                getchar();
        }

        // Release the handle to the process.

        //CloseHandle(进程句柄);

        return exeBase64;
}







//CFind_Offset_GetBaseOfffset.cpp
#include "CFind_Offset.h"
#include "HexStrToBytes.h"
//buf 是目标进程的代码数据
//bufSize 代码段数据的大小
//特征码
//特征码长度
//nOffset返回找到的偏移       =目标进程特征地址-目标进程主模块地址
//staticchar tmpbuf = { 0 };//根据文件大小设置本地的缓冲区 100MB

INT_PTRCFind_Offset::GetBaseOfffsetEx(IN const char*特征码, ININT_PTR 特征码偏移, INBYTE 指令长度, INBYTE 指令前缀长度)
{
        OUT INT_PTR           nOffset = 0;
        BYTE   字节集 = { 0 };
        BYTE   通配符 = { 0 };//备用
        size_t 特征码长度 = strlen(特征码);
        if (特征码长度 > 128)
        {
                MessageBoxA(0, "最大支持128字节特征码长度", "ERROR", 0);
                return 0;
        }

        //16进制字符串转 字节集数组
        特征码长度 = HexStrToBytes(IN 特征码, OUT 字节集, IN 特征码长度);
        BYTE* exebuf = 0;
        size_t exebufsize = 0;
        GetExeData(exebuf, exebufsize);
        if (exebuf == NULL)
        {
                MessageBoxA(0, "未成功获取目标进程代码段", "ERROR", 0);
        }
        BYTE*pexebuf = (BYTE*)exebuf;
        for (size_t i = 0; i < exebufsize; i++)
        {
                if (memcmp(pexebuf + i, 字节集, 特征码长度) == 0)
                {
                        nOffset = i;
                        break;
                }
        }
        //找到了特征码位置
        if (nOffset)
        {
                INT_PTR 指令地址 = nOffset + 特征码偏移;
                DWORD *偏移 = (DWORD*)(pexebuf + 指令地址 + 指令前缀长度);

                nOffset = 指令地址 + 指令长度 + 偏移;
                printf("指令地址=%llX nOffset=%llX\r\n", 指令地址, nOffset);
        }
        return nOffset;
}

INT_PTRCFind_Offset::GetBaseOfffset(const char*特征码, INT_PTR 特征码偏移, BYTE 指令长度, BYTE 指令前缀长度)
{
        OUT INT_PTR           nOffset = 0;
        BYTE   字节集 = { 0 };
        //BYTE   通配符 = { 0 };//备用
        size_t 特征码长度 = strlen(特征码);
        if (特征码长度 > 128)
        {
                MessageBoxA(0, "最大支持128字节特征码长度", "ERROR", 0);
                return 0;
        }

        //16进制字符串转 字节集数组
        特征码长度=HexStrToBytes(IN 特征码, OUT 字节集, IN 特征码长度);
        BYTE* exebuf = 0;
        size_t exebufsize = 0;
        GetExeData(exebuf, exebufsize);
        if (exebuf==NULL)
        {
                MessageBoxA(0, "未成功获取目标进程代码段", "ERROR", 0);
        }
        BYTE*pexebuf = (BYTE*)exebuf;
    for (size_t i=0;i< exebufsize;i++)
    {
                if (memcmp(pexebuf + i, 字节集, 特征码长度) == 0)
                {
                        nOffset = i;
                        break;
               }
    }
        //找到了特征码位置
        if (nOffset)
        {
                INT_PTR 指令地址 = nOffset + 特征码偏移;
                DWORD *偏移 = (DWORD*) (pexebuf+指令地址 + 指令前缀长度);

                nOffset = 指令地址 + 指令长度 + 偏移;
                printf("指令地址=%llX nOffset=%llX\r\n", 指令地址, nOffset);
        }
        return nOffset;
};
//CFind_Offset_MatchSearch.cpp


#include "CFind_Offset.h"
#include "HexStrToBytes.h"

//相等时返回0
int MatchCmp(const BYTE* s1, const BYTE*s2,const BYTE* star1, size_t len)
{
#ifdef _DEBUG
        if (!s1 || !s2 || !star1)
        {
                MessageBoxA(0,"Error指针参数为NULL","MatchCmp", 0);
        }
#endif

        size_t i = 0;
        for (i = 0; i < len; i++)
        {
           if (star1 || (s1 == s2)) //是通配符               memcmp
           {   
               //printf("star1[%d]=%02X s1,s2<02X,%02X>\r\n", star1, s1, s2);
                   continue;

           }else
           {
                   break;
           }
        }

        //printf("i=%zd len=%zd\r\n",i,len);
    if (i==len)
    {
                return 0;        //相等
        }
        else
        {
                return(int)i+1; //不等
        }
       
}
INT_PTRCFind_Offset::MatchSearch(IN const char*特征码带通配符, ININT_PTR 特征码偏移, INBYTE 指令长度, INBYTE 指令前缀长度)
{
        UINT_PTR base = GetExeBase();
        PBYTE pexebuf = 0;
        size_t nSizeExe = 0;
        GetExeData(pexebuf, nSizeExe);

        // // CFind_Offset_MatchSearch
        INT_PTR nOffset = 0;
        {
                //char 特征码带通配符[] = "48 8B 15ZZ**??**FF 90 48080000 48 83 BF C8040000 00";          //11223355667788AAXX88                
                BYTE features;                      
                BYTE star1 = { 0 };                         
                size_t nsize1 = HexStrToBytesEx(特征码带通配符,OUT features, sizeof(features), OUT star1);
               

                if (nSizeExe&&nsize1)
                {
                        for (size_t i = 0; i < nSizeExe- nsize1; i++)
                        {           //int MatchCmp(const BYTE* s1, const BYTE*s2,const BYTE* star1, size_t len)
                                int iret = MatchCmp(pexebuf + i, features, star1, nsize1);
                                if (iret == 0)
                                {
                                        nOffset = i;
                                        break;
                                }
                        }
                }


        }



        //找到了特征码位置
        if (nOffset)
        {
                INT_PTR 指令地址 = nOffset + 特征码偏移;
                DWORD *偏移 = (DWORD*)(pexebuf + 指令地址 + 指令前缀长度);

                //printf("//nOffset=%zX 特征码偏移=%zX <%zX,%d,%X>=%zX\r\n", nOffset, 特征码偏移, 指令地址,指令长度 , 偏移
                //, 指令地址 + 指令长度 + 偏移);

                nOffset = (DWORD)(指令地址 + 指令长度 + 偏移);        //会存在溢出的情况
//#ifdef _DEBUG
//                printf("//%s> 搜索结果<%zX,%zX>\r\n", 特征码带通配符, base + nOffset, nOffset);
//                printf("//指令地址=<%zX,%zX> nOffset=<%zX,%zX>\r\n", base + 指令地址, 指令地址, base + nOffset, nOffset);
//#endif // _DEBUG
        }



        return nOffset;
}

intWriteToFile(const char* szLine)
{
        const char* sFilePath = "基址偏移.h";
        //printf("sFilePath=%s line=%d \n", sFilePath,__LINE__);
        //FileRename(sFilePath);

        FILE* fp = 0;
        fopen_s(&fp,sFilePath, "ab+"); //w+ 清新后写 a+ 在文件尾追加写
        if (fp == NULL)
        {
                return -1;
        }
        fwrite(szLine, strlen(szLine), 1, fp);
        fclose(fp);
        return 0;
}

void CFind_Offset::printfCmdAndFile(const char*buf)
{
        printf(buf);
        WriteToFile(buf);
};

INT_PTRCFind_Offset::MatchSearch(
        IN const char *变量名,
        IN const char*特征码带通配符,
        ININT_PTR 特征码偏移,
        INBYTE 指令长度,
        INBYTE 指令前缀长度)
{
       char buf;
       UINT_PTR exeBase=GetExeBase();
       INT_PTR nOffset = MatchSearch(特征码带通配符, 特征码偏移, 指令长度, 指令前缀长度);
       sprintf_s(buf,"const UINT_PTR %s =0x%zX; // %zX >%s<%zd,%d,%d>\r\n",
               变量名,
               nOffset,
               exeBase+nOffset,特征码带通配符 ,特征码偏移, 指令长度, 指令前缀长度);
       //写文件
       printf(buf);
       WriteToFile(buf);
       return nOffset;
}
//基址偏移.h

//#pragma once
const UINT_PTR CALL02_OFFSET_取任务对象 =F431D0; // 1401431D0 >488D8FE0020000488B01FF5030<31,5,1>
const UINT_PTR CALL01_RCX_OFFSET_取任务对象 =12072E0; // 1404072E0 >488D8FE0020000488B01FF5030<18,5,1>
const UINT_PTR CALL_OFFSET_明文包 =12FE530; // 1404FE530 >41B888130000488D542430488B4808<15,5,1>
const UINT_PTR CALL_RCX_OFFSET_明文包 =5D29FE8; // 144F29FE8 >41B888130000488D542430488B4808<-7,7,3>
const UINT_PTR CALL_OFFSET_背包物品使用 =1178980; // 140378980 >440FB68710030000488B93B0000000488BCBE8<18,5,1>
const UINT_PTR CALL_OFFSET_使用背包物品01 =9C7010; // 13FBC7010 >488BC8450FB6CD41B801000000488BD3E8<16,5,1>
const UINT_PTR CALL_RCX_OFFSET_使用背包物品01 =6E4400; // 13F8E4400 >488BC8450FB6CD41B801000000488BD3E8<-5,5,1>
const UINT_PTR CALL_OFFSET_选怪CALL01 =8FDA40; // 13FAFDA40 >0F28B424F0000000488B8338030000<-5,5,1>
const UINT_PTR CALL_OFFSET_选怪CALL02 =8E7BC0; // 13FAE7BC0 >0F28B424F0000000488B8338030000<-16,5,1>
const UINT_PTR CALL_OFFSET_取控件对象 =1D67F00; // 140F67F00 >4C8B4310488BD7488BC8488B5C24304883C4205F49FFE0<-5,5,1>
const UINT_PTR CALL_OFFSET_寻路 =A06A60; // 13FC06A60 >C6442428028944242CF20F10833C060000<60,5,1>
const UINT_PTR CALL_OFFSET_按键 =1DA30E0; // 140FA30E0 >33C04889BEF00100004889BEF8010000898611010000<48,7,3>
const UINT_PTR CALL_OFFSET01_采集 =6E4400; // 13F8E4400 >4488642428C7442420000000004533C941B001<-8,5,1>
const UINT_PTR CALL_OFFSET02_采集 =9AE9D0; // 13FBAE9D0 >4488642428C7442420000000004533C941B001<22,5,1>
const UINT_PTR OFFSET_怪物人物采集物对象ID数组 =5D2AF30; // 144F2AF30 >32C04D85C07408410FB68080060000<-7,7,3>
const UINT_PTR OFFSET_所有对象数组 =5E0FB30; // 14500FB30 >33C08B4008C1E81DA8010F85<-23,7,3>
const UINT_PTR OFFSET_人物属性对象A =5D29B18; // 144F29B18 >488B01FF50283D5E240000<17,7,3>
const UINT_PTR OFFSET_人物角色坐标基址 =5D2A540; // 144F2A540 > 48 8B 05 ********48 85 C074 **80 B8 88 03 00 00 0D<0,7,3>
const UINT_PTR OFFSET_NPC_ID_LIST =55A2CB0; // 1447A2CB0 >488D3CD04885FF0F84A5<-7,7,3>

//#pragma once
const UINT_PTR CALL02_OFFSET_取任务对象 =F431D0; // 1400431D0 >488D8FE0020000488B01FF5030<31,5,1>
const UINT_PTR CALL01_RCX_OFFSET_取任务对象 =12072E0; // 1403072E0 >488D8FE0020000488B01FF5030<18,5,1>
const UINT_PTR CALL_OFFSET_明文包 =12FE530; // 1403FE530 >41B888130000488D542430488B4808<15,5,1>
const UINT_PTR CALL_RCX_OFFSET_明文包 =5D29FE8; // 144E29FE8 >41B888130000488D542430488B4808<-7,7,3>
const UINT_PTR CALL_OFFSET_背包物品使用 =1178980; // 140278980 >440FB68710030000488B93B0000000488BCBE8<18,5,1>
const UINT_PTR CALL_OFFSET_使用背包物品01 =9C7010; // 13FAC7010 >488BC8450FB6CD41B801000000488BD3E8<16,5,1>
const UINT_PTR CALL_RCX_OFFSET_使用背包物品01 =6E4400; // 13F7E4400 >488BC8450FB6CD41B801000000488BD3E8<-5,5,1>
const UINT_PTR CALL_OFFSET_选怪CALL01 =8FDA40; // 13F9FDA40 >0F28B424F0000000488B8338030000<-5,5,1>
const UINT_PTR CALL_OFFSET_选怪CALL02 =8E7BC0; // 13F9E7BC0 >0F28B424F0000000488B8338030000<-16,5,1>
const UINT_PTR CALL_OFFSET_取控件对象 =1D67F00; // 140E67F00 >4C8B4310488BD7488BC8488B5C24304883C4205F49FFE0<-5,5,1>
const UINT_PTR CALL_OFFSET_寻路 =A06A60; // 13FB06A60 >C6442428028944242CF20F10833C060000<60,5,1>
const UINT_PTR CALL_OFFSET_按键 =1DA30E0; // 140EA30E0 >33C04889BEF00100004889BEF8010000898611010000<48,7,3>
const UINT_PTR CALL_OFFSET01_采集 =6E4400; // 13F7E4400 >4488642428C7442420000000004533C941B001<-8,5,1>
const UINT_PTR CALL_OFFSET02_采集 =9AE9D0; // 13FAAE9D0 >4488642428C7442420000000004533C941B001<22,5,1>
const UINT_PTR OFFSET_怪物人物采集物对象ID数组 =5D2AF30; // 144E2AF30 >32C04D85C07408410FB68080060000<-7,7,3>
const UINT_PTR OFFSET_所有对象数组 =5E0FB30; // 144F0FB30 >33C08B4008C1E81DA8010F85<-23,7,3>
const UINT_PTR OFFSET_人物属性对象A =5D29B18; // 144E29B18 >488B01FF50283D5E240000<17,7,3>
const UINT_PTR OFFSET_人物角色坐标基址 =5D2A540; // 144E2A540 > 48 8B 05 ********48 85 C074 **80 B8 88 03 00 00 0D<0,7,3>
const UINT_PTR OFFSET_NPC_ID_LIST =55A2CB0; // 1446A2CB0 >488D3CD04885FF0F84A5<-7,7,3>
//>>完成所有遍历


//OFFSET_所有对象数组.cpp
#include <windows.h>

/*
//#define OFFSET_所有对象数组   0x5DE7C70   // 49 8B C6 81 60 08 FF FF FF BF//向上找第一个地址
$-2E         | 7D 2C                  | jge mir4g.1403D2269               |
$-2C         | 48 8B 0D EC D8 9A 05   | mov rcx,qword ptr ds:| Mir4G.exe+5E0FB30                  mov rcx qword ptr[????]           EC D8 9A 05 //059AD8EC
$-25         | 99                     | cdq                               |
$-24         | 0F B7 D2               | movzx edx,dx                      |
$-21         | 03 C2                  | add eax,edx                     |
$-1F         | 44 8B C0               | mov r8d,eax                     |
$-1C         | 0F B7 C0               | movzx eax,ax                      |
$-19         | 2B C2                  | sub eax,edx                     |
$-17         | 41 C1 F8 10            | sar r8d,10                        |
$-13         | 48 98                  | cdqe                              |
$-11         | 49 63 D0               | movsxd rdx,r8d                  |
$-E          | 4C 8B 04 D1            | mov r8,qword ptr ds:   |
$-A          | 48 8D 0C 40            | lea rcx,qword ptr ds:|
$-6          | 49 8D 04 C8            | lea rax,qword ptr ds:   |
$-2          | EB 03                  | jmp mir4g.1403D226C               |
$ ==>      | 49 8B C6               | mov rax,r14                     |0x49,0x8B,0xC6,0x81,0x60,0x08,0xFF,0xFF,0xFF,0xBF
$+3          | 81 60 08 FF FF FF BF   | and dword ptr ds:,BFFFFFFF |
$+A          | 48 8D 15 E6 59 94 03   | lea rdx,qword ptr ds:| 143D17C60:L"ExtendedFacebook"

*/

#include <windows.h>
#include "CFind_Offset.h"
const INT_PTR 特征码偏移 = -0x2C;
const DWORD 指令长度 = 7;
const DWORD 指令前缀长度 = 3;

voidOFFSET_所有对象数组()
{

        INT_PTR exeBase = CFind_Offset::GetExeBase();
        BYTE* buf = NULL;
        size_t nSize = 0;
        CFind_Offset::GetExeData(buf, nSize);
        printf("ExeDataBuf=%p nSize=%zx \r\n", buf, nSize);
        //char 特征码2[] = { 0x49,0x8B,0xC6,0x81,0x60,0x08,0xFF,0xFF,0xFF,0xBF };
        BYTE 特征码[] = { 0x49,0x8B,0xC6,0x81,0x60,0x08,0xFF,0xFF,0xFF,0xBF };

        DWORD 特征码地址偏移 = 0;
        BOOL 是否找到 = CFind_Offset::FindOffset((BYTE*)buf, nSize, 特征码, sizeof(特征码), OUT 特征码地址偏移);
        if (是否找到)
        {
                printf("特征码长度=%zd找到的偏移=0x%X 游戏特征地址=0x%llX\r\n", sizeof(特征码), 特征码地址偏移, exeBase + 特征码地址偏移);
                {
                        INT_PTR 指令地址 = 特征码地址偏移 + 特征码偏移;
                        //指令地址 指令长度 指令前缀长度
                        INT_PTR 最终偏移=        CFind_Offset::GetBaseOfffset(指令地址, 指令长度, 指令前缀长度);
                        printf("OFFSET_所有对象数组->(最终偏移=%zx 真实地址=%zx)\r\n", 最终偏移, exeBase+ 最终偏移);
                }
        }
        else
        {
                printf("Error 相应特征码 未定位到 是否找到=%d\r\n", 是否找到);
                getchar();
        }

}

// "498BC6816008FFFFFFBF"                //0x49,0x8B,0xC6,0x81,0x60,0x08,0xFF,0xFF,0xFF,0xBF
//INT_PTRCFind_Offset::GetBaseOfffset(const char*特征码, INT_PTR 特征码偏移, BYTE 指令长度, BYTE 指令前缀长度)       
voidOFFSET_所有对象数组02()
{        //498BC6816008????FFBF
        INT_PTR exeBase = CFind_Offset::GetExeBase();
        INT_PTR 最终偏移 = CFind_Offset::GetBaseOfffset("498BC6816008FFFFFFBF", -0x2C, 7,3);
        printf("OFFSET_所有对象数组02->(最终偏移=%zx 真实地址=%zx)\r\n", 最终偏移, exeBase + 最终偏移);
}
//定位所有基址偏移.cpp
#include "CFind_Offset.h"
#include <time.h>

intWriteToFile(const char* szLine);

char* GetBjTime(IN OUT char*buf,size_t nBufSize)
{
        //GetSystemTime(&sysTm); //获取格林威治标准时间,与北京时间相差8小时
        time_t t = time(NULL);
        tm tp;
        localtime_s(&tp, &t);   // 北京时间
        sprintf_s(buf, nBufSize,"%d/%d/%d->", tp.tm_year + 1900, tp.tm_mon + 1, tp.tm_mday);
        sprintf_s(buf, nBufSize,"%s%d:%d:%d\n",buf,tp.tm_hour, tp.tm_min, tp.tm_sec);

        return buf;
}
int定位所有基址并输入到文件()
{
        {        const char strline0[] = "\r\n#pragma once\r\n";
        printf(strline0);
        WriteToFile(strline0);
        }
        {
        char sz特征码[] = "488D8FE0020000488B01FF5030"; //+0x1F
        CFind_Offset::MatchSearch("CALL02_OFFSET_取任务对象", sz特征码, 0x1F, 5, 1);
        CFind_Offset::MatchSearch("CALL01_RCX_OFFSET_取任务对象", sz特征码, 0x12, 5, 1);
        }
        //return 1;
        {
                char sz特征码[] = "41B888130000488D542430488B4808";
                {

                        char sz变量名[] = "CALL_OFFSET_明文包";
                        CFind_Offset::MatchSearch(sz变量名, sz特征码, 0x0F, 5, 1);

                }
                {

                        char sz变量名[] = "CALL_RCX_OFFSET_明文包";
                        CFind_Offset::MatchSearch(sz变量名, sz特征码, -0x7, 7, 3);

                }

        }
        //CALL_OFFSET_背包物品使用
        {
                char sz特征码[] = "440FB68710030000488B93B0000000488BCBE8"; // +0x12
                char sz变量名[] = "CALL_OFFSET_背包物品使用";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, 0x12, 5, 1);
        }
        {
                char sz特征码[] = "488BC8450FB6CD41B801000000488BD3E8"; // +0x10
                char sz变量名[] = "CALL_OFFSET_使用背包物品01";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, 0x10, 5, 1);
        }
        {
                char sz特征码[] = "488BC8450FB6CD41B801000000488BD3E8"; // -0x05
                char sz变量名[] = "CALL_RCX_OFFSET_使用背包物品01";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, -0x05, 5, 1);
        }
        //CALL_OFFSET_选怪
        {
                char sz特征码[] = "0F28B424F0000000488B8338030000"; //-5
                char sz变量名[] = "CALL_OFFSET_选怪CALL01";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, -0x05, 5, 1);
        }
        {
                char sz特征码[] = "0F28B424F0000000488B8338030000"; //-0x10
                char sz变量名[] = "CALL_OFFSET_选怪CALL02";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, -0x10, 5, 1);
        }
        //CALL_OFFSET_取控件对象
        {
                char sz特征码[] = "4C8B4310488BD7488BC8488B5C24304883C4205F49FFE0"; //-0x05
                char sz变量名[] = "CALL_OFFSET_取控件对象";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, -0x05, 5, 1);
        }
        //CALL_OFFSET_寻路
        {
                char sz特征码[] = "C6442428028944242CF20F10833C060000"; //+0x3C
                char sz变量名[] = "CALL_OFFSET_寻路";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, 0x3C, 5, 1);
        }
        //CALL_OFFSET_按键
        {
                char sz特征码[] = "33C04889BEF00100004889BEF8010000898611010000";
                char sz变量名[] = "CALL_OFFSET_按键";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, 0x30, 7, 3);
        }
        //CALL_OFFSET_采集
        {
                char sz特征码[] = "4488642428C7442420000000004533C941B001"; //-8
                char sz变量名[] = "CALL_OFFSET01_采集";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, -8, 5, 1);
        } {
                char sz特征码[] = "4488642428C7442420000000004533C941B001"; //+0x16
                char sz变量名[] = "CALL_OFFSET02_采集";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, 0x16, 5, 1);
        }
        //OFFSET_怪物人物采集物对象ID数组
        {
                char sz特征码[] = "32C04D85C07408410FB68080060000"; // -0x07
                char sz变量名[] = "OFFSET_怪物人物采集物对象ID数组";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, -7, 7, 3);
        }
        //OFFSET_所有对象数组
        {
                char sz特征码[] = "33C08B4008C1E81DA8010F85"; // -0x17
                char sz变量名[] = "OFFSET_所有对象数组";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, -0x17, 7, 3);
        }
        //OFFSET_人物属性对象A
        {
                char sz特征码[] = "488B01FF50283D5E240000"; //+11
                char sz变量名[] = "OFFSET_人物属性对象A";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, 0x11, 7, 3);
        }
        //OFFSET_人物角色坐标基址
        {
                char sz特征码[] = " 48 8B 05 ********48 85 C074 **80 B8 88 03 00 00 0D"; //+9
                char sz变量名[] = "OFFSET_人物角色坐标基址";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, 0, 7, 3);
        }

        {
                char sz特征码[] = "488D3CD04885FF0F84A5"; //-07
                char sz变量名[] = "OFFSET_NPC_ID_LIST";
                CFind_Offset::MatchSearch(sz变量名, sz特征码, -7, 7, 3);
        }
       
        {
                const char strline0[] = "//>>完成所有遍历-->>OK %t\r\n";
                printf(strline0);
                WriteToFile(strline0);

                char buf;
                GetBjTime(buf, sizeof(buf));

                CFind_Offset::printfCmdAndFile(buf);

        }


        return 1;
}



//main.cpp
// FindBaseOffset.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <time.h>
#include <iostream>
#include "CFind_Offset.h"
#include "HexStrToBytes.h"

char* GetBjTime(IN OUT char*buf, size_t nBufSize);

void 测试带通配符的特征转换()
{
        {
                char s1[] = "0x11,0x22,0x33,0x44,0x55,0xFF,0x1A,0x1b,0x1c,0x330x66";          //11223355667788AAXX88
                char s2[] = "ABCD112233**55??66";
                BYTE b1;
                BYTE b2;
                BYTE star1 = { 0 };
                BYTE star2 = { 0 };
                size_t nsize1 = HexStrToBytesEx(s1, b1, sizeof(b1), star1);
                size_t nsize2 = HexStrToBytesEx(s2, b2, sizeof(b2), star2);
                printf("nsize1=%zd,nsize2=%zd\r\n", nsize1, nsize2);
                getchar();
        }
        {
                char s1[] = "48 8B 15ZZ**??**FF 90 48080000 48 83 BF C8040000 00";          //11223355667788AAXX88
                char s2[] = "48 89 05**??****BE 3F00000080 78 08 000F84";
                BYTE b1;
                BYTE b2;
                BYTE star1 = { 0 };
                BYTE star2 = { 0 };
                size_t nsize1 = HexStrToBytesEx(s1, b1, sizeof(b1), star1);
                size_t nsize2 = HexStrToBytesEx(s2, b2, sizeof(b2), star2);
                printf("nsize1=%zd,nsize2=%zd\r\n", nsize1, nsize2);
                getchar();

        }

}
voidOFFSET_所有对象数组();
voidOFFSET_所有对象数组02();
int定位所有基址并输入到文件();
int main()
{

       定位所有基址并输入到文件();


        getchar();
}

页: [1]
查看完整版本: 游戏安全-用特征码定位基址偏移