书接上文,我们这次来学习多级指针的查找,上节课我们的游戏代码并不复杂。在真正的游戏里,通常一个类里面还会包含另一个类,这类只装着那个类的指针,那个类也可以继续套娃。举个例子,人物类包含背包类,背包类包含武器类,武器类也可以包含弹药量等数据。
最终弹药的数据可以根据如下指针路径找到

Player->Inventory->PrimaryWeapon->ammo

这些路径的长度在不同游戏中不同,一般都是3-7级指针。

对于一个游戏hacker来讲,最重要的技巧之一就是找到我们感兴趣的变量的可靠的指针路径。
下面我们会介绍两个方法来找到这个路径,但是在此之前,我们需要再来写一个更加复杂的游戏,包含多级指针。
个人建议下面的代码不要复制,请自己手打,会大大加深你的理解。出现bug和问题自行百度,解决不了可以留言或者加我联系。

#include <iostream>
#include <stdlib.h>
using namespace std;
class Weapon{private:int damage;int rate_of_fire;int ammo;
public://construct for our weaponWeapon(int ammo, int damage, int rate_of_fire):damage{damage},rate_of_fire{rate_of_fire},ammo{ammo}{}void shoot(){--ammo;}int getammo(){return ammo;}
};
class Inventory{private:int selectedWeapon;Weapon* primaryWeapon;Weapon* secondaryWeapon;int grenadecount;
public://construct for our inventoryInventory():selectedWeapon{0},grenadecount{2}{// allocate memory on the heap and create weapons thereprimaryWeapon = new Weapon(50,1,30);secondaryWeapon = new Weapon(10,5,90);}~Inventory(){ // gets called when Inventory gets deleted// free memory that was used by our weaponsdelete primaryWeapon;delete secondaryWeapon;}void switchWeapon(){selectedWeapon = selectedWeapon == 0 ? 1 : 0;}void fire_one_shot(){if (selectedWeapon == 0)primaryWeapon->shoot();elsesecondaryWeapon->shoot();}void throwGrenade(){--grenadecount;}int getGrenade(){return grenadecount;}int getSelected(){return selectedWeapon;}int getAmmo(){if (selectedWeapon == 0)return primaryWeapon->getammo();elsereturn secondaryWeapon->getammo();}
};class Player{private:int mana;int health;Inventory* inventory;
public:Player(int health = 100, int mana = 100): mana{mana},health{health}{inventory = new Inventory();}~Player(){delete inventory;}int getMana(){return this->mana;}int getHealth(){return this->health;}void castSpell(){this->mana -= 5;}void applyDamage(int damage){this->health -= damage;}void switchWeapon(){inventory->switchWeapon();}void fire_one_shot(){inventory->fire_one_shot();}void throwGrenade(){inventory->throwGrenade();}void printInfo(){cout<< "\n\n\n-----------PLAYER:----------"<< "\nMANA:" << mana<< "\nHEALTH:" << health<< "\nGRENADE:" << inventory->getGrenade()<< "\nSELECT WEAPON:"<< ( (inventory->getSelected() == 0) ? "PRIMARY" : "SECONDARY" )<< "\nAMMO:" << inventory->getAmmo()<< "\n---------------------------       " << endl;}
};
int main()
{static Player* myPlayer = new Player();while (myPlayer->getMana() < 200 && myPlayer->getHealth() < 200){myPlayer->printInfo();cout << "1 - FIRE WEAPON | 2 - SWITCH WEAPON |"<< " 3 - THROW GRENADE | 4 - CAST SPELL | 5 - HIT YOURSELF"<< endl;cout << "SELECTION:";int selection;cin >> selection;switch(selection){case 1:myPlayer->fire_one_shot();cout << "YOU FIRED YOUR WEAPON!" << endl;break;case 2:myPlayer->switchWeapon();cout << "YOU SWITCHED YOUR WEAPON!" << endl;break;case 3:myPlayer->throwGrenade();cout << "YOU HAVE THROWN A GRENADE!" << endl;break;case 4:myPlayer->castSpell();cout << "YOU DID CAST A SPELL!" << endl;break;case 5:myPlayer->applyDamage(5);cout << "STOP HITIING YOURSELF!" << endl;break;}}delete myPlayer;cout << "You have made it!" << endl;system("pause");return 0;
}

我们定义了三个类,我们创造一个player对象的时候,这个对象会创造一个新的inventory对象,这个inventory对象两个新的weapon对象。
所以如果我们现在想访问到selected weapon的ammo,我们不能直接访问到,我们通过inventory类访问到weapon类,通过player类访问到inventory。
这就意味着,如果我们想找到一个可靠的指针路径指向ammo,我们需要反向追踪。
下面是具体措施:

  • 1 找到当前ammo的地址

