Windows 10 April 2018 Updateをデバッグしてみた
2018/05/10追記
Windows 10 April 2018 Update (RS4)でマウスカーソルが画面端に飛ぶ不具合が修正されたかと思われましたが、完全には修正されていませんでした。私が使っているソフトだと、Dependency WalkerとKanjiTranslatorで不具合が発生します。comctl32.dllはバージョンが複数あり、6.10の方は修正されていましたが、5.82の方は修正されていないようです。この記事は公開当初5.82の検証しかしていませんでしたが、6.10の検証結果も踏まえて記事を修正しました。
昨年のWindows 10 Fall Creators Update (RS3)ではマウスカーソルが画面端に飛んでいく不具合がありました。
https://silight.hatenablog.jp/entry/win10fixPatch
今回のWindows 10 April 2018 Update (RS4)で、その不具合が発生しなくなったのですが、本当に修正されたのか念のためcomctl32.dllをOllyDbgで逆アセンブルして確認してみました。
まずはRS3の不具合の箇所から見てみます。(32bit版で検証しています。)
RS3 comctl32.dll 5.82
RS3 comctl32.dll 6.10
重要なのはPeekMessageW
のところです。
PeekMessageW
はPeekMessage
のUnicode版で、ウィンドウメッセージを取得する関数です。この関数が成功すると引数のpMsg
にMSG
構造体が書き込まれます。その後、PeekMessage
の戻り値がEAX
に格納されます。
次にTEST EAX, EAX
でEAX
同士のAND演算(EAX & EAX
)を計算しています。この結果が0になるのはEAX
が0の時だけです。
その直後にJNZ
で先ほどのAND演算の結果が0でなかったときにジャンプしています(JNZ = Jump if Not Zero)。結果的にPeekMessage
の戻り値が0の時だけジャンプせずに次の命令に行きます。
その後、PtInRect
などが実行された後にSetCursorPos
が呼ばれます。
SetCursorPos
はマウスカーソルを引数で指定した座標に移動させる関数です。SetCursorPos
の引数に渡されているのは先ほどのPeekMessage
で取得したMSG
構造体のpt.x
とpt.y
になります。
MSG構造体
https://msdn.microsoft.com/ja-jp/library/windows/apps/xaml/900ks98t(v=vs.120).aspx
これらの処理をC言語のコードにするとこうなります。
MSG msg;
if (!PeekMessageW(&msg, ...))
{
// PtInRectなど
...
SetCursorPos(msg.pt.x, msg.pt.y);
}
さて、ここでPeekMessage
のリファレンスを読むとこう書いてあります。
メッセージを取得した場合、0 以外の値が返ります。
メッセージを取得しなかった場合、0 が返ります。PeekMessage
https://msdn.microsoft.com/ja-jp/library/cc410948.aspx
ということは、PeekMessage
でメッセージを取得できなかった場合に未初期化のMSG
構造体を参照し、SetCursorPos
に未初期化の座標を引数として渡して実行します。逆にPeekMessage
でメッセージを取得できた場合は何もしません。
マウスカーソルを未初期化の座標に移動していたために画面端に飛んでいったわけです。
さて、RS3にバグがあることが確認できたところで、RS4の方も見てみましょう。
RS4 comctl32.dll 5.82
RS4 comctl32.dll 6.10
5.82の方はアドレスが変わっているだけでロジックは変わっていません。6.10の方はGetCursorPos
が追加されたことで未初期化のpt.x
とpt.y
を参照することはなくなりました。
よって、Windows 10 April 2018 Update (RS4)でcomctl32.dllの不具合が6.10だけ修正され、5.82は放置されました。
6.10が修正されたにもかかわらず5.82が修正されなかったのは不自然ですね。もしかしたらMicrosoftが意図的にサポート対象外としているのかもしれません。