编译后,在 .net 可执行文件中操作字符串?

5

我知道对于这个问题,任何答案都可能非常“hacky”(指粗糙的、不规范的技术手段)。但我非常支持尝试这些方法,因为它们可以拓展我们的技术边界,让我们能够在实践中学习。

我的目标是编写一个程序,可以操作一个已知的.exe文件,并修改其中的一个字符串。我目前有一个非常简单的C#程序,就是这个已知的.exe文件:

using System;

namespace Target {
    class Program {

        public static String str = "TESTSTRING";

        static void Main(string[] args) {
            Console.WriteLine(str);
        }
    }
}

编译后,在十六进制编辑器中,我发现该字符串的第一个字母位于第1898个字节处。从那里开始,它似乎以Unicode方式存储。
一些编译器优化直接将字符串放在Console.WriteLine调用中,并且似乎调用了某个构造函数(至少我认为.cctor是这样的)。我玩弄了一些同样长度的其他字符串,以确保我知道每件事情都是什么。我编写了一个应用程序,成功地将TESTSTRING替换为XXXXXXXXXX(请注意它们的长度相同),并运行修改后的exe。效果很好。
但是,如果我尝试使用不同长度的字符串替换该字符串,则输出的exe无法运行。我发现字符串之前的字节似乎包含长度。它似乎是unicode字符串的字节数+1(我不知道+1是什么,也许是空终止符?)。然而,如果我用正确的更新值替换该长度,它仍然无法运行。在字符串结尾后面似乎有几个不同长度的字节。我的猜测是构造函数类似于new String(...),而那些其他字节是构造函数的其他参数(第一个参数是char[]或byte[],其前面跟着它的长度),但我无法解释其他参数具体是什么。
我知道我正在打破通常不会碰的东西,但我对可能性很感兴趣。我不知道.NET exe的结构,如果知道将使我能够做到这一点?用一个不同长度的字符串替换已编译的EXE中的一个字符串?还要如何处理长度超过127的字符串?任何长度超过127的字符串都会影响存储字符串长度所需的字节数。
我希望能够使用任意替换字符串来做到这一点。因此,预编译特定字符串,然后仅使用该预编译字符串及其元数据修补exe不是选项。我应该能够在没有反编译器/编译器的情况下完成此操作。我肯定想以编程方式完成此操作,因此Reflector不是选项。这可以可靠地完成吗?

正如Lucas在他的回答中所写,操作.Net exe的方法是使用ILDasm.exe,修改IL代码,并使用ILAsm.exe重新组装。这有时被称为“往返旅行”。我自己使用它来进行各种C#程序的后期构建操作。您能否解释一下为什么不想使用反编译器/编译器? - RenniePet
例如,我通过这种方式进行的修改之一是混淆(非常简单和原始地)我的程序中的所有字符串。如果您希望我在答案中写更多细节,我可以做到。 - RenniePet
也许没有可用的。天哪,这种黑客方式要是出现在生产代码环境或客户机上,编译器或汇编器的存在都不能保证,并且下载或将其包含在项目中似乎需要大量额外的资源。我可以整天操纵源代码字符串。这是关于我自己设定的低级挑战。 - Corey Ogburn
我想到的一个可怕的例子是,当我在客户端机器上使用某种C#解释器时,可能会想要这样做。Javascript .Net可以在C#运行时(在运行时而不是某种javascript编译器中)在上下文中运行javascript代码,我想知道是否可以将javascript注入到使用Javascript .Net运行它的exe文件中。它并没有提供太多好处,但似乎没有什么是不可能的。这是为了克服挑战而发起的挑战。我的当前珠穆朗玛峰。 - Corey Ogburn
嗯,但你要意识到在生产环境中尝试操作客户端机器上的exe文件可能会涉及文件访问授权问题和/或被本地防病毒程序标记为病毒。无论如何,祝你好运。 - RenniePet
我怀疑它永远不会像那样发展。对我来说,这就像报纸上的数独谜题或欧拉计划问题。 - Corey Ogburn
1个回答

3
你可以使用 ildasm 来完成这个任务。它不是反编译器,而是一个反汇编器。它会产生一个 MSIL 文本输出,你可以修改后再使用 ilasm 重新编译。 编辑:我怎么能忘记呢?Mono.Cecil 对你来说应该非常有

一些说明:

  • .cctor类构造函数 的缩写,也称为 静态构造函数,而不是 实例构造函数
  • 字符串的内部表示仍然是以 null 结尾的,这就是为什么在文件中看到 length + 1。这仅用于更容易地进行互操作(P/Invoke)。
  • 更改长度并偏移字节是行不通的,因为我猜它会破坏文件中存储偏移量的其他数据。您需要更新 exe 中存储的每个偏移量才能使其正常工作。这可能意味着...要反汇编它。这就是 ildasm 的作用。

哪些偏移量会出问题? - Corey Ogburn
1
我不熟悉PE文件格式和MSIL二进制格式,但在二进制文件中通常会有许多偏移量。至少有一个偏移量非常重要:即程序入口点的偏移量。然后,代码和元数据之间存在偏移量。您需要找到关于PE格式、CLR元数据格式和MSIL格式的描述,才能全面了解它们。 - Lucas Trzesniewski
@Corey 我完全忘记了 Mono.Cecil - 去看看吧! - Lucas Trzesniewski
提示: 使用 ilasm 进行重组可能无法适用于使用 VC++ 编写的源代码(我记得多年前在非托管代码上失败了!我完全放弃了 .net,所以不确定现在是否仍然如此!)顺便说一句,我注意到 OP 特别提到了 C#,因此这是一个“提示”。:) - Fr0zenFyr
@Fr0zenFyr 是的,它不能在混合模式程序集上工作。如果您使用/clr:pure编译VC++,它应该可以工作,但是在这种模式下使用C++/CLI也没有太多意义。 - Lucas Trzesniewski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接