ZeroMemory ではなく、SecureZeroMemory を

もうタイトルの通りです。少し前の記事ですが、MSDN コラムに、こんな記事があります。

このコラムに、ZeroMemory がコンパイラの最適化によって無くなってしまうということが書かれています。
せっかくなので試してみました。
まず、ZeroMemory からおさらいです。ZeroMempry はマクロです。

#define ZeroMemory RtlZeroMemory
#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))

単に memset をやっているだけです。
コラムにオプティマイザが云々と記述されていますが、具体的には実行速度優先 O2、Ox です。
コラムを参考に、こんなコードをサンプルにしてみました。

BOOL CheckPassword(LPCSTR lppszPassword)
{
    TCHAR szPasswd[256];

    lstrcpy(szPasswd, lppszPassword);
    BOOL b = InternalCheckPassword(szPasswd);
    ZeroMemory(&szPasswd, sizeof(szPasswd));
    return b;
}

このコードですが、szPasswd という変数は、ZeroMemory の呼び出し後ではアクセスされていません。
このため、オプティマイザは使用しない変数だから、ZeroMemory は必要無いと判断してしまい、最適化処理によって
ZeroMemory を落としてしまうようです。O2 でコンパイルしたアセンブラを見てみます。

?CheckPassword@@YAHPB_W@Z PROC    ; CheckPassword, COMDAT

; 111  : {

sub esp, 516    ; 00000204H
mov eax, DWORD PTR ___security_cookie
xor eax, esp
mov DWORD PTR __$ArrayPad$[esp+516], eax

; 112  :     TCHAR szPasswd[256];
; 113  :
; 114  :     lstrcpy(szPasswd, lppszPassword);

push OFFSET ??_C@_1BC@OMIPJNBO@?$AAp?$AAa?$AAs?$AAs?$AAw?$AAo?$AAr?$AAd?$AA?$AA@
lea eax, DWORD PTR _szPasswd$[esp+520]
push eax
call DWORD PTR __imp__lstrcpyW@8

; 115  :     BOOL b = InternalCheckPassword(szPasswd);

push OFFSET ??_C@_1BC@OMIPJNBO@?$AAp?$AAa?$AAs?$AAs?$AAw?$AAo?$AAr?$AAd?$AA?$AA@
lea ecx, DWORD PTR _szPasswd$[esp+520]
push ecx
call DWORD PTR __imp__lstrcmpiW@8

; 116  :     ::ZeroMemory(&szPasswd, sizeof(szPasswd));
; 117  :     return b;
; 118  : }

mov ecx, DWORD PTR __$ArrayPad$[esp+516]
xor ecx, esp
call @__security_check_cookie@4
add esp, 516    ; 00000204H
ret 0
?CheckPassword@@YAHPB_W@Z ENDP    ; CheckPassword

確かに ZeroMemory(memset)が無くなりました。
では、どのように対応するのかコラムに従うと、

  1. memset 呼出し後にデータに "アクセス" します。
  2. memset を最適化されないコードに置き換える。
  3. このコードでは、最適化(O2、Ox)を無効にする。

になるとのこと。1 と 3 はいいですね。そして、2 の目的を達成するには、SecureZeroMemory を使うというわけです。
SecureZeroMemory を使ってみると、上記のアセンブラは

; 116  :     ::SecureZeroMemory(&szPasswd, sizeof(szPasswd));

mov edx, 512    ; 00000200H
lea ecx, DWORD PTR _szPasswd$[esp+516]
npad 4
$LL6@CheckPassw:
mov BYTE PTR [ecx], 0
add ecx, 1
sub edx, 1
jne SHORT $LL6@CheckPassw

となりました。

確実にメモリをゼロクリアするためには、SecureZeroMemory を使うよう心がけましょう。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。