基址分为固定基址,与随机基址
一般的EXE里 数据段和代码段 相关的地址是固定的
通常DLL里找到的基址都是动态的
常见的基址 形式
一、固定基址
先说固定的基址 举个例子 某个游戏的角色相关的几个地址:
0x400056 //int 血量
0x40006c //float x坐标
0x400070 //float y坐标
或者
[0x458800AC]+0x180 //血量
[0x458800AC]+0x784 //float x坐标
[0x458800AC]+0x788 //float y坐标
//如果上边的地址 在游戏 重新进入后 依然可以通过这个地址读取到正确的值 一般来说这个基址就是固定类型的
二、另一种 动态基址
如果是动态地址 一般是编译器里 随机基址:是
像这种用CE分析出来的基址 一般是这种形式
game.exe+0x780C //血量
game.exe+0x7810 //x坐标
game.exe+0x7814 //y坐标
多级指针形式例子
[game.exe+0x880C]+0x78 //int 血量
[game.exe+0x880C]+0x18c //坐标x float
[game.exe+0x880C]+0x190 //坐标y float
//接下来说说 读取基址的办法
//读取内存数据一般常见的有2种方式
方式1:跨进程读写内存,一般用 ReadProcessMemory来封装接口
int R4INT(UINT_PTR pbase)
{
int dwRet=0;
SIZE_T byReadSize=0;
int ir=ReadProcessMemory(游戏进程句柄,(PVOID)pbase,&dwRet,sizeof(UINT_PTR),&byReadSize);
return dwRet;
}
float R4F(UINT_PTR pbase)
{
float dwRet=0;
SIZE_T byReadSize=0;
int ir=ReadProcessMemory(游戏进程句柄,(PVOID)pbase,&dwRet,sizeof(UINT_PTR),&byReadSize);
return dwRet;
}
方式2: 本地进程读写内存接口,一般可以用指针 如 *(int*),或者*(float*)
例:
int R4INT(UINT_PTR pbase)
{
return *(int*)pbase;
}
float R4F(UINT_PTR pbase)
{
return *(float*)pbase;
}
//读取基址偏移例子:
game.exe+0x780C //血量 R4INT((UINT_PTR)GetModuleHandle("game.exe")+0x780C);
game.exe+0x7810 //x坐标 R4F((UINT_PTR)GetModuleHandle("game.exe")+0x7810);
game.exe+0x7814 //y坐标 R4F((UINT_PTR)GetModuleHandle("game.exe")+0x7814);
[game.exe+0x880C]+0x78 //int 血量 R4INT(R4INT((UINT_PTR)GetModuleHandle("game.exe")+0x880C)+0x78);
[game.exe+0x880C]+0x18c //坐标x float R4F(R4INT((UINT_PTR)GetModuleHandle("game.exe")+0x880C)+0x18c);
[game.exe+0x880C]+0x190 //坐标y float R4F(R4INT((UINT_PTR)GetModuleHandle("game.exe")+0x880C)+0x18c);
[0x458800AC]+0x180 //血量 R4INT(R4INT(0x458800AC)+0x180);
[0x458800AC]+0x784 //float x坐标 R4F(R4INT(0x458800AC)+0x784);
[0x458800AC]+0x788 //float y坐标 R4F(R4INT(0x458800AC)+0x788);
0x400056 //int 血量 R4INT(0x400056)
0x40006c //float x坐标 R4F(0x40006c)
0x400070 //float y坐标 R4F(0x400070)