NET.Reflectorをだます方法

今日、難読化ツールがNET.Reflectorのような難読化解除ユーティリティからメソッドコードを隠す方法について考えました。 奇妙なことに、この問題に関する有用な情報をインターネット上で見つけることができなかったため(検索が不十分だった可能性があります)、自分で少し調査しなければなりませんでした。 カットの下で、結果に関する簡単なメモ。 サンプルコードでは、Mono.Cecilとコード生成が再び使用されるため、必ず最初の記事を読んでください







理論から始めましょう。 各MSIL命令コードは、1バイトまたは2バイトで表すことができます。 たとえば、nop命令は0x00として表されます。 したがって、65,536の異なるオプションがあります。 現時点では、このスペースの一部は有効なMSIL命令コードで占められていますが、ほとんどは無料です。 JITコンパイラーを誤ったコードの命令に切り替えると、アプリケーションがクラッシュします。 NET.Reflectorは、誤った命令にぶつかると、メソッドコードの解析を停止し、「Invalid method body」というメッセージを表示します。これが必要です。



したがって、私たちの目標は、メソッドに誤った命令を挿入することですが、どのような条件下でもそれへの遷移が発生しないようにすることです。 これを行うには、無条件ジャンプを使用できます。



goto MethodCode; //    MethodCode: //   
      
      







Reflectorはコードの到達可能性を分析せず、不適切な命令を分析するとつまずき、メソッドはそれ以上分析しません。 不正な命令への切り替えは発生しないため、アプリケーションは正常に動作します。 Mono.Cecilでは不適切な命令を単純に挿入することができないため、問題はやや複雑です。有効なコードはすべて列挙形式で表示され、標準ツールを使用して独自のコードを追加することはできません。 もちろん、Mono.Cecilのソースはいつでも変更できます。メリットはオープンソースシステムですが、標準のアセンブリで動作するようにしたかったのです。 Mono.Cecilのソースを30分分析した後、不正な命令0x0024を挿入して、Mono.Cecilがそれをスキップして例外をスローしないようにする方法を見つけました。 コードを見てみましょう:



 static void ProtectMethod(string path, string methodName) { var assembly = AssemblyDefinition.ReadAssembly(path); foreach (var typeDef in assembly.MainModule.Types) { foreach (var method in typeDef.Methods) { if (method.Name == methodName) { var ilProc = method.Body.GetILProcessor(); //   internal    OpCode var constructor = typeof(OpCode).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(int), typeof(int) }, null); //  Mono.Cecil     -     4-(int) ,       8 ,        MSIL . ,        8   2 .       OpCode,      .        ,       , Mono.Cecil        Exception,       . int x = 0xff << 0 | //   IL  0x24 << 8 | //   IL  0x00 << 16 | (byte) FlowControl.Next << 24; //       ,    ,  Mono.Cecil     int y = (byte) OpCodeType.Primitive << 0 | (byte) OperandType.InlineNone << 8 | (byte) StackBehaviour.Pop0 << 16 | (byte) StackBehaviour.Push0 << 24; var badOpCode = (OpCode) constructor.Invoke(new object[] {x, y}); //    Instruction badInstruction = Instruction.Create(badOpCode); Instruction firstInstruction = ilProc.Body.Instructions[0]; //         ilProc.InsertBefore(firstInstruction, Instruction.Create(OpCodes.Br_S, firstInstruction)); //        ilProc.InsertBefore(firstInstruction, badInstruction); } } } assembly.Write(path); }
      
      







表示から保護したいアセンブリのメソッドでこのメソッドの結果を検討してください



処理前の方法:

画像

画像



処理後のリフレクターのメソッド:

画像

画像



この場合、処理後、アプリケーションは問題なく起動します。 必要な結果が達成されました。



最終的に、このような難読化は非常に簡単です(アセンブリの変更が必要になります)が、あまり知識のない開発者がコードを表示から保護できることに注意してください。 また、私の意見では、情報自体は非常に興味深いものです。



All Articles