#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