简体   繁体   English

使用Mono.Cecil替换对类型/命名空间的引用

[英]Replace references to a type/namespace using Mono.Cecil

Background (unnecessary, confusing, only for the curious) 背景(不必要,令人困惑,只为好奇)

I'm using the free version of Unity3D for Mobile and it doesn't allow me to use the System.Net.Sockets namespace on mobile devices. 我正在使用Unity3D for Mobile的免费版本,它不允许我在移动设备上使用System.Net.Sockets命名空间。 The problem is that I'm using a compiled .dll library (namely, IKVM) that references the System.Net.Sockets . 问题是我正在使用引用System.Net.Sockets已编译的.dll库(即IKVM)。 I'm not actually using the classes in IKVM that references that references System.Net.Sockets , so instead of buying the $3000 Unity Pro mobile licenses, I made a stub library of the Sockets namespace called dudeprgm.Net.Sockets that just replaces all the classes and methods with stubs (I did this using the Mono source code). 我实际上并没有使用引用System.Net.Sockets IKVM中的类,因此我没有购买3000美元的Unity Pro移动许可证,而是创建了一个名为dudeprgm.Net.SocketsSockets命名空间的存根库, dudeprgm.Net.Sockets替换了所有存根的类和方法(我使用Mono源代码完成此操作)。


My problem 我的问题

I need to replace all System.Net.Sockets.* references in my dlls to dudeprgm.Net.Sockets.* . 我需要将dll中的所有System.Net.Sockets.*引用替换为dudeprgm.Net.Sockets.* I know that something like this is possible and done by other people (See EDIT below, at the bottom of the page) . 我知道这样的事情是可能的并且由其他人完成 (参见下面的编辑 ,在页面底部) I would like to know how to do it myself. 我想知道自己该怎么做。

I was able to come up with the following code using Mono.Cecil. 我能够使用Mono.Cecil提出以下代码。
It goes through all the IL instructions, checks if the operand is an InlineType , then checks if the inline type is part of System.Net.Sockets , then renames it to dudeprgm.Net.Sockets and writes it. 它遍历所有IL指令,检查操作数是否为InlineType ,然后检查内联类型是否是System.Net.Sockets一部分,然后将其重命名为dudeprgm.Net.Sockets并写入。 **I'm not sure if this is the right way to go about "finding-and-replacing" in Mono.Cecil. **我不确定这是否是在Mono.Cecil中进行“查找和替换”的正确方法。 Problem is, this doesn't catch all Sockets usages (see below). 问题是,这并没有捕获所有Sockets使用(见下文)。

private static AssemblyDefinition stubsAssembly;

static void Main(string[] args) {
    AssemblyDefinition asm = AssemblyDefinition.ReadAssembly(args[0]);
    stubsAssembly = AssemblyDefinition.ReadAssembly("Socket Stubs.dll");
    // ...
    // Call ProcessSockets on everything
    // ...
    asm.Write(args[1]);
}

/*
 * This will be run on every property, constructor and method in the entire dll given
 */
private static void ProcessSockets(MethodDefinition method) {
    if (method.HasBody) {
        Mono.Collections.Generic.Collection<Instruction> instructions = method.Body.Instructions;
        for (int i = 0; i < instructions.Count; i++) {
            Instruction instruction = instructions[i];
            if (instruction.OpCode.OperandType == OperandType.InlineType) {
                string operand = instruction.Operand.ToString();
                if (operand.StartsWith("System.Net.Sockets")) {
                    Console.WriteLine(method.DeclaringType + "." + method.Name + "(...) uses type " + operand);
                    Console.WriteLine("\t(Instruction: " + instruction.OpCode.ToString() + " " + instruction.Operand.ToString() + ")");
                    instruction.Operand = method.Module.Import(stubsAssembly.MainModule.GetType("dudeprgm.Net.Sockets", operand.Substring(19)));
                    Console.WriteLine("\tReplaced with type " + "dudeprgm.Net.Sockets" + operand.Substring(18));
                }
            }
        }
    }
}

