[WIP] .NET Patcher Library с использованием DNLIB.
Если у вас есть вопросы, не стесняйтесь задавать мне через gitter! Я рад вам помочь! Принимая запросы на функции!
Мастерская ветвь предоставляет вам текущую стабильную сборку DNPatch. Тем не менее, я, скорее всего, больше не буду оказывать его поддержкой, так как версия 1.0 находится на пути в филиале V1.
DNPatch - это библиотека Ultimate для всех ваших потребностей в исправлении .NET. Он предлагает автоматическое исправление сборки, подпись сканирования и последнее, но не менее важное, обход в обхождение с помощью своих способностей находить методы в переименованных/запутанных типах. Поскольку звезды на GitHub взорвались через несколько дней, DNPatch был расширен из -за нескольких проектов. Наиболее важным является dnpatch.deobfuscation, которая интегрирует DE4DOT непосредственно в DNPatch. Также есть dnpatch.script, который дает вам возможность писать патчи с чистым JSON! Сама библиотека использует dnlib (см. Следующую часть).
Поскольку DNPatch использует DNLIB, настоятельно рекомендуется использовать DNSPY для сначала анализировать ваши сборки, чтобы убедиться, что вы используете правильные имена, смещения и т. Д., Поскольку он использует DNLIB.
Настоятельно рекомендуется вычислять индекс инструкции вместо его определения, чтобы повысить вероятность совместимости с будущими обновлениями.
Конструктор берет имя файла сборки.
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 или любое другое декомпилятор.
Небольшой пример:
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 []), сканируя их тело для подписи 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 [].
Если вы хотите перезаписать методика с помощью оператора 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 ) ;Если вы хотите перезаписать тело с возвратом True/False, сделайте это:
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 ) ;Теперь вы можете переписать имущество и сеттер, как это:
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" ) ;Если вы хотите вводить методы в классы, вызовите InjectMethod. Обязательно установите 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 ) ;На данный момент см.
Если вы хотите сохранить сборку под другим именем, используйте это:
patcher . Save ( String ) ; // filename hereИли если вы хотите заменить исходный файл:
patcher . Save ( bool ) ; // if true it will create a backup first (filename.bak) Баосс, что я могу сделать, если это сильно запутано?! Что ж, послушай, осторожен со своим дедушкой Джо. Используйте «dnpatch.deobfuscation»! У него волшебные силы! Нет, Джо просто 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 и используйте его с помощью test.exe. Для получения дополнительной информации, пожалуйста, обратитесь к отдельному репо.
Я хотел бы поблагодарить этих людей: