小さい頃はエラ呼吸

いつのまにやら肺で呼吸をしています。


Windows 10 SDK(gflags.exe)でヒープメモリ関連のバグを検出する

はじめに

C言語のプログラムで、獲得したヒープメモリ領域をオーバして書き込んだりすると、検出するのが難しいバグにつながります。
Windows 10 SDKに内包されるgflags.exeを使うと、こうしたヒープメモリ関連のバグを検出することができます。

デバッグの理論と実践 ―なぜプログラムはうまく動かないのか
Andreas Zeller
オライリージャパン
売り上げランキング: 136,231

環境
  • Windows10(1809)
  • Windows 10 SDK バージョン 1809 (10.0.17763.0)
gflagsの入手

gflagsは、Windows 10 用 Windows ソフトウェア開発キット (Windows SDK) に含まれています。
以下のページからダウンロードして、インストールします。
Windows SDK アーカイブ - Windows アプリ開発
ダウンロードしたインストーラを起動し、ウィザードに従いインストールしていきます。
f:id:replication:20190929220050p:plain
f:id:replication:20190929215739p:plain
f:id:replication:20190929215750p:plain
f:id:replication:20190929215814p:plain
f:id:replication:20190929215830p:plain

サンプルアプリケーションの作成(sampleApp01.exe)

ヒープメモリの扱いに問題のあるアプリケーションを作成してみます。
サンプルアプリケーションでは、8byteのヒープメモリを確保し、そこに16byteのデータを書き込み、バッファオーバを発生させます。

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <conio.h>

int _tmain(int argc, _TCHAR* argv[])
{
	printf("%s start\n", __FUNCTION__);
	char *p;
	p = (char*)malloc(8);	// 8byte
	ZeroMemory(p, 16);	//->this is buffer over!!

	free(p);
	printf("%s end\n", __FUNCTION__);
	_getch();
	return 0;
}
gflagsの有効/無効

コマンドプロンプトを管理者モードで起動します。
gflagsのインストールフォルダへ移動します。

cd C:\Program Files (x86)\Windows Kits\10\Debuggers\x86

gflagsで監視したいアプリケーションを指定して、gflagsを有効にします。

gflags.exe /p /enable sampleApp01.exe /full

Warning: pageheap.exe is running inside WOW64.
This scenario can be used to test x86 binaries (running inside WOW64)
but not native (IA64) binaries.

path: SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
    sampleapp01.exe: page heap enabled

以下のコマンドで現在gflagsが有効になっているアプリケーションを調べることができます。

gflags.exe /p
>  sampleapp01.exe: page heap enabled with flags (full traces )

検証が終わったら、以下のコマンドでgflagsを無効にします。

gflags.exe /p /disable sampleApp01.exe

ヒープメモリ関連のバグがあるプログラムは、リリース版で動かしてみると正常に動くときもあれば、異常終了することもあります。
gflagsの監視対象にすると、確実にアプリケーションをクラッシュさせることができます。

アプリケーションのクラッシュ原因を探る

アプリケーションのクラッシュ原因を突き止めるには、クラッシュダンプを採取します。コマンドプロンプトから以下のコマンドを実行すると、アプリケーションの異常終了時に、クラッシュダンプを出力するようになります。

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpFolder /t REG_EXPAND_SZ /d ^%LOCALAPPDATA^%\CrashDumps /f
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpCount /t REG_DWORD /d 10 /f
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpType /t REG_DWORD /d 2 /f

クラッシュダンプは以下のフォルダに出力されます。

  • C:\Users\Administrator\AppData\Local\CrashDumps

クラッシュダンプが採取できたら、WinDbg(x86)で解析を行います。
スタートメニューからWindows Kits→WinDbg(x86)を起動します。
WinDbgにさきほど採取したクラッシュダンプをドラッグ&ドロップします。
Access violation - code c0000005 (first/second chance not available)でアクセスバイオレーションが発生していることが分かります。
f:id:replication:20190929233421p:plain

続いて、メニューからFile→Symbol File Pathを選択します。
シンボルパスに、以下を指定するとMicrosoftがWebに公開しているシンボルファイルをダウンロードすることができます。

SRV*c:\symbols*http://msdl.microsoft.com/download/symbols

f:id:replication:20190929225401p:plain
シンボルの読み込みが完了したら、画面下部のテキストエリアに以下のコマンドを入力してEnterキー押すと、ダンプファイルの解析がはじまります。

!analyze -v

解析結果からZeroMemory(p, 16);の部分がクラッシュの原因ということが分かります。ダンプファイルから、ソースコードの行まで特定できるのがすごいですね。
f:id:replication:20190929231744p:plain

おわりに

以上がgflags.exeを使ったヒープ破壊の解析方法です。
!analyze -vの結果、思うような解析が得られない場合は、サンプルアプリケーションのビルド時に生成された.pdbファイルをシンボルとして読み込ませると多くの情報が得られます。