こんにちは。NFLabs. ソリューション事業部のynです。 この記事は、NFLaboratories Advent Calendar 2022 3日目の記事です。
API Monitor
API Monitorとは、IATフッキングを用いてプロセスが呼ぶWindows APIやC ランタイムのAPIを、引数と共にキャプチャするソフトウェアです。 ところが、同じ種類のAPIでもキャプチャする場合としない場合があります。
例えば、Windows API setsをインポートしている場合、そのAPIはキャプチャされません。 本記事では、API MonitorでWindows API Setsをキャプチャする方法を記します。
Windows API Sets
次のコードを例に考えます。
#include <windows.h> #include <stdio.h> int main(void) { SYSTEMTIME st; GetSystemTime(&st); printf("%02d:%02d\n", st.wHour, st.wMinute); return 0; }
ビルドして出力したexeのPEを解析すると、Kernel32.dll
にGetSystemTime
があります。
>dumpbin /imports normal.exe Microsoft (R) COFF/PE Dumper Version 14.34.31935.0 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file normal.exe File Type: EXECUTABLE IMAGE Section contains the following imports: KERNEL32.dll 140002000 Import Address Table 1400028A0 Import Name Table 0 time date stamp 0 Index of first forwarder reference 2F6 GetSystemTime
OneCore_apiset.lib
をリンクしてビルドしてみます。
すると、api-ms-win-core-sysinfo-l1-1-0.dll
にGetSystemTime
があります。
>dumpbin /imports sets.exe Microsoft (R) COFF/PE Dumper Version 14.34.31935.0 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file sets.exe File Type: EXECUTABLE IMAGE Section contains the following imports: api-ms-win-core-sysinfo-l1-1-0.dll 1400020B0 Import Address Table 140002960 Import Name Table 0 time date stamp 0 Index of first forwarder reference 13 GetSystemTime
api-
やext-
から始まる名前をAPI setsと呼び1、実際には存在しないモジュールです。Windowsのライブラリローダが実行時に適切なモジュールへリダイレクトします。詳細な仕組みについてはUndocumentedなこともありここでは説明しません。apisetschema.dll
やApiSetMap
で検索してみてください。
Windows API SetsとAPI Monitor
OneCore_apiset.lib
をリンクしたファイルとkernel32.lib
をリンクしたファイルをそれぞれAPI Monitorで実行してみます。前者はGetSystemTime
が記録されていませんが、後者はされています。
つまり、同じAPIを呼んでいても、リンカにOneCore_apiset.lib
を入力するか否かでAPI Monitorに変化が現れていることが分かります。
IATフッキング
デバッガを使ってプロセスを確認すると、API Monitorから実行したか否かでプロセスのIATに変化があります。このことから、API MonitorはIATフッキングを行っていることが推測できます。
IATを取得するには、取得したいモジュール名をName
メンバとして持つIMAGE_IMPORT_DESCRIPTOR
構造体のFirstThunk
を、Import Directoryから取得します。
このことから、IATフッキングをするためにはモジュール名が必要なことが分かります。したがって、API MonitorがAPI Setsのモジュール名を認識できなかったものと予想します。
API MonitorでAPI Setsをキャプチャするには
定義します。
API Monitorは、APIフォルダにXMLとして型情報が定義されています。実はその中を見るとapi-set-schema.h.xml
などのファイルに一部のAPI Setsが定義されています。
ところが、api-ms-win-core-sysinfo-l1-1-0.dll
は定義されていないため、今回の例では記録できなかったと思われます。
API setsとモジュールの対応関係は、Windows互換レイヤーのWineにあるapisetschema.specを参照するのが一番手っ取り早いと思います。
今回のapi-ms-win-core-sysinfo-l1-1-0.dll
を例に定義方法を説明します。apisetschema.specより実態はkernelbase.dll
です。
API Monitorでは、API\Windows\KernelBase.xml
にkernelbase.dll
が定義されていますので、API\Windows\api-ms-win-core-sysinfo.xml
などの名前でコピーします。
次に、内容の<Module Name="KernelBase.dll">
を<Module Name="api-ms-win-core-sysinfo.dll">
に書き換えて保存します。
これで定義できました。API Monitorを起動してみます。起動時のLoading API Definitions
のFile Count
が1つ増加しているはずです。
再度、OneCore_apiset.lib
をリンクしたファイルをAPI Monitor上で実行してみましょう。GetSystemTime
が記録されているはずです。
最後に
API Setsを用いるとデフォルトのAPI Monitorではキャプチャできないことを紹介しました。もし、意図したAPIがAPI Monitorで表示されない場合は確認してみてください。