[WIP]. NET Patcher Library โดยใช้ DNLIB
หากคุณมีคำถามอย่าลังเลที่จะถามฉันผ่าน Gitter! ฉันดีใจที่ได้ช่วยคุณ! รับคำขอคุณสมบัติ!
สาขาหลักให้การสร้าง DNPatch ที่เสถียรในปัจจุบันแก่คุณ อย่างไรก็ตามฉันมักจะไม่ให้การสนับสนุนอีกต่อไปเนื่องจากเวอร์ชัน 1.0 กำลังอยู่ในสาขา V1
DNPatch เป็นไลบรารีที่ดีที่สุดสำหรับความต้องการการแก้ไข. NET ทั้งหมดของคุณ มันให้บริการแพทช์แอสเซมบลีอัตโนมัติการสแกนลายเซ็นและสุดท้าย แต่ แต่ไม่น้อยกว่าการข้ามของผู้เล่น obfuscators โดยความสามารถในการค้นหาวิธีการในประเภทที่เปลี่ยนชื่อ/ทำให้งง ตั้งแต่ดวงดาวใน GitHub ระเบิดในอีกไม่กี่วัน DNPatch ได้ขยายออกไปโดยสองโครงการ สิ่งที่สำคัญที่สุดคือ dnpatch.deobfuscation ซึ่งรวม DE4DOT ลงใน DNPatch โดยตรง นอกจากนี้ยังมี dnpatch.script ซึ่งให้ความสามารถในการเขียน patchers ด้วย JSON บริสุทธิ์! ห้องสมุดใช้ DNLIB (ดูส่วนถัดไป)
เนื่องจาก DNPatch ใช้ DNLIB จึงขอแนะนำให้ใช้ DNSPY เพื่อวิเคราะห์แอสเซมบลีของคุณก่อนเพื่อให้แน่ใจว่าคุณใช้ชื่อที่ถูกต้องออฟเซ็ต ฯลฯ เพราะใช้ DNLIB เช่นกัน
ขอแนะนำอย่างยิ่งให้คุณคำนวณดัชนีของคำสั่งแทนการกำหนดเพื่อปรับปรุงความเป็นไปได้ของความเข้ากันได้กับการอัปเดตในอนาคต
ตัวสร้างใช้ชื่อไฟล์ของแอสเซมบลี
Patcher patcher = new Patcher ( "Test.exe" ) ;หากคุณต้องการเก็บ maxstack เก่า (ตัวอย่างเช่นชุดประกอบที่ทำให้งงงวย) ใช้โอเวอร์โหลด:
Patcher patcher = new Patcher ( "Test.exe" , true ) ;วิธีการทั้งหมดใช้วัตถุที่เรียกว่าเป้าหมายเป็นอาร์กิวเมนต์ วัตถุถูกกำหนดดังนี้:
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สมมติว่ามีคำแนะนำที่เหมือนกันหลายคำ ตอนนี้ baoss? มันง่าย มีการโอเวอร์โหลดที่ต้องใช้ 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!คุณสามารถค้นหาวิธีการ (เป้าหมาย []) โดยการสแกนร่างกายของพวกเขาสำหรับลายเซ็น opcode
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 [] หรือ string []
หากคุณต้องการเขียนทับ Methodbody ด้วยคำสั่ง Return True/False คุณสามารถทำได้:
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 ) ;หากคุณต้องการค้นหาวิธีการคุณสามารถสแกนไฟล์ทั้งหมดได้ 2 วิธี:
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 คุณสมบัติที่เรียกว่า 'คุณสมบัติ' ถือชื่อของคุณสมบัติเป้าหมาย
PropertyMethod สามารถเป็น 'PropertyMethod.get' หรือ 'PropertyMethod.set'
คำแนะนำคือคำแนะนำใหม่สำหรับ Getter หรือ Setter
ในการสร้างการโทรเช่น "Console.WriteLine (String)" คุณสามารถใช้วิธีนี้:
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" ) ;หากคุณต้องการฉีดวิธีลงในชั้นเรียนให้โทร InfectMethod ตรวจสอบให้แน่ใจว่าได้ตั้งค่า MethodDef และคำแนะนำ ตั้งค่า 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 ) ;สำหรับตอนนี้อ้างถึงหน้านี้: 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) Baoss ฉันจะทำอย่างไรถ้ามันสับสนอย่างหนัก! ฟังอย่างระมัดระวังกับคุณปู่โจของคุณ ใช้ 'dnpatch.deobfuscation'! มันมีพลังวิเศษ! Nah, Joe เป็นเพียง kiddin 'มันใช้ห้องสมุด de4dot อ้างอิงไลบรารี dnpatch.deobfuscation และตรวจสอบให้แน่ใจว่าคุณคัดลอกคนอื่นทั้งหมดจาก zip! จากนั้นทำเช่นนี้:
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 และวางลงในโฟลเดอร์ testscript build และใช้กับ test.exe สำหรับข้อมูลเพิ่มเติมโปรดดูที่ repo แบบสแตนด์อโลน
ฉันอยากจะขอบคุณคนเหล่านี้: