サポート情報 | フォーカスシステムズ サイバーフォレンジックセンター

メールでのお問い合わせ
お問い合わせはこちら
東京証券取引所 プライバシーマーク ISMS JUSE

サポート情報

ホーム > サポート情報一覧 > 仮想メモリ内のWindows API使用フロー

仮想メモリ内のWindows API使用フロー

目次へ

 それでは、実際にAPIの実行状況を大雑把にトレースしてみましょう。[00A06]の処理終了時にブレークポイントを設定し、GetProcAddressが求めているAPIをチェックしていきます。また、APIをコールするときのスタックの値を確認することで、パラメータも確認できます。確認結果を【表1】にまとめてみました。

(※冗長になるパラメータは一部省いてあります。)

 【表1】メモリ上のプログラムのAPIの呼び出し状況

アドレス

Windows API

処理内容・パラメータ等

[0025B]

OpenSMManagerA

サービスマネージャ情報を取得。

 マシン名 = null (ローカルコンピュータ)

 データベース名 = null (SERVICE_ACTIVE_DATABASE)

 希望するアクセス = 0x00000004 (SC_MANAGER_SERVICE)

[0037A]

EnumServicesStatusExA

指定されたサービスマネージャデータベースのサービス情報の列挙。

 SCMデータベースのハンドル = 直前に取得したもの

 サービスのタイプ = 0x00000030 (SERVICE_WIN32)

 サービスの状態 = 0x00000003 (SERVICE_STATE_ALL)

 ステータスバッファ = 0x00000000

 ステータスバッファのサイズ = 0x00000000

[00430]

GlobalAlloc

指定されたバイト数をヒープから割り当て。

 割り当ての属性 = 0x00000040

 割り当てたいバイト数 = 0x00004E20

[00548]

EnumServicesStatusExA

指定されたサービスマネージャデータベースのサービス情報の列挙。

 SCMデータベースのハンドル = 直前に取得したもの

 サービスのタイプ = 0x00000030 (SERVICE_WIN32)

 サービスの状態 = 0x00000003 (SERVICE_STATE_ALL)

 ステータスバッファ = (バッファのポインタ)

 ステータスバッファのサイズ = 0x00004E20

[005F0]

GlobalFree

ヒープ領域を解放。

 グローバルメモリオブジェクトのハンドル = (バッファのポインタ)

[007E7]

EnumWindows

トップレベルウィンドウの列挙

 コールバック関数 = [00789]

 アプリケーション定義の値 = 0x0012EC98 (スタック上のアドレス)

[01732]

LoadLibraryA

指定された実行可能モジュールをロード。

 モジュールのファイル名 = ADVAPI32.DLL

[01745]

RegOpneKeyExA

レジストリキーのオープン。

 ハンドル = 0x80000002 (HKEY_LOCAL_MACHINE)

 サブキー = SOFTWARE\ESET

 セキュリティアクセスマスク = 0x00020019 (KEY_READ)

[01513]

LoadLibraryA

指定された実行可能モジュールをロード。

 モジュールのファイル名 = ADVAPI32.DLL

[0152C]

RegOpneKeyExA

レジストリキーのオープン。

 ハンドル = 0x80000002 (HKEY_LOCAL_MACHINE)

 サブキー = SOFTWARE\AVAST Software

 セキュリティアクセスマスク = 0x00020019 (KEY_READ)

[01F3B]

GetTickCount

システム起動後の時間をミリ秒で取得。

[01FE7]

Sleep

スリープ。

 中断の時間 = 0x00003E80 (16000) ミリ秒

[02087]

GetTickCount

システム起動後の時間をミリ秒で取得。

[021D8]

VirtualProtect

アクセス保護の変更

 コミット済みページ領域アドレス = 0x00400000 (exe本体)

 領域のサイズ = 0x0034DD68 (3,464,552) bytes

 希望アクセス保護 = 0x00000040 (PAGE_EXECUTE_READWRITE)

 従来のアクセス保護を取得するアドレス = 0x0012ECE8 (スタック上のアドレス)

[024D8]

VirtualAlloc