很简单不展开介绍了

  • 2 找到inventory对象中的weapon指针的地址
    右键主武器弹药地址,找到什么写入了这个地址,点击确定,回去游戏中射击一发,我们就看见窗口中多了一条指令,这条指令向我们的ammo地址写入了数据。

双击这个指令可以看到详细信息。

我们看到他把edx的值移动到了eax+08指向的地方。[]就是dereference,类似于*运算符。
中括号内就是值的地址,带上括号就是地址内的值,在这个例子中就是我们的ammo。
我这里和书上的代码不同,书上是dec [eax+08],edx ,可能是编译优化的问题,你自己实践的时候,只要能理解问题就可以了。继续讲解。
回忆一下我们的weapon的写法,别忘了,方法的代码不会放在某个实例中。

class Weapon{private:int damage;int rate_of_fire;int ammo;
}

C++代码中,每个int占4字节,ammo前面有两个int,所以从weapon类到ammo的偏移地址为2*4=8字节。
这也就解释了为什么CE找到的代码修改的值的地址偏移为0x8,我们把这个偏移量记作一级偏移。
也意味着weapon的地址就是eax,详细信息里可以看到CE告诉我们eax值为00CEA588,也就是说inventory中的primaryPointer的值为00CEA588,我们现在去CE中搜索这个值,记得勾选上前面的HEX选项,代表你要搜索的值用16进制表示。
很奇怪的是,我的例子中搜索到了2个地址,很奇怪,因为按照代码来说,应该是只有一个primaryweapon的指针呀。未来这种情况会不断发生,我们需要非常耐心的反复尝试,有时候多个指针路径都可以成功,在这个例子中我们当然知道只有一个可以。

先继续步骤,点击右下角的add address manually (手动添加地址)
勾选指针,1处填入搜索到的结果地址,2处填入偏移地址8。这次以第二个地址为例子。

  • 3找到player对象中的inventory指针的地址
    我们现在需要找到指向inventory的指针的地址。重复我们找primarypointer的方法就可以了。
    右键我们刚才找的地址,这次选择什么访问了这个地址,因为这个指针没有被写入,但是被访问来得到我们primary weapon的地址。
    在弹出的窗口中选择是什么访问了这个指针(自己思考下为什么吧)
    紧着着返回游戏再射击一次。
    我们得到两条指令。

双击第一个打开详细信息。我们可以看到我们的primarypointer 通过dereference eax+0x4得到。
我们再来看一下我们的inventory类的定义代码。

class Inventory{private:int selectedWeapon;Weapon* primaryWeapon;Weapon* secondaryWeapon;int grenadecount;
}

一个int4个字节,下面的就是我们指针了。
也就是inventory的地址+4=primarypointer的地址。
也就是说eax的只就是inventory在player对象中的地址。

记得详细信息里面的寄存器的值都是在上面指令执行之后的值。
我们再次搜索十六进制值,但是不是下面的EAX的值,而是上面那一行可以直接复制的。
The value of the pointer needed to find this address is probably …
对这个值做一次hex扫描,这次还很幸运只得到一个结果,我们选择手动添加地址,或者双击结果到下面再修改,勾选pointer,填入地址,填入两个偏移,一级填4,add offset,二级填8,注意这里的数值都是16进制哦。


确定当前指针路径正确之后,我们还是可以定位到ammo,下一步接着来找player的地址吧。
重复上次的步骤,右键指针,找到是什么访问了这个地址,找到是什么访问了这个指针,回游戏发射一次,我们又看到了代码,表明我们现在做的还是正确的,若是没有,可能就是某个步骤找错了。

双击第一条指令查看详细信息,我们就看到inventorypointer被[eax+08]访问。

老规矩,回忆一下player类的写法。

class Player{private:int mana;int health;Inventory* inventory;
}

两个int在前,正好8字节,复制猜想值再做一次hex搜索,芜湖,我们找到了一个梦寐以求的绿色地址

我们终于找到了我们player对象的地址,也找到了指向这个地址的静态指针
手动添加地址,三层偏移由距离ammo的距离排列为8,4,8

最终我们得到了一条静态的指针路径,也就意味着即使游戏重启我们也可以顺着它找到primary ammo
不用再做搜索了。
也意味着我们以后编写cheat程序可以使用这个路径了。
这样手动找指针路径的练习是十分重要的,请务必自主实现一个,多多练习,这是你唯一真正理解和适应它的方法。
重启游戏验证下,哈哈,除了最后一个静态指针,其他的都失效了,最后我们可以保存CT数据,ctrl+s即可,方便下次可以打开直接使用。

小作业,基于已有的结果,怎么快速找到primary damage,rate_of_fire?
小作业,找到grenadeCount的指针路径,secondary ammo的指针路径。
CE的详细信息的值,就是当前变量结构体的头,我们搜索他就是找到指到它的上一级指针。
最后放上一张图解帮助你更好地理解

