初めまして
日本マイクロソフト、デベロッパーサポート統括部インターネットチームの坂井と申します。
私はチーム内でもエスカレーションエンジニアという偉そうな立場でして、IE 自体の内部のデバッグとか開発との修正のやり取りとかそんな役割を担っています。
そんなわけで、いろんな機能とかよくあるネタは他の人にお任せして、私は何というのかちょっと特殊な調査だったり内部情報をかける範囲で書いてみたいなーと思っています。
ただし、内部の機密情報との関係もあり、すぐにネタが尽きるかもしれません。基本的に公開されているデバッグシンボルで行える範囲での内容になります。
今回は初めてなので、軽めに。「IE からリクエストが出て行っているのか」を Windows Debugger で調べる場合の方法です。
デバッガの使い方とかシンボルって何?はこちらから
32 ビット版 Debugging Tools for Windows
<http://msdn.microsoft.com/ja-jp/windows/hardware/gg463016>
64 ビット版 Debugging Tools for Windows
<http://msdn.microsoft.com/ja-jp/windows/hardware/gg463012>
やってみよう
さてデバッガを入れたら windbg.exe を起動しましょう。次に適当に IE を起動して iexplore.exe にアタッチします。windbg で [File] メニューの [Attach to Process] を選びます。
LCIE 有効な環境だと iexplore.exe が複数いますが、SCODEF:xxx といった引数がついているのがタブプロセスで通信を行うのもこのプロセスなので、これにアタッチします。
アタッチしたら、コマンド欄に以下を入力します。
.sympathSRV*c:\websymbols*http://msdl.microsoft.com/download/symbols
そしてさらに以下を打ち込み g で実行します。
bp wininet!HttpOpenRequestW
そして、IE の画面に戻りどこか適当なページに遷移します。以下は bing.com に移動しています。
そうするとデバッガでブレークします。
HttpOpenRequest はリクエストの起点になる関数で、この引数で HTTP Method や URL を確認できます。
まず kv コマンドで呼び出し履歴を見てみましょう。
0:003> kv2
ChildEBP RetAddr Args to Child
02cfb62c 7549da38 00cc0008 754be2bc 0c8d1e78 WININET!HttpOpenRequestW (FPO: [Non-Fpo])
02cfbe9c 7549d80f 06617970 06617c04 06617970 urlmon!CINetHttp::INetAsyncOpenRequest+0x26d (FPO: [Non-Fpo])
HttpOpenRequest のヘルプを見ると、第一引数がインターネットハンドル、第二引数がメソッドの文字列、第三引数が URL なので、du コマンドでメソッドと URL を見てみます。
0:003> du 754be2bc
754be2bc "GET"
0:003> du 0c8d1e78
0c8d1e78 "/?setmkt=ja-JP&setlang=match&uid"
0c8d1eb8 "=A2503EA1&FORM=NFTOJP"
ということで、サクサクっとメソッドと URL が確認できました。
ここまで来る場合は、少なくとも IE は通信モジュール WinInet.dll にリクエストを要求した、と言えます。
ここまで来ていないなら、HTMLやスクリプトなどのコンテンツを疑ったほうがよいです。
他にポイントとなる関数は以下あたりでしょうか
WININET!HttpAddRequestHeadersW
HTTP Header を追加します
WININET!HttpSendRequestW
実際にリクエストを行います、第二引数で HTTP Header を指定できます
以下は WININET!HttpSendRequestW でブレークしたところです。
Referer や Accept-Langage/User-Agent などなどが見えますね。
ここまで来る場合はリクエスト内容は基本的には出来上がっていますので、コンテンツの問題であることは考えにくくなります。
0:003> kv 2
ChildEBP RetAddr Args to Child
02cfb3e0 7549d644 00cc000c 06435d00 ffffffff WININET!HttpSendRequestW (FPO: [Non-Fpo])
02cfb64c 7549db50 00000000 06617970 00cc0008 urlmon!CINetHttp::INetAsyncSendRequest+0x6d3 (FPO: [Non-Fpo])
0:003> du 06435d00
06435d00 "Referer: http://www.bing.com/?se"
06435d40 "tmkt=ja-JP&setlang=match&uid=A25"
06435d80 "03EA1&FORM=NFTOJP..Accept-Langua"
06435dc0 "ge: ja-JP..User-Agent: Mozilla/5"
06435e00 ".0 (compatible; MSIE 10.0; Windo"
06435e40 "ws NT 6.2; WOW64; Trident/6.0).."
06435e80 "Accept-Encoding: gzip, deflate"
さて、実際にユーザーモードのプログラムからは、winsock の send 関数でリクエストが送信されていきます。
以下でブレークしてみましょう。
0:003> bp ws2_32!send
0:021> g
0:021> kv2
ChildEBP RetAddr Args to Child
05fefa48 75614bf1 000009cc 06528090 000003f1 WS2_32!send (FPO: [Non-Fpo])
05fefa94 756149b4 0068e110 05fefae0 0646ca98 WININET!ICSocket::Send_Start+0x21d (FPO: [Non-Fpo])
送るデータは第二引数にバイト配列で入っています。
文字列として da で表示してみます
0:021> da 06528090
06528090 "GET /?setmkt=ja-JP&setlang=match"
065280b0 "&uid=A2503EA1&FORM=NFTOJP HTTP/1"
065280d0 ".1..Accept: text/html, applicati"
065280f0 "on/xhtml+xml, */*..Referer: http"
06528110 "://www.bing.com/?setmkt=ja-JP&se"
06528130 "tlang=match&uid=A2503EA1&FORM=NF"
06528150 "TOJP..Accept-Language: ja-JP..Us"
06528170 "er-Agent: Mozilla/5.0 (compatibl"
06528190 "e; MSIE 10.0; Windows NT 6.2; WO"
065281b0 "W64; Trident/6.0)..Accept-Encodi"
065281d0 "ng: gzip, deflate, peerdist..Hos"
065281f0 "t: www.bing.com..DNT: 1..Connect"
ここで実際に送り出す raw データを確認することができます。send の時点で適切なデータが送り出されていれば、アプリケーション/IE としてはやれることはすべて完了しているといえます。
もしこの時点でのデータが正しくサーバーに届いているデータがおかしい、という場合は、ネットワーク自体やプロキシサーバーなどのネットワーク経路を疑っていく必要があります。
上記は単純な例ですが、IEでの通信処理をデバッグする場合の基本事項です。ぜひ参考ください。
また、WS2_32!send/recv/WSASend/WSARecv などは、IE に限らず Windows socket を使っているアプリケーションが必ず通信のために呼び出している関数ですので、他のアプリケーションでのデバッグ作業でも非常に有益です。
* なお、IIS は通信を http.sys というカーネルモードのドライバで行っていますのでこの限りではありません。
最後に
上記で使った関数は、いずれも開発者が利用するために公開されている API です。
これらでブレークポイントを設定してデータを確認するだけでも、有効な情報を得られることがご理解いただけたらとてもうれしいです。
実際のトラブルシュートでは、さらにネットワークトレースや Fiddler などを組み合わせて効率的に調査ができます。
もちろんサポート部門では IE 内部のデバッグをしていくわけですが、その場合でもこういった関数を起点にして調査を開始しています。
まあこんな感じで地味にがんばっていることがわかっていただけましたでしょうか。
次回は、「詳細設定」 の画面と対応するレジストリのお話しでもしてみたいなと思います。
それでは