It works fine, but only catches "simple" instructions. 它工作正常,但只捕获“简单”指令。 Decompiled with ildasm , I can see where it replaced the types like here: ildasm反编译,我可以看到它取代了这里的类型:

box        ['Socket Stubs'/*23000009*/]dudeprgm.Net.Sockets.SocketOptionLevel/*01000058*/

But it didn't catch these "complex" instructions: 但它没有抓住这些“复杂”的指示:

callvirt   instance void [System/*23000003*/]System.Net.Sockets.Socket/*0100003F*/::SetSocketOption(valuetype [System/*23000003*/]System.Net.Sockets.SocketOptionLevel/*01000055*/,
                                                                                                                                                valuetype [System/*23000003*/]System.Net.Sockets.SocketOptionName/*01000056*/,
                                                                                                                                                int32) /* 0A000094 */

Now the .dll s are a jumble of dudeprgm.Net.Sockets and System.Net.Sockets references. 现在.dlldudeprgm.Net.SocketsSystem.Net.Sockets引用的混乱。

I'm pretty sure that this is happening because I'm only changing OperandType.InlineType s, but I'm not sure on how else to do this. 我很确定这种情况正在发生,因为我只是在改变OperandType.InlineType ,但我不确定如何做到这一点。 I've tried looking around everywhere, but it seems to me like Mono.Cecil has no way to set operands to a string , everything seems to have to be done using the Cecil API only ( https://stackoverflow.com/a/7215711/837703 ). 我试过到处寻找,但在我看来,像Mono.Cecil无法将操作数设置为string ,似乎只需要使用Cecil API完成所有操作( https://stackoverflow.com/a/ 7215711/837703 )。

(Sorry if I'm using incorrect terms, I'm pretty new to IL in general.) (对不起,如果我使用的是不正确的条款,我对IL一般都是新手。)

Question

How can I replace all places where System.Net.Sockets appear in Mono.Cecil, rather than just where the operand is an InlineType ? 如何替换System.Net.Sockets出现在Mono.Cecil中的所有位置,而不仅仅是操作数是InlineType I don't really want to go through every OperandType there is in Cecil, I was just looking for some find-and-replace method in Cecil where I wouldn't have to work with plain IL myself. 我真的不想查看Cecil中的每一个OperandType ,我只是在Cecil中寻找一些查找和替换方法,我不必自己使用普通的IL。

EDIT: (also unnecessary, confusing, and only for the curious) 编辑:(也没必要,令人困惑,只为好奇)
This person was able to do something similar for $25: http://www.reddit.com/r/Unity3D/comments/1xq516/good_ol_sockets_net_sockets_for_mobile_without/ . 这个人能够以25美元的价格做类似的事情: http//www.reddit.com/r/Unity3D/comments/1xq516/good_ol_sockets_net_sockets_for_mobile_without/

Automatic patcher tool that detects and fixes socket usage in scripts and .dll. 自动修补程序工具,用于检测和修复脚本和.dll中的套接字使用情况。

... ...

"DLL's are patched using Mono.Cecil. ... “DLL使用Mono.Cecil进行修补。...

You can go look at the second screenshot at https://www.assetstore.unity3d.com/en/#!/content/13166 and see that it says that it can replace namespaces. 您可以查看https://www.assetstore.unity3d.com/en/#!/content/13166上的第二个屏幕截图,看看它是否可以替换命名空间。

That library doesn't fit my needs, because 1) it doesn't rename to the namespace I want ( dudeprgm.Net.Sockets ), 2) the library that it is renaming to does not support all the System.Net.Sockets classes that IKVM needs, because IKVM uses pretty much every Sockets class and 3) it costs $25 and I don't really want to buy something that I'm not going to use. 该库不符合我的需求,因为1)它不会重命名为我想要的命名空间( dudeprgm.Net.Sockets ),2)它重命名的库不支持所有的System.Net.Sockets类IKVM需要,因为IKVM几乎使用每个Sockets类而且3)它的成本是25美元而且我真的不想购买我不会使用的东西。 I just wanted to show that replacing namespace/type references in Mono.Cecil is possible. 我只想表明在Mono.Cecil中替换名称空间/类型引用是可能的。

