[WIP] .NET Patcher Library باستخدام DNLIB.
إذا كانت لديك أسئلة ، فلا تتردد في طرحها على Gitter! أنا سعيد لمساعدتك! أخذ طلبات الميزة!
يوفر لك الفرع الرئيسي البنية المستقرة الحالية لـ DNPatch. ومع ذلك ، على الأرجح لن أقدم الدعم لها بعد الآن لأن الإصدار 1.0 في طريقه في فرع V1.
DNPatch هي المكتبة النهائية لجميع احتياجات تصحيح .NET الخاصة بك. إنه يوفر تصحيح التجميع الآلي ، ومسح التوقيع ، وأخيراً ولكن ليس أقل من ذلك ، يتخطى المحتالين من خلال قدرته على إيجاد أساليب في الأنواع التي تم إعادة تسميتها/المحببة. منذ أن انفجرت النجوم على Github في غضون أيام قليلة ، تم تمديد DNPatch من قبل اثنين من المشاريع. أهم واحد هو dnpatch.deobfuscation الذي يدمج de4dot مباشرة في dnpatch. كما يوجد dnpatch.script ، مما يمنحك القدرة على كتابة ترسس مع JSON النقي! تستخدم المكتبة نفسها dnlib (انظر الجزء التالي).
نظرًا لأن DNPatch يستخدم DNLIB ، فمن المستحسن بشدة استخدام DNSPY لتحليل التجميعات الخاصة بك أولاً ، لضمان استخدام الأسماء الصحيحة ، الإزاحة ، إلخ ، لأنه يستخدم DNLIB ASWELL.
يوصى بشدة بحساب فهرس التعليمات بدلاً من تحديده ، لتحسين احتمال التوافق مع التحديثات المستقبلية.
يأخذ المنشئ اسم ملف التجميع.
Patcher patcher = new Patcher ( "Test.exe" ) ;إذا كنت ترغب في الحفاظ على MaxStack القديم (على سبيل المثال للتجميعات المفرطة) ، استخدم الحمل الزائد:
Patcher patcher = new Patcher ( "Test.exe" , true ) ;جميع الطرق تأخذ كائنًا يسمى Target كوسيطة. يتم تعريف الكائن على النحو التالي:
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 targetReturnType والمعلمات حساسة لحالة الأحرف! مثال:
تم تعريف PropertyMethod على النحو التالي:
public enum PropertyMethod
{
Get ,
Set
}يرجى التأكد من عدم تعيين قيم غير متسقة ، على سبيل المثال
var target = new Target
{
Instructions = .. .
Instruction = .. .
}إذا كنت ترغب في تصحيح طرق متعددة ، قم بإنشاء هدف [] ونقله إلى الوظائف ، يتم قبوله من قبل معظمها.
المرجع DNLIB وإنشاء تعليمة [] أو تعليمات مع التعليمات (التعليمات) الخاصة بك ، ثم تعيين فهارس تعيين حيث تكون التعليمات. يمكنك العثور عليها عن طريق هندسة عكسية التجميع الخاص بك عبر DNSPY أو أي decompiler آخر.
مثال صغير:
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
} ;لمسح الأسلوب بأكمله واكتب التعليمات الخاصة بك ، تأكد من عدم تعيين خاصية الفهارس أو الفهرس.
هنا مثال:
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
} ;لتطبيق الإرشادات المعدلة الخاصة بك ، يمكنك الاتصال بالطريقة "التصحيح":
patcher . Patch ( Target ) ;أو
patcher . Patch ( Target [ ] ) ;في بعض الحالات ، قد يكون من المفيد العثور على تعليمات داخل طريقة ، على سبيل المثال إذا تم تحديث الطريقة.
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دعنا نقول أن هناك تعليمات متطابقة متعددة. ماذا الآن ، باوس؟ حسنًا ، الأمر بسيط. هناك تحميل زائد يأخذ int وهو حدوث التعليمات التي ترغب في العثور عليها.
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!يمكنك العثور على طرق (Target []) عن طريق مسح أجسامهم للحصول على توقيع رمز opcy
OpCode [ ] codes = new OpCode [ ] {
OpCodes . Ldstr ,
OpCodes . Call
} ;
var result = p . FindMethodsByOpCodeSignature ( codes ) ; // holds Target[]في بعض الحالات ، قد يكون من الأسهل استبدال التعليمات. في مرحلة التطوير هذه ، لا معنى له ، لكن الميزات ستأتي قريبًا.
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 ) ;دعنا نقول أنك تريد إزالة التعليمات ... حسنًا ، الأمر بسيط مثل هذا:
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 ) ;هممم .... ماذا لو وجدت إخراج وحدة التحكم؟ يمكنك تعديل LDSTR دون حتى إنشاء تعليمات :)
Target target = new Target ( )
{
Namespace = "Test" ,
Class = "Program" ,
Method = "PrintAlot" ,
Index = 0
} ;
p . PatchOperand ( target , "PatchedOperand" ) ; // pass the Target and a string to replaceأو إذا كنت بحاجة إلى تعديل int:
p . PatchOperand ( target , 1337 ) ;كما أنه قادر على تصحيح المعاملات المتعددة في نفس الطريقة باستخدام int [] أو سلسلة [].
إذا كنت تريد الكتابة فوق methodbody مع بيان إرجاع صحيح/خطأ ، يمكنك القيام بذلك:
target = new Target ( )
{
Namespace = "Test" ,
Class = "Program" ,
Method = "VerifyMe"
} ;
p . WriteReturnBody ( target , bool ) ; // bool represents the return valueإذا كنت تريد فقط تفريغ طريقة ، فاستخدم هذا Amigo:
target = new Target ( )
{
Namespace = "Test" ,
Class = "Program" ,
Method = "WriteLog"
} ;
p . WriteEmptyBody ( target ) ;ما عليك سوى القيام بذلك إذا كنت ترغب في الحصول على تعليمات للكائن الهدف:
target = new Target ( )
{
Namespace = "Test" ,
Class = "Program" ,
Method = "WriteLog"
} ;
Instruction [ ] instructions = p . GetInstructions ( target ) ;إذا كنت تريد الكتابة فوق الجسم مع عودة حقيقية/خاطئة افعل هذا:
target = new Target ( )
{
Namespace = "Test" ,
Class = "Program" ,
Method = "WriteLog"
} ;
p . WriteReturnBody ( target , bool ) ;
// bool is the return value, e.g. true will return true ;)إذا كنت ترغب في إزالة الجسم ، فما عليك سوى الاتصال بهذا:
target = new Target ( )
{
Namespace = "Test" ,
Class = "Program" ,
Method = "WriteLog"
} ;
p . WriteEmptyBody ( target ) ;إذا كنت ترغب في العثور على طريقة ، يمكنك ببساطة مسح الملف بأكمله بطريقتين:
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 [ ] ) ;كلا الاتجاهين يعيدون هدفًا [] يحتوي على جميع الأهداف التي تشير إلى النتائج.
إذا كنت ترغب في العثور على التعليمات وكنت تعرف الفئة (واختياريا الطريقة) ، فيمكنك السماح لهذه الطريقة بإرجاع الهدف [] مع المسارات والفهارس.
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 ) ;الآن يمكنك إعادة كتابة Getter و Setter الخاص بممتلكات مثل هذا:
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 تمتلك الخاصية المسمى "Property" اسم الخاصية الهدف.
PropertyMethod يمكن أن يكون "propertymethod.get" أو "propertyMethod.set".
التعليمات هي التعليمات الجديدة لـ Getter أو Setter.
لإنشاء مكالمات مثل "console.writeline (سلسلة)" يمكنك استخدام هذه الطريقة:
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
*/فيما يلي مثال IL لـ 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" ) ;إذا كنت ترغب في ضخ الأساليب في الفصول ، فاستدعاء حقن. تأكد من تعيين MethodDef والتعليمات. تعيين اختياريا السكان المحليين ، المعلمة.
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 ) ;في الوقت الحالي ، راجع هذه الصفحة: https://github.com/0xd4d/dnlib/blob/master/examples/example2.cs
إذا كنت ترغب في حفظ التجميع تحت اسم مختلف ، فاستخدم هذا:
patcher . Save ( String ) ; // filename hereأو إذا كنت تريد استبدال الملف الأصلي:
patcher . Save ( bool ) ; // if true it will create a backup first (filename.bak) باووس ، ماذا يمكنني أن أفعل إذا كان الأمر شاقًا؟! حسنًا ، استمع إلى حذر لجدك جو. استخدم "dnpatch.deobfuscation"! لديها قوى سحرية! ناه ، جو هو مجرد Kiddin ، وهو يستخدم مكتبات De4Dot. الرجوع إلى المكتبة dnpatch.deobfuscation وتأكد أيضًا من نسخ جميع الآخرين من الرمز البريدي! ثم افعل هذا:
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 مع dnpatch.script ، يمكنك الآن نصوص برامج ترشيح مع JSON! مثال 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 "
}]
}قم بتسمية هذا الملف script.json ووضعه في مجلد Build TestScript واستخدمه مع test.exe. لمزيد من المعلومات ، يرجى الرجوع إلى الريبو المستقل.
أود أن أشكر هؤلاء الناس: