免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
本次游戏没法给
内容参考于:微尘网络安全
本人写的内容纯属胡编乱造,全都是合成造假,仅仅只是为了娱乐,请不要盲目相信。
工具下载:
链接:https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd=6tw3
提取码:6tw3
复制这段内容后打开百度网盘手机App,操作更方便哦
上一个内容:29.第二阶段x86游戏实战2-遍历周围-花指令与二叉树数据结构(有如何阅读vm代码混淆代码)
上一个内容里找到了附近npc列表,这个列表采用二叉树数据结构存放的,本次就来使用C++遍历这个二叉树
本次要做的事情,通过C++代码把二叉树的数据全部放到列表里,也就是把二叉树的数据改成下图的样子一次排序,排序的顺序以npc和玩家角色的距离来搞,离得近就排前面离得远就排后面
在上一个内容里分析遍历二叉树的那块写的是0是非当前选中怪物1是当前选中怪物,这不怎么准确,应该说循坏结束条件是不等于0的时候,而不是0是非当前1或其它是当前选择,这个0它仅仅是一个结束循环的条件
现在得到的东西,0x74EFA4是通过偏移得到的上一个内容里的二叉树基址
[[[[[[0x74EFA4]+0x54]+0x4]+0x14]+0x148]+0x10]+0x8 血量 [[[[[[0x74EFA4]+0x54]+0x4]+0x14]+0x148]+0x10]+0x2C名字 [[[[0x74EFA4]+0x54]+0x4]+0x14] npc对象地址 [[[[0x74EFA4]+0x54]+0x4]+0x14]+0x3C x坐标 [[[[0x74EFA4]+0x54]+0x4]+0x14]+0x40 z坐标(高度) [[[[0x74EFA4]+0x54]+0x4]+0x14]+0x44 y坐标 [[[0x74EFA4]+0x54]+0x4] 二叉树第一个数据
然后上面的数据怎样找的,首先使用 [[[0x74EFA4]+0x54]+0x4] 得到第一个数据,[[[0x74EFA4]+0x54]+0x4]这个公式是通过上一个内容分析遍历二叉树的代码得到的,然后使用 dd [[[0x74EFA4]+0x54]+0x4]如下图内存区域
然后偏移0x14位置是对象,也就是下图红框位置
然后数据窗口中跟随过去
跟随之后
然后偏移 0x3C、0x40、0x44位置是坐标,使用浮点数查看
如下图,是坐标数据,为了验证可以在游戏总走到下图红框所示的坐标,看看哪里是否有npc,这里走过去看了是有一个怪物的
然后下一个偏移是找名字首先是0x148,首先把内存区域再切换为地址
找到0x148位置进行数据窗口跟随
跟随之后
然后是偏移0x10位置,然后在0x10位置继续数据窗口跟随
跟随之后,使用ASCII数据地址显示内存
如下图可以看到名字了,到这如果找数据就结束了,也就是一个观察数据,怎样就确定某某偏移就是某数据了就是平感觉,就感觉它像,这种感觉分析多了就会有了
为了一个功能接下来要找一下我们角色的对象基址,使用名字、血量等这种属性是无法找到人物角色基址的,我们人物的数据也在上方二叉树里,所以要通过把二叉树遍历出来,然后把名字和对象内存地址打印出来,然后复制内存地址到CE里搜,如下图
这里是通过使用OD对 010F559C 地址下硬件访问断点追到的人物角色基址的,最终得到的公式[0x766A8C]+0xC,只按了一次CTRL+F9就来到下图位置了,所以不详细写过程了
它的偏移,0x5A6A8C
C++代码与逆向代码对应关系
首先是第一个数据
取左右两边的数据
使用递归循环获取二叉树全部数据,递归循环就是函数自己调用自己,如下图
新加遍历周围按钮
CM.cpp文件的修改 :新加遍历周围按钮点击事件处理函数
// CM.cpp: 实现文件
//
#include "pch.h"
#include "tl.h"
#include "CM.h"
#include "afxdialogex.h"
// CM 对话框
IMPLEMENT_DYNAMIC(CM, CDialogEx)
CM::CM(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_DIALOG1, pParent)
, edi_x(_T(""))
{
}
CM::~CM()
{
}
void CM::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, edi_x);
DDX_Text(pDX, IDC_EDIT2, edi_y);
}
BEGIN_MESSAGE_MAP(CM, CDialogEx)
ON_BN_CLICKED(IDC_BUTTON1, &CM::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &CM::OnBnClickedButton2)
ON_BN_CLICKED(IDC_BUTTON3, &CM::OnBnClickedButton3)
ON_BN_CLICKED(IDC_BUTTON4, &CM::OnBnClickedButton4)
END_MESSAGE_MAP()
// CM 消息处理程序
void CM::OnBnClickedButton1()
{
R_人物属性 a;
a.初始化();
Call_输出调试信息("人物信息:人物状态%d",a.状态);
}
void CM::OnBnClickedButton2()
{
UpdateData(TRUE);
CString str1 = edi_x;
CString str2 = edi_y;
// strtol((const char*)CW2A(str1.GetBuffer(0)), NULL, 10);把字符串转成int数字类型
int x = strtol((const char*)CW2A(str1.GetBuffer(0)), NULL, 10);
int y = strtol((const char*)CW2A(str2.GetBuffer(0)), NULL, 10);
Call_xunlu(x, y);
}
void CM::OnBnClickedButton3()
{
R_遍历背包 a;
a.遍历背包();// 遍历背包
CString str;
str.Format(L"a数量 %d", a.d数量);
AfxMessageBox(str);
for (int i = 0; i < a.d数量; i++)
{
Call_输出调试信息("tl怀旧 背包信息 dwObject -------------%X----------------\r\n", a.列表[i].dwObject);
Call_输出调试信息("tl怀旧 背包信息 名字:%s\r\n", a.列表[i].pName.c_str());
Call_输出调试信息("tl怀旧 背包信息 使用等级:%d\r\n", a.列表[i].p使用等级);
Call_输出调试信息("tl怀旧 背包信息 简介:%s\r\n", a.列表[i].简介.c_str());
Call_输出调试信息("tl怀旧 背包信息 数量:%d\r\n", a.列表[i].p数量);
}
}
void CM::OnBnClickedButton4()
{
// TODO: 在此添加控件通知处理程序代码
R_周围遍历 a;
a.遍历最近怪物();// 让怪物重新排列
for (int i = 0; i < a.d数量; i++)
{
Call_输出调试信息("人物信息:---------------------%s-----%x---------------------", a.列表[i].pName, a.列表[i].dwObject);
Call_输出调试信息("人物信息:人物id:%x", a.列表[i].id);
Call_输出调试信息("人物信息:人物X:%f 人物Y:%f", a.列表[i].fX, a.列表[i].fY);
Call_输出调试信息("人物信息:人物类型:%x 人物距离:%f", a.列表[i].PType, a.列表[i].距离);
}
}
结构.cpp文件的修改:新加 遍历最近怪物函数、周围二叉数函数、AsmGetMonsterData函数
#include "pch.h"
#include "结构.h"
DWORD R_rwjz = *(DWORD*)((DWORD)GetModuleHandleA("Game.exe") + 0x5A6A8C);//人物基地址
void R_人物属性::初始化()
{
__try {
/**
GetModuleHandleA("Game.exe")返回Game.exe模块的模块基址
*/
DWORD 状态基址 = (DWORD)GetModuleHandleA("Game.exe") + 0x59EF6C;
/**
(DWORD*)状态基址 的意思是把 状态基址 的值当成内存地址
*(DWORD*)状态基址 意思把内存地址里的值取出来
*/
DWORD 状态偏移 = *(DWORD*)状态基址 + 0x60;
DWORD 状态偏移1 = *(DWORD*)状态偏移 + 0x14C;
状态 = *(DWORD*)状态偏移1;
DWORD RW偏移 = ReadDword(R_rwjz + 0xc);
M_通用包 = ReadWord(RW偏移 + 0x2c);
M_走路包 = ReadWord(RW偏移 + 0x30);
状态 = ReadDword(状态偏移1);
fX = ReadFloat(RW偏移 + 0x3C);
fY = ReadFloat(RW偏移 + 0x44);
pName = "";
pName = ReadStr((char*)(ReadDword(ReadDword(RW偏移 + 0x148) + 0x10) + 0x2c));
血量 = ReadFloat(ReadDword(ReadDword(RW偏移 + 0x148) + 0x10) + 0x8);
}
__except (1) {
Call_输出调试信息("读物人物信息异常\r\n");
}
}
void R_遍历背包::遍历背包()
{
try {
DWORD s = 0;
//DWORD JZ = (DWORD)GetModuleHandleA("Game.exe") + 0x59F458;
DWORD JZ = (DWORD)GetModuleHandleA("Game.exe") + 0x59F490;
DWORD JZpy = ReadDword(ReadDword(JZ) + 0x181C4);
背包[0].背包数量 = ReadDword(ReadDword(JZ) + 0x181C4 + 0x14); // 道具背包数量
背包[1].背包数量 = ReadDword(ReadDword(JZ) + 0x181C4 + 0x15); // 材料背包数量
背包[2].背包数量 = ReadDword(ReadDword(JZ) + 0x181C4 + 0x16);// 任务背包数量
for (int i = 0; i < 3; i++)
{
CString str;
str.Format(L"数量2:%d %d %d", 背包[0].背包数量, 背包[1].背包数量, 背包[2].背包数量);
//AfxMessageBox(str);
for (int j = 0; j < 背包[i].背包数量; j++)
{
if (i == 0) {
s = j;
}
if (i == 1)
s = j + 背包[0].背包数量;
if (i == 2)
s = j + 背包[0].背包数量 + 背包[1].背包数量;
列表[s].dwObject = ReadDword(JZpy + j * 4);
if (列表[s].dwObject != 0) {
DWORD 值 = ReadDword(列表[s].dwObject + 0x2C);
列表[s].pName = ReadStr((char*)ReadDword(值 + 0x18));
列表[s].p使用等级 = ReadDword(值 + 0x20);
列表[s].简介 = ReadStr((char*)ReadDword(值 + 0x1c));;
列表[s].p数量 = (BYTE)ReadByte(ReadDword(列表[s].dwObject + 0x14) + 0x58);
}
else
{
列表[s].pName = "";
列表[s].p数量 = 0;
列表[s].简介 = "";
列表[s].p使用等级 = 0;
}
d数量++;
}
JZpy = JZpy + 0x80;// 扩展背包大小,写死0x80,扩展背包大小0x80/0x47=十进制的32
}
}
catch (...)
{
Call_输出调试信息("tlhj 返回背包信息异常\r\n");
}
}
void R_周围遍历::周围二叉数(DWORD Tree, R_人物属性 rw)
{
try
{
int ss = 0;
ss++;
if (ss < 5000)
{
BYTE data = -1;
data = ReadByte(Tree + 0xd);
DWORD 左子树 = ReadDword(Tree + 0x0);
DWORD 右子树 = ReadDword(Tree + 0x8);
if (data == 0)
{
列表[d数量].dwObject = ReadDword(Tree + 0x14);
列表[d数量].id = ReadDword(列表[d数量].dwObject + 0x2c);
列表[d数量].fX = ReadFloat(列表[d数量].dwObject + 0x3c);//坐标X
列表[d数量].fY = ReadFloat(列表[d数量].dwObject + 0x44);
列表[d数量].PType = ReadByte(ReadDword(列表[d数量].dwObject + 0x24) + 0x14);
if ((int)列表[d数量].fX == 100 && (int)列表[d数量].fY == 100)
{
}
else
{
// 计算最近距离的公式,所有游戏通用,看不懂死记住就行,小学的公式
列表[d数量].距离 = sqrt((rw.fX - 列表[d数量].fX)*(rw.fX - 列表[d数量].fX) + (rw.fY - 列表[d数量].fY)*(rw.fY - 列表[d数量].fY));
列表[d数量].pName = "";
//Call_输出调试信息("-----r2-------%x", AA);
列表[d数量].pName = ReadStr((char *)(ReadDword(ReadDword(列表[d数量].dwObject + 0x148) + 0x10) + 0x2c));
列表[d数量].血量 = ReadFloat(ReadDword(ReadDword(列表[d数量].dwObject + 0x148) + 0x10) + 0x8);
d数量++;
}
周围二叉数(左子树, rw);
周围二叉数(右子树, rw);
}
}
}
catch (...)
{
Call_输出调试信息("tlhj 遍历二叉数异常\r\n");
}
}
DWORD R_blzw = *(DWORD*)((DWORD)GetModuleHandleA("Game.exe") + 0x59EFA4);
void R_周围遍历::AsmGetMonsterData()
{
Sleep(10);
try
{
DWORD dwTreeBase = *(DWORD*)(R_blzw + 0x54);
dwTreeBase = *(DWORD*)(dwTreeBase + 0x4);
DWORD dwEnvTreeBase = dwTreeBase;
Call_输出调试信息("-----q-------");
if (dwEnvTreeBase) {
R_人物属性 rw;
rw.初始化();
d数量 = 0;
周围二叉数(dwEnvTreeBase, rw);//遍历二叉树
}//正确取到二叉树基址
}
catch (...)
{
Call_输出调试信息("tlhj 得到二叉数根结点异常\r\n");
}
}
R_人物属性 R_周围遍历::遍历最近怪物()
{
this->AsmGetMonsterData();
R_人物属性 a;
R_人物属性 人物;
人物.初始化();
try
{
if (this->d数量 > 0)
{
for (int i = 0; i < (int)this->d数量; i++)
{
for (int j = i + 1; j < (int)this->d数量; j++)
{
if (this->列表[i].距离 > this->列表[j].距离)
{
a = this->列表[j];
this->列表[j] = this->列表[i];
this->列表[i] = a;
}
}
}
if (d数量 >= 1)
{
return this->列表[d数量 - 2];
}
else
{
return 人物;
}
}
return 人物;
}
catch (...)
{
Call_输出调试信息("tlhj 返回最近怪物信息异常\r\n");
}
}
结构.h文件的修改:新加 R_周围遍历结构体,修改了 R_人物属性结构体
#pragma once
#include <string>
#define BLZW (DWORD)GetModuleHandleA("Game.exe") + 0x59EFA4//遍历周围 和人物状态同一个
using namespace std;
struct R_人物属性
{
DWORD 状态;
FLOAT 血量;
DWORD 最大血量;
FLOAT fX;
FLOAT fY;
DWORD id;
DWORD dwObject;
DWORD PType;
DWORD M_走路包;
FLOAT 距离;
DWORD M_通用包;
PCHAR pName = "";
void 初始化();
};
struct R_背包属性 {
DWORD dwObject;
string pName;
BYTE p数量;
string 简介;
DWORD p使用等级;
};
struct R_背包类
{
BYTE 背包数量 = 0;
};
struct R_遍历背包 {
R_背包类 背包[0x3];
R_背包属性 列表[0x100];
DWORD d数量 = 0;
void 遍历背包();
};
struct 坐标 {
FLOAT x;
FLOAT y;
};
struct R_周围遍历
{
R_人物属性 列表[0x100];
DWORD d数量 = 0;
void 周围二叉数(DWORD Tree, R_人物属性 dw);
void AsmGetMonsterData();
R_人物属性 遍历最近怪物();
};
上方的代码不全,只有手写的代码
完整代码:
链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg?pwd=q9n5
提取码:q9n5
复制这段内容后打开百度网盘手机App,操作更方便哦