メモリ領域の取得

 予約またはコミットしたい領域 = null (システム依存)

 領域のサイズ = 0x0002E400 (189,440) bytes

 割り当てのタイプ = 0x00001000 (MEM_COMMIT)

 アクセス保護のタイプ = 0x00000004 (PAGE_READWRITE)

[025BD]

RtlDecompressBuffer

圧縮バッファの解凍

 フォーマット = 0x00000002 (COMPRESSION_FORMAT_LZNT1)

 アンコンプレスバッファ = 直前のVirtualAllocで得られたアドレス

 アンコンプレスバッファサイズ = 0x0002E400 (189,440) bytes

 コンプレスバッファ = 0x007216C0 (exeの領域内)

 コンプレスバッファサイズ = 0x00024696 (149,142) bytes

 最終アンコンプレスサイズ = 0x0012FD78 (スタック上のアドレス)

[01042]

VirtualProtect

アクセス保護の変更

 コミット済みページ領域アドレス = 0x00400000 (exe本体)

 領域のサイズ = 0x0034DD68 (3,464,552) bytes

 希望アクセス保護 = 0x00000004 (PAGE_READWRITE)

 従来のアクセス保護を取得するアドレス = 0x0012EC7C (スタック上のアドレス)

[02775]

RtlZeroMemory

メモリの0埋め

 ディスティネーション = RtlDecompressBufferの展開先

 領域のサイズ= 0x0002E400 (189,440) bytes

[0282D]

VirtualFree

メモリの解放

 解放される領域 = [024D8]で確保した領域

[01228]

VirtualProtect

アクセス保護の変更

 コミット済みページ領域アドレス = 0x00400000 (exe本体)

 領域のサイズ = 0x00000400 (1,024) bytes

 希望アクセス保護 = 0x00000002 (PAGE_READONLY)

 従来のアクセス保護を取得するアドレス = 0x0012ECA0 (スタック上のアドレス)

[0134C]

VirtualProtect

アクセス保護の変更

 コミット済みページ領域アドレス = 0x00401000 (exe本体)

 領域のサイズ = 0x00012D21 (77,089) bytes

 希望アクセス保護 = 0x00000020 (PAGE_EXECUTE_READ)

 従来のアクセス保護を取得するアドレス = 0x0012EC9C (スタック上のアドレス)

[0134C]

VirtualProtect

アクセス保護の変更

 コミット済みページ領域アドレス = 0x00414000 (exe本体)

 領域のサイズ = 0x0000009A (154) bytes

 希望アクセス保護 = 0x00000002 (PAGE_READONLY)

 従来のアクセス保護を取得するアドレス = 0x0012EC9C (スタック上のアドレス)

[0134C]

VirtualProtect

アクセス保護の変更

 コミット済みページ領域アドレス = 0x00415000 (exe本体)

 領域のサイズ = 0x0001B3D8 (111,576) bytes

 希望アクセス保護 = 0x00000004 (PAGE_READWRITE)

 従来のアクセス保護を取得するアドレス = 0x0012EC9C (スタック上のアドレス)

[0134C]

VirtualProtect

アクセス保護の変更

 コミット済みページ領域アドレス = 0x00431000 (exe本体)

 領域のサイズ = 0x00003DC (988) bytes

 希望アクセス保護 = 0x00000002 (PAGE_READONLY)

 従来のアクセス保護を取得するアドレス = 0x0012EC9C (スタック上のアドレス)

以下、API呼び出し時の返り先のアドレスを次のWindows APIのアドレスにすることにより、連続的にAPIを呼び出している。また、スタックには、連続で処理を呼び出しても動くように引数が設定されている。

[02B52]

RtlZeroMemory

メモリの0埋め

 ディスティネーション = 仮想メモリで動作している自身の領域

            (「仮想メモリ取得した方法の正体」で取得した領域)

 領域のサイズ= 0x00002B59 (11,097) bytes

 

VirtualFree

メモリの解放

 解放される領域 =仮想メモリで動作している自身の領域

         (「仮想メモリ取得した方法の正体」で取得した領域)

 

CreateThread

呼び出し側プロセスの仮想アドレス空間で実行するべき1個のスレッドを生成

 セキュリティ記述子 = 0x00000000 (既定のセキュリティ識別子)

 初期のスタックサイズ = 0x00000000 (既定サイズ)

 スレッドの機能 = 0x00413C10 (プログラム本体内のアドレス)

 スレッドの引数 = 0x00000000 (引数はNULL)

 作成オプション = 0x00000000 (作成と同時に実行)

 スレッド識別子 = 0x00000000 (スレッド識別子は格納しない)

 

RtlExitUserThread

自身のスレッドを終了

 

 この処理で、Windows APIの呼び出しで今までとは別の手法があったので、併せて解説しておきます。

 通常、APIを含め、callによる呼び出しの後は、必ずretnでスタックに設定されているアドレスへ戻る挙動をします。返していえば、そのスタックのアドレスに任意のアドレスをあらかじめ設定しておくことができれば、callの戻り先を任意に操作することができる、ともいえます。

 その手法を用いて、APIを呼び出した後、その戻り先のアドレスを次のAPIのアドレスにすることで、連続的にAPIを呼び出すこともできます。当然、その場合は適切にAPIの引数をスタックに格納しておくことが必要となります。今回のランサムウェアでは、そのような技法が見られました(【図47】参照)。

CryptoWall_IDA_Step019

【図47】リターンアドレスを細工したAPIの連続呼び出し

 

 RtlZeroMemoryのAPI開始時のスタックの先頭位置にはリターンアドレスが入っていますが、そのリターン先が0x77496B15となっています。これは、VirtualFreeのAPIのアドレスです。つまり、RtlZeroMemoryが終了し、リターンする先は、VirtualFreeの開始位置なのです。

 RtlZeroMemoryのリターン先のアドレスの後には、RtlZeroMemoryの引数が続きます。そして、その後ろはVirtualFree終了時のリターンアドレスになりますが、今度はそこにCreateThreadのアドレスが格納されているのです。さらにその先は、RtlExitUserThreadが呼ばれるよう、同様にパラメータが続きます。これは、メモリに展開し、動いていたプログラムをクリアし、領域を開放するため、通常の処理のようにリターンして次のコードを実行させることができないことから編み出された方法と思われます。

 

 【表1】の処理の流れと内容を見渡して見ましょう。

 サービスマネージャから情報を引き出しているほか、レジストリを参照してセキュリティ製品の情報を参照している形跡があります。そして、その後に特に注目すべき挙動があります。VirtualAllocを行い、そこにRtlDecompressBufferで情報を展開しているのです。その後に、VirtualProtectで実行プログラム上のアクセス保護を変更して書き込めるようにしており、その後に展開した領域をクリアした上で解放しています。展開されたデータの内容と、その行先が気になりますが、行先の候補としてはアクセス保護を変更されたプログラム本体である可能性が考えられます。その後も、アクセス保護をこまめに変更しています。最後に、現在動作している自身のプログラムの領域をゼロクリアした上で開放し、新たなスレッドを起動して、自身のスレッドを終了しています。

 この流れから、大きな2つの着眼点があると思います。一つは、VirtualAllocで確保された領域に展開された情報がどのようなもので、その情報を何に使用しているか、という点です。もう一つは、自身のスレッドを終了する前に起動しているスレッドは、どのような処理を行うのか、という点です。

 このように、Windows APIの呼び出しをトレースするだけでも、ある程度マルウェアの動きを推定できます。また、精査するポイントを探すのに役立ちます。このことから、何かあったときに調査できる仕組みとして、日ごろからある程度のイベントを取得して、振る舞いを記録し、チェックできるようになっていれば、有用だと考えられます。Counter TackのSentinelなどは、組織内のPCの挙動イベントを記録し、サーバで保存、解析を行っており、有事の際の調査では初動の調査で威力を発揮するのではないかと思います。

 では、先に述べた2つの着眼点について、できるだけ追いかけてみたいと思います。まず、この展開された領域にはどのような情報が格納されているのでしょうか。展開結果を探ってみたいと思います。

 

< 仮想メモリ内のWindows APIの使用目 次 新たな仮想メモリに展開された情報の内容 >