x64 で引数を確認する
引数の場所
x64 では x86 の __fastcall のようにレジスタを利用して引数を渡します。関数へ渡す引数のうち、はじめの4個はそれぞれ、RCX、RDX、R8、R9 に入り、 5 個目以上は x86 のようにスタックに積まれますが、rsp+28h 以降に確認することが出来ます。
実際に引数を確認する
それでは、さっそく引数が本当に見えてくるか試してみましょう。
実験台はメモ帳 (notepad.exe) です。下記のように、今まさにファイルを選択してこれからファイルを開こう、とするところでデバッガをアタッチして、 実際に選択したファイル名がデバッガで見えてくるかどうか試してみましょう。
上図でわかるように、デスクトップの中に作った New Folder の中の hello.txt を開こうとしているところです。
デバッガのディレクトリに移動して、tlist を実行してメモ帳の PID (プロセス ID) を取得します。
C:\Debuggers> tlist
0 System Process
4 System
428 smss.exe
...
4864 cmd.exe Administrator: Command Prompt - tlist
4212 notepad.exe Untitled - Notepad
3428 tlist.exe
上記の結果 PID は 4212 であることがわかったので、-p オプションで 4212 を指定して cdb で開きます。
C:\Debuggers> cdb -p 4212 Microsoft (R) Windows Debugger Version 6.11.0001.404 AMD64 Copyright (c) Microsoft Corporation. All rights reserved. *** wait with pending attach Symbol search path is: srv*C:\websymbols*http://msdl.microsoft.com/download/symbols Executable search path is: ModLoad: 00000000`ff450000 00000000`ff47f000 C:\Windows\system32\notepad.exe ModLoad: 00000000`76f30000 00000000`770b6000 C:\Windows\system32\ntdll.dll ... ModLoad: 000007fe`fe680000 000007fe`fe687000 C:\Windows\system32\NSI.dll ModLoad: 000007fe`fcd50000 000007fe`fcd6c000 C:\Windows\system32\SAMLIB.dll (1074.f1c): Break instruction exception - code 80000003 (first chance) ntdll!DbgBreakPoint: 00000000`76f76060 cc int 3
シンボルパスを設定していない人は、設定しておいてください。
ファイルを開くので、CreateFileW のアドレスを探します。
0:004> x kernel32!*CreateFileW* 00000000`76e2c4e0 kernel32!CreateFileW = <no type information> 00000000`76eb7700 kernel32!LZCreateFileW = <no type information>
bp コマンドで CreateFileW にブレークポイントを設定します。
0:004> bp kernel32!CreateFileW
では、プログラムを実行します。
0:004> g
ここで、hello.txt を開く動作をします。
すると、次のようにブレークポイントがヒットします。
Breakpoint 0 hit kernel32!CreateFileW: 00000000`76e2c4e0 4489442418 mov dword ptr [rsp+18h],r8d ss:00000000`000de680=05294d00
レジスタの情報とスタックを確認します。
0:000> r rax=0000000000000003 rbx=0000000000000000 rcx=00000000052999f0 rdx=0000000080000000 rsi=0000000000000000 rdi=000000000024fbf0 rip=0000000076e2c4e0 rsp=00000000000de668 rbp=000000000024d5a0 r8=0000000000000003 r9=0000000000000000 r10=006c006f00460020 r11=0000000005299830 r12=00000000001aaf70 r13=000000000024fc48 r14=0000000000000111 r15=0000000000000000 iopl=0 nv up ei pl zr na po nc cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 kernel32!CreateFileW: 00000000`76e2c4e0 4489442418 mov dword ptr [rsp+18h],r8d ss:00000000`000de680=05294d00 0:000> kn # Child-SP RetAddr Call Site 00 00000000`000de668 000007fe`fe63a144 kernel32!CreateFileW 01 00000000`000de670 000007fe`fe639f67 COMDLG32!CFileValidate::_TestItemOpen+0x11c 02 00000000`000de6f0 000007fe`fe6388b4 COMDLG32!CFileValidate::_ValidateItems+0x107 03 00000000`000de770 000007fe`fe62c0ec COMDLG32!CFileValidate::SetItems+0x2fc 04 00000000`000de800 000007fe`fe62ab49 COMDLG32!CFileOpenSave::_ActOnItems+0x130 05 00000000`000de870 000007fe`fe62a88a COMDLG32!CFileOpenSave::_HandleOkNow+0x281 06 00000000`000de920 000007fe`fe602935 COMDLG32!CFileOpenSave::_HandleOkAndClose+0x2a 07 00000000`000de950 000007fe`fe5f2e09 COMDLG32!CFileOpenSave::_OnCommandMessage+0x309 08 00000000`000de9c0 00000000`76d3f92b COMDLG32!CFileOpenSave::s_OpenSaveDlgProc+0x595 09 00000000`000decb0 00000000`76d3f70a USER32!UserCallDlgProcCheckWow+0x1b6 0a 00000000`000ded70 00000000`76d5d1f0 USER32!DefDlgProcWorker+0xf0 0b 00000000`000dedf0 00000000`76d4b649 USER32!SendMessageWorker+0x457 0c 00000000`000dee80 000007fe`fbdc7383 USER32!SendMessageW+0x5b 0d 00000000`000deed0 000007fe`fbdcaf86 COMCTL32!Button_ReleaseCapture+0x157 0e 00000000`000def10 00000000`76d4d53e COMCTL32!Button_WndProc+0xd3a 0f 00000000`000deff0 00000000`76d4e530 USER32!UserCallWinProcCheckWow+0x1ad 10 00000000`000df0b0 00000000`76d4e4a8 USER32!CallWindowProcAorW+0xdb 11 00000000`000df100 000007fe`fe5f1f71 USER32!CallWindowProcW+0x18 12 00000000`000df140 00000000`76d4d53e COMDLG32!CFileOpenSave::s_OKButtonSubclass+0x73 13 00000000`000df180 00000000`76d4d7c6 USER32!UserCallWinProcCheckWow+0x1ad
ここで、CreateFile のプロトタイプは次のようになります。
HANDLE WINAPI CreateFile( __in LPCTSTR lpFileName, __in DWORD dwDesiredAccess, __in DWORD dwShareMode, __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, __in DWORD dwCreationDisposition, __in DWORD dwFlagsAndAttributes, __in_opt HANDLE hTemplateFile );
つまり第一引数はファイル名が渡されているはずです。
そこで第一引数、すなわち rcx をみてみます。rcx は 00000000052999f0 ですから...
0:000> dc 00000000052999f0 00000000`052999f0 003a0043 0055005c 00650073 00730072 C.:.\.U.s.e.r.s. 00000000`05299a00 004b005c 00690065 00750073 0065006b \.K.e.i.s.u.k.e. 00000000`05299a10 0044005c 00730065 0074006b 0070006f \.D.e.s.k.t.o.p. 00000000`05299a20 004e005c 00770065 00460020 006c006f \.N.e.w. .F.o.l. 00000000`05299a30 00650064 005c0072 00650068 006c006c d.e.r.\.h.e.l.l. 00000000`05299a40 002e006f 00780074 00000074 00000000 o...t.x.t....... 00000000`05299a50 00000000 00000000 158a4789 800000b7 .........G...... 00000000`05299a60 00000064 ff8c9b9c 4f30c90f c377b2b5 d.........0O..w.
確かにファイル名が入っています。ワイドキャラクタであることを既知とすれば、 du コマンドを使って、はじめから次のようにしても OK です。
0:000> du rcx 00000000`052999f0 "C:\Users\Keisuke\Desktop\New Fol" 00000000`05299a30 "der\hello.txt"
以上で、確かに rcx に第一引数が渡されていることが確認できました。
第5引数は dwCreationDisposition ですが、esp+28h をみると次のように 3 であることがわかります。
0:000> dc esp+28h 00000000`000de690 00000003 00000000 00000080 00000000 ................ 00000000`000de6a0 00000000 00000000 76e2c4ca 00000000 ...........v.... 00000000`000de6b0 40000000 000029f1 0024d510 00000000 ...@.)....$..... 00000000`000de6c0 052999f0 00000000 0024fc40 00000000 ..).....@.$..... 00000000`000de6d0 0024fc40 00000000 0024fbf0 00000000 @.$.......$..... 00000000`000de6e0 001aaf70 00000000 fe639f67 000007fe p.......g.c..... 00000000`000de6f0 00000000 00000000 00000000 00000000 ................ 00000000`000de700 0024d5a0 00000000 00000001 00000000 ..$.............
dwCreationDisposition の 3 は OPEN_EXISTING であり、ファイルがあるときにのみ開くことを意味します。
この資料では x64 の環境で引数をみるデモを行いました。