Game Hacking Fundamentals 学习笔记4相关推荐

  1. Game Hacking Fundamentals 学习笔记1

    激动人心,我的书总算回来了,发了两本,第一本不知道是丢了还是那个人没发,总之第二个是收到了.除了NF专辑算是我第二次海淘. PS:强烈安利NF,真的才华横溢,懂得都懂. PS:强烈安利韩国游戏moto ...

  2. 计算机图形学基础:光栅图像(Fundamentals of computer graphic:Raster Images) 学习笔记

    <Fundamentals of computer graphics>4th edition: 3. Raster Images 本文仅仅是本人的学习笔记,由于自己能力有限,可能存在许多错 ...

  3. ASP.NET Core 2 学习笔记(三)中间件

    原文:ASP.NET Core 2 学习笔记(三)中间件 之前ASP.NET中使用的HTTP Modules及HTTP Handlers,在ASP.NET Core中已不复存在,取而代之的是Middl ...

  4. alfs学习笔记-自动化构建lfs系统

    一名linux爱好者,记录构建Linux From Scratch的过程 经博客园-骏马金龙前辈介绍,开始接触学习lfs,用博客记录学习笔记,如有写的不恰当的地方,望多多指正. 笔记中只是记录一些问题 ...

  5. 【原创】Windows® Embedded CE 6.0 Fundamentals 读书笔记_Chapter 9

    Chapter 9 第九章主要是介绍关于应用程序开发的一章.这一章比较适合应用层开发的人员来了解如何基于wince6.0开发应用层程序,首先我 们还是先看一些单词 //================ ...

  6. 《安全测试指南》——信息收集测试【学习笔记】

    [信息收集测试] 1.搜索引擎信息收集(OTG-INFO-001) 通过搜索引擎收集以下: · 网络拓扑图和配置 · 管理员和其他员工的归档文章和邮件 · 登录过程和用户名的格式 · 用户名和密码 · ...

  7. 游戏黑客圣经GHB1学习笔记 part1(1-5)

    游戏黑客圣经(Game Hacking Bible1) 我在这里记录我所有课程的学习笔记,包括一些小技巧以及源码,俗话说好记性不如烂笔头,写在这里,用于温故而知新. 前言 学习游戏黑客的必备条件 智力 ...

  8. kestrel java_Kestrel Web 服务器学习笔记

    前言: ASP.NET Core 已经不是啥新鲜的东西,很多新启的项目都会首选 Core 做开发: 而 Kestrel 可以说是微软推出的唯一真正实现跨平台的 Web 服务器了: Kestrel 利用 ...

  9. RedShift: Transparent SNARKs from List Polynomial Commitments学习笔记

    1. 引言 纽约大学Kattis和Matter Labs团队2019年论文<RedShift: Transparent SNARKs from List Polynomial Commitmen ...

最新文章

  1. C# 写Windows服务
  2. 闪烁点击效果css,CSS3自定义闪烁动画效果实例
  3. 老板让我用少量样本 finetune 模型,我还有救吗?急急急,在线等!
  4. 你的模型真的陷入局部最优点了吗?
  5. 赶在520之前,程序员如何用Python送上最特别的“我爱你”表白
  6. 职称计算机承诺书,职称申报承诺书范本
  7. 电切镜行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  8. Hibernate复习笔记
  9. 5.2.8.字符设备驱动代码实践1
  10. Unity实现导航到鼠标点击位置并显示路线
  11. Silverlight开发中的疑难杂症-控件设计篇-如何实现一个NumericBox(下)
  12. 美赛O奖论文翻译-2015埃博拉病毒
  13. Java不生成 xml注解_java注解生成xml和包含CDATA
  14. java实现旅行商问题_Java中旅行商问题的强力算法
  15. 编程之美学习笔记——数字相关(一)
  16. 泛微oa 明细数据合计
  17. macos安装盘第三方工具制作_如何制作macOS High Sierra USB启动安装盘
  18. 非网页版微信机器人-Wechaty
  19. HTML5 canvas 拖尾效果(或尾巴 或方向标 或留痕。。。)
  20. 4G模块-EM05驱动调试分享-02(Android上层更改)

热门文章

  1. RKMEDIA--VI的使用
  2. PR视频剪辑教程_05_字幕(附PR常用快捷键)
  3. haimianjie工作日记:2023年6月
  4. (3)elasticsearch相关概念和索引的CURD
  5. 2018年英语计算机职称考试成绩,2018年重庆职称英语考试成绩查询时间及入口
  6. [Leetcode] 58. 最后一个单词的长度
  7. “浅薄”绝不该是中国程序员的性格特征
  8. ET199加密锁设置和使用
  9. 用计算机算出女神的生日,Excel中通过出生日期智能计算年龄或虚岁 | 我爱分享网...
  10. Melo作为程序员的2016年