追逐自己的梦想----------辅助制作第十五课:实现动态更新基址

最近刚开学,事情很多,所以博客也有很久没有更新了,很久没有写博客,好像心态也变了


由于游戏更新,我们不得不去更新游戏的基址,如果每次都手动去找基址,那肯定是相当麻烦的,所以我们要做的就是利用编程来实现基址的动态更新。


需要写的函数:

HexStrCmp(IN const char* szpHexStr1 , IN const char* szpHexStr1);

ScanFeatureCode();等一系列函数。

然后再实现通配符支持就可以实现基址的自动更新了。


下面直接给出源码:

#pragma once
#include<Windows.h>

void HexStrToX(IN OUT CHAR* szpHexbuf);//通配符的支持

DWORD BytesToHexStr(IN BYTE* nbData, DWORD nbDataSize, OUT char* szpHexBuf); //字节集转十六进制

BOOL HexStrCmp(IN const char*Hexstr1, IN const char* Hexstr2);// 十六进制字符串比较

char IsLowToBigCase(char c);//如果c是小写字母则返回大写字母

BOOL HexStrToBigCase(IN OUT char* szHexStr); //将16进制字符串转化为大写

BOOL CharToHex(OUT char* szpHexbuf, BYTE c);//将字符转化为十六进制

DWORD ScanFeatureCode(HANDLE hProcess,
	IN OUT char* szpFeatureCode,
	DWORD ndStartAddress = 00400000,
	DWORD ndEndAddress  = 0x7FFFFFFF); //扫描特征码的函数

void OneKeyUpdateBaseAddr(HANDLE hProcess); //一键更新基址





#include "stdafx.h"
#include "ScanFeatureCode.h"
#include<stdio.h>

char IsLowToBigCase(char c)//如果c是小写字母则返回大写字母
{
	if (c >= 'a' && c <= 'z'){
		//转化为大写字母
		return c = c + 'A' - 'a';
	}
	return c;
}


BOOL HexStrToBigCase(IN OUT char* szHexStr) //将16进制字符串转化为大写
{
	DWORD ndStrlen = strlen(szHexStr);

	for (DWORD i = 0; i < ndStrlen; i++){
		szHexStr[i] = IsLowToBigCase(szHexStr[i]);
	}
	return TRUE;
}
DWORD BytesToHexStr(IN BYTE* nbData, DWORD nbDataSize, OUT char* szpHexBuf) //字节集转十六进制
{
	//1 --- 01
	for (DWORD i = 0; i < nbDataSize; i++){
		//sprintf_s(&szpHexBuf[i * 2], 3, "%02X", nbData[i]);
		CharToHex(&szpHexBuf[i * 2], nbData[i]);
	}

	return TRUE;
}

BOOL HexStrCmp(IN const char*Hexstr1, IN const char* Hexstr2)// 十六进制字符串比较
{
	DWORD ndHexlen1 = strlen(Hexstr1);
	DWORD ndHexlen2 = strlen(Hexstr2);
	if (ndHexlen1 > ndHexlen2)
		ndHexlen1 = ndHexlen2;

	for (DWORD i = 0; i < ndHexlen1; i++){
		if (Hexstr1[i] == 'X' || Hexstr2[i] == 'X')
			continue;
		if (Hexstr1[i] == Hexstr2[i])
			continue;

		return FALSE;
	}

	return TRUE;
}


#define PAGESIZE 0x1024 //每次读取的大小
DWORD ScanFeatureCode(HANDLE hProcess,
	IN OUT char* szpFeatureCode,
	DWORD ndStartAddress,
	DWORD ndEndAddress) //扫描特征码的函数
{
	//支持通配符
	HexStrToX(szpFeatureCode);
	//特征码如果存在小写字母,则转化为大写
	HexStrToBigCase(szpFeatureCode);
	DWORD ndLenHexCode = strlen(szpFeatureCode); //0xaF 占用两个字节  所以到除2才是16进制的长度
	BYTE *nbDataBuf = new BYTE[PAGESIZE + ndLenHexCode / 2 + 2];
	DWORD RealSize = 0;//实际读取的缓冲区的大小
	for (DWORD ndCurAddr = ndStartAddress; ndCurAddr < ndEndAddress - ndLenHexCode / 2; ndCurAddr += PAGESIZE){
		ReadProcessMemory(hProcess, (LPVOID)ndCurAddr, (LPVOID)nbDataBuf, PAGESIZE + ndLenHexCode / 2 + 2, &RealSize);
		//将nbDataBuf逐字节的比较
		for (DWORD i = 0; i < PAGESIZE; i++){
			char szpTempHex[256] = "";
			BytesToHexStr(&nbDataBuf[i], ndLenHexCode/2, szpTempHex);
			if (HexStrCmp(szpTempHex, szpFeatureCode) != FALSE){
				return ndCurAddr + i;
			}
		}
	}

	return NULL;
}

