因此,为了获得更多的倒车经验,我目前正在尝试为一款名为《无主之地2》的视频游戏编写外部黑客程序。我发现了一条指令,似乎可以用来减少健康,并为游戏中的所有实体提供总弹药。 (即用NOP填充它不会对我有帮助,因为它会使我以及所有敌人处于上帝模式,并且会给所有东西以弹药。)我的目标是让一个命令使我进入上帝模式,而另一个命令给我inf。弹药,不影响任何其他生物。有谁知道我如何才能仅在使用Godmode命令时为我的健康而在我使用inf时为我的弹药无此共享指令。弹药命令?我想我需要以某种方式弄清楚该指令是否被用于更新我的玩家值(可能是通过将基址的其他偏移量与该偏移量处的敌人值进行比较),但是我还需要弄清楚如何确定该指令正在尝试修改我的健康状况或弹药,以便仅当它正在修改与我当前处于活动状态的任一命令相对应的命令时,我才能对其进行NOP操作。任何想法都欢迎!

#1 楼

共享指令的喜悦!这里有一些想法供您考虑,我将使用Cheat Engine进行演示,因为它已迅速成为游戏黑客的出色动态分析工具。

1。不用寻找写入地址的指令,而是右键单击它并寻找访问该地址的指令。在那里,您会找到从地址读取值的指令以及写入该地址的指令。读取值的指令示例可能是健康状态的HUD表示。要知道显示健康条的距离有多远,它会从您的健康地址中读取该值。该指令执行的操作。然后,您可以在该指令之前创建代码注入,并将自定义值移动到被引用或指向的地址中。例如,假设这是一条从您的健康地址读取的指令:

移动eax,[ecx + 0C]

在这种情况下,[ecx + 0C]指向您的健康地址。那里的值被移到eax寄存器中。您可以做的是在该指令上创建代码注入,并在mov指令运行之前使用此代码将自定义健康值写入[ecx + 0C]。这将更改健康状况的实际值,因此将从地址中读取该自定义值。使用Cheat Engine可以很容易做到这一点(通过其本机代码注入功能),但否则需要您研究代码保存。

2.要使用您发现的共享指令,您必须找到一种方法,以区分要影响的内容和要写入的其余地址。这看起来像是一项艰巨的任务,尤其是当您在GameMaker游戏中找到一条共享指令时,其中成百上千的地址都是通过一条指令写入的,但请不要担心!

您的选择是找到差异在以下位置:

A) Memory addresses (Including the stack)
B) Registers (General purpose, FPU/XMM, special purpose, etc.)


右键单击共享指令,然后选择“找出该指令访问的地址”。将弹出一个新窗口,显示该指令正在写入的地址。在该窗口中,您可以做很多事情。

首先,Cheat Engine提供了一个方便的数据/结构分解工具,可用于比较多个内存地址之间的值。如果选择所有地址(按住Shift键或Ctrl键单击感兴趣的地址),然后单击鼠标右键,将看到一个打开数据剖析工具的选项。在这里,您可以比较值以找到相同偏移量之间的差异!通常,您可以在此处找到一个包含所有地址之间不同值的寄存器(您将希望查找一个不是动态内存地址的不同值,因为该值在重新启动游戏时会改变)。

最后,当查看寄存器的内容时​​,该窗口上有两个小按钮:“ S”和“ F”。

“ S”可让您查看堆栈。在这里,您可以寻找可区分的价值。 “ F”使您可以查看FPU和XMM寄存器的内容。有时,后者可能会有所帮助,因为,例如,FPU可能仅用于健康状况,而不是用于共享指令写入的任何其他值。

综上所述,您将使用发现的任何唯一值来编写自定义代码注入,从而使您可以挑选出自己感兴趣的值。假设您的指令是这样的:

mov [edx + 0C],eax

然后说,在寄存器ebx中,您发现了2B的唯一值。就像这样:

label(customCode)
label(restoreFlags)
label(originalCode)
label(return)

customCode:
  pushf //Preserve flags register by pushing onto the stack
  cmp ebx,2B //Does ebx contain the value you're interested in?
  jne restoreFlags //If not, restore flags register and resume normal execution
  mov eax,(float)100 //If so, move a custom health value into eax for originalCode
  //Execution flow from here moves to restoreFlags

restoreFlags:
  popf //Restore flags register
  //Execution flow from here moves to originalCode

originalCode:
  mov [edx+0C],eax //eax contains either value from normal execution, or custom health
  jmp return //Return to the point we injected and resume normal execution


我并不是说这是无耻的自我宣传,但我在YouTube频道上经营了3年多通过游戏入侵来逆转。如果游戏是您的媒介,并且您喜欢通过视频学习,那么我想您真的可以从我的CE教程系列中学到很多东西。我还教授游戏专用的技巧,例如Cuphead,ELEX等。

祝你好运!

#2 楼

这里有点冒昧,但是这里有一些想法可能对您有所帮助,而这些想法不适合您的注释:

3D引擎通常在灵活的继承层次结构中使用实体对象。我假设类似以下内容:在大多数通用语言(如C ++)中,每个类都会有一个指向所有类方法实现的单独的函数表。例如,当我们在takeDamage -Object上调用Player时,我们希望对所有GameEntities实施的方法都将执行。因此,NOP'ing该函数将具有您之前所述的效果。

tl; dr

似乎您有两个有效的选择:查找正确的函数指针进行操作或检查this指针的身份,该身份通常作为第一个参数传递给成员函数。

评论


我认为这里还有更多与编码值有关的事情。如果他们直接处理数据,则应该可以使用“精确搜索”功能轻松找到正确的数据。但是,他们无法找到它的原因让我感到这些功能之一正在以某种方式对值进行编码,并且调用该功能来编码/解码游戏使用的每个值。因此,通过搜索找不到正确的内存点。找到的位置在解码功能的错误一端。

– Mugen
19年1月30日在4:29