使用它在C ++中的内存中的起始地址编辑字符串

时间:2012-11-14 03:36:30

标签: c++ string edit inject memory-address

我真的希望以前没有问过这个问题,但我的谷歌搜索没有提出任何内容,所以我想我会问。

我正在处理一个小脚本,我将DLL注入游戏并编辑特定事件发生时显示的特定字符串。我已经找到了这个字符串驻留在内存中的位置,并编写了一个基本的sigscanning函数,以便在运行时找到它。我现在的问题是,给定起始地址,我如何/可以用我自己的特定字符串替换此字符串?

比如说,字符串是“我喜欢煎饼”,我想用“煎饼很糟糕,华夫饼最好!”来代替它。怎么会这样做呢?

谢谢!

哦是的,如果重要的话,源代码中的字符串是一个const char。我很确定它没有,但添加该信息并没有什么坏处!

2 个答案:

答案 0 :(得分:2)

如果您要替换的字符串至少与其替换字符串一样长,那么它很简单:将其替换到位。否则,你无法可靠地宣称你对煎饼的厌恶和对华夫饼的喜爱。

答案 1 :(得分:1)

如您所述,引用字符串的汇编指令通常如下所示:

push offset aString

组装和链接后,这将解析为实际地址:

push 0x00ABCDEF

这为您提供了两个选项:

  • 写入数据:修改aString的内容(即0x00ABCDEF指向的内存)
  • 编写代码:修改对aString
  • 的引用

写入数据

当编译源代码涉及标准C字符串文字(内存中不可变的字符数组)时,在运行时,字符串通常映射到包含所有其他只读数据的某个只读页面。这些数据通常是连续打包的,以减少程序的内存占用。这是你试图写一个更大的字符串时遇到的问题。您将覆盖下一条数据,对此覆盖数据的任何引用现在将指向大字符串的中间位置。

通过更改数据来编写更长的字符串并非易事,因为为了不丢失原始的功能行为,您必须在字符串前进后移动所有数据。之后,您必须更新所有对移位数据的引用(其中一些可以使用指针算法动态计算)。正如我所说,这个过程并不重要 - 你试图在没有完整(如果有的话)符号信息的情况下重新定位链接器的任务。

编写代码

简单的方法是在任意位置编写新字符串。这可能是未使用但在进程中已经保留的内存(通常称为“代码洞穴”),或者它可能是您在注入DLL时映射的字符串文字。或者,您可以在注入后在运行时动态分配它。

下一步是查找对aString的所有引用,并将其替换为引用新字符串。

奖金方法:)

由于您正在深入研究这一级别的逆向工程,您可能会遇到绕行/拦截/仪表的概念。这里可以应用类似的方法来拦截所有引用并在运行时重定向它们。与上面列出的“编写代码”方法相比,这会对性能产生更大的影响,但会保证所有访问都被捕获并重定向。

访问时的硬件断点设置为字符串指向的数据。当触发断点时,某些寄存器将保存字符串的地址。在汇编中,这看起来像这样:

mov esi, 0x00ABCDEF
...

如果访问了第一个字符,代码可能会这样做:

mov al, byte ptr ds:[esi]

当您的断点被点击时,您可以设置线程上下文(在Windows上为SetThreadContext)以修改esi的值以指向您的新字符串。