BOOL CharToHex(OUT char* szpHexbuf, BYTE c)//将字符转化为十六进制
{
	BYTE bLow = 0;
	BYTE bHigh = 0;
	bLow = c % 16; //低位
	bHigh = c / 16; //高位

	if (bHigh > 9){
		szpHexbuf[0] = 'A' + bHigh - 10;
	}
	else{
		szpHexbuf[0] = '0' + bHigh;
	}

	if (bLow > 9){
		szpHexbuf[1] = 'A' + bLow - 10;
	}
	else{
		szpHexbuf[1] = '0' + bLow;
	}
	szpHexbuf[2] = '\0';

	return TRUE;
}


BOOL IsHexStr(char c){ //判断字符是否是十六进制字符串

	if (c >= '0' && c <= '9')
		return TRUE;
	else if (c >= 'a' && c <= 'z')
		return TRUE;
	else if (c >= 'A' && c <= 'Z')
		return TRUE;
	else
		return FALSE;

}

void HexStrToX(IN OUT CHAR* szpHexbuf)//通配符的支持
{
	DWORD ndStrlen = strlen(szpHexbuf);
	for (DWORD i = 0; i < ndStrlen; i++){
		if (IsHexStr(szpHexbuf[i]) == FALSE)
			szpHexbuf[i] = 'X';
	}

	return;
}


DWORD  ReadBaseAddr(HANDLE hProcess , DWORD ndCurAddr , DWORD ndSize  ){
	DWORD ndTemp = NULL;
	ReadProcessMemory(hProcess, (LPVOID)ndCurAddr, &ndTemp, ndSize, NULL);
	return ndTemp; 
}


void OneKeyUpdateBaseAddr(HANDLE hProcess) //一键更新基址
{
	DWORD ndCurAddr = NULL;
	DWORD ndBaseAddr = NULL;

	//人物属性
	char szpFeatureCode[256] = "C745FCFFFFFFFF8D47D0B9";
	ndCurAddr = ScanFeatureCode(hProcess, szpFeatureCode);
	ndBaseAddr= ReadBaseAddr(hProcess, ndCurAddr + 0xb,  4);
	printf("#define Base_RoleProperty 0x%X //人物属性基址 \n", ndBaseAddr);


	//背包基址A1********8B8498100400008BB0C40C00000BB0C80C0000
	strcpy_s(szpFeatureCode,"A1********8B8498100400008BB0C40C00000BB0C80C0000");
	ndCurAddr = ScanFeatureCode(hProcess, szpFeatureCode);
	ndBaseAddr = ReadBaseAddr(hProcess, ndCurAddr+1, 4);
	printf("#define Base_BackPacketList  0x%X //背包列表基址 \n", ndBaseAddr);

	//背包CALL 8B87081600008B8FD01B00005350518BCFE8
	strcpy_s(szpFeatureCode, "8B87081600008B8FD01B00005350518BCFE8");
	ndCurAddr = ScanFeatureCode(hProcess, szpFeatureCode);
	ndBaseAddr = ReadBaseAddr(hProcess, ndCurAddr+ 18, 4);
	ndBaseAddr = ndBaseAddr + ndCurAddr + 18 + 4;
	printf("#define Base_BackPacketCall 0x%X //背包物品使用call \n", ndBaseAddr);


	return;
}


以上代码就完成了对基址更新,其他的就在mian函数中调用这个接口就可以了,具体代码就不给出了




程主要以口袋西游为例,学习一个网络游戏是怎么通过游戏服务器与玩家客户端进行通信交互的,通过OD,CE等工具对游戏进行调试,找到各个数据基址(例如角色基址,背包基址等),找出游戏里面的功能CALL(例如寻路CALL,打坐CALL等)及参数分析,并且编码实现功能。本程可以带领你游戏逆向入门可以学会 CE,OD,找游戏基址,功能CALL等实现变态功能可以更深入的理解从高级语言到汇编语言的一个对应过程可以学会 逆向软件  外挂与反外挂 破解防破解  游戏安全的基础知识可以为以后的及逆向高级程 打下良好的基础可以自己分析游戏数据,用C语言实现游戏外挂功能等重点:  本套程的重点就是带领大家分析游戏数据,毫不客气的说,各位学完此套程对分析游戏数据这块会有一个质的飞跃。程目录  01.程简介及功能演示  02.CE找人物基址及人物属性偏移  03.OD找人物基址及人物属性偏移  04.创建MFC DLL项目  05.代码实现输出人物信息  06.发包函数概述  07.怎么看待重写的发包函数  08.普通发包与线程发包  09.找打坐CALL及参数分析  10.代码实现打坐CALL  11.喊话CALL及参数分析  12.代码实现喊话CALL  13.找寻路CALL及参数分析  14.代码编写寻路CALL  15.穿装备CALL及参数分析  16.代码实现穿装备CALL  17.NPC对话CALL  18.代码实现NPC对话CALL  19.唤出宠物  20.宠物合体  21.收回宠物  22.取下宠物
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值