
ConfuserEx2の難読化解除ツール。アンチタンパー、圧縮機、定数、制御フロー、リソース復元をサポートします。
UnconfuserEx の拡張フォーク。最新の ConfuserEx2 バリアントへの対応改善、アンチタンパー復元、圧縮除去、制御フロー復元、リソース再構築を備えています。
https://github.com/user-attachments/assets/de2c7fd9-6736-4f39-83c0-3c25aa9c1f24
もしマルウェアサンプルを扱ったことがあるなら、その一部は ConfuserEx で難読化されています。最新版に対して公開されているいくつかの難読化解除ツールを試しましたが、うまく動作しませんでした。そこで、その最新版に対して動作した公開ツールをフォークし、自分のニーズに合わせて修正することにしました。
このリポジトリは MadMin3r/UnconfuserEx のフォークです。彼にもクレジットを捧げます。オリジナルのプロジェクトは、ConfuserEx2 に特化した難読化解除ツールを作成し、実際の保護を除去できるようにするという困難な部分を担っていました。
このプロジェクトが行うのはまさにそれです。固定された順序でリムーバーのリストを実行し、可能な限りメソッドボディ/リソース/メタデータを書き換え、新しいアセンブリを出力します。重要なのは順序です。コンプレッサーとアンチタンパーは早期に実行する必要があります。なぜなら、モジュールの残りの部分がまだ実際の IL ではない可能性があるからです。
上流のバージョンはすでに有用でしたが、いくつかのケースが頻繁に発生していました。
その一つが LZMA パスです。一部のサンプルでは、定数/リソースのペイロードのように見えるバイトが渡されますが、LZMA プロパティが無意味です。そのままデコーダに渡すと、ばかげた辞書サイズになり、最終的に配列の次元がサポート範囲を超えているなどの例外が発生します。そのため、このバージョンではプロパティをチェックし、辞書サイズを上限で制限し、非圧縮サイズを上限で制限し、デコーダが不合理なメモリを割り当てる前に停止します。
LZMA properties => CE FD 62 5F 9F
Invalid LZMA properties byte 0xCE or unreasonable dictionary size
定数には別の馬鹿げたけど実際にある問題がありました。リゾルバコードの多くは、ゲッター呼び出しの前に置かれている ID が ldc.i4 であることを期待しています。しかし、それが単一の命令ではなくなっている場合があります。小さな算術式になっているのです。
ldc.i4 0x1234
ldc.i4 0x55
xor
call string <const getter>(int32)
オリジナルのフォークは xor を認識し、GetLdcI4Value() を呼び出して、xor が明らかに整数ロードではないためにエラーになります。このバージョンでは、小さな算術シーケンスを逆向きにトレースし、スタックをエミュレートし、1つの ldc.i4 にまとめてから、通常のリゾルバに処理を渡します。
つまり、これをまったく異なる定数保護として扱うのではなく、次のようになります。
ldc.i4 0x1261
call string <const getter>(int32)
その後、既存の通常/x86 定数リゾルバパスがその役割を果たせます。
制御フローは微妙なところでした。
スイッチリムーバーは、通常の ConfuserEx スイッチディスパッチャの形状を処理できます。ブロックを走査し、次のターゲットを復元し、デッドブロックを削除し、健全なメソッドボディを生成します。しかし、メソッドの一部しか理解できないサンプルもあります。メソッドの半分を変異させて、まだ難読化されていることに気づくと、出力は役に立たなくなります。なぜなら、IL が壊れ、何が起こったかを判断するクリーンな方法がなくなるからです。
そのため、このバージョンではメソッドボディを操作する前にスナップショットを取得します。
instructions
exception handlers
難読化解除が例外をスローした場合、またはメソッドがその後も難読化されたままに見える場合、元のボディが復元されます。ログには「このメソッドは解決できませんでした」と表示されますが、アセンブリが静かに破損することはありません。たとえ1つのメソッドが奇妙なディスパッチャを持っていたとしても。
ジャンプ/トランポリン制御フローも独自のパスを持つようになりました。一部のメソッドはスイッチディスパッチャではなく、実際のブロックに到達するまで連鎖する小さなブランチトランポリンです。これらは検出され、折りたたまれるようになりました。スイッチのみのパスでは無視されません。
コンプレッサーリムーバーは、他のすべての前に実行する必要がある部分です。
ConfuserEx のコンプレッサースタブは通常、実際のアセンブリを圧縮したまま保持し、小さなローダーを起動し、ペイロードを展開し、実行時にロードします。
リムーバーはローダーの形状を見つけ、埋め込まれたペイロードを抽出し、展開し、モジュールを実際のアセンブリに交換します。通常およびコンパクトなコンプレッサーレイアウトの両方を処理します。
[+] Compressor detected
[+] Extracted compressed module payload
[+] Decompressed real module
[+] Continuing pipeline on unpacked assembly
アンチタンパーには現在2つのパスがあります。
通常/動的アンチタンパーは、保護されたセクションからメソッドボディを復号し、復元されたボディをモジュールに書き戻します。JIT アンチタンパーはより厄介で、ボディはランタイムが要求したときに実体化されることを意図しています。
大まかな形状は次のとおりです。
find init
extract keys
find encrypted JIT body section
derive per method key
read body
write CilBody back
これは依然としてパターンベースです。スタブが十分に変更されていれば、見逃します。もちろん。
リソースは定数と同様に処理されます。暗号化されたリソースブロブを見つけ、キー/復号化形状を回復し、復号化し、必要に応じて展開し、通常の .NET ツールが期待する場所にリソースを戻します。
また、オプションの埋め込み PE 再構築パスもあります。一部の保護されたサンプルは、リソース内にマネージド PE を保持しています。再構築を有効にすると、リムーバーはそのペイロードも解析および書き換えようとします。アンタッチされた内部アセンブリを持つ難読化解除された外部アセンブリを残すことはありません。
UnConfuserEx.exe sample.exe sample.clean.exe --rebuild-embedded-pe
サンプルがリソース内に別のマネージドアセンブリを隠していることがわかっている場合にこれを使用します。ペイロードがマネージド PE でない場合、再構築パスはそのままにしておくはずです。
ビルド:
dotnet build .\UnConfuserEx.sln -c Release
実行:
.\UnConfuserEx\bin\Release\net9.0\UnConfuserEx.exe .\protected.exe
明示的な出力パスを指定:
.\UnConfuserEx\bin\Release\net9.0\UnConfuserEx.exe .\protected.exe .\protected.clean.exe
出力パスを指定しない場合、入力ファイルの隣に -deobfuscated を付けた名前で書き出します。
埋め込みマネージドペイロードの場合:
.\UnConfuserEx\bin\Release\net9.0\UnConfuserEx.exe .\protected.exe .\protected.clean.exe --rebuild-embedded-pe
これは現在のサポートリストです。考えられるすべての ConfuserEx フォークが動作することを意味するわけではありません。これらは、パイプラインが検出方法を知っている形状です。
おそらくコードに隠れているものもあり、リストアップするのを忘れています xD。
有用なログは、単に出力が動作しなかったと言うだけでなく、どの段階で失敗したかを教えてくれるものです。
修正された定数パスの例:
Constants detected, attempting to remove
Found 3 constant getter(s)
Detected constant decryption type is Dynamic
Decompressed constants blob to 18492 byte(s)
Resolving getter <Module>::???????? as String with 41 call site method(s)
Removed all instances of getter <Module>::????????
意図的に放置された制御フローメソッドの例:
Removing obfuscation from method System.Void Example::Run()
Method System.Void Example::Run() still appears obfuscated after deobfuscation -- left original body intact
Removed obfuscation from 42 methods. Failed to remove from 0 methods. 1 methods left untouched
2番目のログは完璧ではありませんが、少なくとも正直です。
すべてのヘルパー形状を変更するカスタム ConfuserEx フォーク。
小さなスタック式ではなく、完全な制御フローの混乱を経て ID を計算する定数ゲッター。
静的エミュレータが知らないランタイム値に依存するディスパッチャを持つ制御フローグラフ。
IL エミュレーションではなく実際のランタイム実行を必要とするネイティブヘルパー。
難読化される前にすでに壊れていたアセンブリ。
異なる暗号化ボディレイアウトを持つ JIT アンチタンパーバリアント。
問題を有用にしたい場合は、再現に十分なデータを含めてください。
サンプルをアップロードする前にファイル拡張子を削除してください。
すべてを一緒にアーカイブし、以下を含めてください:
Command:
UnConfuserEx.exe <target> <optional output>
Failure stage:
- compressor
- anti tamper
- constants
- control flow
- resources
- writing output
- runtime after deobfuscation
Expected result:
Actual result:
Console output:
Archive link:
Notes / investigation:
「動作しません」とだけ送っても、たぶん「そうですよね」という答えが返ってくるでしょう。




小規模で焦点を絞った修正は、大規模な書き換えよりも優れています。
新しい保護形状のサポートを追加する場合は、それを所有するリムーバーに閉じ込めてください。フォールバック動作を追加する場合は、失敗が出力アセンブリを破損しないようにしてください。制御フローに触れる場合は、修正した奇妙なサンプルが存在する唯一の奇妙なサンプルではないと想定してください :DDD。
ツールをデバッグしにくくしないでください。
このプロジェクトは MadMin3r/UnconfuserEx に基づいています。
オリジナルのプロジェクトは基盤と主要な難読化解除パイプラインの大部分を提供しました。このフォークは、信頼性の向上、追加の保護バリアントのサポート、実際のサンプルで観察されたエッジケースの処理に重点を置いています。
このプロジェクトはソフトウェア工学の演習ではなく、実用的なリバースエンジニアリングツールとして始まりました。完全なコード品質よりも、保護されたアセンブリを確実に復元することに常に焦点が当てられてきました。
このツールは、許可されたマルウェア分析、リバースエンジニアリング、ソフトウェア復元、相互運用性、および教育研究を目的としています。
ユーザーは、該当する法律を遵守し、ソフトウェアまたはシステムを分析、アクセス、または処理する前に必要な許可を取得する責任を負います。
Zypherion Technologies は、このツールの不正使用を許可せず、第三者による誤用に対する責任を否認します。
このリポジトリまたは www.zypherion.tech の内容は法律上のアドバイスではありません。