
Golang バイナリ向けのコマンドライン Windows API トレーシングツール。
Golang バイナリ向けのコマンドライン Windows API トレーシングツールです。
注意: このツールは PoC であり、進行中のプロトタイプですので、そのように扱ってください。フィードバックはいつでも歓迎します!
Golang プログラムは、そのビルド方法や実行時の動作に関して多くの特徴がありますが、OS レイヤーとやり取りする必要があるため、どこかの時点で Windows API の関数を呼び出す必要があります。
Go のランタイムパッケージには asmstdcall という関数が含まれています。この関数は Windows API とのやり取りを行うための一種の「ゲートウェイ」です。この関数が Windows API の関数を呼び出すと想定されているため、関数のアドレスやそのパラメータなどの情報にアクセスできる必要があります。ここからがさらに興味深くなります。
Asmstdcall は、次の構造体に類似したものへのポインタを単一のパラメータとして受け取ります。
struct LIBCALL {
DWORD_PTR Addr;
DWORD Argc;
DWORD_PTR Argv;
DWORD_PTR ReturnValue;
[...]
}
これらのフィールドの一部(戻り値など)は API 関数が呼び出された後に設定され、他のもの(関数アドレス、引数の数、引数のリスト)は asmstdcall によって受け取られます。いずれにせよ、これらが設定されるとき、asmstdcall 関数が Golang でコンパイルされたプログラムの実行に関する多くの興味深い情報を操作していることは明らかです。
gftrace は、asmstdcall とその動作を利用して、前述の構造体の特定のフィールドを監視し、ユーザーにログ出力します。このツールは、関数名、そのパラメータ、および Golang アプリケーションによって呼び出された各 Windows 関数の戻り値をログ出力することができます。これらすべてを、単一の API 関数をフックしたり、そのシグネチャを用意したりする必要なく実現します。
また、このツールは Go ランタイムの初期化によるノイズを無視し、その後(つまり main パッケージからの関数)に呼び出された関数のみをログ出力しようとします。
このプロジェクトと調査について詳しく知りたい場合は、ブログ記事 をご覧ください。
最新の リリース をダウンロードしてください。
gftrace.exe <filepath> <params>
gftrace.cfg ファイルでトレースしたい関数をカンマ区切りでスペースなしで指定するだけです:
CreateFileW,ReadFile,CreateProcessW
Golang のパッケージ Y のメソッド X が特定のシナリオで呼び出す正確な Windows API 関数は、メソッド自体の分析か、推測によってのみ決定できます。それを決定するために使用できる興味深い特性がいくつかあります。たとえば、Golang アプリケーションは "Wide" および "Ex" セットの関数(例:CreateFileW、CreateProcessW、GetComputerNameExW など)を常に好んで呼び出す傾向があるため、分析時にそれを考慮することができます。
デフォルトの設定ファイルには、私がすでにテストした(少なくともそのほとんど)複数の関数が含まれており、Golang アプリケーションがいつか呼び出す可能性があると確信できます。最終的にはこれを更新しようと思います。
"os.ReadFile" を 2 回呼び出すシンプルな Golang ファイルで CreateFileW() と ReadFile() をトレース:
- CreateFileW("C:\Users\user\Desktop\doc.txt", 0x80000000, 0x3, 0x0, 0x3, 0x1, 0x0) = 0x168 (360)
- ReadFile(0x168, 0xc000108000, 0x200, 0xc000075d64, 0x0) = 0x1 (1)
- CreateFileW("C:\Users\user\Desktop\doc2.txt", 0x80000000, 0x3, 0x0, 0x3, 0x1, 0x0) = 0x168 (360)
- ReadFile(0x168, 0xc000108200, 0x200, 0xc000075d64, 0x0) = 0x1 (1)
TunnelFish マルウェアで CreateProcessW() をトレース:
- CreateProcessW("C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe", "powershell /c "Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn; Get-Recipient | Select Name -ExpandProperty EmailAddresses -first 1 | Select SmtpAddress | ft -hidetableheaders"", 0x0, 0x0, 0x1, 0x80400, "=C:=C:\Users\user\Desktop", 0x0, 0xc0000ace98, 0xc0000acd68) = 0x1 (1)
- CreateProcessW("C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe", "powershell /c "Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn; Get-Recipient | Select Name -ExpandProperty EmailAddresses -first 1 | Select SmtpAddress | ft -hidetableheaders"", 0x0, 0x0, 0x1, 0x80400, "=C:=C:\Users\user\Desktop", 0x0, 0xc0000c4ec8, 0xc0000c4d98) = 0x1 (1)
- CreateProcessW("C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe", "powershell /c "Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn; Get-Recipient | Select Name -ExpandProperty EmailAddresses -first 1 | Select SmtpAddress | ft -hidetableheaders"", 0x0, 0x0, 0x1, 0x80400, "=C:=C:\Users\user\Desktop", 0x0, 0xc00005eec8, 0xc00005ed98) = 0x1 (1)
- CreateProcessW("C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe", "powershell /c "Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn; Get-Recipient | Select Name -ExpandProperty EmailAddresses -first 1 | Select SmtpAddress | ft -hidetableheaders"", 0x0, 0x0, 0x1, 0x80400, "=C:=C:\Users\user\Desktop", 0x0, 0xc0000bce98, 0xc0000bcd68) = 0x1 (1)
- CreateProcessW("C:\WINDOWS\system32\cmd.exe", "cmd /c "wmic computersystem get domain"", 0x0, 0x0, 0x1, 0x80400, "=C:=C:\Users\user\Desktop", 0x0, 0xc0000c4ef0, 0xc0000c4dc0) = 0x1 (1)
- CreateProcessW("C:\WINDOWS\system32\cmd.exe", "cmd /c "wmic computersystem get domain"", 0x0, 0x0, 0x1, 0x80400, "=C:=C:\Users\user\Desktop", 0x0, 0xc0000acec0, 0xc0000acd90) = 0x1 (1)
- CreateProcessW("C:\WINDOWS\system32\cmd.exe", "cmd /c "wmic computersystem get domain"", 0x0, 0x0, 0x1, 0x80400, "=C:=C:\Users\user\Desktop", 0x0, 0xc0000bcec0, 0xc0000bcd90) = 0x1 (1)
[...]
Sunshuttle マルウェアで複数の関数をトレース:
- CreateFileW("config.dat.tmp", 0x80000000, 0x3, 0x0, 0x3, 0x1, 0x0) = 0xffffffffffffffff (-1)
- CreateFileW("config.dat.tmp", 0xc0000000, 0x3, 0x0, 0x2, 0x80, 0x0) = 0x198 (408)
- CreateFileW("config.dat.tmp", 0xc0000000, 0x3, 0x0, 0x3, 0x80, 0x0) = 0x1a4 (420)
- WriteFile(0x1a4, 0xc000112780, 0xeb, 0xc0000c79d4, 0x0) = 0x1 (1)
- GetAddrInfoW("reyweb.com", 0x0, 0xc000031f18, 0xc000031e88) = 0x0 (0)
- WSASocketW(0x2, 0x1, 0x0, 0x0, 0x0, 0x81) = 0x1f0 (496)
- WSASend(0x1f0, 0xc00004f038, 0x1, 0xc00004f020, 0x0, 0xc00004eff0, 0x0) = 0x0 (0)
- WSARecv(0x1f0, 0xc00004ef60, 0x1, 0xc00004ef48, 0xc00004efd0, 0xc00004ef18, 0x0) = 0xffffffff (-1)
- GetAddrInfoW("reyweb.com", 0x0, 0xc000031f18, 0xc000031e88) = 0x0 (0)
- WSASocketW(0x2, 0x1, 0x0, 0x0, 0x0, 0x81) = 0x200 (512)
- WSASend(0x200, 0xc00004f2b8, 0x1, 0xc00004f2a0, 0x0, 0xc00004f270, 0x0) = 0x0 (0)
- WSARecv(0x200, 0xc00004f1e0, 0x1, 0xc00004f1c8, 0xc00004f250, 0xc00004f198, 0x0) = 0xffffffff (-1)
[...]
DeimosC2 フレームワークエージェントで複数の関数をトレース:
- WSASocketW(0x2, 0x1, 0x0, 0x0, 0x0, 0x81) = 0x130 (304)
- setsockopt(0x130, 0xffff, 0x20, 0xc0000b7838, 0x4) = 0xffffffff (-1)
- socket(0x2, 0x1, 0x6) = 0x138 (312)
- WSAIoctl(0x138, 0xc8000006, 0xaf0870, 0x10, 0xb38730, 0x8, 0xc0000b746c, 0x0, 0x0) = 0x0 (0)
- GetModuleFileNameW(0x0, "C:\Users\user\Desktop\samples\deimos.exe", 0x400) = 0x2f (47)
- GetUserProfileDirectoryW(0x140, "C:\Users\user", 0xc0000b7a08) = 0x1 (1)
- LookupAccountSidw(0x0, 0xc00000e250, "user", 0xc0000b796c, "DESKTOP-TEST", 0xc0000b7970, 0xc0000b79f0) = 0x1 (1)
- NetUserGetInfo("DESKTOP-TEST", "user", 0xa, 0xc0000b7930) = 0x0 (0)
- GetComputerNameExW(0x5, "DESKTOP-TEST", 0xc0000b7b78) = 0x1 (1)
- GetAdaptersAddresses(0x0, 0x10, 0x0, 0xc000120000, 0xc0000b79d0) = 0x0 (0)
- CreateToolhelp32Snapshot(0x2, 0x0) = 0x1b8 (440)
- GetCurrentProcessId() = 0x2584 (9604)
- GetCurrentDirectoryW(0x12c, "C:\Users\user\AppData\Local\Programs\retoolkit\bin") = 0x39 (57)
[...]
gftrace は GPL v3 ライセンスの下で公開されています。詳細については、LICENSE という名前のファイルを参照してください。