[wip] dnlibを使用したpatcherライブラリ。
ご質問がある場合は、お気軽にお問い合わせください!私はあなたを助けてくれてうれしいです!機能のリクエストを取ります!
マスターブランチは、DNPatchの現在の安定したビルドを提供します。ただし、バージョン1.0はV1ブランチでの道を進んでいるため、もうサポートを提供していない可能性があります。
DNPatchは、すべての.NETパッチングニーズの究極のライブラリです。自動化されたアセンブリのパッチ、署名スキャン、および最後になりましたが、非難/難読化されたタイプのメソッドを見つける能力により、難読化者のバイパスを提供します。 Githubの星が数日で爆発して以来、DNPatchはいくつかのプロジェクトによって拡張されました。最も重要なのは、DE4DOTをDNPATCHに直接統合するDNPATCH.DEOBFUSCATIONです。また、dnpatch.scriptがあります。これにより、純粋な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を参照し、命令[]または命令を作成して命令を作成し、命令を割り当てます。
小さな例:
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!オペコード署名のために体をスキャンすることで、メソッド(ターゲット[])を見つけることができます
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」にすることができます。
指示は、ゲッターまたはセッターの新しい指示です。
「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" ) ;クラスにメソッドを注入する場合は、injectMethodを呼び出します。 MethodDefと手順を設定してください。オプションで、地元の人、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」を使用してください!魔法の力があります!いや、ジョーはただの子供で、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で使用します。詳細については、スタンドアロンリポジトリを参照してください。
これらの人々に感謝したい: