Jump to content
Tuts 4 You

[C#] dnlib patcher code


mrexodia

Recommended Posts

Posted (edited)

Today I wrote a small class that assists with patching .NET binaries.

using System;
using System.IO;
using dnlib.DotNet;
using dnlib.DotNet.Emit;

namespace MyNamespace
{
    class Patcher
    {
        public delegate bool PatchStrategy(AssemblyDef asm);

        private static bool patchMethodReturnBool(AssemblyDef asm, string classPath, string methodName, bool returnValue, int numArguments = 0)
        {
            var method = findMethod(asm, classPath, methodName);
            if (method != null && method.Parameters.Count == numArguments)
            {
                //patch instructions
                var instructions = method.Body.Instructions;
                if (returnValue)
                    instructions.Insert(0, OpCodes.Ldc_I4_1.ToInstruction()); //true
                else
                    instructions.Insert(0, OpCodes.Ldc_I4_0.ToInstruction()); //false
                instructions.Insert(1, OpCodes.Ret.ToInstruction());
                return true;
            }
            return false;
        }

        private static MethodDef findMethod(TypeDef type, string methodName)
        {
            if (type != null)
            {
                foreach (var method in type.Methods)
                {
                    if (method.Name == methodName)
                        return method;
                }
            }
            return null;
        }

        private static MethodDef findMethod(AssemblyDef asm, string classPath, string methodName)
        {
            return findMethod(findType(asm, classPath), methodName);
        }

        private static TypeDef findType(AssemblyDef asm, string classPath)
        {
            foreach (var module in asm.Modules)
            {
                foreach (var type in module.Types)
                {
                    if (type.FullName == classPath)
                        return type;
                }
            }
            return null;
        }

        public static bool PatchAssembly(string path, ref string error, PatchStrategy patcher)
        {
            var bakpath = path + ".bak";
            try
            {
                //handle backup
                if (!File.Exists(bakpath))
                    File.Copy(path, bakpath);
                else
                    File.Copy(bakpath, path, true);
            }
            catch (Exception x)
            {
                error = x.ToString();
                return false;
            }
            try
            {
                DateTime creationTime = File.GetCreationTime(path);

                //load module
                var module = ModuleDefMD.Load(File.ReadAllBytes(path));

                //execute patching strategy
                if (!patcher(module.Assembly))
                    return false;

                //write assembly
                if (module.IsILOnly)
                    module.Write(path);
                else
                    module.NativeWrite(path);

                //restore file date
                File.SetLastWriteTime(path, creationTime);
                File.SetCreationTime(path, creationTime);
                return true;
            }
            catch (Exception x)
            {
                File.Copy(bakpath, path, true);
                error = x.ToString();
            }
            return false;
        }
    }
}

For every patch you write a strategy like this:

public static bool PatchRegistrationCheck(AssemblyDef asm)
{
    string classPath = "MyNamespace.MyClass";
    /*
     * public bool IsRegistered(RegistrationData rd)
     * {
     *     return true;
     * }
     */
    if (!patchMethodReturnBool(asm, classPath, "IsRegistered", true, 2)) //2 parameters (this + rd)
        throw new Exception("MyClass.IsRegistered not patched!");
    return true;
}

Then you call it like this:

Patcher.PatchAssembly(filePath, Patcher.PatchRegistrationCheck);

Hope it will be useful for some of you.

Greetings

Edited by Mr. eXoDia
  • Like 12

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...