C# 如何将代码附加到正在运行的 .NET .EXE 的末尾,最好是从该 .EXE 内部?

Posted

技术标签:

【中文标题】C# 如何将代码附加到正在运行的 .NET .EXE 的末尾,最好是从该 .EXE 内部?【英文标题】:C# How do I append code to the end of a running .NET .EXE, preferably from inside that .EXE? 【发布时间】:2021-12-19 03:48:55 【问题描述】:

正在运行的 .NET .EXE 可以将数据附加到自身吗?是什么阻止了它?

我可以启动一个单独的进程来完成它。

但我不知道如何在它运行时写入它自己。有没有办法做到这一点? 在 .NET 中

编辑:最好不要像在其他地方写出来然后复制/重命名这样的骇人听闻的解决方案

EDIT2:澄清可执行文件的类型

EDIT3:目的:将二进制流写入我正在运行的 EXE 文件允许我然后解析磁盘上的 .EXE 文件以获取这些字节并在程序中使用它们强>。无需创建任何新文件或注册表项或类似的东西。它是自包含的。这非常方便。

EDIT4:对于那些反对这个文件的人,请在尝试之前考虑:FILE ZIPPINGDLL LINKINGPORTABLE APPLICATIONS的功能抹黑这个想法,

【问题讨论】:

“我知道一旦 .EXE 运行,您可以在其末尾插入字节” - 呃,不完全是。或者至少,它肯定没有那么简单。是什么让你产生了这种想法? 我认为您需要先了解程序加载器的工作原理,以及 PE 图像格式的工作原理。 Win32 PE 可执行程序(.exe 文件等)不是指令的线性列表,您可以在其中简单地添加更多指令:它是一种结构化格式,当它由操作系统(例如重定位、基地址等)。 嗯.. 不,您不能只在其末尾插入字节。此外,尝试这样做会立即引起任何体面的病毒扫描程序的注意。 @Ken White 我不关心病毒扫描程序这是我自己的程序 要求只留下潜在的恶意和/或不稳定的方式。它们都不能保证正确保存结果。更重要的是,“可移植”定义被高度限制为单个文件。这是完全错误的。请看一下它的定义en.wikipedia.org/wiki/Portable_application。您可以将它“移植”在一个目录中 - 几个文件。包括所有引用的 GAC DLL。并且没有注册表或操作系统设置。 【参考方案1】:

如 cmets 所述,以这种方式存储数据会产生很多不良后果,但还有一个更大的问题:“是什么阻止了它?”的答案。题。 Windows PE 加载程序锁定图像文件以在执行时写入,因此您无法获得具有写入权限的文件的 HANDLE,如 NtCreateFile 和 @987654322 @ 带有 FILE_WRITE_DATA 选项的系统调用以及任何删除文件的尝试都会失败。此块在内核级别实现,并在NtCreateProcess 系统调用期间设置,在实际调用进程及其模块入口点之前。

在不将数据写入磁盘、将其发送到远程服务器并且没有内核权限的情况下,唯一可能的肮脏技巧是通过辅助可执行文件、代码注入或命令行参数脚本(例如使用 PowerShell)来使用另一个进程,这些脚本可以杀死释放锁的进程,将数据附加到文件末尾并重新启动它。当然,这些选项会产生更糟糕的后果,我写它只是为了说明操作系统的限制(故意制造的)以及为什么没有专业软件使用这种技术来存储数据。

编辑:由于您决心完成此行为,因此我发布了通过辅助可执行文件(文件副本)附加数据的概念证明,该方法依赖于在 TEMP 文件夹中执行图像的新副本,并将路径传递给原始可执行文件,因此它可以被“写入”,因为它没有运行和锁定。 对于读者,我建议不要在生产中使用它

using System;
using System.IO;
using System.Reflection;
using System.Diagnostics;

namespace BadStorage

    class Program
    
        static void Main(string[] args)
        
            var temp = Path.GetTempPath();
            var exePath = Assembly.GetExecutingAssembly().Location;
            if (exePath.IndexOf(temp, StringComparison.OrdinalIgnoreCase) >= 0 && args.Length > 0)
            
                // "Real" main
                var originalExe = args[0];
                if (File.Exists(originalExe))
                
                    // Your program code...

                    byte[] data =  0xFF, 0xEE, 0xDD, 0xCC ;
                    // Write
                    using (var fs = new FileStream(originalExe, FileMode.Append, FileAccess.Write, FileShare.None))
                        fs.Write(data, 0, data.Length);

                    // Read
                    using (var fs = new FileStream(originalExe, FileMode.Open, FileAccess.Read, FileShare.Read))
                    
                        fs.Seek(-data.Length, SeekOrigin.End);
                        fs.Read(data, 0, data.Length);
                    
                
            
            else
            
                // Self-copy
                var exeCopy = Path.Combine(temp, Path.GetFileName(exePath));
                File.Copy(exePath, exeCopy, true);
                var p = new Process()
                
                    StartInfo = new ProcessStartInfo()
                    
                        FileName = exeCopy,
                        Arguments = $"\"exePath\"",
                        UseShellExecute = false
                    
                ;
                p.Start();
            
        
    


【讨论】:

您可以在另一个进程的内存空间中执行它并写入磁盘上的图像。有没有一种干净有效的方法来做到这一点?还是更好的方法?没有人想做这件事吗?会不会很好?我厌倦了人们告诉我事情是不可能的。 是的,正如我所说的,另一个带有另一个图像文件的进程可以终止你的进程并写入数据。即使它远非清洁,它也是可能的。没有更好的方法,因为 Windows 阻止您这样做。 看,这个想法并非完全没有价值。你显然非常致力于它。由于这里没有人会改变您的想法,我建议您熟悉 PE 文件格式(如果您喜欢 Linux,则为 ELF)并构建一个非常小的概念验证,您可以从中构建。我建议放弃 .NET 以简化事情。如果它有效,至少看看你是如何实现它的会很有趣,而且充其量你会实现你似乎想要的这种便携式应用程序革命。就我个人而言,我只是希望你在互联网上的礼仪有所改变,坦率地说,在这个帖子上这是一种耻辱。 @8vtwo 那个十六进制编辑器不能创造奇迹,我测试了它不适用于我的可执行文件,也许你正在编辑的过程只是复制到另一个位置,所以文件没有被锁定(像一个自提取程序)。我正在更新答案以演示此方法。 @GrowingBrick 这可能是 OP 错误假设文件可以在运行时解锁的真正原因。如果他只是使用任务管理器查看 exe 的文件来源或其命令行参数,他自己就能弄清楚。要么,要么它作为服务在另一个进程中运行。我怀疑他甚至能够提供一个可重复的样本来证明他的主张。

以上是关于C# 如何将代码附加到正在运行的 .NET .EXE 的末尾,最好是从该 .EXE 内部?的主要内容,如果未能解决你的问题,请参考以下文章

使用设计器 ASP.NET C# 将事件附加到占位符内的控件

C#:以干净的方式将调试器附加到进程

如何将调试器附加到在 Windows Azure VM 上运行的应用程序?

VB.NET 从 DataTable 对象将表附加到数据库

如何使用 C# 将字符附加到 MongoDB 文档中的字符串

c#无法将文本附加到现有文件[关闭]