NFLabs. エンジニアブログ

セキュリティやソフトウェア開発に関する情報を発信する技術者向けのブログです。

API MonitorでWindows API Setsをキャプチャする

こんにちは。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.dllGetSystemTimeがあります。

>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.dllGetSystemTimeがあります。

>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.dllApiSetMapで検索してみてください。

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.xmlkernelbase.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 DefinitionsFile Countが1つ増加しているはずです。

再度、OneCore_apiset.libをリンクしたファイルをAPI Monitor上で実行してみましょう。GetSystemTimeが記録されているはずです。

最後に

API Setsを用いるとデフォルトのAPI Monitorではキャプチャできないことを紹介しました。もし、意図したAPIがAPI Monitorで表示されない場合は確認してみてください。