追逐自己的梦想----------辅助制作第九课:分析怪物列表及怪物属性的封装等
2015-01-11 14:13
531 查看
本节课中我们要对怪物列表以及怪物列表属性进行分析
首先我们选中一只怪,然后攻击怪物改变血量来找到怪物血量的地址,然后通过它找到怪物列表的基址
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],ECX
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
以上代码就完成了对怪物列表基址单元的分析,下面就是对怪物列表进行封装了
封装怪物列表
以上代码就完成了对怪物列表数据的分析和封装,最后只需要利用SendMessageA来发送消息到主线程就可以了
具体代码参见源码:辅助制作第九课源码下载地址
首先我们选中一只怪,然后攻击怪物改变血量来找到怪物血量的地址,然后通过它找到怪物列表的基址
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],ECX
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
以上代码就完成了对怪物列表基址单元的分析,下面就是对怪物列表进行封装了
封装怪物列表
typedef struct FREAK { char* szpName; //怪物名称 BOOL IsDead; //是否活着 int Hp; //怪物血量 int level;//怪物等级 float X1; //x float Y1;//y float X2; //x float Y2;//y }_FREAK; class FreakList :public BaseData{ public: FreakList(); ~FreakList(); DWORD GetFreakNameOffset(); //获取怪物名字 DWORD GetFreakIsDeadOffset(); //获取死亡状态 DWORD GetFreapHpOffset(); //获取怪物HP DWORD 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] + 320 if (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; } //获取怪物HP DWORD 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] + 320 if (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来发送消息到主线程就可以了
具体代码参见源码:辅助制作第九课源码下载地址
相关文章推荐
- 追逐自己的梦想----------辅助制作第一课:人物属性分析
- 追逐自己的梦想----------辅助制作第十六课:分析技能列表
- 追逐自己的梦想----------辅助制作第十课:分析动作数组以及攻击捡物品等功能call的封装
- 追逐自己的梦想----------辅助制作第五课:分析并测试物品使用CALL
- 追逐自己的梦想----------辅助制作第十一课:选怪功能分析
- 追逐自己的梦想----------辅助制作第二十二课:分析修炼条件的判断
- 追逐自己的梦想----------辅助制作第三十课:NPC对话更正以及封装查找NPC对象函数
- 追逐自己的梦想----------辅助制作第六课:背包数组分析和根据物品名称来使用物品
- 追逐自己的梦想----------辅助制作第二十九课:分析打开NPC后功能打开
- 追逐自己的梦想----------辅助制作第三十四课:向仓库存入N个物品对象函数封装实现
- 追逐自己的梦想----------辅助制作第二十四课:寻路call的分析
- 追逐自己的梦想----------辅助制作第三十六课:物品购买分析
- 追逐自己的梦想----------辅助制作第三十二课:向仓库存入N个物品对象分析缓冲区解密
- 追逐自己的梦想----------辅助制作第三十八课:物品出售的分析和实现
- 追逐自己的梦想----------辅助制作第三十五课:从仓库取出N个物品分析与实现
- 追逐自己的梦想----------辅助制作第二十八课:打开系统NPC CALL分析
- 追逐自己的梦想----------辅助制作第十七课:实现技能列表的遍历及判断技能是否可用
- 追逐自己的梦想----------辅助制作第二课:人物气功加点分析
- 追逐自己的梦想----------辅助制作第三十一课:向仓库存入N个物品对象分析
- 追逐自己的梦想----------辅助制作第二十七课:身上装备更换的分析与实现