[WIP] .NET Patcher Library mit DNLIB.
Wenn Sie Fragen haben, können Sie mich gerne über Gitter fragen! Ich bin froh, dir zu helfen! Feature -Anfragen annehmen!
Der Master -Zweig bietet Ihnen den aktuellen stabilen Build von DNPatch. Ich werde es jedoch höchstwahrscheinlich nicht mehr unterstützen, da Version 1.0 in der V1 -Filiale auf dem Weg ist.
DNPatch ist die ultimative Bibliothek für alle .NET -Patching -Anforderungen. Es bietet automatisierte Baugruppen -Patching, Signaturenscannen und nicht zuletzt, aber nicht zuletzt die Umgehung von Verschleiern durch seine Fähigkeit, Methoden in umbenannten/verschleierten Typen zu finden. Da die Sterne auf Github in wenigen Tagen explodierten, wurde DNPatch durch einige Projekte erweitert. Das wichtigste ist Dnpatch.deobfuscation, die DE4DOT direkt in DNPatch integriert. Außerdem gibt es dnpatch.script, das Ihnen die Möglichkeit gibt, Patchiker mit reinem JSON zu schreiben! Die Bibliothek selbst verwendet DNLIB (siehe nächster Teil).
Da DNPatch DNLIB verwendet, wird dringend empfohlen, zuerst DNSPY zu verwenden, um Ihre Baugruppen zu analysieren, um sicherzustellen, dass Sie die richtigen Namen, Offsets usw. verwenden, da es auch DNLIB verwendet.
Es wird dringend empfohlen, den Index des Befehls zu berechnen, anstatt ihn zu definieren, um die Wahrscheinlichkeit einer Kompatibilität mit zukünftigen Updates zu verbessern.
Der Konstruktor nimmt den Dateinamen der Montage an.
Patcher patcher = new Patcher ( "Test.exe" ) ;Wenn Sie den alten Maxstack (zum Beispiel für verschleierte Baugruppen) behalten möchten, verwenden Sie die Überlastung:
Patcher patcher = new Patcher ( "Test.exe" , true ) ;Alle Methoden nehmen ein Objekt namens Target als Argument an. Das Objekt ist wie folgt definiert:
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 targetReturnype und Parameter sind fallsempfindlich! Beispiel:
PropertyMethod ist definiert wie folgt:
public enum PropertyMethod
{
Get ,
Set
}Bitte stellen Sie sicher, dass Sie keine inkonsistenten Werte zuweisen, z. B.
var target = new Target
{
Instructions = .. .
Instruction = .. .
}Wenn Sie mehrere Methoden erstellen möchten, erstellen Sie ein Ziel [] und übergeben es an die Funktionen, es wird von den meisten von ihnen akzeptiert.
Referenz DNLIB und erstellen Sie eine Anweisung oder Anweisung mit Ihren Anweisungen und weisen Sie zugewiesene Indizes zu, in denen sich die Anweisungen befinden.
Kleines Beispiel:
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
} ;Um den gesamten Methodbody zu löschen und Ihre Anweisungen zu schreiben, stellen Sie sicher, dass Sie die Indexe oder die Indexeigenschaft nicht zuweisen.
Hier ist ein Beispiel:
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
} ;Um Ihre geänderten Anweisungen anzuwenden, können Sie die Methode "Patch" aufrufen:
patcher . Patch ( Target ) ;oder
patcher . Patch ( Target [ ] ) ;In einigen Fällen kann es nützlich sein, eine Anweisung innerhalb einer Methode zu finden, beispielsweise wenn die Methode aktualisiert wurde.
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 objectNehmen wir an, es gibt mehrere identische Anweisungen. Was jetzt, Baoss? Nun, es ist einfach. Es gibt eine Überlastung, die ein INT nimmt, das die Anweisung ist, die Sie finden möchten.
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!Sie können Methoden finden (Ziel []), indem Sie ihren Körper nach einer Opcode -Signatur scannen
OpCode [ ] codes = new OpCode [ ] {
OpCodes . Ldstr ,
OpCodes . Call
} ;
var result = p . FindMethodsByOpCodeSignature ( codes ) ; // holds Target[]In einigen Fällen kann es einfacher sein, eine Anweisung zu ersetzen. Zu diesem Zeitpunkt der Entwicklung macht es keinen Sinn, aber die Merkmale werden bald kommen.
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 ) ;Angenommen, Sie möchten Anweisungen entfernen ... Nun, es ist einfach:
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 ) ;Hmmm .... Was ist, wenn Sie die Konsolenausgabe beleidigend finden? Sie können den LDTR ändern, ohne auch nur eine Anweisung zu erstellen :)
Target target = new Target ( )
{
Namespace = "Test" ,
Class = "Program" ,
Method = "PrintAlot" ,
Index = 0
} ;
p . PatchOperand ( target , "PatchedOperand" ) ; // pass the Target and a string to replaceoder falls Sie einen int ändern müssen:
p . PatchOperand ( target , 1337 ) ;Es ist auch in der Lage, mehrere Operanden in derselben Methode zu patchen, indem es int [] oder String [] verwendet wird.
Wenn Sie den Methodebody mit einer Rückgabe -TRUE/Falsch -Anweisung überschreiben möchten, können Sie dies tun:
target = new Target ( )
{
Namespace = "Test" ,
Class = "Program" ,
Method = "VerifyMe"
} ;
p . WriteReturnBody ( target , bool ) ; // bool represents the return valueWenn Sie nur einen Methodbody leeren möchten, verwenden Sie diesen Amigo:
target = new Target ( )
{
Namespace = "Test" ,
Class = "Program" ,
Method = "WriteLog"
} ;
p . WriteEmptyBody ( target ) ;Tun Sie dies einfach, wenn Sie Anweisungen des Zielobjekts erhalten möchten:
target = new Target ( )
{
Namespace = "Test" ,
Class = "Program" ,
Method = "WriteLog"
} ;
Instruction [ ] instructions = p . GetInstructions ( target ) ;Wenn Sie den Körper mit einer Rückkehr wahr/falsch überschreiben möchten, tun Sie Folgendes:
target = new Target ( )
{
Namespace = "Test" ,
Class = "Program" ,
Method = "WriteLog"
} ;
p . WriteReturnBody ( target , bool ) ;
// bool is the return value, e.g. true will return true ;)Wenn Sie den Körper entfernen möchten, nennen Sie einfach Folgendes:
target = new Target ( )
{
Namespace = "Test" ,
Class = "Program" ,
Method = "WriteLog"
} ;
p . WriteEmptyBody ( target ) ;Wenn Sie eine Methode finden möchten, können Sie einfach die gesamte Datei auf 2 Arten scannen:
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 [ ] ) ;Beide Möglichkeiten geben ein Ziel zurück [], das alle Ziele enthält, die auf die Ergebnisse hinweisen.
Wenn Sie die Anweisungen finden möchten und die Klasse (und optional die Methode) kennen, können Sie diese Methode ein Ziel [] mit den Pfaden und Indizes zurückgeben.
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 ) ;Jetzt können Sie den Getter und Setter einer Immobilie wie folgt umschreiben:
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 Die Eigenschaft "Eigentum" hält den Namen der Zieleigenschaft.
PropertyMethod kann 'PropertyMethod.get' oder 'PropertyMethod.set' sein.
Anweisungen sind die neuen Anweisungen für Getter oder Setter.
Um Anrufe wie "Console.WriteLine (String)" zu erstellen, können Sie diese Methode verwenden:
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
*/Hier ist ein IL -Beispiel für die Konsole.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" ) ;Wenn Sie Methoden in Klassen injizieren möchten, rufen Sie InjectMethod auf. Stellen Sie sicher, dass Sie Methode und Anweisungen festlegen. Optional Einstellungsheimische, 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 ) ;Weitere Informationen finden Sie auf dieser Seite: https://github.com/0xd4d/dnlib/blob/master/examples/example2.cs
Wenn Sie die Montage unter einem anderen Namen speichern möchten, verwenden Sie Folgendes:
patcher . Save ( String ) ; // filename hereOder wenn Sie die Originaldatei ersetzen möchten:
patcher . Save ( bool ) ; // if true it will create a backup first (filename.bak) Baoss, was kann ich tun, wenn es stark verschleiert wird?! Hören Sie auf Ihren Opa Joe zu. Verwenden Sie 'dnpatch.deobfuscation'! Es hat magische Kräfte! Nein, Joe ist nur ein Kind, es verwendet die DE4DOT -Bibliotheken. Verweisen Sie auf die Bibliothek dnpatch.deobfuscation und stellen Sie sicher, dass Sie auch alle anderen aus dem Reißverschluss kopieren! Dann machen Sie das:
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 Mit Dnpatch.Script können Sie jetzt Patchiker mit JSON skript machen! Beispiel 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 "
}]
}Nennen Sie diesen Datei -Skript.json und platzieren Sie ihn in den Testscript -Build -Ordner und verwenden Sie ihn mit test.exe. Weitere Informationen finden Sie im eigenständigen Repo.
Ich möchte diesen Leuten danken: