GithubHelp home page GithubHelp logo

ioncodes / dnpatch Goto Github PK

View Code? Open in Web Editor NEW
312.0 31.0 48.0 1.82 MB

.NET Patcher library using dnlib

License: MIT License

C# 100.00%
dnlib deobfuscation de4dot dotnet decompiler patcher ildasm reverse-engineering

dnpatch's Introduction

dnpatch

[WIP] .NET Patcher library using dnlib.

If you have questions feel free to ask me via Gitter! I'm glad to help you out! Taking feature requests!

Build status Github All Releases Join the chat at https://gitter.im/dnpatch/Lobby

IMPORTANT

The master branch provides you the current stable build of dnpatch. However, I will most likely not provide support for it anymore since version 1.0 is on it's way in the v1 branch.

What is dnpatch?

dnpatch is the ultimate library for all your .NET patching needs. It offers automated assembly patching, signature scanning and last but but not least bypassing of obfuscators by its ability to find methods in renamed/obfuscated types. Since the stars on GitHub exploded in a few days, dnpatch has been extended by a couple of projects. The most important one is dnpatch.deobfuscation which integrates de4dot directly into dnpatch. Also there is dnpatch.script, which gives you the ability to write patchers with pure JSON! The library itself uses dnlib (see next part).

Notes

Since dnpatch uses dnlib, it is highly recommended to use dnSpy to analyze your assemblies first, to ensure that you use the correct names, offsets, etc, because it uses dnlib aswell.

Recommendations

It is highly recommended that you calculate the instruction's index instead of defining it, to improve the likelihood of compatibility with future updates.

Patching

The constructor takes the filename of the assembly.

Patcher patcher = new Patcher("Test.exe");

If you want to keep the old maxstack (for example for obfuscated assemblies) use the overload:

Patcher patcher = new Patcher("Test.exe", true);

Targeting Methods

All methods take an object called Target as an argument. The object is defined as follows:

public string Namespace { get; set; } // needed
public string Class { get; set; } // needed
public string Method { get; set; } // needed

/* If you want to patch multiple indexes in the method */
public int[] Indexes { get; set; }
public Instruction[] Instructions { get; set; }

/* If you want to patch 1 index in the method */
public int Index { get; set; } = -1;
public Instruction Instruction { get; set; }

/* If the path to the method has more than 1 nested class use this */
public string[] NestedClasses { get; set; }

/* If the path to the method has 1 nested class use this */
public string NestedClass { get; set; }

/* If you want to set the parameters for the method (if it's overloaded) use this */
public string[] Parameters { get; set; }

/* If you want to set the return type for the method use this */
public string ReturnType { get; set; }

/* If you want to rewrite the getters or setters of a property use this */
public string Property { get; set; } // The name
public PropertyMethod PropertyMethod { get; set; } // See below, determines patch target

ReturnType and Parameters are case sensitive! Example:

  • String[]
  • Int32
  • etc

PropertyMethod is defined as this:

public enum PropertyMethod
{
	Get,
	Set
}

Please make sure that you don't assign inconsistent values, e.g.

var target = new Target
{
    Instructions = ...
    Instruction = ...
}

If you want to patch multiple methods create a Target[] and pass it to the functions, it is accepted by the most of them.

Creating Instructions

Reference dnlib and create an Instruction[] or Instruction with your Instruction(s), then assign assign indexes where the Instructions are.You can find them by reverse engineering your assembly via dnSpy or any other decompiler.

Small Example:

Instruction[] opCodes = {
    Instruction.Create(OpCodes.Ldstr, "Hello Sir 1"),
    Instruction.Create(OpCodes.Ldstr, "Hello Sir 2")
};
int[] indexes = {
    0, // index of Instruction
    2
};
Target target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "Print",
    Instructions = opCodes,
    Indexes = indexes
};

Patch the whole methodbody

To clear the whole methodbody and write your instructions, make sure that you don't assign the Indexes or Index property.

Here is an example:

Instruction[] opCodes = {
    Instruction.Create(OpCodes.Ldstr, "Hello Sir"),
    Instruction.Create(OpCodes.Call, p.BuildCall(typeof(Console), "WriteLine", typeof(void), new[] { typeof(string) })),
    Instruction.Create(OpCodes.Ret)
};
Target target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "Print",
    Instructions = opCodes
};

Apply the patch

To apply your modified instructions you can call the method 'Patch':

patcher.Patch(Target);

or

patcher.Patch(Target[]);

Finding an instruction

In some cases, it might be useful to find an instruction within a method, for example if the method was updated.

Instruction opCode = Instruction.Create(OpCodes.Ldstr, "TheTrain");
Instruction toFind = Instruction.Create(OpCodes.Ldstr, "TheWord");
Target target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "FindMe",
    Instruction = opCode // you can also set it later
};
target.Index = p.FindInstruction(target, toFind);
// now you have the full Target object

Let's say there are multiple identical instructions. What now, baoss? Well, it's simple. There's an overload that takes an int which is the occurence of the instruction which you'd like to find.

Instruction opCode = Instruction.Create(OpCodes.Ldstr, "TheTrain");
Instruction toFind = Instruction.Create(OpCodes.Ldstr, "TheWord");
Target target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "FindMe",
    Instruction = opCode // you can also set it later
};
target.Index = p.FindInstruction(target, toFind, 2); // Sir, find the second occurence!

Finding methods by OpCode signature

You can find methods (Target[]) by scanning their body for an OpCode signature

OpCode[] codes = new OpCode[] {
	OpCodes.Ldstr,
	OpCodes.Call
};
var result = p.FindMethodsByOpCodeSignature(codes); // holds Target[]

Replacing instructions

In some cases it might be easier to just replace an instruction. At this point of development, it doesn't make much sense, but the features will come soon.

Instruction opCode = Instruction.Create(OpCodes.Ldstr, "I love kittens");
Target target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "ReplaceMe",
    Instruction = opCode,
    Index = 0
};
p.ReplaceInstruction(target);

Removing instructions

Let's say you want to remove instructions... Well it's simple as this:

Target target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "RemoveMe",
    Indexes = new[]{0,1} // the indexes, you can also just use 'Index'
};
p.RemoveInstruction(target);

Patching operands

Hmmm.... What if you find the console output offending? You can modify the Ldstr without even creating an instruction :)

Target target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "PrintAlot",
    Index = 0
};
p.PatchOperand(target, "PatchedOperand"); // pass the Target and a string to replace

or incase you need to modify an int:

p.PatchOperand(target, 1337);

It is also able to patch multiple operands in the same method by using int[] or string[].

Returning true/false

If you want to overwrite the methodbody with a return true/false statement you can do this:

target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "VerifyMe"
};
p.WriteReturnBody(target, bool); // bool represents the return value

Clearing methodbodies

If you just want to empty a methodbody, use this amigo:

target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "WriteLog"
};
p.WriteEmptyBody(target);

Getting instructions from target

Simply do this if you want to get instructions of the Target object:

target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "WriteLog"
};
Instruction[] instructions = p.GetInstructions(target);

Writing return bodies

If you want to overwrite the body with a return true/false do this:

target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "WriteLog"
};
p.WriteReturnBody(target, bool);
// bool is the return value, e.g. true will return true ;)

If you want to remove the body simply call this:

target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "WriteLog"
};
p.WriteEmptyBody(target);

Find methods

If you want to find a method, you can simply scan the whole file by 2 ways:

p.FindInstructionsByOperand(string[]);
// or p.FindInstructionsByOperand(int[]);
// string[] with all operands in the method, if there are multiple identical operands, make sure to have the same amount as in the method.

// or do this via opcodes:
p.FindInstructionsByOpcode(OpCode[]);

Both ways return an Target[] which contains all targets pointing to the findings.

Find instructions in methods or classes

If you want to find the instructions and you know the class (and optionally the method), you can let this method return a Target[] with the pathes and indexes.

p.FindInstructionsByOperand(Target,int[],bool);
// int[]: the operands
// bool: if true it will search for the operands once, it will delete the index if the index was found

// for opcodes:
p.FindInstructionsByOpcode(Target,int[],bool);

Patch properties

Now you can rewrite a property's getter and setter like this:

target = new Target()
{
	Namespace = "Test",
	Class = "Program",
	Property = "IsPremium", // Property name
	PropertyMethod = PropertyMethod.Get, // Getter or Setter
	Instructions = new []
	{
		Instruction.Create(OpCodes.Ldc_I4_1),
		Instruction.Create(OpCodes.Ret)  
	} // the new instructions
};
p.RewriteProperty(target); // Will overwrite it with return true in getter

The property called 'Property' holds the name of the target property.
PropertyMethod can be 'PropertyMethod.Get' or 'PropertyMethod.Set'.
Instructions are the new Instructions for the getter or setter.

Building calls

To build calls like "Console.WriteLine(string)" you can use this method:

p.BuildCall(typeof(Console), "WriteLine", typeof(void), new[] { typeof(string) })
/* 
 * Type -> type, a Type instance
 * string -> method, the name of the method
 * Type -> returnType, a Type instance of the return value
 * Type[] -> parameters, an array with the parameter's Types
 */

Here is an IL example for Console.WriteLine:

Patcher p = new Patcher("Test.exe");
Instruction[] opcodesConsoleWriteLine = {
    Instruction.Create(OpCodes.Ldstr, "Hello Sir"), // String to print
    Instruction.Create(OpCodes.Call, p.BuildCall(typeof(Console), "WriteLine", typeof(void), new[] { typeof(string) })), // Console.WriteLine call
    Instruction.Create(OpCodes.Ret) // Always return smth
};
Target target = new Target()
{
    Namespace = "Test",
    Class = "Program",
    Method = "Print",
    Instructions = opcodesConsoleWriteLine
};
p.Patch(target);
p.Save("Test1.exe");

Injecting methods (Untested)

If you want to inject methods into classes, call InjectMethod. Make sure to set MethodDef and Instructions. Optionally set Locals, ParameterDefs.

Target target = new Target();
MethodImplAttributes methImplFlags = MethodImplAttributes.IL | MethodImplAttributes.Managed;
MethodAttributes methFlags = MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot;
MethodDef meth1 = new MethodDefUser("MyMethod",
            MethodSig.CreateStatic(mod.CorLibTypes.Int32, mod.CorLibTypes.Int32, mod.CorLibTypes.Int32),
            methImplFlags, methFlags);
target.ParameterDefs = new[] { new ParamDefUser("a", 1) };
target.Locals = new[] { new Local(mod.CorLibTypes.Int32) };
target.MethodDef = meth1;
target.Class = "";
// ... target as always...
patcher.InjectMethod(target);

For now refer to this page: https://github.com/0xd4d/dnlib/blob/master/Examples/Example2.cs

Saving the patched assembly

If you want to save the assembly under a different name use this:

patcher.Save(String); // filename here

Or if you want to replace the original file:

patcher.Save(bool); // if true it will create a backup first (filename.bak)

Deobfuscation [BETA]

Baoss, what can I do if it's heavily obfuscated?! Well, listen careful to your grandpa Joe. Use 'dnpatch.deobfuscation'! It has magic powers! Nah, Joe is just kiddin', it uses the de4dot libraries. Reference the library dnpatch.deobfuscation and make sure that you also copy all others from the zip! Then do this:

Deobfuscation d = new Deobfuscation(string, string);
// string 1 -> file to deobfuscate
// string 2 -> new filename for the deobfuscated file
d.Deobfuscate(); // Deobfuscates the file and writes it to the disk

Scripting

With dnpatch.script you're now able to script patchers with JSON! Example JSON:

{
    "target":"Test.exe",
    "targets":[{
        "ns":"Test",
        "cl":"Program",
        "me":"ReplaceMe",
        "ac":"replace",
        "index":0,
        "instructions":[{
            "opcode":"ldstr",
            "operand":"script working"
        }]
    },{
        "ns":"Test",
        "cl":"Program",
        "me":"RemoveMe",
        "ac":"empty"
    }]
}

Name this file script.json and place it into TestScript build folder and use it with Test.exe. For more info please refer to the standalone repo.

Credits

I'd like to thank these people:

  • 0xd4d for creating dnlib
  • 0xd4d for creating de4dot
  • Rottweiler for the PRs and help!
  • 0megaD for the fixes which my eyes missed and for using dnpatch in his projects!
  • DivideREiS for fixing my typos and getting my lazy ass back to work on the BuildMemberRef/BuildCall method!

dnpatch's People

Contributors

amazingalek avatar andrewshulgin avatar dividereis avatar ioncodes avatar rottweiler avatar tchivs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dnpatch's Issues

Target: "Object reference not set to an instance of an object."

This is the code snippet. (Yes, I have already confirmed that the "dllpath" is correct)
START CODE
patcher = new Patcher(dllPath);
Target target = new Target()
{
Namespace = "-",
Class = "UserData",
Method = "IsPremium",
Indices = new[] { 0, 1, 2, 3, 4, 5, 6, 7 }
};
patcher.RemoveInstruction(target);
patcher.Save(dllPath);
END CODE

"patcher.RemoveInstruction(target);" gives "Object reference not set to an instance of an object." error even though I have created an instance of it.

Any help is greatly appreciated!

Adding instructions

This is probably a stupid question, but does Patcher.Patch() add instructions to a method body at a given index without replacing the entire thing? If not, how would I do so?

Also, when I do this:
what it should do: http://i.imgur.com/NTUPHRd.png
(calls static method in the default namespace from another assembly)
in code: http://i.imgur.com/fNsbefL.png

I get this error: "Error: dnlib.DotNet.Writer.ModuleWriterException: Error calculating max stack value."

Any help is greatly appreciated,
erherhh4herh.

[Wrong code in release] PatchHelper / GetInstructions

Hello i found a bug in PatchHelper.GetInstructions

its suposed to return Instruction[] and anyway no matter how hard i tried it was always returnign me an exception that i cannot cast IList to Instruction[]

so my quick workaround was to edit it from this code below

public Instruction[] GetInstructions(Target target)
{
	TypeDef type = this.FindType(target.Namespace + "." + target.Class, target.NestedClasses);
	MethodDef methodDef = this.FindMethod(type, target.Method, target.Parameters, target.ReturnType);
	return (Instruction[])methodDef.Body.Instructions;
}

into this one

public Instruction[] GetInstructions(Target target)
{
	TypeDef type = this.FindType(target.Namespace + "." + target.Class, target.NestedClasses);
	IEnumerator<Instruction> enumerator = this.FindMethod(type, target.Method, target.Parameters, target.ReturnType).Body.Instructions.GetEnumerator();
	List<Instruction> list = new List<Instruction>();
	while (enumerator.MoveNext())
	{
		Instruction item = enumerator.Current;
		list.Add(item);
	}
	return list.ToArray();
}

if someone of you have some time please apply it to new release THANKS :) it will deffenetly help others
Hope you guys are doing well!!!

How to creat instructions of stfld?

For example instruction viewed by dnspy:
stfld bool namespace.class::localVar
So, how to creat this instruction with Instruction.Create() ? Thanks

Jump helper function

Currently building jump instructions is a bit annoying since you have to initialize them outside the instruction array. It becomes worse when you need to change it later. I would like to see an option similar to method call builder that would allow to create those jumps while initializing instruction array.
One idea I had was to extend Instruction with an optional string id field and create instruction child type (ResolveLaterInstruction?) that can be replaced by a processor before patching. Ideally I would like instruction array initialization to look something like this.

Instruction[] opCodes = {
                Instruction.Create(OpCodes.Ldarg_0),
                Instruction.Create(OpCodes.Call, p.BuildCall(typeof(Mod), "get_Assembly", typeof(System.Reflection.Assembly), new Type[]{})),
                Instruction.BuildJump(OpCodes.Brtrue_S, "assemblyIsNull"),
                Instruction.Create(OpCodes.Ldc_I4_1),
                Instruction.Create(OpCodes.Ret),
                Instruction.Create(OpCodes.Ldc_I4_0, null, "assemblyIsNull"),
                Instruction.Create(OpCodes.Ret)
            };

After method Patch is called it goes through the list of instructions and resolves those jumps. This way some errors can be thrown before dnlib tries to save the assembly, it is easier to keep track what jumps where and it is easier to modify whole thing later.

This is from the top of the head solution and I have not looked at the code so sorry if there are some obvious problems with it.

Some beginner questions about patching


            Console.WriteLine("Type new player health:");
            string health = Console.ReadLine();
Patcher p = new Patcher("C:/Program Files (x86)/Steam/steamapps/common/Game/Game_Data/Managed/Assembly-CSharp.dll");
            Instruction HealthCode = Instruction.Create(OpCodes.Ldstr, "InputDataManager.inst.players[this.playerIndex].health = " + health + ";");
            Instruction HealthFind = Instruction.Create(OpCodes.Ldstr, "InputDataManager.inst.players[this.playerIndex].player.trail.UpdateTail(InputDataManager.inst.players[this.playerIndex].health, this.rb.position);");
            Target target = new Target()
            {
                Namespace = "",
                Class = "Player",
                Method = "Spawn",
                Instruction = HealthCode
            };
            target.Index = p.FindInstruction(target, HealthFind)+4;
            p.Patch(target);
           p.Save("C:/Program Files (x86)/Steam/steamapps/common/Game/Game_Data/Managed/Assembly-CSharp.dll")

For some reason when I try to save the patch it gives me this error at the last line
System.IO.IOException: 'The requested operation cannot be performed on a file with a user-mapped section open. :
I've checked process explorer and nothing else has the dll open. Is p.Save only used for saving a new version of the assembly and not for saving changes to the current one or something?

Also does setting an index after the last line of a method just makes the the instructions afterward?

 Instruction[] SpeedCodes = {
                Instruction.Create(OpCodes.Ldstr, "this.idleSpeed = 20f * " + speed +";"),
                Instruction.Create(OpCodes.Ldstr, "this.boostSpeed = 85f * " + speed +";"),
                Instruction.Create(OpCodes.Ldstr, "Vector3 temp = base.transform.localScale;"),
                Instruction.Create(OpCodes.Ldstr, "temp = new Vector3(" + xscale + "f, " + yscale + "f, 1f);"),
                Instruction.Create(OpCodes.Ldstr, "this.render.gameObject.transform.localScale = temp;"),
                 Instruction.Create(OpCodes.Ldstr, "this.rb.gameObject.transform.localScale = temp;")
            };
//the last instruction of the method
            Instruction SpawnFind = Instruction.Create(OpCodes.Ldstr, "this.Spawn();"); 
            int[] indexes =
            {
                p.FindInstruction(target, SpawnFind )+1,
               p.FindInstruction(target, SpawnFind )+2,
                p.FindInstruction(target, SpawnFind )+3,
               p.FindInstruction(target, SpawnFind )+4,
               p.FindInstruction(target, SpawnFind )+5,
               p.FindInstruction(target, SpawnFind )+6,
            };
            Target target2 = new Target()
            {
                Namespace = "",
                Class = "Player",
                Method = "Start",
                Instructions = SpeedCodes,
                Indices = indexes
            };

Thanks for any help you can give!
edit: after awhile I realized it's probably the path to the dll but I don't know what's wrong

Suggestion

A friendly suggestion: consider using a more generic API - for example, instead of requiring file names as constructor parameters (though very useful), please also provide overloads with something more general like a Stream - if an app is working with assemblies in memory, this saves the author the trouble of recompiling the dnpatch library or using temporary files.

Awesome project, by the way!

Exception when saving

Hello,

Thank you for providing a very useful library.

I'm unfortunately having a problem with a simple example:

Exception:

dnlib.DotNet.Writer.ModuleWriterException
  HResult=0x80131500
  Message=Found some other method's instruction or a removed instruction. You probably removed an instruction that is the target of a branch instruction or an instruction that's the first/last instruction in an exception handler.
  Source=dnlib
  StackTrace:
   at dnlib.DotNet.DummyLogger.Log(Object sender, LoggerEvent loggerEvent, String format, Object[] args)
   at dnlib.DotNet.Writer.ModuleWriterBase.dnlib.DotNet.ILogger.Log(Object sender, LoggerEvent loggerEvent, String format, Object[] args)
   at dnlib.DotNet.Writer.MetaData.dnlib.DotNet.Writer.IWriterError.Error(String message)
   at dnlib.DotNet.Writer.MethodBodyWriter.ErrorImpl(String message)
   at dnlib.DotNet.Writer.MethodBodyWriterBase.GetOffset(Instruction instr)
   at dnlib.DotNet.Writer.MethodBodyWriterBase.WriteShortInlineBrTarget(BinaryWriter writer, Instruction instr)
   at dnlib.DotNet.Writer.MethodBodyWriterBase.WriteOperand(BinaryWriter writer, Instruction instr)
   at dnlib.DotNet.Writer.MethodBodyWriterBase.WriteInstruction(BinaryWriter writer, Instruction instr)
   at dnlib.DotNet.Writer.MethodBodyWriterBase.WriteInstructions(BinaryWriter writer)
   at dnlib.DotNet.Writer.MethodBodyWriter.WriteFatHeader()
   at dnlib.DotNet.Writer.MethodBodyWriter.Write()
   at dnlib.DotNet.Writer.MetaData.WriteMethodBodies()
   at dnlib.DotNet.Writer.MetaData.Create()
   at dnlib.DotNet.Writer.MetaData.CreateTables()
   at dnlib.DotNet.Writer.ModuleWriter.WriteImpl()
   at dnlib.DotNet.Writer.ModuleWriterBase.Write(Stream dest)
   at dnlib.DotNet.Writer.ModuleWriterBase.Write(String fileName)
   at dnlib.DotNet.ModuleDef.Write(String filename)
   at dnpatch.PatchHelper.Save(String name)
   at dnpatch.Patcher.Save(String name)
   at My_Patcher.Program.Main(String[] args) in E:\Documents\Visual Studio 2017\My_Patcher\My_Patcher\Program.cs:line 25

and this is the code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using dnpatch;

namespace My_Patcher
{
    class Program
    {
        static void Main(string[] args)
        {
            Patcher p = new Patcher("Test.1.Server.exe");
            Target target = new Target()
            {
                Namespace = "ns0",
                Class = "GClass2",
                Method = "method_30",
                Indices = new[] { 26, 27 }
            };
            p.RemoveInstruction(target);
            p.Save("Test.1.Server_patched.exe");
        }
    }
}

I've downloaded and referenced dnpatch.dll and dnlib.dll from the releases zip and don't have any errors or warnings when compiling.

I'll be very grateful for your assistance please.

thanks

Unable to cast object of type 'System.Collections.Generic.List`1[dnlib.DotNet.Emit.Instruction]' to type 'dnlib.DotNet.Emit.Instruction[]'

The codes are below:
Patcher patcher1 = new Patcher("xxxx.dll", true); Target target1 = new Target() { Namespace = "Pxxxx.App", Class = "Global", Method = "get_Code" }; Instruction[] instructions = patcher1.GetInstructions(target1);
Invalid cast exception pops up just likes that:
Unable to cast object of type 'System.Collections.Generic.List`1[dnlib.DotNet.Emit.Instruction]' to type 'dnlib.DotNet.Emit.Instruction[]' in dnpatch.PatchHelper.GetInstructions(Target target)

Find method by opcode in Namespace/Class

Makes finding private obfuscated methods in an Assembly with ongoing releases easier.
In my case I most often know which class I need to patch so there is no need to search through everything. In fact it makes it more difficult by needing larger signature. I suggest adding optional parameters to Patcher.FindMethodsByOpCodeSignature(OpCode[] signature, string namespace=null, string class=null).

Fails to patch methods with try/catch blocks

Patching fails if target method contains try/catch block. I have attached a test library and here is the reproduction code:

            var patcher = new dnpatch.Patcher("data/Test.dll");
            var target = new Target
            {
                Namespace = "Test",
                Class = "TestClass",
                Method = "TestMethod",
            };
            patcher.WriteReturnBody(target,true);
            patcher.Save("TestNew.dll");

Test.zip

Throws dnlib.DotNet.Writer.ModuleWriterException exception {"Found some other method's instruction or a removed instruction. You probably removed an instruction that is the target of a branch instruction or an instruction that's the first/last instruction in an exception handler."}

I have not gotten to test with v1 so not sure if it is the same there.

Patched target is about 40KB smaller than original file after saving to disk

I wrote a simple program that loads a .NET compiled DLL, replaces a single instruction for a method, and then saves the resultant patch to a new file. When I inspect the new file, it's about 40KB smaller than the original, so it's obviously missing quite a bit from the original assembly. When I inspect the newly patched file, it looks like there are entire PE sections missing that were in the original. Do I need to use dnlib functions to manually read in all the PE sections and then re-write them to my newly patched file? Or am I forgetting to do something else to preserve all the original pieces of the file? Here's my code to give context:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using dnpatch;

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
             /*
             * Replaces the instructions at the given index
             */
            Patcher p = new Patcher("MyOriginalFile.dll");
            Instruction opCodesManipulateOffset = Instruction.Create(OpCodes.Ldc_I4, 112);

            Target target = new Target()
                {
                    Namespace = "MyTargetNamespace",
                    Class = "MyTargetClass",
                    Method = "MyTargetMethod",
                    Instruction = opCodesManipulateOffset,
                    Index = 75,
                    Parameters = new[] { "Int32", "String", "String" }
                };
                p.Patch(target);
                p.Save("MyTargetPatchedFile.dll");
            
        }
    }
}

help with error please

Sorry to trouble you but I'm getting the following error when saving after a WriteReturnBody:

Unhandled Exception: System.MissingMethodException: Method not found: 'dnlib.DotNet.Writer.MetaDataOptions dnlib.DotNet.Writer.ModuleWriterOptionsBase.get_MetaDataOptions()'.
at dnpatch.PatchHelper.Save(String name)
at dnpatch.Patcher.Save(String name)
at Test_Patcher.Program.Main(String[] args) in E:\Documents\Visual Studio 2017\Test_Patcher\Test_Patcher\Program.cs:line 29

line 29 is p.Save( "test_temp");

I'll be grateful for your assistance please, thanks.

Problem about method referance and call method from another module

I'm using dnpatch to edit an existing binary and edit an existing method to call a method in an assembly that is already referenced by the binary. Ploverinfo.Framework.dll is the binary which I need to edit, and Ploverinfo.CommonLib.dll is the referenced file.
Some codes of these two files are as below.
Ploverinfo.CommonLib.dll:

using xxxx.xxxx;
namespace Ploverinfo.CommonLib.App
{
	// Token: 0x020000B2 RID: 178
	public class Config
	{
		......
		public string getValue(string strKey)
		{
			if (this.ht.ContainsKey(strKey))
			{
				return this.ht[strKey].ToString();
			}
			return "";
		}
		......
		private Hashtable ht = new Hashtable();
	}
	
	public class Global
	{
		public static string get_LicenseCode()
		{
			if (!string.IsNullOrEmpty(Global._LicenseCode))
			{
				return Global._LicenseCode;
			}
			Global._LicenseCode = Global.license.getValue("LicenseCode");
			if (string.IsNullOrEmpty(Global._LicenseCode))
			{
				Global._LicenseCode = Global.config.getValue("RegCode");
			}
			return Global._LicenseCode;
		}
		......
		public static Config license = new Config();
		protected static string _LicenseCode = "";
		......
	}
}

Ploverinfo.Framework.dll:

using xxxx.xxxx
using Ploverinfo.CommonLib.App;
using Ploverinfo.CommonLib.App.Cryptography;
using Ploverinfo.CommonLib.Model;
using Ploverinfo.CommonLib.Net;
namespace Ploverinfo.Framework.WebServiceCaller
{
	// Token: 0x02000003 RID: 3
	public class User
	{
	    ......
		public string GetLicenseCode(/* some parameters */)
		{
			......
		}
		......
	}
}

I want to edit the existing method GetLicenseCode to just like this, which can be edited easily by dnspy as snapshot1.

namespace Ploverinfo.Framework.WebServiceCaller
{
	// Token: 0x02000003 RID: 3
	public class User
	{
	    ......
		public string GetLicenseCode(/* some parameters */)
		{
			return Global.license.getValue("LicenseCode");
		}
		......
	}
}

snapshot1:(http://www.hostpic.org/images/1708260636320102.jpg)

Then I write some codes to insert il instructions into the previous GetLicenseCode method as below.

ModuleRef mod_CommonLib = new ModuleRefUser(ModuleDefMD.Load("Ploverinfo.CommonLib.dll"));
ModuleDef mod_Framework = ModuleDefMD.Load("Ploverinfo.Framework.dll");
//ldsfld Ploverinfo.CommonLib.App.Config Ploverinfo.CommonLib.App.Global::license
TypeRef globalRef = new TypeRefUser(mod_Framework, "Ploverinfo.CommonLib.App", "Global", mod_CommonLib);
TypeRef configRef = new TypeRefUser(mod_Framework, "Ploverinfo.CommonLib.App", "Config", mod_CommonLib);
TypeSig type2 = configRef.ToTypeSig();
MemberRef LicenseRef = new MemberRefUser(mod_Framework, "license", new FieldSig(type2), globalRef);
Instruction InsLicenseCodeRef = Instruction.Create(OpCodes.Ldsfld, LicenseRef);
//ldstr "LicenseCode"
Instruction InsLicenseCode = Instruction.Create(OpCodes.Ldstr, "LicenseCode");
//callvirt System.String Ploverinfo.CommonLib.App.Config::getValue(System.String)
MemberRef getValCall = new MemberRefUser(mod_Framework, "getValue",
MethodSig.CreateStatic(mod_Framework.CorLibTypes.String, mod_Framework.CorLibTypes.String),
                configRef);
Instruction InsgetValCall = OpCodes.Callvirt.ToInstruction(getValCall);
//ret
 Instruction InsRet = Instruction.Create(OpCodes.Ret);
Instruction[] toPatch = 
{
     InsLicenseCodeRef,
     InsLicenseCode,
     InsgetValCall,
     InsRet
 };
...
/* Insert instructions into GetLicenseCode method */

After the patch, the codes of GetLicenseCode are as below, and the il codes in dnspy are as snapshot2.

public string GetLicenseCode(/* some parameters */)
{
	Global.license;
	return Config.getValue("LicenseCode");
}

snapshot2: (http://www.hostpic.org/images/1708260636320081.jpg)
I do not know where the problem is. Is there anyone who can help me? Thanks.

Nuget package?

Hi! Love this project! Are you planning to release a Nuget package?

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.