[01] Similar problem [01]类似的问题

Your problem with replacing references to a dll (and types within) with another dll (and types within) is technically similar to problem known as 用另一个dll(和其中的类型)替换对dll(和其中的类型)的引用的问题在技术上类似于已知的问题

Google: "c# add strong name to 3rd party assembly" 谷歌:“c#为第三方组装添加强名”

In this problem you want to have your application signed by strong name and possibly installed into GAC or Ngen-ed, but your application depends on a legacy 3rd party library which does not have a strong name added at compile time, which breaks the requirement saying that a strong named assembly can use only strong named assemblies. 在这个问题中,您希望您的应用程序使用强名称进行签名,并且可能已安装到GAC或Ngen-ed中,但您的应用程序依赖于在编译时未添加强名称的旧版第三方库,这违反了要求强命名程序集只能使用强命名程序集。 You don't have source code for the 3rd party library, only binaries, so you can't recompile it (== "simplified description") 您没有第三方库的源代码,只有二进制文件,因此您无法重新编译它(==“简化描述”)

There are several solutions possible, 3 most typical being: 有几种可能的解决方案,最常见的是3种:

[02] Similar problem's solution #1 [02]类似问题的解决方案#1

You can use ildasm / ilasm round trip , convert all binaries into text form, change all references into their strong name equivalents (recursively) and turn text back into code. 您可以使用ildasm / ilasm round trip ,将所有二进制文件转换为文本形式,将所有引用更改为强名称等效(递归)并将文本转换回代码。 Examples: http://buffered.io/posts/net-fu-signing-an-unsigned-assembly-without-delay-signing/ and https://stackoverflow.com/a/6546134/2626313 示例: http//buffered.io/posts/net-fu-signing-an-unsigned-assembly-without-delay-signing/https://stackoverflow.com/a/6546134/2626313

[03] Similar problem's solution #2 [03]类似问题的解决方案#2

You can use tools already written to solve exactly this problem, example: http://brutaldev.com/post/2013/10/18/NET-Assembly-Strong-Name-Signer 您可以使用已编写的工具来解决此问题,例如: http//brutaldev.com/post/2013/10/18/NET-Assembly-Strong-Name-Signer

[04] Similar problem's solution #3 [04]类似问题的解决方案#3

You can create a tool crafted to match your exact needs. 您可以创建一个精心设计的工具来满足您的确切需求。 It is possible, I have done it, it took several weeks and the code weighs several thousand lines of code. 有可能,我已经完成了,花了几个星期,代码重达几千行代码。 For the most dirty work I have reused (with some slight modifications) mainly source code from (unordered): 对于我已经重复使用的最脏的工作(稍作修改)主要来自(无序)源代码:

  • ApiChange.Api.Introspection.CorFlagsReader.cs ApiChange.Api.Introspection.CorFlagsReader.cs
  • GACManagerApi.Fusion GACManagerApi.Fusion
  • brutaldev/StrongNameSigner brutaldev / StrongNameSigner
  • icsharpcode/ILSpy icsharpcode / ILSpy
  • Mono.Cecil.Binary Mono.Cecil.Binary
  • Mono.Cecil.Metadata Mono.Cecil.Metadata
  • Mono.ResGen Mono.ResGen
  • Ricciolo.StylesExplorer.MarkupReflection Ricciolo.StylesExplorer.MarkupReflection
  • and reading http://referencesource.microsoft.com/ 并阅读http://referencesource.microsoft.com/

[05] Your problem [05]你的问题

