• 注册
  • SPTarkov 动态 SPTarkov 动态 关注:230 内容:59

    Difficulties 困难

  • 查看作者
  • 打赏作者
  • 当前位置: ODDBA社区 > SPTarkov 动态 > 正文
  • 6
  • SPTarkov 动态
  • SPT主创
    初窥堂奥
    VIP2
    SPTarkov项目组

    Hello everyone, Today I'll provide you with a highly technical post.

    大家好,今天我将为大家提供一个高度技术性的帖子。

    Maybe someone with the technical expertise that can figure out the issue that I'm having will read this.

    也许有技术专长的人能够找出我所遇到的问题,会看到这篇文章。

    The problem

    问题所在

    In EFT 0.13.0.x, EFT introduced a modernized comminucation system for handling active connecions and making requests over the HTTPS and WSS protocols.

    在EFT 0.13.0.x中,EFT引入了一个现代化的通信系统,用于处理主动连接和通过HTTPS和WSS协议提出请求。

    This system assumes that general comminucation happens over HTTPS protocol.

    这个系统假设一般的交流是通过HTTPS协议进行的。

    Attempt 1: SSL certificate

    尝试1:SSL证书

    My intial idea was to generate a self-signed X509 certificate with SSL server privileges and then manually enroll the certificate:

    我最初的想法是用SSL服务器权限生成一个自签名的X509证书,然后手动注册该证书:

    using System;
    using System.Net;
    using System.Security.Cryptography;
    using System.Security.Cryptography.X509Certificates;

    namespace Haru.CertEnroll
    {
        class Program
        {
            static void Main(string[] args)
            {
                Load(“Haru SSL Authority”);
                Console.ReadKey();
            }

            public static void Load(string subject)
            {
                using (var store = new X509Store(StoreLocation.LocalMachine))
                {
                    store.Open(OpenFlags.ReadWrite);
                    var certs = store.Certificates.Find(X509FindType.FindBySubjectName, subject, false);

                    // remove expired certificates
                    if (certs.Count > 0 && certs[0].NotAfter < DateTime.Now.AddDays(1))
                    {
                        store.Certificates.Remove(certs[0]);
                    }

                    // generate new certificate
                    if (certs.Count == 0)
                    {
                        var start = DateTime.UtcNow.AddDays(–1);
                        var end = DateTime.UtcNow.AddMonths(1);
                        var cert = GenerateSelfSigned(subject, start, end);
                        store.Certificates.Add(cert);
                    }
                }
            }
           

            private static X509Certificate2 GenerateSelfSigned(string name, DateTime start, DateTime end)
            {
                using (RSA rsa = RSA.Create(2048))
                {
                    // allow multiple lookups
                    var builder = new SubjectAlternativeNameBuilder();
                    builder.AddIpAddress(IPAddress.Loopback);
                    builder.AddDnsName(“localhost”);

                    // create request for SSL server
                    var req = new CertificateRequest($”CN={name} SSL Authority”, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
                    {
                        CertificateExtensions = {
                            new X509BasicConstraintsExtension(false, false, 0, false),
                            new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false),
                            new X509EnhancedKeyUsageExtension(new OidCollection { new Oid(“1.3.6.1.5.5.7.3.1”) }, false),
                            builder.Build()
                        }
                    };
                    req.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(req.PublicKey, false));

                    // create certificate with both public and private key
                    var cert = req.CreateSelfSigned(start, end);

                    // export certificate
                    var password = string.Empty;
                    var exportable = cert.Export(X509ContentType.Pfx, password);
                    return new X509Certificate2(exportable, password, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);
                }
            }
        }
    }

    The problem is that I could never bind it to netsh since I do not have access to EFT's appid.

    问题是,我无法将其与netsh绑定,因为我无法访问EFT的appid。

    I do not know another method of binding the certificate to a port on windows.

    我不知道在WINDOWS上将证书绑定到一个端口的其他方法。

    Attempt 2: Harmony transpile patch

    尝试2:和声转码补丁

    The second try was to modify the code instructions directly using a transpile patch.
    第二次尝试是使用转译补丁直接修改代码指令。

    The original obfuscated method is as follows:

    原始的混淆方法如下:

    // Token: 0x06002012 RID: 8210 RVA: 0x001BF6DC File Offset: 0x001BD8DC
    public static \uE2c2 CreateFromLegacyParams(\uE2C3 legacyParams)
    {
        string[] array = legacyParams.Url.Replace(\uED30.\uE000(11698), “”).Split(new char[]
        {
            '/'
        }, 2);
        string backendName = array[0];
        string backendMethod = \uED30.\uE000(31052) + array[1];
        return new \uE2c2
        {
            // code stripped
            // 剥离的代码
        };
    }

    The resulting string of \uED30.\uE000(11698) is “https://”.

    结果字符串 \uED30.\uE000(11698) 是 “https://”。

    In order to fix it, we just need to replace the call for the value with our own:
    为了解决这个问题,我们只需要用我们自己的值来取代对该值的调用:

    protected static IEnumerable<CodeInstruction> Patch(ILGenerator generator, IEnumerable<CodeInstruction> instructions)
    {
        var codes = new List<CodeInstruction>(instructions);

        // change instructions
        codes[2] = new CodeInstruction(OpCodes.Nop);
        codes[3] = new CodeInstruction(OpCodes.Ldstr, “http://”);

        // apply changes
        return codes.AsEnumerable();
    }

    Turns out I was wrong.

    事实证明我错了.

    [Error  : Unity Log] InvalidProgramException:
    Invalid IL code in DMD<CreateFromLegacyParams>?1322007296:_::CreateFromLegacyParams ():
    IL_0040: call      0x0a000004
    [Error  : Unity Log] 无效的程序异常:
    DMD中无效的IL代码<CreateFromLegacyParams>?1322007296:_::CreateFromLegacyParams ():
    IL_0040: call      0x0a000004

    The problem is that HarmonyX nor Mono.Cecil cannot restore the right type name due to usage of unknown UTF8 codes as type names.

    问题是,由于使用未知的UTF8代码作为类型名称,HarmonyX和Mono.Cecil都不能恢复正确的类型名称。

    Manually constructing the type through reflection also failed due to the type name issue.

    由于类型名称问题,通过反射手动构建类型也失败了。

    I need your help!

    我需要你的帮助!

    I need HARU to either patch out the code or to have the server work with HTTPS certificates.

    我需要HARU来修补代码或让服务器与HTTPS证书一起工作。

    Restriction is that only net472 code may be used, external libraries are permitted if I review their code to be maintainable.

    限制是只能使用net472的代码,如果我审查他们的代码是可维护的,则允许使用外部库。

    Appendix A: Full instructions of  \uE2c2.CreateFromLegacyParams(\uE2C3 legacyParams)

    附录A:完整的指示  \uE2c2.CreateFromLegacyParams(\uE2C3 legacyParams)

    ldarg.0 NULL
    ldfld string ::Url
    ldc.i4 11698
    call static string ::(int )
    ldstr “”
    callvirt string string::Replace(string oldValue, string newValue)
    ldc.i4.1 NULL
    newarr System.Char
    dup NULL
    ldc.i4.0 NULL
    ldc.i4.s 47
    stelem.i2 NULL
    ldc.i4.2 NULL
    callvirt string[] string::Split(char[] separator, int count)
    br Label1
    ldloc.0 NULL [Label3]
    ldc.i4.0 NULL
    ldelem.ref NULL
    stloc.1 NULL
    br Label2
    stloc.0 NULL [Label1]
    br Label3
    ldc.i4 31052 [Label2]
    call static string ::(int )
    ldloc.0 NULL
    ldc.i4.1 NULL
    ldelem.ref NULL
    call static string string::Concat(string str0, string str1)
    stloc.2 NULL
    newobj void ::.ctor()
    dup NULL
    ldloc.1 NULL
    stfld string ::BackendName
    dup NULL
    ldloc.2 NULL
    stfld string ::BackendMethod
    dup NULL
    ldnull NULL
    stfld string[] ::FallbackBackendNames
    dup NULL
    ldarg.0 NULL
    ldfld bool ::UseCache
    stfld bool ::ShouldUseCache
    dup NULL
    ldarg.0 NULL
    ldfld string ::CacheId
    stfld string ::OverrideCacheId
    dup NULL
    ldarg.0 NULL
    ldfld object ::DefaultObjectInCaseOfCache
    stfld object ::DefaultObjectInCaseOfCache
    dup NULL
    ldarga.s 0
    call object ::get_Params()
    stfld object ::Params
    dup NULL
    ldarg.0 NULL
    ldfld byte? ::Retries
    stfld byte? ::Retries
    dup NULL
    ldarg.0 NULL
    ldfld int ::TimeoutSeconds
    ldc.i4.0 NULL
    bgt Label4
    call static int ::get_DefaultTimeoutSeconds()
    br Label5
    ldarg.0 NULL [Label4]
    ldfld int ::TimeoutSeconds
    stfld int ::TimeoutSeconds [Label5]
    dup NULL
    ldarg.0 NULL
    ldfld ERequestHandlingMode ::HandlingMode
    stfld ERequestHandlingMode ::HandlingMode
    ret NULL

    炉火纯青
    VIP4
    2021
        // change instructions
        codes[3] = new CodeInstruction(OpCodes.Nop);  //<--  should be 'codes[2]', is it a slip of the pen?
        codes[3] = new CodeInstruction(OpCodes.Ldstr, “http://”);


  • Senko-sanSlip of the pen! Thanks for the comment! [s-15] 笔滑! 谢谢你的评论! [s-15]
    拉黑 1年前 电脑端回复
  • 回复
    略有小成

    看天书听天问。。。。。。。。。。。。。。。。

    回复
    SPT主创
    初窥堂奥
    VIP2
    SPTarkov项目组

    I think I found a solution, but it's not without sacrifice. It looks like running the server embedded into EFT is causing me the headache, UnityEngine has many lmitiations in it's runtime which is causing me problems. Using a different HTTP server (STA's WebSocketSharp) and running the server standalone resolved the issue for me. The problem now is that modding is no longer using the same framework, I'll have to revisit the problem later.

    我想我找到了一个解决方案,但它不是没有牺牲的。看起来运行嵌入EFT的服务器让我很头疼,UnityEngine在它的运行时有许多lmitiations,这给我带来了问题。使用不同的HTTP服务器(STA的WebSocketSharp)和独立运行服务器为我解决了这个问题。现在的问题是,modding不再使用相同的框架,我必须在以后重新审视这个问题。

    回复
    初来乍到

    看不懂顶

    回复
    炉火纯青

    世界因你而精彩

    回复

    请登录之后再进行评论

    登录
  • 签到
  • 任务
  • 发布
  • 模式切换
  • 偏好设置
  • 帖子间隔 侧栏位置: