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 の環境で引数をみるデモを行いました。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Web/DB プログラミング徹底解説