从内存中提取私钥

逆向工程 视窗 C++ 记忆 可执行
2021-06-12 05:36:57

我正在尝试提取用于加密游戏修改(SA-MP,封闭源代码,在 Windows 上运行)中的通信的私钥,它使用 RakNet 进行通信和大概的加密。我使用的语言是 Python,我想自动获取密钥,尽管手动也可以。不过,我对如何继续感到有些困惑!

由于 RakNet 源现在可以在 GitHub 上获得,这里描述了加密:https : //github.com/OculusVR/RakNet/blob/master/DependentExtensions/cat/crypt/tunnel/KeyAgreement.hpp#L38

我很确定我可以通过 WireShark 获得挑战(例如“52A0106B14E27E13”,但是,那有什么好处?)。

我尝试使用 ollydbg 调试游戏,但是如果我在生成密钥时尝试调试,游戏只会崩溃。我也尝试使用 CheatEngine 来扫描内存,但是 GTA:SA 是一个如此大的游戏,程序在扫描几次后就死机了,所以我从来没有得到任何可用的结果。

1个回答

由于评论历史太长,因此将其作为答案。

问题的类源代码似乎有一个函数void GenerateKey(BigTwistedEdwards *math, IRandom *prng, Leg *key)可以在Leg中创建密钥我认为这是用 key=new Leg 在某处创建的,所以它不会是一个单一的地址。(实际上,Leg可能是 auint32或 a uint64,并且Leg *key是指向这些整数值数组的指针)。

也许,如果您GenerateKey在二进制文件中找到该函数,您可以添加一些对CreateFile,WriteFileCloseFile在其末尾的调用以获取密钥,并且可执行文件检测是否存在调试器,但不检测可执行文件本身是否存在被修改。

似乎KeyAgreement.cpp是保存该GenerateKey功能的文件它会生成一个密钥,直到do .. while循环找到可接受的密钥,因此该do .. while循环的结尾是您想要放置断点的位置(如果您可以调试可执行文件)或添加对将密钥写入文件的函数的调用。

现在,我们需要GenerateKey在可执行文件或其 DLL 之一中找到该函数。您可以使用任何列出 DLL 导出的工具,希望其中一个 DLL 可以导出KeyAgreementCommon::GenerateKey. 如果幸运的话,您会在那里找到它,然后就大功告成了。Dependeny Walker是一个很好的工具。

假设该函数被编译到主 .exe 或 .dll 中但未导出,则有点困难。幸运的是,它KeyAgreement.cpp保存了一堆带有非常不同签名的漂亮字符数组,它们应该是唯一的并且很容易找到。您可以尝试以下方法之一:

  • Q_XXX数组添加signrch并在所有 .exes 和.dlls 上运行它
  • 将您的 .exe 和 .dll 分别加载到十六进制编辑器中,然后Q_XXX对它们运行字节搜索数组,直到找到正确数组。

接下来,您想知道这些字节的使用位置。最简单的方法是将您认为正确的文件加载到Ida Pro 中,在那里找到您的字符数组,然后检查 XREF。应该只有其中之一,来自KeyAgreementCommon::InstantiateMath. KeyAgreementCommon::GenerateKey如果您的开发人员没有更改源代码,则此后的功能应该是

如果他们确实更改了源代码,也许他们会稍微调整一下功能。(也许他们决定除了 384 位版本之外不想使用任何东西,所以他们丢弃了 256 位和 512 位数组。这就是我说搜索所有 3 个数组的原因。)现在我们想要找到GenerateKey当我们只知道函数时InstantiateMath函数。

幸运的是,它们都在.hpp文件中被声明为公开的这意味着它们应该出现在类 vtable 中的某个地方。检查 Ida 以获取对该InstatiateMath函数的数据 x 引用这应该是 vtable 条目。同一个 vtable 应该保存InitializeGenerateKey函数的地址,所以检查引用旁边的函数InstantiateMath