追逐自己的梦想----------辅助制作第九课:分析怪物列表及怪物属性的封装等
来源:互联网 发布:淘宝摄影服务招商 编辑:程序博客网 时间:2024/05/16 17:20
本节课中我们要对怪物列表以及怪物列表属性进行分析
首先我们选中一只怪,然后攻击怪物改变血量来找到怪物血量的地址,然后通过它找到怪物列表的基址
t通过ce中的跟随访问了这个地址的代码,得到如下地址
可能的基址316B6208
+5b4 怪物血量
dc [45fb988 + 4*7]+320
+314 是否活着 活着为1
+5B4 血量
+5b8 怪物等级
+1018 X
+1020 Y
+1024 X
+102c Y
//基址的内存单元代码
007F13DE FFD0 CALL EAX
007F13E0 83F8 01 CMP EAX,0x1
007F13E3 7F 16 JG SHORT Client.007F13FB
007F13E5 A1 A8F21E03 MOV EAX,DWORD PTR DS:[0x31EF2A8]
007F13EA 8B0B MOV ECX,DWORD PTR DS:[EBX]
007F13EC 890C85 88B95F04 MOV DWORD PTR DS:[EAX*4+0x45FB988],ECX //基址
007F13F3 40 INC EAX
007F13F4 A3 A8F21E03 MOV DWORD PTR DS:[0x31EF2A8],EAX
007F13F9 EB 14 JMP SHORT Client.007F140F
007F13FB 8B13 MOV EDX,DWORD PTR DS:[EBX]
007F13FD 8B4A 10 MOV ECX,DWORD PTR DS:[EDX+0x10]
007F1400 C1E1 04 SHL ECX,0x4
首先我们选中一只怪,然后攻击怪物改变血量来找到怪物血量的地址,然后通过它找到怪物列表的基址
t通过ce中的跟随访问了这个地址的代码,得到如下地址
可能的基址316B6208
+5b4 怪物血量
316B6200
+5bc 怪物血量
再将这两个地址在ce中搜索就可以得到他的基址
然后在OD中通过dd 来查看基址中的数据,再通过下硬件访问断点就可以得到如下的基址:
45fb98c
通过查看基址中的数据可以得到如下的分析:
dc [45fb98c + 4*0]+320 //名字
007F13EC 890C85 88B95F04 MOV DWORD PTR DS:[EAX*4+0x45FB988],ECXdc [45fb988 + 4*7]+320
+314 是否活着 活着为1
+5B4 血量
+5b8 怪物等级
+1018 X
+1020 Y
+1024 X
+102c Y
//基址的内存单元代码
007F13DE FFD0 CALL EAX
007F13E0 83F8 01 CMP EAX,0x1
007F13E3 7F 16 JG SHORT Client.007F13FB
007F13E5 A1 A8F21E03 MOV EAX,DWORD PTR DS:[0x31EF2A8]
007F13EA 8B0B MOV ECX,DWORD PTR DS:[EBX]
007F13EC 890C85 88B95F04 MOV DWORD PTR DS:[EAX*4+0x45FB988],ECX //基址
007F13F3 40 INC EAX
007F13F4 A3 A8F21E03 MOV DWORD PTR DS:[0x31EF2A8],EAX
007F13F9 EB 14 JMP SHORT Client.007F140F
007F13FB 8B13 MOV EDX,DWORD PTR DS:[EBX]
007F13FD 8B4A 10 MOV ECX,DWORD PTR DS:[EDX+0x10]
007F1400 C1E1 04 SHL ECX,0x4
以上代码就完成了对怪物列表基址单元的分析,下面就是对怪物列表进行封装了
封装怪物列表typedef struct FREAK{char* szpName; //怪物名称BOOL IsDead; //是否活着int Hp; //怪物血量int level;//怪物等级float X1; //xfloat Y1;//yfloat X2; //xfloat Y2;//y}_FREAK;class FreakList :public BaseData{public:FreakList();~FreakList();DWORD GetFreakNameOffset(); //获取怪物名字DWORD GetFreakIsDeadOffset(); //获取死亡状态DWORD GetFreapHpOffset(); //获取怪物HPDWORD GetFreakLevelOffset(); //获取怪物等级DWORD GetFreakX1Offset(); //获取怪物的X坐标DWORD GetFreakY1Offset(); //获取怪物的Y坐标DWORD GetFreakX2Offset(); //获取怪物的X坐标DWORD GetFreakY2Offset(); //获取怪物的Y坐标void PrintFreak();//调试怪物数组的数据private:const int MaxFreakNum = 20; //最大怪物数目FREAK freak[20]; //怪物列表数组DWORD nameOffset = 0x320; //名字偏移DWORD IsDeadOffset = 0x314; //死亡状态DWORD HpOffset = 0x5b4; //hp偏移DWORD LevelOffset = 0x5b8; //等级偏移DWORD X1offset = 0x1018; //X偏移DWORD Y1offset = 0x1020; //Y偏移DWORD X2offset = 0x1024; //X偏移DWORD Y2offset = 0x102c; //Y偏移};
//怪物列表的构造函数FreakList::FreakList(){DWORD nObj = NULL;memset(freak, 0, sizeof(FREAK)*20);try{for (int i = 0; i < MaxFreakNum; i++){nObj = *(DWORD*)(this->GetBaseFreakAddr() + 4 * i);//dc[45fb988 + 4 * 7] + 320if (nObj != NULL){freak[i].szpName = (char*)(nObj + 0x320);freak[i].IsDead = *(int*)(nObj + 0x314);freak[i].level = *(DWORD*)(nObj + 0x5b8);freak[i].Hp = *(DWORD*)(nObj + 0x5b4);freak[i].X1 = *(float*)(nObj + 0x1018);freak[i].Y1 = *(float*)(nObj + 0x1020);freak[i].X2 = *(float*)(nObj + 0x1024);freak[i].Y2 = *(float*)(nObj + 0x102c);}}}catch (...){}}//怪物列表的析构函数FreakList::~FreakList(){memset(freak, 0, sizeof(FREAK)* 20);}//获取怪物名字DWORD FreakList::GetFreakNameOffset(){return nameOffset;} //获取死亡状态DWORD FreakList::GetFreakIsDeadOffset(){return IsDeadOffset;}//获取怪物HPDWORD FreakList::GetFreapHpOffset(){return HpOffset;}//获取怪物等级DWORD FreakList::GetFreakLevelOffset(){return LevelOffset;}//获取怪物的X坐标DWORD FreakList::GetFreakX1Offset(){return X1offset;}//获取怪物的Y坐标DWORD FreakList::GetFreakY1Offset(){return Y1offset;}//获取怪物的X坐标DWORD FreakList::GetFreakX2Offset(){return X2offset;}//获取怪物的Y坐标DWORD FreakList::GetFreakY2Offset(){return Y2offset;}//调试怪物数组的数据void FreakList::PrintFreak(){for (int i = 0; i < MaxFreakNum; i++){//dc[45fb988 + 4 * 7] + 320if (freak[i].level >0){DbgPrint_String("怪物名字:%s ,死亡状态: %d ,怪物等级: %d ,怪物HP: %d ,X1 %f ,Y1 %f ,X2 %f ,Y2 %f",freak[i].szpName, \freak[i].IsDead, \freak[i].level, \freak[i].Hp, \freak[i].X1, \freak[i].Y1, \freak[i].X2, \freak[i].Y2);}}}
以上代码就完成了对怪物列表数据的分析和封装,最后只需要利用SendMessageA来发送消息到主线程就可以了
具体代码参见源码:辅助制作第九课源码下载地址
0 0
- 追逐自己的梦想----------辅助制作第九课:分析怪物列表及怪物属性的封装等
- 追逐自己的梦想----------辅助制作第十课:分析动作数组以及攻击捡物品等功能call的封装
- 追逐自己的梦想----------辅助制作第一课:人物属性分析
- 追逐自己的梦想----------辅助制作第十六课:分析技能列表
- 追逐自己的梦想----------辅助制作第十七课:实现技能列表的遍历及判断技能是否可用
- 追逐自己的梦想----------辅助制作第十二课:选怪功能封装
- 追逐自己的梦想----------辅助制作第二十二课:分析修炼条件的判断
- 追逐自己的梦想----------辅助制作第二十四课:寻路call的分析
- 追逐自己的梦想----------辅助制作第二十七课:身上装备更换的分析与实现
- 追逐自己的梦想----------辅助制作第三十八课:物品出售的分析和实现
- 追逐自己的梦想----------辅助制作第二课:人物气功加点分析
- 追逐自己的梦想----------辅助制作第五课:分析并测试物品使用CALL
- 追逐自己的梦想----------辅助制作第二十一课:分析技能自动修炼call
- 追逐自己的梦想----------辅助制作第二十五课:存仓库call分析
- 追逐自己的梦想----------辅助制作第二十八课:打开系统NPC CALL分析
- 追逐自己的梦想----------辅助制作第二十九课:分析打开NPC后功能打开
- 追逐自己的梦想----------辅助制作第三十六课:物品购买分析
- 追逐自己的梦想----------辅助制作第七课:封装调试函数OutputDebugString(),使其可调试任意参数个数
- LEETCODE: Binary Tree Preorder Traversal
- 【Java】Java单例模式的七种写法 (全)
- muduo网络库之net库源码分析(1)
- eclipse插件下载最新地址
- 第三篇:uCOS-II 任务的创建,挂起,恢复,删除
- 追逐自己的梦想----------辅助制作第九课:分析怪物列表及怪物属性的封装等
- 十九、运算符重载(三)String类的改进实现、[]运算符重载、+运算符重载、+=运算符重载、<<运算符重载、>>运算符重载
- java基础---面向对象
- 天声人語 20150110
- linux 配置 rsync 服务
- 【2015-1】【组合计数】12.28 bigraph
- 第五章 树和二叉树知识导图
- shell脚本消耗机器的CPU实例
- 动态创建gridpanel