zoukankan      html  css  js  c++  java
  • 怎样让1+1=3?

    如下所示的是一个.NET程序。我们在这段程序中定义了一个作整数加法运算的Add方法,但是我希望将针对这个方法的调用转移到另一个Add2方法上,为此我定义了一个Override方法。

    class Program
    {
        static void Main()
        {
            Override(() => Add(default, default), () => Add2(default, default));
            Console.WriteLine($"Add(1, 1) == {Add(1, 1)}");
            Console.ReadLine();
        }
    
        public static int Add(int x, int y) => x + y;
        public static int Add2(int x, int y) => x + y + 1;
        public static void Override(Expression<Action> originalCall, Expression<Action> targetCall);
    }

    从如下所示的输出可以看出:虽然源程序我们调用的是Add方法,实际上最终的调用被转移到Add2方法上。

    image

    我们知道通过C#编写的.NET程序在编译后会转化成IL Code,在运行时以及时编译的方式转化成机器指令。如果想“篡改”某个方法的实现,要么在JIT之前改变IL代码,要么直接修改最终的机器指令。Override方法采用的是第二种解决方案,如下所示的该方法的实现,基本的思路就是将将原方法的机器指令修改为JUMP(对应x86二进制为0xE9)指令实现向目标方法的跳转。

    public static void Override(Expression<Action> originalCall, Expression<Action> targetCall)
    {
        var originalMethod = ((MethodCallExpression)originalCall.Body).Method;
        var targetMethod = ((MethodCallExpression)targetCall.Body).Method;
    
        RuntimeHelpers.PrepareMethod(originalMethod.MethodHandle);
        RuntimeHelpers.PrepareMethod(targetMethod.MethodHandle);
    
        var sourceAddress = originalMethod.MethodHandle.GetFunctionPointer();
        var targetAddress = (long)targetMethod.MethodHandle.GetFunctionPointer();
    
        int offset = (int)(targetAddress - (long)sourceAddress - 4 - 1); 
    
        byte[] instruction = {
            0xE9, // JUMP
            (byte)(offset & 0xFF),
            (byte)((offset >> 8) & 0xFF),
            (byte)((offset >> 16) & 0xFF),
            (byte)((offset >> 24) & 0xFF)
        };
    
        Marshal.Copy(instruction, 0, sourceAddress, instruction.Length);
    }

    这个方式有时候会很有用,我最近应用的场景是希望篡改.NET Core应用中针对IHostEnvironment的如下三个扩展方法的实现,因为我们的部署环境并没有按照默认的命名约定(Development、Staging和Production)这样导致了这三个方法返回错误的结果。但是IsDevelopment方法的返回结果在.NET Core服务承载系统中很重要,所以不得不篡改它的实现逻辑。

    public static class HostEnvironmentEnvExtensions
    {
        public static bool IsDevelopment(this IHostEnvironment hostEnvironment)
        =>hostEnvironment.IsEnvironment(Environments.Development);
    
        public static bool IsProduction(this IHostEnvironment hostEnvironment)
        =>hostEnvironment.IsEnvironment(Environments.Production);
    
        public static bool IsStaging(this IHostEnvironment hostEnvironment)
        =>hostEnvironment.IsEnvironment(Environments.Staging);
    }
    
    public static class Environments
    {
        public static readonly string Development = "Development";
        public static readonly string Production = "Production";
        public static readonly string Staging = "Staging";
    }

    从某种意义上讲,这也体现了.NET Core Hosting System在设计上的一个问题,希望在以后的版本中能够解决这个问题。

  • 相关阅读:
    基于C#和Asp.NET MVC开发部标视频和苏标主动安全监控平台
    基于Java Netty框架构建高性能的部标808协议的GPS服务器
    交通部796部标平台开发索引
    GPS部标监控平台的功能设计(一)-功能列表
    基于Java Mina框架的部标jt808服务器设计和开发
    基于Asp.NET MVC框架+SignalR +ActiveMQ + Ali OSS 服务构建苏标主动安全智能防控平台
    部标809协议2019版本与2011版本的区别
    出租车Jt/T 905协议与部标1078协议融合的网约车视频监控平台
    基于JT/T 1078协议设计和开发部标视频服务器
    基于Html5+HLS协议播放符合部标1078协议的实时流媒体视频
  • 原文地址:https://www.cnblogs.com/artech/p/11354583.html
Copyright © 2011-2022 走看看