Giter VIP home page Giter VIP logo

jitex's Introduction

Jitex Jitex Build Nuget

A library to modify MSIL/Native code at runtime.

It's a library built in .NET Standard 2.0, works on all version >=.NET Core 2.0.

.NET Core (2.1 ~ 3.1) .NET 5~7 .NET Framework (4.6.1 ~ 4.8) Mono
Windows (x64/ARM64) ✔️ ✔️ ❌ Not supported ❌ Not supported
Linux (x64/ARM64) ✔️ ✔️ ❌ Not supported ❌ Not supported
MacOS (x64/ARM64) ✔️ ✔️ ❌ Not supported​ ❌ Not supported

Jitex can help you replace code at runtime easily.

using System;
using Jitex;

JitexManager.AddMethodResolver(context =>
{
    if (context.Method.Name.Contains("Sum"))
        context.ResolveMethod<Func<int, int, int>>(Mul); //Replace Sum by Mul
});

int result = Sum(5, 5); //Output is 25
Console.WriteLine(result);

static int Sum(int n1, int n2) => n1 + n2;
static int Mul(int n1, int n2) => n1 * n2;

Support

Intercept call

using System;
using Jitex;

JitexManager.MethodResolver += context =>
{
    if (context.Method.Name.Contains("Sum"))
        context.InterceptCall();
};

//Every call from Sum, will be pass here.
JitexManager.Interceptor += async context =>
{
    //Get parameters passed in call
    int n1 = context.GetParameterValue<int>(0);
    int n2 = context.GetParameterValue<int>(1);

    n1 *= 10;
    n2 *= 10;

    //Override parameters value
    context.SetParameterValue(0, n1);
    context.SetParameterValue(1, n2);

    //Or we can just set return value
    context.SetReturnValue(100);
};

int result = Sum(5, 5); //Output is 100
Console.WriteLine(result);

int Sum(int n1, int n2) => n1 * n2;

Replace Method

/// <summary>
///     Take sum of 2 random numbers
/// </summary>
/// <returns></returns>
public static int SumReplace () 
{
  const string url = "https://www.random.org/integers/?num=2&min=1&max=999&col=2&base=10&format=plain&rnd=new";
  using HttpClient client = new HttpClient ();
  using HttpResponseMessage response = client.GetAsync (url).Result;
  string content = response.Content.ReadAsStringAsync ().Result;
    
  string[] columns = content.Split ("\t");
    
  int num1 = int.Parse (columns[0]);
  int num2 = int.Parse (columns[1]);
    
  return num1 + num2;
}

private static void MethodResolver (MethodContext context) 
{
  if (context.Method.Name == "Sum") {
    //Replace Sum to our SumReplace
    MethodInfo replaceSumMethod = typeof (Program).GetMethod (nameof (SumReplace));
    context.ResolveMethod (replaceSumMethod);
  }
}

Detour Method

private static void MethodResolver (MethodContext context) {
  if (context.Method.Name == "Sum") {
    //Detour by MethodInfo
    MethodInfo detourMethod = typeof (Program).GetMethod (nameof (SumDetour));
    context.ResolveDetour (detourMethod);
    //or
    context.ResolveDetour<Action> (SumDetour);

    //Detour by Action or Func
    Action<int, int> detourAction = (n1, n2) => {
      Console.WriteLine ("Detoured");
      Console.WriteLine (n1 + n2);
    };
    context.ResolveDetour (detourAction);

    //Detour by Address
    IntPtr addressMethod = default; //Address of method to execute.
    context.ResolveDetour (addressMethod);
  }
}

Replace MSIL

private static void MethodResolver (MethodContext context) 
{
  if (context.Method.Name == "Sum") {
    //num1 * num2
    byte[] newIL = {
    (byte) OpCodes.Ldarg_0.Value, //parameter num1
    (byte) OpCodes.Ldarg_1.Value, //parameter num2
    (byte) OpCodes.Mul.Value,
    (byte) OpCodes.Ret.Value
    };
      
    MethodBody body = new MethodBody (newIL, context.Method.Module);
    context.ResolveBody (body);
  }
}

Replace Native Code

private static void MethodResolver (MethodContext context) 
{
  if (context.Method.Name == "Sum") {
    Assembler assembler = new Assembler (64);

    //Replace with fatorial number:
    //int sum = num1+num2;
    //int fatorial = 1;
    //for(int i = 2; i <= sum; i++){
    //    fatorial *= i;
    //}
    //return fatorial;
    assembler.add (edx, ecx);
    assembler.mov (eax, 1);
    assembler.mov (ecx, 2);
    assembler.cmp (edx, 0x02);
    assembler.jl (assembler.@F);
    assembler.AnonymousLabel ();
    assembler.imul (eax, ecx);
    assembler.inc (ecx);
    assembler.cmp (ecx, edx);
    assembler.jle (assembler.@B);
    assembler.AnonymousLabel ();
    assembler.ret ();
      
    using MemoryStream ms = new MemoryStream ();
    assembler.Assemble (new StreamCodeWriter (ms), 0);
      
    byte[] asm = ms.ToArray ();
      
    context.ResolveNative (asm);
  }
}

