2023年11月26日发(作者:)
⽹络游戏逆向分析-9-⾃动更新基址
⽹络游戏逆向分析-9-⾃动更新基址
基址在每次更新之后都会修改,这个⽐较⿇烦,不然每次都得重新找,⾮常消耗体⼒和时间。
⾃动更新基址原理
搜索游戏进程的内存,然后把硬编码依次和内存⾥⾯数据进⾏匹配,匹配到了之后就返回地址,地址附近就是基址了,通过加减来得到基址。
这⾥要扯到⼀些关于硬编码和机器指令的问题了,从整个计算机来看实际上要跑的东西在CPU上,只能识别0和1,但是为了后⾯的多种多样功
能,通过对0和1的组合来实现了机器指令,CPU可以直接通过这个0和1的指令来进⾏不同的操作,这个指令就叫做机器指令也可以说是硬编
码(也就是硬件上的编码)根据CPU的不同⽽不同,⽽我们常⽤的汇编指令,是唯⼀⼀个可以和机器指令⼀⼀对应的东西,因为如果直接⽤机器指
令对于开发来说⾮常⾮常⿇烦。所以我们常⽤的是汇编语⾔,⽽我们通过⼀些Ollydbg,xdbg这些东西,都是通过CPU⾥⽤的机器指令翻译成的汇
编指令,这个流程的⼯具叫做反汇编引擎,⽐如说:
这个ollydbg⾥⾯的1是内存地址,2是机器码的内容,3是汇编指令的内容。实际上运⾏的是内存地址⾥⾯存放的机器码,只不过这个调试器帮我们
翻译成了汇编指令,然后我们修改汇编指令的时候也帮我们修改了机器码这样⼦。
⾃动更新基址思路
所以这⾥我们可以参考机器码,我们把整个内存的机器码读出来,然后通过机器码⽐对得到对应的有关地址的机器码指令,然后转成字符串,读取
得到基址。
开始
这⾥我们随便⽤⼀段东西把:
需要注意的是,这⾥的机器码尽量多弄⼀下,这样来达到机器码是唯⼀的别的地⽅不能会重复。
逻辑都在代码⾥⾯了:
#include"UpdateAddr.h"
BOOL ByteToChar(BYTE* ByteArray, char* CharArray, int ByteLen)
{
//ByteArray是字节数组
//CharArray是字符数组
//ByteLen 是字节数组长度
for (int i = 0; i < ByteLen; i++)
{
wsprintfA(&CharArray[i * 2], "%02X", ByteArray[i]);
}
return TRUE;
}
BOOL CmpMachineStr(char* TempReadMachineCodeStr,char* MachineCodeStr, int MachineCodeStrLen)
{
// TempReadMachineCodeStr 读取的机器码字符串
// MachineCodeStr 特征机器码字符串
//MachineCodeStrLen特征机器码字符串长度
for (int i = 0; i < MachineCodeStrLen; i++)
{
if (TempReadMachineCodeStr[i] != MachineCodeStr[i])
return FALSE;
}
return TRUE;
}
BOOL ScanProcess(HANDLE HandleProcess, DWORD BeginAddr, DWORD EndAddr, char* MachineCodeStr, int MachineCodeStrLen)
{
//HandleProcess是进程的句柄,BeginAddr是起始内存地址,EndAddr是结束内存地址,MachineCode是机器码的字符串表达形式
//MachineCodeLen是机器码字符串长度。
int Flag = 0;
//每次读取0x1000个机器码的内容进⾏⽐较。
BYTE TempReadMachineCode[0x1000] = { 0 };
for (DWORD TempBeginAddr = BeginAddr; TempBeginAddr < EndAddr - 0x1000; TempBeginAddr += (0x1000 - MachineCodeStrLen))
{
//将机器码缓冲区⽤0填充
memset(TempReadMachineCode, 0x0, 0x1000);
//读0x1000个机器码到byte缓冲数组⾥。
BOOL RetReadProcessMemory = ReadProcessMemory(HandleProcess,(LPVOID)TempBeginAddr,TempReadMachineCode, 0x1000, NULL);
if (RetReadProcessMemory == 0)
continue;
//把byte字节数组转换成字符串
char TempReadMachineCodeStr[0x2001]={ 0 };
ByteToChar(TempReadMachineCode, TempReadMachineCodeStr, 0x1000);
//开始⽐较
for (int i = 0; i < 0x2001 - MachineCodeStrLen;i++)
{
BOOL ret = CmpMachineStr(TempReadMachineCodeStr + i,MachineCodeStr,MachineCodeStrLen);
if (ret == TRUE)
{
cout << "找到了地址为";
printf("%Xn", TempBeginAddr + i / 2);
Flag = 1;
}
}
}
if (Flag == 0)
cout << "未找到" << endl;
for (int i = 0; i < MachineCodeStrLen; i++)
{
if (MachineCodeStr[i] == '?')
continue;
if (TempReadMachineCodeStr[i] != MachineCodeStr[i])
return FALSE;
}
return TRUE;
}
完善2
添加⼀个⽂件来⽅便读取:
BOOL ReadCodeFile()
{
FILE* fp;
errno_t errnoFile = fopen_s(&fp, "", "r");
if (errnoFile != 0)
return FALSE;
fclose(fp);
delete[]TempStrBuff;
return TRUE;
}
完善5:
编写Main函数将内容通过地址+偏移,然后读取:
int main()
{
HANDLE HandleProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 1144);
if (!HandleProcess)
{
cout << "打开进程失败" << endl;
return 0;
}
vector
//读取⽂件中的字符串
ReadStrFile(AllFileStr);
//分割⽂件中的字符串
vector
split(AllFileStrToPartition, AllFileStr);
for (int i = 0; i < (); i++)
{
DWORD BaseAddr = 0;
DWORD DataBaseAddr = 0;
DWORD Context = 0;
顺带说⼀句,⽹游逆向⽆限期延迟更新了,因为这个游戏⽐较⽼了研究起来也没有价值,还有个原因是技术就这么写,对发包函数的处理,以及搜
索数据的处理,然后往上找基址。这个只能在应⽤层玩,⼀些更⾼难度的⽐如反调试,加壳脱壳,Windows内核就可以轻松解决掉。所以后⾯准备


发布评论