游戏安全-用特征码定位基址偏移
BytesToHexStr.hBytesToHexStr.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]