投稿者:Paul Rascagneres、Warren Mercer
はじめに
異なる言語およびハードウェア プラットフォーム間に相互運用のための共有フレームワークを提供する Microsoft エコシステムのコンポーネントとして、.NET はその重要性をますます高めています。PowerShell やその他の管理機能など、多くの Microsoft のツールは、その機能を .NET プラットフォームに依存しています。こういった状況の中、.NET がマルウェア開発者にとっても魅力的な言語となっているのは言うまでもありません。したがって、マルウェアの研究者は、言語にも精通するとともに、このプラットフォームで動作する悪意あるソフトウェアの分析に必要なスキルを備えている必要があります。
ILSpy などの分析ツールは、アプリケーションからコードを逆コンパイルすることでは研究者の役に立ちますが、これらを使って多くのサンプルの分析を自動化することはできません。この記事では、Microsoft が提供する SOS 拡張を使用して .NET アプリケーションを WinDBG で分析する方法について、検証します。
この記事では次のことを説明します。
- .NET API にブレークポイントを挿入して PowerShell スクリプトを分析する方法。
- パッカーのロジックの分析に従って .NET サンプルを自動的に展開するスクリプトを簡単に作成する方法。
さらに、Cisco Talos の github で Python スクリプト(WinDBG pykd 拡張に基づく)をダウンロードして .NET の分析を自動化することができます。 このスクリプトは本記事にも記載します。
SOS 拡張
SOS 拡張により、WinDBG で .NET がサポートされるようになります。この拡張では豊富なコマンド セットが提供されます。この記事では分析に利用できるコマンドを取り上げますが、それらはそのごく一部です。
まず、SOS 拡張を配置する場所は、使用する .NET のバージョンによって異なっています。SOS 拡張を使用するには、WinDBG にライブラリをロードする必要があります。
.NET 4 の場合、拡張は CLR.dll に配置することで、次のコマンドでロードできます。
.loadby sos clr
.NET 2 および 3 では、SOS 拡張は mscorwks ライブラリに配置します。
.loadby sos mscorwks
この記事では次のようなコマンドを使用します。
- !bpmd:このコマンドは、マネージ コード(.NET)にブレークポイントを挿入するために使用します。このコマンドは 2 つの引数を使用します。最初の引数は .NET dll で、関数の場所を示します。2 番目の引数は関数名です。
- !CLRStack:このコマンドは、CLR スタックの内容を表示します。.NET 関数の引数を特定するのに役立ちます。
- !DumpObj:このコマンドは、引数で指定された特定のオブジェクトに関する情報を表示します。
この記事ではこれら 3 つのコマンドを使用して、特定の .NET API 内にブレークポイントを作成し、API に渡された引数を取得し、内容を表示します。
使用例 #1:PowerShell 分析
あまり知られていませんが、PowerShell は .NET Framework を使用できます。.NET API の使用状況を調べることにより、PowerShell 分析を簡単に自動化できます。
例1:Start-Process API
この例では、次の PowerShell コードを分析します。
PS> start-process notepad.exe
このタスクを実行する際、PowerShell は Process.Start() API. を使用します。これにより、(SOS 拡張をロードした後)この API にブレークポイントを挿入できます。これは、コード実行を意図的に停止する箇所です。
0:011> .loadby sos clr
0:011> !bpmd system.dll System.Diagnostics.Process.Start
Found 6 methods in module 00007fff97581000...
breakpoint: bp 00007FFF977C96D9 [System.Diagnostics.Process.Start(System.Diagnostics.ProcessStartInfo)]
breakpoint: bp 00007FFF97E8057D [System.Diagnostics.Process.Start(System.String, System.String)]
breakpoint: bp 00007FFF97E80539 [System.Diagnostics.Process.Start(System.String)]
breakpoint: bp 00007FFF97E804B6 [System.Diagnostics.Process.Start(System.String, System.String, breakpoint: bp 00007FFF977C72DA [System.Diagnostics.Process.Start()]
Adding pending breakpoints...
ブレークポイントを設定したら、PowerShell スクリプトを実行するコマンド「g」を入力できます。Start-Process プロセスが実行されると WinDBG は停止します。
Breakpoint 0 hit System_ni+0x2496d9: 00007fff`977c96d9 488d0d08711e00 lea rcx,[System_ni+0x4307e8 (00007fff`979b07e8)]
CLRStack コマンドは、Process.Start API に提供された引数を表示します。この例での引数は、System.Diagnostics.ProcessStartInfo オブジェクトです。
0:008> !CLRStack -p OS Thread Id: 0x2d34 (8) Child SP IP Call Site 000000a7f9ace700 00007fff977c96d9 System.Diagnostics.Process.Start(System.Diagnostics.ProcessStartInfo) PARAMETERS: startInfo (<CLR reg>) = 0x0000028cbd5faa18
最後に、DumpObj コマンドで、オブジェクトの内容を表示します。
0:008> !DumpObj /d 0000028cbd5faa18 Name: System.Diagnostics.ProcessStartInfo MethodTable: 00007fff979ae380 EEClass: 00007fff975e29f0 Size: 144(0x90) bytes File: C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll Fields: MT Field Offset Type VT Attr Value Name 00007fff9897de98 40027f3 8 System.String 0 instance 28cbd5fde18 fileName 00007fff9897de98 40027f4 10 System.String 0 instance 000 arguments [...redacted...] 00007fff9897ad70 4002806 58 System.WeakReference 0 instance 000 weakParentProces 00007fff979af0a0 4002807 60 ....StringDictionary 0 instance 000 environmentVaria 00007fff982e5ec0 4002808 68 ...tring, mscorlib]] 0 instance 000 environment
ProcessStartInfo オブジェクトの最初のフィールドは、filename という System.String オブジェクトです。DumpObj を使用してオブジェクトの内容を取得できます。
0:008> !DumpObj /d 0000028cbd5fde18 Name: System.String MethodTable: 00007fff9897de98 EEClass: 00007fff982d35f0 Size: 88(0x58) bytes File: C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll String: C:\WINDOWS\system32\notepad.exe
filename 文字列がメモ帳のバイナリへのパスになっていることがわかります。
例2:DownloadFile API
この 2 番目の例では、次のコードを分析します。
PS> $a = New-Object System.Net.WebClient PS> $a.DownloadFile("http://blog.talosintelligence.com/","c:\users\lucifer\demo.txt")
このコードの目的は、ファイルをダウンロードしてハード ドライブに保存することです。これは、マルウェアがペイロードをダウンロードするためによく使用している手法です。
この例では、DownloadFile AP にブレークポイントを配置し、「g」を押して PowerShelI を実行する必要があります。
0:008> .loadby sos clr 0:008> !bpmd system.dll System.Net.WebClient.DownloadFile Found 2 methods in module 00007fff97581000... MethodDesc = 00007fff976c1fe8 MethodDesc = 00007fff976c1ff8 Setting breakpoint: bp 00007FFF97DCAE0C [System.Net.WebClient.DownloadFile(System.Uri, System.String)] Setting breakpoint: bp 00007FFF97DCADBC [System.Net.WebClient.DownloadFile(System.String, System.String)] Adding pending breakpoints… 0:008> g
API が実行されると、WinDBG は PowerShell スクリプトの実行を自動的に停止します。
Breakpoint 7 hit System_ni+0x84adbc: 00007fff`97dcadbc 4885d2 test rdx,rdx
ここで、前のケースとまったく同じように CLRStack および DumpObj コマンドを使用することも可能です。今回はそうせずに、レジスタから直接、値を取得します(Microsoft のメモリ ロケーションの標準により、最初の文字列は RDX+0xC にあり、2 番目の文字列は R8+0xC にあります)。
0:008> du rdx+c 0000028c`bd53f13c "http://blog.talosintelligence.co" 0000028c`bd53f17c "m/" 0:008> du r8+c 0000028c`bd53f3b4 "c:\users\lucifer\desktop\demo.tx" 0000028c`bd53f3f4 "t"
実行画面の一部を以下に示します。
使用例 #2:.NET の展開
Talos では日常的に、圧縮されたマルウェア サンプルを扱っています。先頃、シリア政府の Web サイトでホストされていた、圧縮 .NET 実行可能ファイル(http://www[.]syriantax[.]gov[.]sy/css/igfxCUIService.exe)を特定しました。最初に気になったのは、これが標的型攻撃の一部なのかどうかという点でした。その後の調査の結果、Web サイトが感染してこのマルウェアの配信に利用されたことが確信できました。このマルウェアは njRAT であると判明しました。njRAT は、長年広範囲に配信されてよく知られている、パブリックのリモート監視ツールです。njRAT の発見自体はそれほど興味深いことではないのですが、njRAT の展開方法についてブログ記事を書くのは有益であろうと考えました。
そういうわけで、この使用例では、静的分析を使用して未知の .NET パッカーに対処する方法を説明します。また、WinDBG を使用した動的分析とともに、このタイプのパッカーの展開プロセスを自動化する WinDBG スクリプトの作成方法も取り上げます。
静的分析
このマルウェア サンプルの分析では、最初に de4dot を使用しました。これを使うと既知のパッカーを迅速に特定できるからです。これはオープン ソースの分析プラットフォームで、ここ から入手できます。
C:> de4dot-x64.exe -d -r c:\to_test
de4dot v3.1.41592.3405 Copyright (C) 2011-2015 de4dot@gmail.com
Latest version and source code: https://github.com/0xd4d/de4dot Detected Unknown Obfuscator (c:\to_test\21acd3457c1a58[...]1bfeeaf3c0cd79bfe) Detected Unknown Obfuscator (c:\to_test\344ce133363f09[...]bbd2257a298484051) Detected Unknown Obfuscator (c:\to_test\45c695e610d786[...]af65408fb6080300f) Detected Unknown Obfuscator (c:\to_test\61653b2811fb7c[...]04f9807a775f25773) Detected Unknown Obfuscator (c:\to_test\ac7bd77245bdf2[...]aee4d06563f057ca6) Detected Unknown Obfuscator (c:\to_test\b607e87acdcb2e[...]d30eddddffbeec320) Detected Unknown Obfuscator (c:\to_test\e93c0aed6bbb4a[...]6c2efe65942f83504)
このセクションでは、オープン ソースの .NET デコンパイラ、ILSpy も使用します。これはこちら から入手できます。
XOR 化された亜種
サンプル:45c695e610d78178ec5ca6f4e1993afacf4e435b566cd2caf65408fb6080300f
パッカーのエントリ ポイントは ob6eaGgG7Bht6B35c0.G9puOotvCiNCkEEPD9.XHh0nc9pu です。この情報は、ILSpy を利用して展開することで特定できます。
パッカーは最初に、Base64 でエンコードされた文字列をデコードします(変数 G9puOotvCiNCkEEPD9.EHQI8XHAH)。デコードしたこの文字列を、XOR キーとして機能する第 2 の引数とともに、関数 G9puOotvCiNCkEEPD9.vovYCiNCk() に渡します。
出力をスクロールし、逆コンパイルされた .NET 実行可能ファイルを見ていくと、ILSpy による XOR の動作を特定できます。使用されている「^」関数を見ることで、これが XOR 動作であることがわかります。
最後に、関数の出力が、引数として関数 Assembly.Load() に渡されます。 この関数は、.NET バイナリをロードするのに使用されます。
Assembly.Load() に渡される引数はバイト配列で、Windows バイナリ(PE32)を含みます。この例では、展開されたマルウェアはバイト配列となっています。
AES 亜種
サンプル:21acd3457c1a589e117988fe0456e50ed627f051a97ccd11bfeeaf3c0cd79bfe
パッカーのこの亜種に含まれるロジックは同じですが、XOR 難読化を使用する代わりに AES 暗号化(別名 Rijndael)が使用されています。
最後に、Assembly.Load() 関数を使用して、復号されたデータがメモリにロードされます。
共通点
分析した各サンプルでは、使用されるアルゴリズムは異なっていますが(エンコーディングと暗号化)、ロジックはまったく同じです。Assembly.Load() 関数の引数で見つかったバイト配列型変数をダンプできれば、展開済みのマルウェアが得られます。
WinDBG による動的分析
.NET バージョン 4
.NET 4 のサンプルの動的分析を行うには、こちらから入手できる WinDBG SOS 拡張を取得する必要があります。この拡張により、Microsoft Debugger を使用した.NET 4 のデバッグが可能になります。
では、圧縮されたマルウェアを実行します。
最初の手順は、CLRJIT ライブラリがロードされたらデバッガの実行を停止することです。
0:000> sxe ld clrjit 0:000> g (dc0.1594): Unknown exception - code 04242420 (first chance) ModLoad: 70fc0000 71040000 C:\Windows\Microsoft.NET\Framework\v4.0.30319\clrjit.dll eax=00000000 ebx=00800000 ecx=00000000 edx=00000000 esi=00000000 edi=0044e000 eip=7736e85c esp=006fe4fc ebp=006fe558 iopl=0 nv up ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 ntdll!NtMapViewOfSection+0xc: 7736e85c c22800 ret 28h
次に、WinDBG SOS 拡張をロードして、.NET アプリケーション(管理されるアプリケーション)の分析を行います。
0:000> .load "C:\\Psscor4\\x86\\x86\\psscor4.dll"
これで、.NET デバッグに関連する新しい WinDBG コマンドを利用できるようになりました。ブレークポイントは、.NET API の使用状況に基づいて設定できます。この例では、Assembly.Load() API に着目します。
0:000> !bpmd mscorlib.dll System.Reflection.Assembly.Load
Found 8 methods in module 71041000...
MethodDesc = 71100b50
MethodDesc = 71100b7c
MethodDesc = 71100b88
MethodDesc = 71100b94
MethodDesc = 71100bb8
MethodDesc = 71100bd0
MethodDesc = 71100bdc
MethodDesc = 71100be8
Setting breakpoint: bp 71B29095 [System.Reflection.Assembly.Load(Byte[], Byte[], System.Security.Policy.Evidence)]
Setting breakpoint: bp 71B29037 [System.Reflection.Assembly.Load(Byte[], Byte[], System.Security.SecurityContextSource)]
Setting breakpoint: bp 71B28FFF [System.Reflection.Assembly.Load(Byte[], Byte[])]
Setting breakpoint: bp 71B28F9C [System.Reflection.Assembly.Load(Byte[])]
Setting breakpoint: bp 71395949 [System.Reflection.Assembly.Load(System.Reflection.AssemblyName, System.Security.Policy.Evidence)]
Setting breakpoint: bp 713F3479 [System.Reflection.Assembly.Load(System.Reflection.AssemblyName)]
Setting breakpoint: bp 71B28F3D [System.Reflection.Assembly.Load(System.String, System.Security.Policy.Evidence)]
Setting breakpoint: bp 713C880D [System.Reflection.Assembly.Load(System.String)]
Adding pending breakpoints...
(現時点では、拡張にバグがあり、コマンドを 2 回実行する必要があります)。
Assembly.Load() 関数が実行されると、デバッガはマルウェアの実行を停止します。
0:000> g
Breakpoint 3 hit
eax=00000000 ebx=006ff2dc ecx=026b30b8 edx=0000000a esi=026b30b8 edi=006ff250
eip=71b28f9c esp=006ff210 ebp=006ff218 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
mscorlib_ni+0xae8f9c:
71b28f9c e80368fdff call mscorlib_ni+0xabf7a4 (71aff7a4)
引数を取得する方法としては、前の使用例で述べたのとまったく同様に、CLRStack および DumpObj コマンドを使用することももちろん可能です。この例では、レジスタの内容のみを使用します。Assembly.Load() に渡される引数は、Stack (ESP) で入手できます。
0:000> dp esp 006ff210 00000000 026b30b8 006ff238 009504ae 006ff220 00000000 00000000 00000000 00000000 006ff230 00000000 00000000 006ff244 7240ea56 006ff240 00a149a8 006ff298 724293ef 006ff2dc 006ff250 006ff288 725b24b0 006ff3b0 724293a8 006ff260 ecebc740 006ff404 006ff370 006ff324 006ff270 7246e611 006ff2dc 00000000 ecebc740 006ff280 006ff250 006ff370 006ff424 725b0890
スタックの 2 番目の値は、バイト配列へのポインタです(0x026b30b8)。
0:000> dp 026b30b8 026b30b8 71504448 00005e00 00905a4d 00000003 026b30c8 00000004 0000ffff 000000b8 00000000 0:000> db 026b30b8+8 L16 026b30c0 4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00 MZ.............. 026b30d0 b8 00 00 00 00 00 ......
2 番目の引数、0x5e00 は、バイト配列のサイズです(赤字)。その後には、MZ で始まる PE ファイルのファイル ヘッダー、0x4d 0x5a が続きます(青字。ただし、データがリトル エンディアン形式で保存されているため、反転)。これで、WinDBG 内から直接、展開済みサンプルをダンプできます。
.writemem C:\\unpacked_sample.exe 026b30b8+8 L00005e00
.NET バージョン 2 および 3
.NET バージョン 2 と 3 でコンパイルされたマルウェアの動的分析プロセスは同じです。ただし、Assembly.Load() API に引数を渡す方法が違います。ここでは、引数はスタックを使用せず、ECX レジスタに保存されます。
0:000> dp ecx 024ba0b8 71504448 00005e00 00905a4d 00000003 024ba0c8 00000004 0000ffff 000000b8 00000000 0:000> db ecx+8 L16 024ba0c0 4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00 MZ.............. 024ba0d0 b8 00 00 00 00 00
形式は前の例とまったく同じで、配列のサイズは赤字、ロードされるバイナリは青字となっています。
自動展開
前述の分析をもとに、汎用的な展開ツールを作成できます。付録 2 に、.NET バージョン 2、3、4 用の、この WinDBG スクリプトを記載しています。
このスクリプトは、次の構文を使用して呼び出すことができます。
"c:\Program Files (x86)\Windows Kits\10\Debuggers\x86\cdb.exe" -c "$$>a< C:\unpack.script C:\unpacked_sample.exe" "c:\sample.exe"
Python スクリプト
.NET 分析を自動化する Python スクリプトを Cisco Talos の github リポジトリ からダウンロードできます。 WinDBG で Python を実行できるようにするには、スクリプトに pykd 拡張が必要です。スクリプトは、この記事で前述した SOS コマンドを使用します。その目的は、より良い出力を得ることです。スクリプトの先頭で、設定を記述しています。
dump_byte_array=1 dump_byte_array_path="c:\\path\\to\\directory\\" bp_list = [ ["system.dll", "System.Diagnostics.Process.Start"], ["system.dll", "System.Net.WebClient.DownloadFile"], ["mscorlib.dll", "System.Reflection.Assembly.Load"] ]
bp_list 変数にはブレークポイントのリストが含まれます。この例では、スクリプトは 3 つの .NET API(System.Diagnotics.Process.Start、System.Net.WebClient.Download.File、Sysyem.Reflection.Assembly.Load)でブレークポイントを挿入します。3 つの関数の引数は、WinDBG で表示されます。
dump_byte_array 変数が 1 に設定されると、スクリプトは自動的に、分析された関数(ブレークポイントが配置されている場所)の引数で提供されたバイト配列をダンプします。このダンプは dump_byte_array_path ディレクトリに配置されます。
このスクリプトではテキストまたは JSON での出力が可能です。この記事の例ではテキストで出力されていますが、JsonDebug 変数を「True」に設定すれば、JSON に変更できます。
例 1:
Assembly.Load 関数が呼び出された際のスクリプトの出力を以下に示します。
0:000> .loadby sos clr 0:000> .load pykd.dll 0:000> !py C:\Users\lucifer\NET_plugin.py [.NET plugin] Beginning, setting breakpoints... [.NET plugin] breakpoint: mscorlib.dll System.Reflection.Assembly.Load mscorlib_ni+0xb4fa65 [.NET plugin] breakpoint: mscorlib.dll System.Reflection.Assembly.Load mscorlib_ni+0xb4fa07 [.NET plugin] breakpoint: mscorlib.dll System.Reflection.Assembly.Load mscorlib_ni+0xb4f9cf [.NET plugin] breakpoint: mscorlib.dll System.Reflection.Assembly.Load mscorlib_ni+0xb4f96c [.NET plugin] breakpoint: mscorlib.dll System.Reflection.Assembly.Load mscorlib_ni+0x38a5a1 [.NET plugin] breakpoint: mscorlib.dll System.Reflection.Assembly.Load mscorlib_ni+0x3bda7d [.NET plugin] breakpoint: mscorlib.dll System.Reflection.Assembly.Load mscorlib_ni+0xb4f90d [.NET plugin] breakpoint: mscorlib.dll System.Reflection.Assembly.Load mscorlib_ni+0x3968dd [.NET plugin] Let's go... [.NET plugin] Breakpoint: System.Reflection.Assembly.Load(Byte[]) [.NET plugin] Argument 0: rawAssembly [.NET plugin] !DumpObj /d 0x02f67e04 Name: System.Byte[] MethodTable: 6b5f60f8 EEClass: 6b190878 Size: 5644(0x160c) bytes Array: Rank 1, Number of elements 5632, Type Byte (Print Array) Content: MZ......................@...............................................!..L.!This program cannot Fields: None [.NET plugin] let's dump 0x02f67e04+8 Size:5644 .writemem c:\users\lucifer\Desktop\dump_1496942775_0x02f67e04_5644.dmp 0x02f67e04+8 L5644
Assembly.Load の引数のバイト配列の内容は、自動的に c:\users\lucifer\Desktop\dump_1496942775_0x02f67e04_5644.dmp に保存されます。
例 2:
start-process を実行する PowerShell スクリプトのスクリプト出力を以下に示します。
[.NET plugin] Breakpoint: System.Diagnostics.Process.Start(System.Diagnostics.ProcessStartInfo)
[.NET plugin] Argument 0: startInfo
[.NET plugin] !DumpObj /d 0x000001ad173cdb68
Name: System.Diagnostics.ProcessStartInfo
MethodTable: 00007ffd7e3ee798
EEClass: 00007ffd7e0229f0
Size: 144(0x90) bytes
File:
C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll
Fields:
MT Field Offset Type VT Attr Value Name
07ffd69e969d0 40027fa 8 System.String 0 instance 01ad173d0f20 fileName
07ffd69e969d0 40027fb 10 System.String 0 instance 00000000000 arguments
07ffd69e969d0 40027fc 18 System.String 0 instance 1ad173d4bf8 directory
07ffd69e969d0 40027fd 20 System.String 0 instance 000000000000 verb
07ffd7e3c2a50 40027fe 78 System.Int32 1 instance 0 windowStyle
07ffd69ea1fb0 40027ff 7c System.Boolean 1 instance 0 errorDialog
07ffd69eafc48 4002800 70 System.IntPtr 1 instance 0 errorDialogPare
07ffd69ea1fb0 4002801 7d System.Boolean 1 instance 1 useShellExecut
07ffd69e969d0 4002802 28 System.String 0 instance 000000000000 userName
07ffd69e969d0 4002803 30 System.String 0 instance 000000000000 domain
07ffd69ea4068 4002804 38 ...rity.SecureString 0 instance 00000000 password
07ffd69e969d0 4002805 40 System.String 0 instance 0 passwordInClearText
07ffd69ea1fb0 4002806 7e System.Boolean 1 instance, 1 loadUserProfile
07ffd69ea1fb0 4002807 7f System.Boolean 1 instance 0 redirectStandar
07ffd69ea1fb0 4002808 80 System.Boolean 1 instance 0 redirectStandard
07ffd69ea1fb0 4002809 81 System.Boolean 1 instance 0 redirectStandard
07ffd69e9b048 400280a 48 System.Text.Encoding 0 instance 0 standardOutp
07ffd69e9b048 400280b 50 System.Text.Encoding 0 instance 0 standardErro
07ffd69ea1fb0 400280c 82 System.Boolean 1 instance 0 createNoWindow
07ffd69eadec8 400280d 58 System.WeakReference 0 instance 0000 weakParentPr
07ffd7e3ef4b8 400280e 60 ....StringDictionary 0 instance 0000 envVariables
07ffd697a69f0 400280f 68 ...tring, mscorlib]] 0 instance 0000 environment
[.NET plugin] !DumpObj /d 000001ad173d0f20
Name: System.String
MethodTable: 00007ffd69e969d0
EEClass: 00007ffd697950e0
Size: 82(0x52) bytes
File:
C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: C:\WINDOWS\system32\calc.exe
スクリプトは、引数と、興味深いフィールド(例では fileName 文字列)の内容を表示しています。
例 3:
Powershell で DownloadFile API が使用された際のスクリプトの出力を以下に示します。
[.NET plugin] Breakpoint: System.Net.WebClient.DownloadFile(System.Uri, System.String) [.NET plugin] Argument 1: address [.NET plugin] !DumpObj /d 0x000001ad17315e78 Name: System.Uri MethodTable: 00007ffd7e3f4cf0 EEClass: 00007ffd7dfc5fd0 Size: 72(0x48) bytes File: C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll Fields: MT Field Offset s Type VT Attr Value Name 07ffd69e969d0 400040b 8 System.String 0 instance 000001ad172c5ea8 m_String 07ffd69e969d0 400040c 10 System.String 0 instance 000000000 m_originalUnico 07ffd7e3f51d8 400040d 18 System.UriParser 0 instance 001ad17032b40 m_Syntax 07ffd69e969d0 400040e 20 System.String 0 instance 00000000000 m_DnsSafeHost 07ffd7e3c2788 400040f 30 System.UInt64 1 instance 37615763456 m_Flags 07ffd7e3f5590 4000410 28 System.Uri+UriInfo 0 instance 01ad17315f00 m_Info 07ffd69ea1fb0 4000411 38 System.Boolean 1 instance 0 m_iriParsing 07ffd69e969d0 40003fb 220 System.String 0 shared static UriSchemeFile 07ffd69e969d0 40003fc 228 System.String 0 shared static UriSchemeFtp 07ffd69e969d0 40003fd 230 System.String 0 shared static UriSchemeGoph 07ffd69e969d0 40003fe 238 System.String 0 shared static UriSchemeHttp 07ffd69e969d0 40003ff 240 System.String 0 shared static UriSchemeHttps 07ffd69e969d0 4000400 248 System.String 0 shared static UriSchemeWs 07ffd69e969d0 4000401 250 System.String 0 shared static UriSchemeWss 07ffd69e969d0 4000402 258 System.String 0 shared static UriSchemeMail 07ffd69e969d0 4000403 260 System.String 0 shared static UriSchemeNews 07ffd69e969d0 4000404 268 System.String 0 shared static UriSchemeNntp 07ffd69e969d0 4000405 270 System.String 0 shared static UriSchemeNet 07ffd69e969d0 4000406 278 System.String 0 shared static UriSchemeNetP 07ffd69e969d0 4000407 280 System.String 0 shared static SchemeDelimit 07ffd7e3b4bd0 4000412 288 ...etSecurityManager 0 static s_ManagerRef 07ffd69e96fb0 4000413 290 System.Object 0 shared static s_IntranetLock 07ffd69ea1fb0 4000414 9c4 System.Boolean 1 shared static s_ConfigInitia 07ffd69ea1fb0 4000415 9c5 System.Boolean 1 shared static s_ConfigInitia 07ffd7e3afef8 4000416 9c0 System.Int32 1 shared static s_IdnScope 07ffd69ea1fb0 4000417 9c6 System.Boolean 1 shared static s_IriParsing 07ffd69e96fb0 4000418 298 System.Object 0 shared static s_initLock 07ffd69e97b20 400041c 2a0 System.Char[] 0 shared static HexLowerChars 07ffd69e97b20 400041d 2a8 System.Char[] 0 shared static _WSchars [.NET plugin] !DumpObj /d 000001ad172c5ea8 Name: System.String MethodTable: 00007ffd69e969d0 EEClass: 00007ffd697950e0 Size: 94(0x5e) bytes File: C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll String: http://blog.talosintelligence.com/ Fields: MT Field Offset Type VT Attr Value Name 07ffd69e99310 400026f 8 System.Int32 1 instance 34 m_stringLength 07ffd69e97b88 400027 c System.Char 1 instance 68 m_firstChar 07ffd69e969d0 4000274 90 System.String 0 shared static Empty [.NET plugin] Argument 2: fileName [.NET plugin] !DumpObj /d 0x000001ad172c61c8 Name: System.String MethodTable: 00007ffd69e969d0 EEClass: 00007ffd697950e0 Size: 92(0x5c) bytes File: C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll String: c:\users\lucifer\desktop\demo.txt Fields: MT Field Offset Type VT Attr Value Name 07ffd69e99310 400026f 8 System.Int32 1 instance 33 m_stringLength 07ffd69e97b88 4000270 c System.Char 1 instance 63 m_firstChar 07ffd69e969d0 4000274 90 System.String 0 shared static Empty
最初の引数は System.URI オブジェクトです。オブジェクトは自動的に解析され、関連する内容が WinDBG に表示されます。この例では、最初のフィールドが表示されています(m_string 文字列)。この文字列には、アクセスした URL が含まれています。2 番目の引数は文字列であり、これも表示されています。
例 4:
JSON 形式のスクリプト出力を以下に示します(start-process 実行)。
0:020> .loadby sos clr 0:020> .load pykd 0:020> !py c:\Users\lucifer\DotNETPlugin.py { "date": 1500306926, "bp": "System.Diagnostics.Process.Start(System.Diagnostics.ProcessStartInfo)", "arguments": { "0": { "fields": { "0": { "Type": "System.String", "Name": "fileName", "string": "C:\\WINDOWS\\system32\\calc.exe" }, "1": { "Type": "System.String", "Name": "arguments", "string": "" }, "2": { "Type": "System.String", "Name": "directory", "string": "C:\\Users\\lucifer" }, "3": { "Type": "System.String", "Name": "verb", "string": "" }, [...redacted...] "20": { "Type": "....StringDictionary", "Name": "environmentVariables", "value": "0000000000000000" }, "21": { "Type": "...tring,", "Name": "environment", "value": "instance" } }, "name": "startInfo", "offset": "0x0000025c1c572170" } } }
まとめ
WinDBG は、Microsoft が提供する非常に強力なツールです。構文やインターフェイスになじみがないため、マルウェア分析ツールとしてあまり認識されていないかもしれません。適切な拡張機能があれば、マネージ コード(.NET)の分析に簡単に利用できるのです。
この記事が皆さんの好奇心を刺激して、今後、.NET などのマネージ コードの分析が必要となった場合には、WinDBG を検討していただけると幸いです。
付録
IOC
圧縮されたサンプル SHA256
- 21acd3457c1a589e117988fe0456e50ed627f051a97ccd11bfeeaf3c0cd79bfe
- 344ce133363f005346210611d5abd2513934a32739bc6e1bbd2257a298484051
- 45c695e610d78178ec5ca6f4e1993afacf4e435b566cd2caf65408fb6080300f
- 61653b2811fb7c672584d00417cbc1a56c8372331f1913104f9807a775f25773
- ac7bd77245bdf284d36ce1f9e2cb6a21d2dbd38aa1964dbaee4d06563f057ca6
- b607e87acdcb2ef0f102298decc57ca3ea20fabbf02375fd30eddddffbeec320
- e93c0aed6bbb4af734403e02d399c124f2d07f8e701fb716c2efe65942f83504
展開されたサンプル SHA256
- 35dee9106e4521e5adf295cc945355d72eb359d610230142e5dd4adda9678dee
- b5ce02ee3dfccf28e86f737a6dde85e9d30ff0549ec611d115a1d575b5291c2e
- d9a732dcf87764a87f17c95466f557fac33f041ac6f244dba006ba155d8e9aea
- fe068ce56b258762c10cc66525c309e79026c0e44103ca9b223c51382722cb09
WinDBG スクリプト
.NET 4 よりも前
sxe ld mscorjit g .loadby sos mscorwks !bpmd mscorlib.dll System.Reflection.Assembly.Load .echo "Weird bug... bp twice..." !bpmd mscorlib.dll System.Reflection.Assembly.Load g r $t1 = ecx .printf "Byte array: ";r $t1 r $t2 = poi($t1+4) .printf "Size: ";r $t2 db $t1+8 L$t2 .echo "dump in the file: ${$arg1}" .writemem ${$arg1} $t1+8 L$t2 .kill q
.NET 4
sxe ld clrjit g .load "C:\\Psscor4\\x86\\x86\\psscor4.dll" !bpmd mscorlib.dll System.Reflection.Assembly.Load .echo "Weird bug... bp twice..." !bpmd mscorlib.dll System.Reflection.Assembly.Load g r $t1 = poi(esp+4) .printf "Byte array: ";r $t1 r $t2 = poi($t1+4) .printf "Size: ";r $t2 db $t1+8 L$t2 .echo "dump in the file: ${$arg1}" .writemem ${$arg1} $t1+8 L$t2 .kill q
本稿は 2017年7月19日に Talos Group のブログに投稿された「Unravelling .NET with the Help of WinDBG」の抄訳です。