[WIP]使用dnlib的.NET PATCHER庫。
如果您有問題,請隨時通過吉特問我!我很高興為您提供幫助!接受功能請求!
主分支為您提供當前穩定的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 ) ;所有方法都以一個稱為目標的對像作為參數。該對象定義如下:
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返回類型和參數對案例敏感!例子:
propertyMethod定義為:
public enum PropertyMethod
{
Get ,
Set
}請確保您不會分配不一致的值,例如
var target = new Target
{
Instructions = .. .
Instruction = .. .
}如果要修補多種方法創建一個目標[]並將其傳遞給功能,則大多數方法都接受了它。
引用DNLIB並使用您的指令創建指令[]或指令,然後分配指令所在的索引。您可以通過DNSpy或任何其他分解器來反向工程來找到它們。
小例子:
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簽名來找到方法(target [])
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 []或字符串[]以相同方法修補多個操作數。
如果您想用返回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 ) ;如果要找到一種方法,則可以通過兩種方式掃描整個文件:
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和設定器:
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
*/這是Console.Writeline的IL示例:
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和說明。可選設置當地人,參數defs。
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/master/examples/example2.cs
如果要以其他名稱保存組件,請使用以下方式:
patcher . Save ( String ) ; // filename here或者如果要替換原始文件:
patcher . Save ( bool ) ; // if true it will create a backup first (filename.bak) Baoss,如果它沉重混淆,該怎麼辦?好吧,請謹慎對待您的喬(Joe)。使用“ dnpatch.deobfuscation”!它具有魔力!不,喬只是孩子,它使用了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 "
}]
}命名此文件腳本。 JSON並將其放入testscript構建文件夾中,然後將其與test.exe一起使用。有關更多信息,請參閱獨立倉庫。
我要感謝這些人: