pixartist
pixartist

Reputation: 1155

Injecting resources into .net executable?

is it possible to inject resources into .net applications (after compilation) so they can be used by the application via resource streams ?

I've read that .net resources differ from regular winapi .exe resources. Is that true ?

I know the tool "resource hacker", it can inject pretty much anything into an exe ( as far as I know), but I'm not sure about .net files. (at, work, can't test it right now).

Upvotes: 0

Views: 1828

Answers (1)

Michael
Michael

Reputation: 3150

If the template code for your self-extracting exe is simple enough, I would suggest embedding it as a resource in the application that you initially intended to write (the one that you wanted to use to do the resource manipulation).

That way, you can use a combination of C#'s CodeDomProvider and ResourceWriter to produce a self-contained exe file with your desired resources baked in.

Basically, the flow is like so:

  • Extract template for your "self extracting executable" from your app (embedded as a resource file - this file contains the Main(string args[]) method of your program in text format)
  • Write your desired resources to a resource stream
  • Create a CodeDomProvider and call CompileAssemblyFromSource with parameters that specify the resource stream you created in the prior step

Edit: Here is a working example. It embeds the string Hello World! (from a file as a byte[] to show you can use this concept with "binary resource" data) into a console application:

using System;
using System.CodeDom.Compiler;
using System.Diagnostics;
using System.IO;
using System.Resources;

namespace DynamicEmbed
{
    class Program
    {
        static void Main(string[] args)
        {
            var parameters = new CompilerParameters
            {
                GenerateExecutable = true,
                OutputAssembly = Path.Combine(Environment.CurrentDirectory, Path.GetTempFileName()) + ".exe",
            };

            // Based on the code your template uses, these will need to change
            parameters.ReferencedAssemblies.Add("System.dll");
            parameters.ReferencedAssemblies.Add("System.Core.dll");
            parameters.ReferencedAssemblies.Add("System.Linq.dll");

            // Create the embedded resource file on disk
            string embeddedResourceFile = Path.GetTempFileName();
            using (var rw = new ResourceWriter(embeddedResourceFile))
            {
                var tempFile = Path.GetTempFileName();
                File.WriteAllText(tempFile, "Hello, World!");

                rw.AddResourceData("my.resource.key", "ResourceTypeCode.ByteArray", File.ReadAllBytes(tempFile));
            }

            // Embed the resource file into the exe
            parameters.EmbeddedResources.Add(embeddedResourceFile);

            // Source code for dynamically generated exe
            string source =
@"
using System;
using System.Linq;
using System.Resources;

namespace DynamicallyEmbeded
{
    class Program
    {
        static void Main(string[] args)
        {
            var resourceName = typeof(Program).Assembly.GetManifestResourceNames()[0];
            Console.WriteLine(""Embedded resource name: {0}"", resourceName);

            var stream = typeof(Program).Assembly.GetManifestResourceStream(resourceName);
            var resourceData = new byte[] { };
            using (var rr = new ResourceReader(stream))
            {
                var resourceType = """";
                rr.GetResourceData(""my.resource.key"", out resourceType, out resourceData);
            }

            var contents = new string(resourceData.Select(x => (char)x).ToArray());
            Console.WriteLine(""Embedded resource contents: {0}"", contents);

            Console.Write(""Press any key to continue . . ."");
            Console.ReadKey();
        }
    }
}";

            // Create the code
            CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
            var results = provider.CompileAssemblyFromSource(parameters, source);

            // Start the program (just to show it worked)
            if (results.Errors.Count == 0)
            {
                Process.Start(parameters.OutputAssembly);
            }
        }
    }
}

Upvotes: 4

Related Questions