7

I have a compiled .NET assembly with a specific resource file embedded (named 'Script.xml'). I need to programmatically change it out for another.

Is this possible to do without recompiling from source?

Currently, I do a search for text I know is in the file and it works well. But I need to do it for another project where I don't know any of the contents of the resource file and I need to find another method.

FileStream exe = new FileStream(currentexe, FileMode.Open);

//find xml part of exefile
string find = "<?xml version=\"1.0\"?>";
string lastchars = new string(' ', find.Length);
while (exe.CanRead) {
    lastchars = lastchars.Substring(1) + (char)exe.ReadByte();
    if (lastchars == find) {
        exe.Seek(-find.Length, SeekOrigin.Current);
        break;
    }
}

//output serialized script
int bytenum = 0;
foreach (byte c in xml) {
    if (c == 0) break;
    exe.WriteByte(c);
    bytenum++;
}

//clean out extra data
while (bytenum++ < ScriptFileSize) {
    exe.WriteByte(0x20);
}
exe.Close();

4 Answers 4

4

You could use Cecil to open the assembly and insert a resource (I do). YMMV

Sign up to request clarification or add additional context in comments.

3 Comments

It doesn't break the PDBs if you use Cecil to correctly read and regenerate the PDBs.
I was guessing this to be the case, but 1.5yrs ago I couldn't figure out how to do it. Do you have an example?
It was already working back then. But nowadays with the newly APIs you'd to it like indicated here: github.com/jbevain/cecil/wiki/Debug-symbols
4

Your current mechanism is very fragile - it won't work for signed assemblies (as the hash will change) or if you need to replace one resource with a larger one (as all the other offsets may move). It also has issues in terms of character encodings and the general mechanism to find the right point in the file anyway, but those are relatively unimportant given that I don't think the approach is appropriate to start with.

If you need replaceable resources, I'd put them in a different file altogether, which doesn't have the relatively delicate format of an assembly.

3 Comments

The resource file can get bigger and it still works because it can be padded with spaces (up to a max size: 'ScriptFileSize'). And unfortunately it needs to be contained in a single file for this project.
@Nick: That's effectively saying it can't get bigger than the existing resource, because the existing resource will always be ScriptFileSize. I would really, really try to redesign this. If you absolutely have to do it, use a library which knows about the assembly file format (like Cecil - mono-project.com/Cecil) but try to avoid doing it if at all possible.
@Jon: True, I forgot to mention that the assembly is originally compiled with a ton of padding already there to match the const ScriptFileSize. I give plenty of space and have never run out of it and this is currently running on hundreds of computers successfully. But I do really, really want to redesign it which is why I am posting here.
1

You're probably looking for System.Runtime.Emit to dynamically compile an assembly.

Comments

1

You can dynamically build Assemblies using reflection, specifically the AssemblyBuilder class, and include resources in your dynamically built assembly. I'm not sure it's possible to disassemble an existing assembly using reflection (although now I'm interested).

I would bark up another tree if possible.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.