Although the problem you have described looks like just a subset of what I'm describing above, it may well turn out to be the same problem if you want to use GAC installation which in turn requires strong name signing. 虽然您所描述的问题看起来只是我上面描述的问题的一部分,但如果您想使用GAC安装,则可能会出现同样的问题,而GAC安装又需要强名称签名。

My recommendation for you is 我给你的建议是

[06] Your problem's solution #1 [06]你的问题的解决方案#1

Give the easiest solution [02] a tryand to get into least trouble use ilasm/ildasm tools from the Mono package not the ones provided by Microsoft's .NET Framework (Microsoft's Resgen in .NET Framework 4.5 is broken and cannot round-trip resx format, Ildasm output does not handle non-ASCII characters correctly etc. While you can't fix Microsoft's broken closed source, you can fix Mono's open source but I did not have to.) 提供最简单的解决方案[02]尝试使用Mono软件包中的ilasm / ildasm工具,而不是微软.NET Framework提供的工具(.NET Framework 4.5中的Microsoft Resgen已损坏且不能往返resx格式, Ildasm输出不能正确处理非ASCII字符等。虽然你无法修复微软破解的闭源,你可以修复Mono的开源,但我不需要。)

[07] Your problem's solution #2 [07]你的问题的解决方案#2

If [06] does not work for you then study (debug) → ILSpy ← and study Mono documentation for various command line tools doing what you need and their sources - you'll see how exactly they use the Mono.Cecil library 如果[06]不适合你,那么学习(调试)→ ILSpy ←并研究各种命令行工具的Mono文档,做你需要的东西及其来源 - 你会看到他们如何使用Mono.Cecil库

If you face the need to validate strong named or even signed assemblies (tampering them will invalidate the signatures) or remove the signatures etc. You are going to dive into code longer than a simple Stack Overflow answer can describe. 如果您需要验证强名称或甚至签名的程序集(篡改它们将使签名无效)或删除签名等。您将深入研究代码的时间超过简单的Stack Overflow答案可以描述的内容。

[08] Your problem's solution #3 [08]你的问题的解决方案#3

Lurking around what ILMerge does and how can point you to an easier solution 潜伏在ILMerge的周围,​​以及如何为您提供更简单的解决方案

[09] Your problem's solution #4 [09]你的问题的解决方案#4

Another easier solution might be (if IKVM supports it) hooking the AssemblyResolve event where you can remap dll name into physical dll, loaded eg From totally different file or from a resource stream etc. As shown in several answers of older Stack Overflow question Embedding DLLs in a compiled executable 另一个更简单的解决方案可能是(如果IKVM支持它)挂钩AssemblyResolve事件,您可以将dll名称重新映射到物理dll,例如从完全不同的文件或资源流等加载。如旧堆栈溢出问题嵌入DLL的几个答案中所示在已编译的可执行文件