Inject custom MetadataToken

You can inject a custom metadata too, in this way, you can "execute" metadatatoken not referenced in compile-time:

/// <summary>
///     Example of a external library to replace Sum.
/// </summary>
/// <remarks>
///     We replace Sum to return the PID of process running. To do this, normally we need
///     reference assembly (System.Diagnostics.Process) and class Process.
///     In this case, the original module, dont have any reference to namespace System.Diagnostics.Process.
///     As we pass the MetadataToken from Process.GetCurrentProcess().Id, its necessary resolve that manually,
///     because CLR dont have any information about that in original module.
/// </remarks>
public static class ExternLibrary
{
    private static MethodInfo _getCurrentProcess;
    private static MethodInfo _getterId;

    static ExternLibrary()
    {
        LoadAssemblyDiagnostics();
    }

    public static void Initialize()
    {
        JitexManager.AddMethodResolver(MethodResolver);
        JitexManager.AddTokenResolver(TokenResolver);
    }

    private static void LoadAssemblyDiagnostics()
    {
        string pathAssembly = Path.Combine(Directory.GetCurrentDirectory(), "../../../../", "System.Diagnostics.Process.dll");
        Assembly assemblyDiagnostics = Assembly.LoadFrom(pathAssembly);
        Type typeProcess = assemblyDiagnostics.GetType("System.Diagnostics.Process");
        _getCurrentProcess = typeProcess.GetMethod("GetCurrentProcess");
        _getterId = _getCurrentProcess.ReturnType.GetProperty("Id", BindingFlags.Public | BindingFlags.Instance).GetGetMethod();
    }

    private static void TokenResolver(TokenContext context)
    {
        if (context.TokenType == TokenKind.Method && context.Source.Name == "Sum")
        {
            if (context.MetadataToken == _getCurrentProcess.MetadataToken)
            {
                context.ResolveMethod(_getCurrentProcess);
            }
            else if (context.MetadataToken == _getterId.MetadataToken)
            {
                context.ResolveMethod(_getterId);
            }
        }
    }
    
    private static void MethodResolver(MethodContext context)
    {
        if (context.Method.Name == "Sum")
        {
            List<byte> newIl = new List<byte>();
            newIl.Add((byte)OpCodes.Call.Value);
            newIl.AddRange(BitConverter.GetBytes(_getCurrentProcess.MetadataToken));
            newIl.Add((byte)OpCodes.Call.Value);
            newIl.AddRange(BitConverter.GetBytes(_getterId.MetadataToken));
            newIl.Add((byte)OpCodes.Ret.Value);
            MethodBody methodBody = new MethodBody(newIl.ToArray(), _getCurrentProcess.Module);
            context.ResolveBody(methodBody);
        }
    }
}
static void Main (string[] args) {
    ExternLibrary.Initialize ();
    int result = Sum (1, 7);
    Console.WriteLine (result); //output is PID
}

Replace content string

private static void TokenResolver (TokenContext context) {
  if (context.TokenType == TokenKind.String && context.Content == "Hello World!")
    context.ResolveString ("H3110 W0RLD!");
}
static void Main (string[] args) {
    ExternLibrary.Initialize ();
    HelloWorld (); //output is H3110 W0RLD!
}

static void HelloWorld () {
    Console.WriteLine ("Hello World!");
}

Modules

Jitex can support modules. To create your own module, just extend JitexModule:

public class ModuleJitex : JitexModule
{
    protected override void MethodResolver(MethodContext context)
    {
        //...
    }

    protected override void TokenResolver(TokenContext context)
    {
        //...
    }
}

And load module:

JitexManager.LoadModule<ModuleJitex>();
//or...
JitexManager.LoadModule(typeof(ModuleJitex));

ASP.NET Core support

To load module in ASP.NET Core, just call UseModule in Configure (Startup.cs):

app.UseModule<ModuleJitex>();
app.UseModule<ModuleJitex1>();
app.UseModule<ModuleJitex2>();
//or
app.UseModule(typeof(ModuleJitex);

Proof of Concept

Nitter - A easy mocker for .NET

AutoMapper Patcher - A simple remover AutoMapper at runtime.

InAsm - Run assembly directly from a method.

Thanks

Replace methods was an idea to increase performance in .NET Applications. Searching a way to do that, i've found this hook implementation from @xoofx Writing a Managed JIT in C# with CoreCLR, which became core of Jitex.

Support

Logo

Icon made by iconixar from www.flaticon.com
I'm trying be better in english language too, so probably you will see some grammatical errors... Feel free to notify me.

jitex's People

Contributors

hitmasu avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.