(EDIT #1: after comments) (编辑#1:评论后)

[10] Your problem's solution #5 [10]你的问题的解决方案#5

If your more or less general question actually boils down into "How can I make IKVM.dll to use my socket classes instead of those from namespace System.Net.Sockets" then quite straightforward solution might be: 如果您或多或少的一般性问题实际上归结为“如何使IKVM.dll使用我的套接字类而不是命名空间System.Net.Sockets中的那些”,那么非常简单的解决方案可能是:

Compile and deploy your own customized version of IKVM.dll using source code available at http://www.ikvm.net/download.html - no binary Mono.Cecil magic needed. 使用http://www.ikvm.net/download.html上提供的源代码编译和部署您自己的自定义版本的IKVM.dll - 不需要二进制Mono.Cecil魔术。

As all code is open it should be possible to find and redirect all references pointing to namespace System.Net into dudeprgm.Net by 由于所有代码都是打开的,因此应该可以找到并将指向命名空间System.Net所有引用重定向到dudeprgm.Net

  • [10.1] get IKVM source code and all other prerequisites and make sure you can compile working IKVM.dll [10.1]获取IKVM源代码和所有其他先决条件,并确保您可以编译工作IKVM.dll
  • [10.2] add dudeprgm.Net.cs project to the solution [10.2]将dudeprgm.Net.cs项目添加到解决方案中
  • [10.3] in all source files find and remove everything looking like using System.Net [10.3]在所有源文件中查找并删除所有using System.Net
  • [10.4] in all source files full text find and replace everything that looks like System.Net with dudeprgm.Net [10.4]在所有源文件中,全文通过dudeprgm.Net查找并替换看起来像System.Netdudeprgm.Net
  • [10.5] compile. [10.5]编译。 When compiler complains about a missing symbol (that was before in the System.Net namespace) then add it to your stub file. 当编译器抱怨缺少符号(之前在System.Net命名空间中)时,然后将其添加到存根文件中。 goto [10.5] 转到[10.5]
  • [10.6] if the above step does not settle down as "build ok" after 2 hours then think about another solution (or get some sleep) [10.6]如果上述步骤在2小时后没有安定下来“建立正常”,那么考虑另一种解决方案(或睡一会儿)
  • [10.7] check IKVM license ( http://sourceforge.net/p/ikvm/wiki/License/ ) if there is something you must change/claim/acknowledge as the original source code was modified [10.7]检查IKVM许可证( http://sourceforge.net/p/ikvm/wiki/License/ )是否有必要更改/声明/确认的内容,因为原始源代码已被修改

(EDIT #2: after comments) (编辑#2:评论后)

[11] Your problem's solution #6 [11]你的问题的解决方案#6

If you choose track [04] and working with text files and ilasm/ildasm tools (style [02] ) would not seem productive then below is the key relevant part of my automatic strong name signer which changes assembly references into other references using Mono.Cecil. 如果您选择track [04]并使用文本文件和ilasm/ildasm工具(样式[02] )似乎效率不高,那么下面是我的自动强名称签名者的关键相关部分,它使用Mono将程序集引用更改为其他引用。塞西尔。 The code is pasted as is (without lines of code before, after and all around) in a form that works for me. 代码按原样粘贴(不含代码行,之前,之后和所有代码),以适合我的形式。 Reading keys: a is Mono.Cecil.AssemblyDefinition , b implements Mono.Cecil.IAssemblyResolver , key method in b instance is the method AssemblyDefinition Resolve(AssemblyNameReference name) which translates required DLL name into call to AssemblyDefinition.ReadAssembly(..) . 读取键: a is Mono.Cecil.AssemblyDefinitionb implements Mono.Cecil.IAssemblyResolverb实例中的键方法是AssemblyDefinition Resolve(AssemblyNameReference name) ,它将所需的DLL名称转换为对AssemblyDefinition.ReadAssembly(..)调用。 I did not need to parse the instruction stream, remapping assembly references was enough (I can paste here few other pieces from my code if needed) 我不需要解析指令流,重新映射汇编引用就足够了(如果需要,我可以在这里粘贴我的代码中的其他几个部分)

/// <summary>
/// Fixes references in assembly pointing to other assemblies to make their PublicKeyToken-s compatible. Returns true if some changes were made.
/// <para>Inspiration comes from https://github.com/brutaldev/StrongNameSigner/blob/master/src/Brutal.Dev.StrongNameSigner.UI/MainForm.cs
/// see call to SigningHelper.FixAssemblyReference
/// </para>
/// </summary>
public static bool FixStrongNameReferences(IEngine engine, string assemblyFile, string keyFile, string password)
{
    var modified = false;

    assemblyFile = Path.GetFullPath(assemblyFile);

    var assemblyHasStrongName = GetAssemblyInfo(assemblyFile, AssemblyInfoFlags.Read_StrongNameStatus)
        .StrongNameStatus == StrongNameStatus.Present;

    using (var handle = new AssemblyHandle(engine, assemblyFile))
    {
        AssemblyDefinition a;

        var resolver = handle.GetAssemblyResolver();

        a = handle.AssemblyDefinition;

        foreach (var reference in a.MainModule.AssemblyReferences)
        {
            var b = resolver.Resolve(reference);

            if (b != null)
            {
                // Found a matching reference, let's set the public key token.
                if (BitConverter.ToString(reference.PublicKeyToken) != BitConverter.ToString(b.Name.PublicKeyToken))
                {
                    reference.PublicKeyToken = b.Name.PublicKeyToken ?? new byte[0];
                    modified = true;
                }
            }
        }

        foreach (var resource in a.MainModule.Resources.ToList())
        {
            var er = resource as EmbeddedResource;
            if (er != null && er.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase))
            {
                using (var targetStream = new MemoryStream())
                {
                    bool resourceModified = false;

                    using (var sourceStream = er.GetResourceStream())
                    {
                        using (System.Resources.IResourceReader reader = new System.Resources.ResourceReader(sourceStream))
                        {
                            using (var writer = new System.Resources.ResourceWriter(targetStream))
                            {
                                foreach (DictionaryEntry entry in reader)
                                {
                                    var key = (string)entry.Key;
                                    if (entry.Value is string)
                                    {
                                        writer.AddResource(key, (string)entry.Value);
                                    }
                                    else
                                    {
                                        if (key.EndsWith(".baml", StringComparison.OrdinalIgnoreCase) && entry.Value is Stream)
                                        {
                                            Stream newBamlStream = null;
                                            if (FixStrongNameReferences(handle, (Stream)entry.Value, ref newBamlStream))
                                            {
                                                writer.AddResource(key, newBamlStream, closeAfterWrite: true);
                                                resourceModified = true;
                                            }
                                            else
                                            {
                                                writer.AddResource(key, entry.Value);
                                            }
                                        }
                                        else
                                        {
                                            writer.AddResource(key, entry.Value);
                                        }
                                    }
                                }
                            }
                        }

                        if (resourceModified)
                        {
                            targetStream.Flush();
                            // I'll swap new resource instead of the old one
                            a.MainModule.Resources.Remove(resource);
                            a.MainModule.Resources.Add(new EmbeddedResource(er.Name, resource.Attributes, targetStream.ToArray()));
                            modified = true;
                        }
                    }
                }
            }
        }

        if (modified)
        {
            string backupFile = SigningHelper.GetTemporaryFile(assemblyFile, 1);

            // Make a backup before overwriting.
            File.Copy(assemblyFile, backupFile, true);
            try
            {
                try
                {
                    AssemblyResolver.RunDefaultAssemblyResolver(Path.GetDirectoryName(assemblyFile), () => {
                        // remove previous strong name https://groups.google.com/forum/#!topic/mono-cecil/5If6OnZCpWo
                        a.Name.HasPublicKey = false;
                        a.Name.PublicKey = new byte[0];
                        a.MainModule.Attributes &= ~ModuleAttributes.StrongNameSigned;

                        a.Write(assemblyFile);
                    });

                    if (assemblyHasStrongName)
                    {
                        SigningHelper.SignAssembly(assemblyFile, keyFile, null, password);
                    }
                }
                catch (Exception)
                {
                    // Restore the backup if something goes wrong.
                    File.Copy(backupFile, assemblyFile, true);

                    throw;
                }
            }
            finally
            {
                File.Delete(backupFile);
            }
        }
    }

    return modified;
}

[12] Your turn [12]轮到你了

This is actually meant to be an extension to @xmojmer's answer. 这实际上是@ xmojmer答案的延伸。

I wrote a small bash script to automate xmojmer's option [02] : 我写了一个小的bash脚本来自动化xmojmer的选项[02]

# vsilscript.sh

# Usage:
# Open Cygwin
# . vsilscript.sh <original .dll to patch>
# output in "Sockets_Patched" subdirectory
nodosfilewarning=true # just in case cygwin complains
ILASM_PATH="/cygdrive/c/Windows/Microsoft.NET/Framework64/" # modify for your needs
ILASM_PATH="$ILASM_PATH"$(ls "$ILASM_PATH" -v | tail -n 1)
ILDASM_PATH="/cygdrive/c/Program Files (x86)/Microsoft SDKs/Windows/v8.1A/bin/NETFX 4.5.1 Tools" # modify for your needs
PATH="$ILDASM_PATH:$ILASM_PATH:$PATH"
base=$(echo $1 | sed "s/\.dll//g")
ildasm /out=$base".il" /all /typelist $base".dll"
cp $base".il" "tempdisassembled.il"
cat "tempdisassembled.il" | awk '
BEGIN { print ".assembly extern socketstubs { }"; }
{ gsub(/\[System[^\]]*\]System\.Net\.Sockets/, "[socketstubs]dudeprgm.Net.Sockets", $0); print $0; }
END { print "\n"; }
' 1> $base".il" #change the awk program to swap out different types
rm "tempdisassembled.il"
mkdir "Sockets_Patched"
# read -p "Press Enter to assemble..."
ilasm /output:"Sockets_Patched/"$base".dll" /dll /resource:$base".res" $base".il"

Modify the ILASM_PATH and ILDASM_PATH variables if your computer is 32bit or have ilasm and ildasm on different locations. 如果您的计算机是32位或在不同位置具有ilasmildasm ,请修改ILASM_PATHILDASM_PATH变量。 This script assumes you are using Cygwin on Windows. 此脚本假定您在Windows上使用Cygwin

The modification happens in the awk command. 修改发生在awk命令中。 It adds a reference to my library of stubs (called socketstubs.dll , and is stored in the same directory.) by adding 它通过添加添加对我的存根库(称为socketstubs.dll ,并存储在同一目录中)的引用。

.assembly extern sockectstubs { }

at the beginning of the disassembled IL code. 在反汇编的IL代码的开头。 Then, for each line, it looks for [System]System.Net.Sockets and replaces them with [socketstubs]dudeprgm.Net.Sockets . 然后,对于每一行,它查找[System]System.Net.Sockets并用[socketstubs]dudeprgm.Net.Sockets替换它们。 It adds a newline at the end of the IL code, or else ilasm won't re-assemble it, as per the docs : 它在IL代码的末尾添加了换行符,否则ilasm将不会根据文档重新组合它:

Compilation might fail if the last line of code in the .il source file does not have either trailing white space or an end-of-line character. 如果.il源文件中的最后一行代码没有尾随空格或行尾字符,则编译可能会失败。

The final patched .dll will be placed in a new directory called "Sockets_Patched". 最终修补的.dll将放在一个名为“Sockets_Patched”的新目录中。

You can modify this script to swap any two namespaces in any dll: 您可以修改此脚本以交换任何dll中的任何两个名称空间:

  1. Replace the System in [System[^\\]] to whatever assembly contains your old namespace [System[^\\]]System替换为包含旧命名空间的任何程序集
  2. Replace System\\.Net\\.Sockets with your old namespace and put a backslash in front of every period 用您的旧命名空间替换System\\.Net\\.Sockets并在每个句点前放置一个反斜杠
  3. Replace all socketstubs in the script with your library containing the new namespace 将脚本中的所有socketstubs替换为包含新命名空间的库
  4. Replace dudeprgm.Net.Sockets with your new namespace 用您的新命名空间替换dudeprgm.Net.Sockets

You could wrap the sockets objects in an interface and then dependency inject the implementation you really want. 您可以将套接字对象包装在一个接口中,然后依赖注入您真正想要的实现。 The code might be a little tedious, but you can swap out the sockets to anything you want after that without directly referencing System.Net.Sockets 代码可能有点乏味,但您可以在不直接引用System.Net.Sockets的情况下将套接字交换到您想要的任何内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM