アプリケーション・プログラムがシステムコールをすると、(処理内容にもよりますが)OS内部ではCPUをカーネルモードに切り替えて処理を行います。デバッガを使って、この流れを見てみましょう。
(本記事の初稿は2004年です。64ビットCPUが普及した現在でも有用な内容と思われるので、そのままの内容で公開します。)
■ネイティブAPI
本題に入る前に、ネイティブAPIの説明をします。Win32アプリケーションプログラムはUSER32, KERNEL32, GDI32のDLLで公開されているAPIをコールすることでシステムを呼び出します。これらのDLLがシステム内部をコールしてくれるわけです。ただしKERNEL32は直接Windowsのカーネルを呼び出すことをしません。なぜなら、WindowsNT/2000/XPはWin32専用に作られているわけではないからです。Win32以外のサブシステム、POSIXサブシステム、OS/2サブシステム、INTERIXサブシステムなどの元ではWin32以外のアプリケーションプログラムも動作させることが可能です。(WindowsXPではPOSIXサブシステム、OS/2サブシステムが廃止されましたが。)
KERNEL32は(Win32専用ではない汎用的な)APIをコールし、このAPI内部でカーネルを呼び出しています。この汎用的なAPIをネイティブAPIと呼びます。このネイティブAPIを実装・公開しているのはNTDLLというDLLです。なおUSER32, GDI32は提供する機能がWin32に特化したものであるため、直接カーネル(NTOSKRNL.EXE, WIN32K.SYSなど)を呼び出します。
NTDLL.DLLの提供するネイティブAPIについて知らなくてもプログラミングする際に困ることはありませんが、概要がわかるとWindowsの内部動作をより深く理解でき、プログラミングするのが楽しくなります。
■プログラム
ネイティブAPI/カーネルモード移行箇所の調査に使うプログラムのソースコードです。(nativeapi.c menu.h menu.rc)Visual Studioを用いてビルドします。ビルド時の注意事項です。(1)DEBUGビルドすること。(2)コンソールアプリではなく、GUIアプリとしてビルド。(リンカの設定は/SUBSYSTEM:WINDOWS)(3)リンカでデバッグ情報の生成(/DEBUG, /PDB)を有効にしておくこと。(4)シンボル「_DEBUG」を定義しておくこと。
// ネイティブAPI/カーネルモード移行箇所の調査をするためのプログラム(Win32/Win64共用) // (コンソールアプリではなく)GUIアプリとしてビルドすること。 // (RELEASEビルドではなく)DEBUGビルドし、デバッガ内から実行すること。 // 単独で実行するとデバッガが起動するか「不正な処理をしました」になる。 #include <windows.h> #include <stdio.h> #include <string.h> #include <tchar.h> #include "menu.h" LRESULT CALLBACK WindowFunc(HWND, UINT, WPARAM, LPARAM); TCHAR title[]=TEXT("ネイティブAPI/カーネルモード移行箇所の調査"); TCHAR szWinName[]=TEXT("NativeAPI"); int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode) { HWND hwnd; MSG msg; WNDCLASSEX wcl; wcl.cbSize=sizeof(WNDCLASSEX); wcl.hInstance=hThisInst; wcl.lpszClassName=szWinName; wcl.lpfnWndProc=WindowFunc; wcl.style=0; wcl.hIcon=LoadIcon(NULL, IDI_APPLICATION); wcl.hIconSm=NULL; wcl.hCursor=LoadCursor(NULL, IDC_ARROW); wcl.lpszMenuName=TEXT("MyMenu"); wcl.cbClsExtra=0; wcl.cbWndExtra=0; wcl.hbrBackground=(HBRUSH) GetStockObject(WHITE_BRUSH); if(!RegisterClassEx(&wcl)) return 0; hwnd=CreateWindow( szWinName, title, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hThisInst, NULL ); ShowWindow(hwnd, nWinMode); UpdateWindow(hwnd); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // END of while() return (int)msg.wParam; } // END of WinMain() LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { TCHAR messtr[256]; LPBYTE baseadr=0x0; MEMORY_BASIC_INFORMATION mbi; HDC hdc; switch(message){ case WM_COMMAND: switch(LOWORD(wParam)) { case IDM_KERNEL32: _tcscpy(messtr, TEXT("Click OK to break before VirtualQuery() function.(KERNEL32)")); MessageBox(hwnd, messtr, title, MB_ICONEXCLAMATION|MB_OK); #ifdef _DEBUG DebugBreak(); #endif VirtualQuery(baseadr, &mbi, sizeof(mbi)); _tcscpy(messtr, TEXT("VirtualQuery() was executed.(KERNEL32)")); MessageBox(hwnd, messtr, title, MB_ICONINFORMATION|MB_OK); break; case IDM_GDI32: _tcscpy(messtr, TEXT("Click OK to break before Ellipse() function.(GDI32)")); MessageBox(hwnd, messtr, title, MB_ICONEXCLAMATION|MB_OK); hdc=GetDC(hwnd); SelectObject(hdc, (HBRUSH)GetStockObject(LTGRAY_BRUSH)); SelectObject(hdc, (HPEN)GetStockObject(BLACK_PEN)); #ifdef _DEBUG DebugBreak(); #endif Ellipse(hdc, 10, 10, 60, 60); InvalidateRect(hwnd, NULL, 1); ReleaseDC(hwnd, hdc); _tcscpy(messtr, TEXT("Ellipse() was executed.(GDI32)")); MessageBox(hwnd, messtr, title, MB_ICONINFORMATION|MB_OK); break; case IDM_USER32: _tcscpy(messtr, TEXT("Click OK to break before GetDC() function.(USER32)")); MessageBox(hwnd, messtr, title, MB_ICONEXCLAMATION|MB_OK); #ifdef _DEBUG DebugBreak(); #endif hdc=GetDC(hwnd); SelectObject(hdc, (HBRUSH)GetStockObject(LTGRAY_BRUSH)); SelectObject(hdc, (HPEN)GetStockObject(BLACK_PEN)); Ellipse(hdc, 10, 10, 60, 60); InvalidateRect(hwnd, NULL, 1); ReleaseDC(hwnd, hdc); _tcscpy(messtr, TEXT("GetDC() was executed.(USER32)")); MessageBox(hwnd, messtr, title, MB_ICONINFORMATION|MB_OK); break; case IDM_EXIT: PostQuitMessage(0); break; } // END of switch() break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, message, wParam, lParam); } // END of switch() return 0; } // END of WindowFunc()
#define IDM_KERNEL32 101 #define IDM_GDI32 102 #define IDM_USER32 103 #define IDM_EXIT 104
#include "menu.h" MyMenu MENU { POPUP "INT3(&I)" { MENUITEM "KERNEL32 function(&K)", IDM_KERNEL32 MENUITEM "GDI32 function(&G)", IDM_GDI32 MENUITEM "USER32 function(&U)", IDM_USER32 MENUITEM SEPARATOR MENUITEM "Exit(&X)", IDM_EXIT } }
ビルドしたら、そのEXEファイルをデバッガ(windbg)内から実行します。Visual Studioのデバッガではなくwindbgを使うのは、32-bitアプリだけでなく64-bitアプリについても調べるためです。(本稿執筆時のVisual Studio 2005 betaは64ビットプロセスのデバッグができない。(=64ビットプロセスにアタッチできない。))プルダウンメニュー「INT3」を開くと、「KERNEL32 function」「GDI32 function」「USER32 function」が並んでおり、例えば「KERNEL32 function」を選択すると、メッセージボックスが現れ「Click OK to break before VirtualQuery() function.(KERNEL32)」と表示されます。OKボタンを押すとデバッガに制御が移るので、そこからステップ実行することで、VirtualQuery()がどのような手順で実行されるのかを眺めることができるわけです。「GDI32 function」「USER32 function」についても同様です。
■Win32(ネイティブ)の場合
まずWin32(ネイティブ)について見てみましょう。以下、WindowsXP Professional SP2+Pentium4(Northwood)の環境で実行します。windbgの「File -> Open Executable…」でEXEファイルを開くとCommandウィンドウが開くので、「0:000>」プロンプトの所に「g」と入力してENTERキーを押します。するとnativeapi.exeのウィンドウが表示されるので、プルダウンメニューから「KERNEL32 function」「GDI32 function」「USER32 function」のいずれかを選択します。メッセージボックスが表示されたら、OKボタンを押します。デバッガに制御が移り「0:000>」プロンプトが表示されたのを確認したら、ステップ実行していきます。(F11キーもしくはF8キーを押すか、「0:000>」プロンプトの所に「t」と入力してENTERキーを押す。)最初はKERNEL32のfunctionです。
VirtualQuery()呼び出し時の実行内容 Microsoft (R) Windows Debugger Version 6.3.0017.0 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: D:\nativeapi\nativeapi\Debug\nativeapi.exe Symbol search path is: SRV*c:\websymbols*http://msdl.microsoft.com/download/symbols Executable search path is: ModLoad: 00400000 0047d000 nativeapi.exe ModLoad: 7c940000 7c9dd000 ntdll.dll ModLoad: 7c800000 7c931000 C:\WINDOWS\system32\kernel32.dll ModLoad: 77cf0000 77d7f000 C:\WINDOWS\system32\USER32.dll ModLoad: 77ed0000 77f16000 C:\WINDOWS\system32\GDI32.dll (658.e64): Break instruction exception - code 80000003 (first chance) eax=00251eb4 ebx=7ffda000 ecx=00000007 edx=00000080 esi=00251f48 edi=00251eb4 eip=7c941230 esp=0012fb20 ebp=0012fc94 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ntdll!DbgBreakPoint: 7c941230 cc int 3 0:000> g ModLoad: 762e0000 762fd000 C:\WINDOWS\system32\IMM32.DLL ... 途中省略 ModLoad: 770d0000 7715c000 C:\WINDOWS\system32\oleaut32.dll (658.e64): Break instruction exception - code 80000003 (first chance) eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=7c941230 esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!DbgBreakPoint: 7c941230 cc int 3 0:000> t eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=7c941231 esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!DbgBreakPoint+0x1: 7c941231 c3 ret 0:000> t eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=00424480 esp=0012fac0 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 *** WARNING: Unable to verify checksum for nativeapi.exe nativeapi!WindowFunc+0xd0: 00424480 3bf4 cmp esi,esp 0:000> t eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=00422bae esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!ILT+2985(__RTC_CheckEsp): 00422bae e9dd1d0000 jmp nativeapi!_RTC_CheckEsp (00424990) 0:000> t eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=00424990 esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!_RTC_CheckEsp: 00424990 7501 jnz nativeapi!_RTC_CheckEsp+0x3 (00424993) [br=0] 0:000> t eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=00424992 esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!_RTC_CheckEsp+0x2: 00424992 c3 ret 0:000> t eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=00424487 esp=0012fac0 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!WindowFunc+0xd7: 00424487 8bf4 mov esi,esp 0:000> t eax=0012fba0 ebx=00000000 ecx=00000000 edx=00150608 esi=0012fac0 edi=0012fcd8 eip=7c80b859 esp=0012fab0 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 kernel32!VirtualQuery: 7c80b859 8bff mov edi,edi 0:000> t eax=0012fba0 ebx=00000000 ecx=00000000 edx=00150608 esi=0012fac0 edi=0012fcd8 eip=7c80b85b esp=0012fab0 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 kernel32!VirtualQuery+0x2: 7c80b85b 55 push ebp ... 途中省略 0:000> t eax=0012fba0 ebx=00000000 ecx=00000000 edx=00150608 esi=0012fac0 edi=0012fcd8 eip=7c80b869 esp=0012fa9c ebp=0012faac iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 kernel32!VirtualQuery+0x10: 7c80b869 e8baffffff call kernel32!VirtualQueryEx (7c80b828) 0:000> t eax=0012fba0 ebx=00000000 ecx=00000000 edx=00150608 esi=0012fac0 edi=0012fcd8 eip=7c80b828 esp=0012fa98 ebp=0012faac iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 kernel32!VirtualQueryEx: 7c80b828 8bff mov edi,edi ... 途中省略 0:000> t eax=0012faa8 ebx=00000000 ecx=00000000 edx=00150608 esi=0012fac0 edi=0012fcd8 eip=7c80b83f esp=0012fa7c ebp=0012fa94 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 kernel32!VirtualQueryEx+0x17: 7c80b83f ff15bc12807c call dword ptr [kernel32!_imp__NtQueryVirtualMemory (7c8012bc)] {ntdll!ZwQueryVirtualMemory (7c94e213)} ds:0023:7c8012bc=7c94e213 0:000> t eax=0012faa8 ebx=00000000 ecx=00000000 edx=00150608 esi=0012fac0 edi=0012fcd8 eip=7c94e213 esp=0012fa78 ebp=0012fa94 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!ZwQueryVirtualMemory: 7c94e213 b8b2000000 mov eax,0xb2 0:000> t eax=000000b2 ebx=00000000 ecx=00000000 edx=00150608 esi=0012fac0 edi=0012fcd8 eip=7c94e218 esp=0012fa78 ebp=0012fa94 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!ZwQueryVirtualMemory+0x5: 7c94e218 ba0003fe7f mov edx,0x7ffe0300 0:000> t eax=000000b2 ebx=00000000 ecx=00000000 edx=7ffe0300 esi=0012fac0 edi=0012fcd8 eip=7c94e21d esp=0012fa78 ebp=0012fa94 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!ZwQueryVirtualMemory+0xa: 7c94e21d ff12 call dword ptr [edx]{ntdll!KiFastSystemCall (7c94eb8b)} ds:0023:7ffe0300=7c94eb8b 0:000> t eax=000000b2 ebx=00000000 ecx=00000000 edx=7ffe0300 esi=0012fac0 edi=0012fcd8 eip=7c94eb8b esp=0012fa74 ebp=0012fa94 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCall: 7c94eb8b 8bd4 mov edx,esp 0:000> t eax=000000b2 ebx=00000000 ecx=00000000 edx=0012fa74 esi=0012fac0 edi=0012fcd8 eip=7c94eb8d esp=0012fa74 ebp=0012fa94 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCall+0x2: 7c94eb8d 0f34 sysenter 0:000> t eax=00000000 ebx=00000000 ecx=00000001 edx=ffffffff esi=0012fac0 edi=0012fcd8 eip=7c94e21f esp=0012fa78 ebp=0012fa94 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!ZwQueryVirtualMemory+0xc: 7c94e21f c21800 ret 0x18 0:000> t eax=00000000 ebx=00000000 ecx=00000001 edx=ffffffff esi=0012fac0 edi=0012fcd8 eip=7c80b845 esp=0012fa94 ebp=0012fa94 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 kernel32!VirtualQueryEx+0x1d: 7c80b845 85c0 test eax,eax
KERNEL32のVirtualQuery()を呼ぶとVirtualQueryEx()が呼び出され、さらにNTDLLのZwQueryVirtualMemory()が呼び出されてから、NTDLLのKiFastSystemCall()内のsysenter命令を用いてカーネルモードに移行しているのがわかります。次はGDI32のfunctionです。
Ellipse()呼び出し時の実行内容 Microsoft (R) Windows Debugger Version 6.3.0017.0 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: D:\nativeapi\nativeapi\Debug\nativeapi.exe Symbol search path is: SRV*c:\websymbols*http://msdl.microsoft.com/download/symbols Executable search path is: ModLoad: 00400000 0047d000 nativeapi.exe ModLoad: 7c940000 7c9dd000 ntdll.dll ModLoad: 7c800000 7c931000 C:\WINDOWS\system32\kernel32.dll ModLoad: 77cf0000 77d7f000 C:\WINDOWS\system32\USER32.dll ModLoad: 77ed0000 77f16000 C:\WINDOWS\system32\GDI32.dll (738.36c): Break instruction exception - code 80000003 (first chance) eax=00251eb4 ebx=7ffda000 ecx=00000007 edx=00000080 esi=00251f48 edi=00251eb4 eip=7c941230 esp=0012fb20 ebp=0012fc94 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ntdll!DbgBreakPoint: 7c941230 cc int 3 0:000> g ModLoad: 762e0000 762fd000 C:\WINDOWS\system32\IMM32.DLL ... 途中省略 ModLoad: 770d0000 7715c000 C:\WINDOWS\system32\oleaut32.dll (738.36c): Break instruction exception - code 80000003 (first chance) eax=01b00017 ebx=00000000 ecx=00550000 edx=7601068d esi=0012fac0 edi=0012fcd8 eip=7c941230 esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!DbgBreakPoint: 7c941230 cc int 3 0:000> t eax=01b00017 ebx=00000000 ecx=00550000 edx=7601068d esi=0012fac0 edi=0012fcd8 eip=7c941231 esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!DbgBreakPoint+0x1: 7c941231 c3 ret 0:000> t eax=01b00017 ebx=00000000 ecx=00550000 edx=7601068d esi=0012fac0 edi=0012fcd8 eip=00424586 esp=0012fac0 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 *** WARNING: Unable to verify checksum for nativeapi.exe nativeapi!WindowFunc+0x1d6: 00424586 3bf4 cmp esi,esp 0:000> t eax=01b00017 ebx=00000000 ecx=00550000 edx=7601068d esi=0012fac0 edi=0012fcd8 eip=00422bae esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!ILT+2985(__RTC_CheckEsp): 00422bae e9dd1d0000 jmp nativeapi!_RTC_CheckEsp (00424990) 0:000> t eax=01b00017 ebx=00000000 ecx=00550000 edx=7601068d esi=0012fac0 edi=0012fcd8 eip=00424990 esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!_RTC_CheckEsp: 00424990 7501 jnz nativeapi!_RTC_CheckEsp+0x3 (00424993) [br=0] 0:000> t eax=01b00017 ebx=00000000 ecx=00550000 edx=7601068d esi=0012fac0 edi=0012fcd8 eip=00424992 esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!_RTC_CheckEsp+0x2: 00424992 c3 ret 0:000> t eax=01b00017 ebx=00000000 ecx=00550000 edx=7601068d esi=0012fac0 edi=0012fcd8 eip=0042458d esp=0012fac0 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!WindowFunc+0x1dd: 0042458d 8bf4 mov esi,esp 0:000> t eax=7601068d ebx=00000000 ecx=00550000 edx=7601068d esi=0012fac0 edi=0012fcd8 eip=77edc83b esp=0012faa8 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 GDI32!Ellipse: 77edc83b 8bff mov edi,edi ... 途中省略 0:000> t eax=7ffdf000 ebx=7601068d ecx=00550000 edx=7601068d esi=00010000 edi=0012fcd8 eip=77edc8b6 esp=0012fa84 ebp=0012faa4 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 GDI32!Ellipse+0xa4: 77edc8b6 e80c000000 call GDI32!NtGdiEllipse (77edc8c7) 0:000> t eax=7ffdf000 ebx=7601068d ecx=00550000 edx=7601068d esi=00010000 edi=0012fcd8 eip=77edc8c7 esp=0012fa80 ebp=0012faa4 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 GDI32!NtGdiEllipse: 77edc8c7 b880100000 mov eax,0x1080 0:000> t eax=00001080 ebx=7601068d ecx=00550000 edx=7601068d esi=00010000 edi=0012fcd8 eip=77edc8cc esp=0012fa80 ebp=0012faa4 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 GDI32!NtGdiEllipse+0x5: 77edc8cc ba0003fe7f mov edx,0x7ffe0300 0:000> t eax=00001080 ebx=7601068d ecx=00550000 edx=7ffe0300 esi=00010000 edi=0012fcd8 eip=77edc8d1 esp=0012fa80 ebp=0012faa4 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 GDI32!NtGdiEllipse+0xa: 77edc8d1 ff12 call dword ptr [edx]{ntdll!KiFastSystemCall (7c94eb8b)} ds:0023:7ffe0300=7c94eb8b 0:000> t eax=00001080 ebx=7601068d ecx=00550000 edx=7ffe0300 esi=00010000 edi=0012fcd8 eip=7c94eb8b esp=0012fa7c ebp=0012faa4 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCall: 7c94eb8b 8bd4 mov edx,esp 0:000> t eax=00001080 ebx=7601068d ecx=00550000 edx=0012fa7c esi=00010000 edi=0012fcd8 eip=7c94eb8d esp=0012fa7c ebp=0012faa4 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCall+0x2: 7c94eb8d 0f34 sysenter 0:000> t eax=00000001 ebx=7601068d ecx=00000001 edx=ffffffff esi=00010000 edi=0012fcd8 eip=77edc8d3 esp=0012fa80 ebp=0012faa4 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 GDI32!NtGdiEllipse+0xc: 77edc8d3 c21400 ret 0x14 0:000> t eax=00000001 ebx=7601068d ecx=00000001 edx=ffffffff esi=00010000 edi=0012fcd8 eip=77edc8bb esp=0012fa98 ebp=0012faa4 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 GDI32!Ellipse+0xa9: 77edc8bb 5f pop edi
GDI32のEllipse()を呼ぶとGDI32内のNtGdiEllipse()が呼び出され、NTDLLのKiFastSystemCall()内のsysenter命令を用いてカーネルモードに移行しているのがわかります。(NTDLLのその他のルーチンがコールされていないことに注意。)最後にUSER32のfunctionです。
GetDC()呼び出し時の実行内容 Microsoft (R) Windows Debugger Version 6.3.0017.0 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: D:\nativeapi\nativeapi\Debug\nativeapi.exe Symbol search path is: SRV*c:\websymbols*http://msdl.microsoft.com/download/symbols Executable search path is: ModLoad: 00400000 0047d000 nativeapi.exe ModLoad: 7c940000 7c9dd000 ntdll.dll ModLoad: 7c800000 7c931000 C:\WINDOWS\system32\kernel32.dll ModLoad: 77cf0000 77d7f000 C:\WINDOWS\system32\USER32.dll ModLoad: 77ed0000 77f16000 C:\WINDOWS\system32\GDI32.dll (9d0.970): Break instruction exception - code 80000003 (first chance) eax=00251eb4 ebx=7ffdd000 ecx=00000007 edx=00000080 esi=00251f48 edi=00251eb4 eip=7c941230 esp=0012fb20 ebp=0012fc94 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ntdll!DbgBreakPoint: 7c941230 cc int 3 0:000> g ModLoad: 762e0000 762fd000 C:\WINDOWS\system32\IMM32.DLL ... 途中省略 ModLoad: 770d0000 7715c000 C:\WINDOWS\system32\oleaut32.dll (9d0.970): Break instruction exception - code 80000003 (first chance) eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=7c941230 esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!DbgBreakPoint: 7c941230 cc int 3 0:000> t eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=7c941231 esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!DbgBreakPoint+0x1: 7c941231 c3 ret 0:000> t eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=00424653 esp=0012fac0 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 *** WARNING: Unable to verify checksum for nativeapi.exe nativeapi!WindowFunc+0x2a3: 00424653 3bf4 cmp esi,esp 0:000> t eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=00422bae esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!ILT+2985(__RTC_CheckEsp): 00422bae e9dd1d0000 jmp nativeapi!_RTC_CheckEsp (00424990) 0:000> t eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=00424990 esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!_RTC_CheckEsp: 00424990 7501 jnz nativeapi!_RTC_CheckEsp+0x3 (00424993) [br=0] 0:000> t eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=00424992 esp=0012fabc ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!_RTC_CheckEsp+0x2: 00424992 c3 ret 0:000> t eax=00000001 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=0042465a esp=0012fac0 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!WindowFunc+0x2aa: 0042465a 8bf4 mov esi,esp 0:000> t eax=0075053e ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=77cf8697 esp=0012fab8 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 USER32!NtUserGetDC: 77cf8697 b891110000 mov eax,0x1191 0:000> t eax=00001191 ebx=00000000 ecx=7c95056d edx=00150608 esi=0012fac0 edi=0012fcd8 eip=77cf869c esp=0012fab8 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 USER32!NtUserGetDC+0x5: 77cf869c ba0003fe7f mov edx,0x7ffe0300 0:000> t eax=00001191 ebx=00000000 ecx=7c95056d edx=7ffe0300 esi=0012fac0 edi=0012fcd8 eip=77cf86a1 esp=0012fab8 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 USER32!NtUserGetDC+0xa: 77cf86a1 ff12 call dword ptr [edx]{ntdll!KiFastSystemCall (7c94eb8b)} ds:0023:7ffe0300=7c94eb8b 0:000> t eax=00001191 ebx=00000000 ecx=7c95056d edx=7ffe0300 esi=0012fac0 edi=0012fcd8 eip=7c94eb8b esp=0012fab4 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCall: 7c94eb8b 8bd4 mov edx,esp 0:000> t eax=00001191 ebx=00000000 ecx=7c95056d edx=0012fab4 esi=0012fac0 edi=0012fcd8 eip=7c94eb8d esp=0012fab4 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ntdll!KiFastSystemCall+0x2: 7c94eb8d 0f34 sysenter 0:000> t eax=b0010cba ebx=00000000 ecx=00000001 edx=ffffffff esi=0012fac0 edi=0012fcd8 eip=77cf86a3 esp=0012fab8 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 USER32!NtUserGetDC+0xc: 77cf86a3 c20400 ret 0x4 0:000> t eax=b0010cba ebx=00000000 ecx=00000001 edx=ffffffff esi=0012fac0 edi=0012fcd8 eip=00424666 esp=0012fac0 ebp=0012fcd8 iopl=0 nv up ei pl zr na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 nativeapi!WindowFunc+0x2b6: 00424666 3bf4 cmp esi,esp
USER32のNtUserGetDC()を呼び出すと()、そのままNTDLLのKiFastSystemCall()内のsysenter命令を用いてカーネルモードに移行しているのがわかります。(NTDLLのその他のルーチンがコールされていないことに注意。)
上記例ではsysenter命令を用いてカーネルモードへ移行していますが、sysenterはPentiumIIで導入された命令です。それ以前のCPU(Pentium, Pentium PROなど)で動作するWindowsNT 4.0/2000などではソフトウェア割り込み(int 2E)を使ってカーネルモードに移行します。WindowsXPのNTDLL.DLLにもKiIntSystemCall()という名前でint 2Eを用いたカーネルモード移行ルーチンが残っています。(Die Windows HistoryにWindowsXPをPentiumで動作させている例が載っているのを見ると、おそらくこうした場合に使われているものと推測される。)
■Win32(WOW64)の場合
Win32(WOW64)について調べます。本題に入る前にWOW64について見ておきます。WOW64とは64-bit版Windows上でWin32アプリを実行するためのエミュレーション層を指します。主として3つのDLL(WOW64.DLL WOW64WIN.DLL WOW64CPU.DLL)から構成されます。WOW64.DLLとWOW64WIN.DLLがWIN32アプリのシステムコールをintercept(横取り)して64-bitのシステムコールに置き換えて実行します。WOW64.DLLが横取りした分についてはNTDLL.DLL(64-bit native)経由でNTOSKRNL.EXE(64-bit native)がコールされ、WOW64WIN.DLLが横取りした分については直接WIN32K.SYS(64-bit native)がコールされます。WOW64CPU.DLLはCPUのモード切替を担当します。(MSDNの資料には「WOW64CPU.DLLはx64では不要」と記述されているが、x64プロセッサの32-bitから64-bitへの切り替えはWOW64CPU.DLLで行われており、必須であるものと思われる。)
以下、WindowsXP Professional x64 Edition(RC1)+Athlon64(NewCastle)の環境で実行します。windbgはVersion 6.4.4.4(x64版-beta)を使います。最初はKERNEL32のfunctionです。
VirtualQuery()呼び出し時の実行内容 Microsoft (R) Windows Debugger Version 6.4.0004.4 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: D:\nativeapi\nativeapi\Debug\nativeapi.exe Symbol search path is: SRV*C:\websymbols*http://msdl.microsoft.com/download/symbols Executable search path is: ModLoad: 00000000`00400000 00000000`0047d000 nativeapi.exe ModLoad: 00000000`77ea0000 00000000`77ff3000 ntdll.dll ModLoad: 00000000`77b70000 00000000`77bb6000 C:\WINDOWS\system32\wow64.dll ModLoad: 00000000`77b20000 00000000`77b69000 C:\WINDOWS\system32\wow64win.dll ModLoad: 00000000`77b10000 00000000`77b19000 C:\WINDOWS\system32\wow64cpu.dll (70.73c): Break instruction exception - code 80000003 (first chance) ntdll!DbgBreakPoint: 00000000`77ef4050 cc int 3 0:000> g ModLoad: 00000000`77ce0000 00000000`77e92000 NOT_AN_IMAGE ModLoad: 00000000`7d4d0000 00000000`7d5d0000 NOT_AN_IMAGE ModLoad: 00000000`7d5e0000 00000000`7d6f0000 C:\WINDOWS\syswow64\ntdll32.dll ModLoad: 00000000`77ce0000 00000000`77e92000 NOT_AN_IMAGE ModLoad: 00000000`77bc0000 00000000`77ccf000 NOT_AN_IMAGE ModLoad: 00000000`7d4d0000 00000000`7d5d0000 C:\WINDOWS\syswow64\kernel32.dll ModLoad: 00000000`7d940000 00000000`7da10000 C:\WINDOWS\syswow64\USER32.dll ModLoad: 00000000`7d810000 00000000`7d8a0000 C:\WINDOWS\syswow64\GDI32.dll (70.73c): WOW64 breakpoint - code 4000001f (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. ntdll32!DbgBreakPoint: 00000000`7d5f002d cc int 3 0:000:x86> g ModLoad: 00000000`7dee0000 00000000`7df40000 C:\WINDOWS\syswow64\IMM32.DLL ... 途中省略 ModLoad: 00000000`75810000 00000000`758d0000 C:\WINDOWS\syswow64\USERENV.dll (70.73c): WOW64 breakpoint - code 4000001f (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. ntdll32!DbgBreakPoint: 00000000`7d5f002d cc int 3 0:000:x86> t ntdll32!DbgBreakPoint+0x1: 00000000`7d5f002e c3 ret 0:000:x86> t *** WARNING: Unable to verify checksum for nativeapi.exe *** ERROR: Module load completed but symbols could not be loaded for nativeapi.exe nativeapi+0x24480: 00000000`00424480 3bf4 cmp esi,esp 0:000:x86> t nativeapi+0x24482: 00000000`00424482 e827e7ffff call nativeapi+0x22bae (00422bae) 0:000:x86> t nativeapi+0x22bae: 00000000`00422bae e9dd1d0000 jmp nativeapi+0x24990 (00424990) 0:000:x86> t nativeapi+0x24990: 00000000`00424990 7501 jnz nativeapi+0x24993 (00424993) [br=0] 0:000:x86> t nativeapi+0x24992: 00000000`00424992 c3 ret 0:000:x86> t nativeapi+0x24487: 00000000`00424487 8bf4 mov esi,esp 0:000:x86> t nativeapi+0x24489: 00000000`00424489 6a1c push 0x1c 0:000:x86> t nativeapi+0x2448b: 00000000`0042448b 8d85c8feffff lea eax,[ebp-0x138] ss:002b:00000000`002cfb78=cccccccc 0:000:x86> t nativeapi+0x24491: 00000000`00424491 50 push eax 0:000:x86> t nativeapi+0x24492: 00000000`00424492 8b8decfeffff mov ecx,[ebp-0x114] ss:002b:00000000`002cfb9c=00000000 0:000:x86> t nativeapi+0x24498: 00000000`00424498 51 push ecx 0:000:x86> t nativeapi+0x24499: 00000000`00424499 ff1558b34700 call dword ptr [nativeapi+0x7b358 (0047b358)] {kernel32!VirtualQuery (7d4eac15)} ds:002b:00000000`0047b358=7d4eac15 0:000:x86> t kernel32!VirtualQuery: 00000000`7d4eac15 8bff mov edi,edi 0:000:x86> t kernel32!VirtualQuery+0x2: 00000000`7d4eac17 55 push ebp 0:000:x86> t kernel32!VirtualQuery+0x3: 00000000`7d4eac18 8bec mov ebp,esp ... 途中省略 0:000:x86> t kernel32!VirtualQuery+0x10: 00000000`7d4eac25 e8baffffff call kernel32!VirtualQueryEx (7d4eabe4) 0:000:x86> t kernel32!VirtualQueryEx: 00000000`7d4eabe4 8bff mov edi,edi 0:000:x86> t kernel32!VirtualQueryEx+0x2: 00000000`7d4eabe6 55 push ebp 0:000:x86> t kernel32!VirtualQueryEx+0x3: 00000000`7d4eabe7 8bec mov ebp,esp ... 途中省略 0:000:x86> t kernel32!VirtualQueryEx+0x17: 00000000`7d4eabfb ff15e0024e7d call dword ptr [kernel32!_imp__NtQueryVirtualMemory (7d4e02e0)] {ntdll32!NtQueryVirtualMemory (7d5fcac6)} ds:002b:00000000`7d4e02e0=7d5fcac6 0:000:x86> t ntdll32!NtQueryVirtualMemory: 00000000`7d5fcac6 b820000000 mov eax,0x20 ... 途中省略 0:000:x86> t ntdll32!ZwQueryVirtualMemory+0xb: 00000000`7d5fcad1 64ff15c0000000 call dword ptr fs:[000000c0] fs:0053:00000000`000000c0=???????? 0:000:x86> t wow64cpu!X86SwitchTo64BitMode: 00000000`77b11870 ea2c38b1773300 jmp 0033:wow64cpu!CpupReturnFromSimulatedCode (77b1382c) 0:000:x86> t wow64cpu!CpupReturnFromSimulatedCode: 00000000`77b1382c 67448b0424 mov r8d,[esp] ss:00000000`002cfa4c=7d5fcad8 ... 途中省略 0:000> t wow64cpu!CpupReturnFromSimulatedCode+0x22: 00000000`77b1384e 448bda mov r11d,edx 0:000> t wow64cpu!TurboDispatchJumpAddressStart: 00000000`77b13851 41ff24cf 0:000> t wow64cpu!ServiceNoTurbo: 00000000`77b13855 4189b5a4000000 mov [r13+0xa4],esi ds:00000000`0012ef54=00976ab0 ... 途中省略 0:000> t wow64cpu!ServiceNoTurbo+0x22: 00000000`77b13877 ff15f3d7ffff call qword ptr [wow64cpu!_imp_Wow64SystemServiceEx (0000000077b11070)] ds:00000000`77b11070=0000000077b767b0 0:000> t wow64!Wow64SystemServiceEx: 00000000`77b767b0 4c8bdc mov r11,rsp ... 途中省略 0:000> t wow64!Wow64SystemServiceEx+0xd3: 00000000`77b76883 41ffd4 call r12 {wow64!whNtQueryVirtualMemory (0000000077b820c0)} 0:000> t wow64!whNtQueryVirtualMemory: 00000000`77b820c0 488bc4 mov rax,rsp ... 途中省略 0:000> t wow64!whNtQueryVirtualMemory+0x3f: 00000000`77b820ff e8bc86ffff call wow64!Wow64ShallowThunkSIZE_T32TO64 (0000000077b7a7c0) 0:000> t wow64!Wow64ShallowThunkSIZE_T32TO64: 00000000`77b7a7c0 4885d2 test rdx,rdx ... 途中省略 0:000> t wow64!Wow64ShallowThunkSIZE_T32TO64+0x15: 00000000`77b7a7d5 c20000 ret 0x0 0:000> t wow64!whNtQueryVirtualMemory+0x44: 00000000`77b82104 85ff test edi,edi ... 途中省略 0:000> t wow64!whNtQueryVirtualMemory+0xfb: 00000000`77b821bb e870fdffff call wow64!whNtQueryVirtualMemory_MemoryBasicInformation (0000000077b81f30) 0:000> t wow64!whNtQueryVirtualMemory_MemoryBasicInformation: 00000000`77b81f30 488bc4 mov rax,rsp ... 途中省略 0:000> t wow64!whNtQueryVirtualMemory_MemoryBasicInformation+0xbc: 00000000`77b81fec ff1546f2feff call qword ptr [wow64!_imp_NtQueryVirtualMemory (0000000077b71238)] ds:00000000`77b71238=0000000077ef2f90 0:000> t ntdll!ZwQueryVirtualMemory: 00000000`77ef2f90 4c8bd1 mov r10,rcx 0:000> t ntdll!NtQueryVirtualMemory+0x3: 00000000`77ef2f93 b820000000 mov eax,0x20 0:000> t ntdll!NtQueryVirtualMemory+0x8: 00000000`77ef2f98 0f05 syscall 0:000> t ntdll!NtQueryVirtualMemory+0xa: 00000000`77ef2f9a c3 ret 0:000> t wow64!whNtQueryVirtualMemory_MemoryBasicInformation+0xc2: 00000000`77b81ff2 4c8ba42498000000 mov r12,[rsp+0x98] ss:00000000`0012e4d8=000000000012e4e0
まず冒頭のModLoadの行にご注目ください。仮想アドレス空間にロードされたDLLが列挙されています。64ビットネイティブなDLLとして、NTDLL.DLL WOW64.DLL WOW64WIN.DLL WOW64CPU.DLLがロードされています。さらにWIN32アプリがコールしてくるスタブルーチンとしてのKERNEL32.DLL USER32.DLL GDI32.DLLもロードされており、KERNEL32.DLLがネイティブAPIコールのために使うNTDLL32.DLLもロードされています。
KERNEL32のVirtualQuery()をコールすると、VirtualQueryEx()がコールされ、NTDLL32NtQueryVirtualMemory()、ZwQueryVirtualMemory()がコールされます。32-bit版Windowsであればここでカーネルモードへ移行するところでしょうが、そうはならずにセグメント間CALL命令(call dword ptr fs:[000000c0])でWOW64に制御を移します。最初にWOW64CPU.DLLのX86SwitchTo64BitModeで32-bit mode(Compatibility mode)から64-bit modeに移行します。その後はWOW64CPU内のいくつかのルーチン、WOW64のwhNtQueryVirtualMemory(),whNtQueryVirtualMemory_MemoryBasicInformation()などを実行した後に(64ビットネイティブな)NTDLLのNtQueryVirtualMemory()、ZwQueryVirtualMemory()がコールされ(エントリーポイントはどちらも同じ)、ここでようやくsyscall命令を用いてカーネルモードへ移行します。(KiFastSystemCall()をコールするのではなく、直接syscall命令を実行している点に注意。)
GDI32のfunctionについても見てみます。
Ellipse()呼び出し時の実行内容 Microsoft (R) Windows Debugger Version 6.4.0004.4 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: D:\nativeapi\nativeapi\Debug\nativeapi.exe Symbol search path is: SRV*C:\websymbols*http://msdl.microsoft.com/download/symbols Executable search path is: ModLoad: 00000000`00400000 00000000`0047d000 nativeapi.exe ModLoad: 00000000`77ea0000 00000000`77ff3000 ntdll.dll ModLoad: 00000000`77b70000 00000000`77bb6000 C:\WINDOWS\system32\wow64.dll ModLoad: 00000000`77b20000 00000000`77b69000 C:\WINDOWS\system32\wow64win.dll ModLoad: 00000000`77b10000 00000000`77b19000 C:\WINDOWS\system32\wow64cpu.dll (51c.1d8): Break instruction exception - code 80000003 (first chance) ntdll!DbgBreakPoint: 00000000`77ef4050 cc int 3 0:000> g ModLoad: 00000000`77ce0000 00000000`77e92000 NOT_AN_IMAGE ModLoad: 00000000`7d4d0000 00000000`7d5d0000 NOT_AN_IMAGE ModLoad: 00000000`7d5e0000 00000000`7d6f0000 C:\WINDOWS\syswow64\ntdll32.dll ModLoad: 00000000`77ce0000 00000000`77e92000 NOT_AN_IMAGE ModLoad: 00000000`77bc0000 00000000`77ccf000 NOT_AN_IMAGE ModLoad: 00000000`7d4d0000 00000000`7d5d0000 C:\WINDOWS\syswow64\kernel32.dll ModLoad: 00000000`7d940000 00000000`7da10000 C:\WINDOWS\syswow64\USER32.dll ModLoad: 00000000`7d810000 00000000`7d8a0000 C:\WINDOWS\syswow64\GDI32.dll (51c.1d8): WOW64 breakpoint - code 4000001f (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. ntdll32!DbgBreakPoint: 00000000`7d5f002d cc int 3 0:000:x86> g ModLoad: 00000000`7dee0000 00000000`7df40000 C:\WINDOWS\syswow64\IMM32.DLL ... 途中省略 ModLoad: 00000000`75810000 00000000`758d0000 C:\WINDOWS\syswow64\USERENV.dll (51c.1d8): WOW64 breakpoint - code 4000001f (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. ntdll32!DbgBreakPoint: 00000000`7d5f002d cc int 3 0:000:x86> t ntdll32!DbgBreakPoint+0x1: 00000000`7d5f002e c3 ret 0:000:x86> t *** WARNING: Unable to verify checksum for nativeapi.exe *** ERROR: Module load completed but symbols could not be loaded for nativeapi.exe nativeapi+0x24586: 00000000`00424586 3bf4 cmp esi,esp 0:000:x86> t nativeapi+0x24588: 00000000`00424588 e821e6ffff call nativeapi+0x22bae (00422bae) 0:000:x86> t nativeapi+0x22bae: 00000000`00422bae e9dd1d0000 jmp nativeapi+0x24990 (00424990) 0:000:x86> t nativeapi+0x24990: 00000000`00424990 7501 jnz nativeapi+0x24993 (00424993) [br=0] 0:000:x86> t nativeapi+0x24992: 00000000`00424992 c3 ret 0:000:x86> t nativeapi+0x2458d: 00000000`0042458d 8bf4 mov esi,esp 0:000:x86> t nativeapi+0x2458f: 00000000`0042458f 6a3c push 0x3c 0:000:x86> t nativeapi+0x24591: 00000000`00424591 6a3c push 0x3c 0:000:x86> t nativeapi+0x24593: 00000000`00424593 6a0a push 0xa 0:000:x86> t nativeapi+0x24595: 00000000`00424595 6a0a push 0xa 0:000:x86> t nativeapi+0x24597: 00000000`00424597 8b85bcfeffff mov eax,[ebp-0x144] ss:002b:00000000`002cfb6c=fc0104f3 0:000:x86> t nativeapi+0x2459d: 00000000`0042459d 50 push eax 0:000:x86> t nativeapi+0x2459e: 00000000`0042459e ff15dcb24700 call dword ptr [nativeapi+0x7b2dc (0047b2dc)] {GDI32!Ellipse (7d82cc68)} ds:002b:00000000`0047b2dc=7d82cc68 0:000:x86> t GDI32!Ellipse: 00000000`7d82cc68 8bff mov edi,edi ... 途中省略 0:000:x86> t GDI32!Ellipse+0xaa: 00000000`7d82cca7 e80c000000 call GDI32!NtGdiEllipse (7d82ccb8) 0:000:x86> t GDI32!NtGdiEllipse: 00000000`7d82ccb8 b888110000 mov eax,0x1188 ... 途中省略 0:000:x86> t GDI32!NtGdiEllipse+0xe: 00000000`7d82ccc6 64ff15c0000000 call dword ptr fs:[000000c0] fs:0053:00000000`000000c0=???????? 0:000:x86> t wow64cpu!X86SwitchTo64BitMode: 00000000`77b11870 ea2c38b1773300 jmp 0033:wow64cpu!CpupReturnFromSimulatedCode (77b1382c) 0:000:x86> t wow64cpu!CpupReturnFromSimulatedCode: 00000000`77b1382c 67448b0424 mov r8d,[esp] ss:00000000`002cfa54=7d82cccd ... 途中省略 0:000> t wow64cpu!CpupReturnFromSimulatedCode+0x22: 00000000`77b1384e 448bda mov r11d,edx 0:000> t wow64cpu!TurboDispatchJumpAddressStart: 00000000`77b13851 41ff24cf jmp qword ptr [r15+rcx*8]{wow64cpu!ServiceNoTurbo (0000000077b13855)} ds:00000000`77b13590=0000000077b13855 0:000> t wow64cpu!ServiceNoTurbo: 00000000`77b13855 4189b5a4000000 mov [r13+0xa4],esi ds:00000000`0012ef54=0096d200 ... 途中省略 0:000> t wow64cpu!ServiceNoTurbo+0x22: 00000000`77b13877 ff15f3d7ffff call qword ptr [wow64cpu!_imp_Wow64SystemServiceEx (0000000077b11070)] ds:00000000`77b11070=0000000077b767b0 0:000> t wow64!Wow64SystemServiceEx: 00000000`77b767b0 4c8bdc mov r11,rsp ... 途中省略 0:000> t wow64!Wow64SystemServiceEx+0xd3: 00000000`77b76883 41ffd4 call r12 {wow64win!whNtGdiEllipse (0000000077b49f00)} 0:000> t wow64win!whNtGdiEllipse: 00000000`77b49f00 4883ec38 sub rsp,0x38 ... 途中省略 0:000> t wow64win!ZwGdiEllipse+0x3: 00000000`77b571f3 b888110000 mov eax,0x1188 0:000> t wow64win!ZwGdiEllipse+0x8: 00000000`77b571f8 0f05 syscall 0:000> t wow64win!ZwGdiEllipse+0xa: 00000000`77b571fa c3 ret 0:000> t wow64win!whNtGdiEllipse+0x21: 00000000`77b49f21 4883c438 add rsp,0x38 0:000> t wow64win!whNtGdiEllipse+0x25: 00000000`77b49f25 c3 ret 0:000> t wow64!Wow64SystemServiceEx+0xd6: 00000000`77b76886 8bd8 mov ebx,eax
GDI32のEllipse()をコールすると、NtGdiEllipse()がコールされます。32-bit版Windowsであればここで直接カーネルモードへ移行しますが、そうはならずにセグメント間CALL命令(call dword ptr fs:[000000c0])でWOW64に制御を移します。最初にWOW64CPU.DLLのX86SwitchTo64BitModeで32-bit mode(Compatibility mode)から64-bit modeに移行します。その後はWOW64CPU内のいくつかのルーチン、WOW64WINのwhNtGdiEllipse(),ZwGdiEllipse()をコールし(どちらもエントリーポイントは同じ)、ここでようやくsyscall命令を用いてカーネルモードへ移行します。(NTDLLのルーチンをコールしていない点に注意。)
最後にUSER32のfunctionについて見てみます。
GetDC()呼び出し時の実行内容 Microsoft (R) Windows Debugger Version 6.4.0004.4 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: D:\nativeapi\nativeapi\Debug\nativeapi.exe Symbol search path is: SRV*C:\websymbols*http://msdl.microsoft.com/download/symbols Executable search path is: ModLoad: 00000000`00400000 00000000`0047d000 nativeapi.exe ModLoad: 00000000`77ea0000 00000000`77ff3000 ntdll.dll ModLoad: 00000000`77b70000 00000000`77bb6000 C:\WINDOWS\system32\wow64.dll ModLoad: 00000000`77b20000 00000000`77b69000 C:\WINDOWS\system32\wow64win.dll ModLoad: 00000000`77b10000 00000000`77b19000 C:\WINDOWS\system32\wow64cpu.dll (fc.72c): Break instruction exception - code 80000003 (first chance) ntdll!DbgBreakPoint: 00000000`77ef4050 cc int 3 0:000> g ModLoad: 00000000`77ce0000 00000000`77e92000 NOT_AN_IMAGE ModLoad: 00000000`7d4d0000 00000000`7d5d0000 NOT_AN_IMAGE ModLoad: 00000000`7d5e0000 00000000`7d6f0000 C:\WINDOWS\syswow64\ntdll32.dll ModLoad: 00000000`77ce0000 00000000`77e92000 NOT_AN_IMAGE ModLoad: 00000000`77bc0000 00000000`77ccf000 NOT_AN_IMAGE ModLoad: 00000000`7d4d0000 00000000`7d5d0000 C:\WINDOWS\syswow64\kernel32.dll ModLoad: 00000000`7d940000 00000000`7da10000 C:\WINDOWS\syswow64\USER32.dll ModLoad: 00000000`7d810000 00000000`7d8a0000 C:\WINDOWS\syswow64\GDI32.dll (fc.72c): WOW64 breakpoint - code 4000001f (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. ntdll32!DbgBreakPoint: 00000000`7d5f002d cc int 3 0:000:x86> g ModLoad: 00000000`7dee0000 00000000`7df40000 C:\WINDOWS\syswow64\IMM32.DLL ... 途中省略 ModLoad: 00000000`75810000 00000000`758d0000 C:\WINDOWS\syswow64\USERENV.dll (fc.72c): WOW64 breakpoint - code 4000001f (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. ntdll32!DbgBreakPoint: 00000000`7d5f002d cc int 3 0:000:x86> t ntdll32!DbgBreakPoint+0x1: 00000000`7d5f002e c3 ret 0:000:x86> t *** WARNING: Unable to verify checksum for nativeapi.exe *** ERROR: Module load completed but symbols could not be loaded for nativeapi.exe nativeapi+0x24653: 00000000`00424653 3bf4 cmp esi,esp 0:000:x86> t nativeapi+0x24655: 00000000`00424655 e854e5ffff call nativeapi+0x22bae (00422bae) 0:000:x86> t nativeapi+0x22bae: 00000000`00422bae e9dd1d0000 jmp nativeapi+0x24990 (00424990) 0:000:x86> t nativeapi+0x24990: 00000000`00424990 7501 jnz nativeapi+0x24993 (00424993) [br=0] 0:000:x86> t nativeapi+0x24992: 00000000`00424992 c3 ret 0:000:x86> t nativeapi+0x2465a: 00000000`0042465a 8bf4 mov esi,esp 0:000:x86> t nativeapi+0x2465c: 00000000`0042465c 8b4508 mov eax,[ebp+0x8] ss:002b:00000000`002cfcb8=00190196 0:000:x86> t nativeapi+0x2465f: 00000000`0042465f 50 push eax 0:000:x86> t nativeapi+0x24660: 00000000`00424660 ff15f8b44700 call dword ptr [nativeapi+0x7b4f8 (0047b4f8)] {USER32!NtUserGetDC (7d958cc0)} ds:002b:00000000`0047b4f8=7d958cc0 0:000:x86> t USER32!NtUserGetDC: 00000000`7d958cc0 b80a100000 mov eax,0x100a ... 途中省略 0:000:x86> t USER32!NtUserGetDC+0xe: 00000000`7d958cce 64ff15c0000000 call dword ptr fs:[000000c0] fs:0053:00000000`000000c0=???????? 0:000:x86> t wow64cpu!X86SwitchTo64BitMode: 00000000`77b11870 ea2c38b1773300 jmp 0033:wow64cpu!CpupReturnFromSimulatedCode (77b1382c) 0:000:x86> t wow64cpu!CpupReturnFromSimulatedCode: 00000000`77b1382c 67448b0424 mov r8d,[esp] ss:00000000`002cfa8c=7d958cd5 ... 途中省略 0:000> t wow64cpu!CpupReturnFromSimulatedCode+0x22: 00000000`77b1384e 448bda mov r11d,edx 0:000> t wow64cpu!TurboDispatchJumpAddressStart: 00000000`77b13851 41ff24cf jmp qword ptr [r15+rcx*8]{wow64cpu!Thunk1ArgSp (0000000077b13cde)} ds:00000000`77b135a8=0000000077b13cde 0:000> t wow64cpu!Thunk1ArgSp: 00000000`77b13cde 4d6313 movsxd r10,[r11] ds:00000000`002cfa94=00190196 0:000> t wow64cpu!Thunk1ArgSp+0x3: 00000000`77b13ce1 eb4b jmp wow64cpu!Thunk0Arg (0000000077b13d2e) 0:000> t wow64cpu!Thunk0Arg: 00000000`77b13d2e e83d000000 call wow64cpu!CpupSyscallStub (0000000077b13d70) 0:000> t wow64cpu!CpupSyscallStub: 00000000`77b13d70 0f05 syscall 0:000> t wow64cpu!CpupSyscallStub+0x2: 00000000`77b13d72 c3 ret 0:000> t wow64cpu!Thunk0Arg+0x5: 00000000`77b13d33 4d89b42480140000 mov [r12+0x1480],r14 ds:00000000`7efdc480=0000000000000000
USER32のNtUserGetDC()をコールすると、いくつかの処理をした後にセグメント間CALL命令(call dword ptr fs:[000000c0])でWOW64に制御を移します。最初にWOW64CPU.DLLのX86SwitchTo64BitModeで32-bit mode(Compatibility mode)から64-bit modeに移行します。WOW64CPU内のいくつかのルーチンを実行した後に
WOW64CPU内のCpupSyscallStub()をコールし、ここでsyscall命令を用いてカーネルモードへ移行します。
(NTDLLのルーチンをコールしていない点に注意。)
■Win64の場合
最後にWin64について調べます。システムコール時の流れはWin32(ネイティブ)の場合と大体同じです。
Win32(WOW64)の場合と同様にWindowsXP Professional x64 Edition(RC1)+Athlon64(NewCastle)の環境で実行します。windbgはVersion 6.4.4.4(x64版-beta)を使います。最初はKERNEL32のfunctionです。
VirtualQuery()呼び出し時の実行内容 Microsoft (R) Windows Debugger Version 6.4.0004.4 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: D:\nativeapi\nativeapi64\Debug\nativeapi.exe Symbol search path is: SRV*C:\websymbols*http://msdl.microsoft.com/download/symbols Executable search path is: ModLoad: 00000000`00400000 00000000`0040f000 nativeapi.exe ModLoad: 00000000`77ea0000 00000000`77ff3000 ntdll.dll ModLoad: 00000000`77ce0000 00000000`77e92000 C:\WINDOWS\system32\kernel32.dll ModLoad: 00000000`77bc0000 00000000`77ccf000 C:\WINDOWS\system32\USER32.dll ModLoad: 000007ff`7fc80000 000007ff`7fd17000 C:\WINDOWS\system32\GDI32.dll (19c.6e8): Break instruction exception - code 80000003 (first chance) ntdll!DbgBreakPoint: 00000000`77ef4050 cc int 3 0:000> g ModLoad: 000007ff`7d3d0000 000007ff`7d409000 C:\WINDOWS\system32\IMM32.DLL ... 途中省略 ModLoad: 000007ff`7c550000 000007ff`7c654000 C:\WINDOWS\system32\USERENV.dll (19c.6e8): Break instruction exception - code 80000003 (first chance) ntdll!DbgBreakPoint: 00000000`77ef4050 cc int 3 0:000> t ntdll!DbgBreakPoint+0x1: 00000000`77ef4051 c3 ret 0:000> t *** WARNING: Unable to verify checksum for nativeapi.exe *** ERROR: Module load completed but symbols could not be loaded for nativeapi.exe nativeapi+0x12a8: 00000000`004012a8 41b830000000 mov r8d,0x30 0:000> t nativeapi+0x12ae: 00000000`004012ae 488d942440010000 lea rdx,[rsp+0x140] ss:00000000`0012fc20=fffff80000000000 0:000> t nativeapi+0x12b6: 00000000`004012b6 488b4c2430 mov rcx,[rsp+0x30] ss:00000000`0012fb10=0000000000000000 0:000> t nativeapi+0x12bb: 00000000`004012bb ff15976d0000 call qword ptr [nativeapi+0x8058 (0000000000408058)] ds:00000000`00408058=0000000077cec3e0 0:000> t kernel32!VirtualQuery: 00000000`77cec3e0 4883ec38 sub rsp,0x38 ... 途中省略 0:000> t kernel32!VirtualQuery+0x20: 00000000`77cec400 ff15ba51ffff call qword ptr [kernel32!_imp_NtQueryVirtualMemory (0000000077ce15c0)] ds:00000000`77ce15c0=0000000077ef2f90 0:000> t ntdll!ZwQueryVirtualMemory: 00000000`77ef2f90 4c8bd1 mov r10,rcx 0:000> t ntdll!ZwQueryVirtualMemory+0x3: 00000000`77ef2f93 b820000000 mov eax,0x20 0:000> t ntdll!ZwQueryVirtualMemory+0x8: 00000000`77ef2f98 0f05 syscall 0:000> t ntdll!ZwQueryVirtualMemory+0xa: 00000000`77ef2f9a c3 ret 0:000> t kernel32!VirtualQuery+0x26: 00000000`77cec406 85c0 test eax,eax
冒頭のModLoadの行を見ると、仮想アドレス空間にロードされているDLLのファイル名はWin32(ネイティブ)の場合と
同じであることがわかります。(混乱しそうですが、64-bit版WindowsでのNTDLL.DLL system32ディレクトリ内のKERNEL32.DLL GDI32.DLL USER32.DLL はすべて64ビットネイティブなDLLです。)KERNEL32のVirtualQuery()をコールするとNTDLLのZwQueryVirtualMemory()がコールされ、そこでsyscall命令を用いてカーネルモードへ移行しています。次はGDI32です。
Ellipse()呼び出し時の実行内容 Microsoft (R) Windows Debugger Version 6.4.0004.4 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: D:\nativeapi\nativeapi64\Debug\nativeapi.exe Symbol search path is: SRV*C:\websymbols*http://msdl.microsoft.com/download/symbols Executable search path is: ModLoad: 00000000`00400000 00000000`0040f000 nativeapi.exe ModLoad: 00000000`77ea0000 00000000`77ff3000 ntdll.dll ModLoad: 00000000`77ce0000 00000000`77e92000 C:\WINDOWS\system32\kernel32.dll ModLoad: 00000000`77bc0000 00000000`77ccf000 C:\WINDOWS\system32\USER32.dll ModLoad: 000007ff`7fc80000 000007ff`7fd17000 C:\WINDOWS\system32\GDI32.dll (708.348): Break instruction exception - code 80000003 (first chance) ntdll!DbgBreakPoint: 00000000`77ef4050 cc int 3 0:000> g ModLoad: 000007ff`7d3d0000 000007ff`7d409000 C:\WINDOWS\system32\IMM32.DLL ... 途中省略 ModLoad: 000007ff`7c550000 000007ff`7c654000 C:\WINDOWS\system32\USERENV.dll (708.348): Break instruction exception - code 80000003 (first chance) ntdll!DbgBreakPoint: 00000000`77ef4050 cc int 3 0:000> t ntdll!DbgBreakPoint+0x1: 00000000`77ef4051 c3 ret 0:000> t *** WARNING: Unable to verify checksum for nativeapi.exe *** ERROR: Module load completed but symbols could not be loaded for nativeapi.exe ... 途中省略 0:000> t nativeapi+0x139d: 00000000`0040139d ff155d6c0000 call qword ptr [nativeapi+0x8000 (0000000000408000)] ds:00000000`00408000=000007ff7fcd13c0 0:000> t GDI32!Ellipse: 000007ff`7fcd13c0 4883ec68 sub rsp,0x68 ... 途中省略 0:000> t GDI32!Ellipse+0x13c: 000007ff`7fcd14fc e85fbdfdff call GDI32!NtGdiEllipse (000007ff7fcad260) 0:000> t GDI32!NtGdiEllipse: 000007ff`7fcad260 4c8bd1 mov r10,rcx 0:000> t GDI32!ZwGdiEllipse+0x3: 000007ff`7fcad263 b888110000 mov eax,0x1188 0:000> t GDI32!ZwGdiEllipse+0x8: 000007ff`7fcad268 0f05 syscall 0:000> t GDI32!ZwGdiEllipse+0xa: 000007ff`7fcad26a c3 ret 0:000> t GDI32!Ellipse+0x13f: 000007ff`7fcd1501 4c8b6c2438 mov r13,[rsp+0x38] ss:00000000`0012faa8=0000000000000001
GDI32のEllipse()をコールすると、GDI32内のNtGdiEllipse()、ZwGdiEllipse()がコールされ(どちらもエントリーポイントは同じ)、ここで直接syscall命令を用いてカーネルモードへ移行します。(NTDLLのルーチンをコールしていない点に注意。)最後にUSER32です。
GetDC()呼び出し時の実行内容 Microsoft (R) Windows Debugger Version 6.4.0004.4 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: D:\nativeapi\nativeapi64\Debug\nativeapi.exe Symbol search path is: SRV*C:\websymbols*http://msdl.microsoft.com/download/symbols Executable search path is: ModLoad: 00000000`00400000 00000000`0040f000 nativeapi.exe ModLoad: 00000000`77ea0000 00000000`77ff3000 ntdll.dll ModLoad: 00000000`77ce0000 00000000`77e92000 C:\WINDOWS\system32\kernel32.dll ModLoad: 00000000`77bc0000 00000000`77ccf000 C:\WINDOWS\system32\USER32.dll ModLoad: 000007ff`7fc80000 000007ff`7fd17000 C:\WINDOWS\system32\GDI32.dll (2d4.56c): Break instruction exception - code 80000003 (first chance) ntdll!DbgBreakPoint: 00000000`77ef4050 cc int 3 0:000> g ModLoad: 000007ff`7d3d0000 000007ff`7d409000 C:\WINDOWS\system32\IMM32.DLL ... 途中省略 ModLoad: 000007ff`7c550000 000007ff`7c654000 C:\WINDOWS\system32\USERENV.dll (2d4.56c): Break instruction exception - code 80000003 (first chance) ntdll!DbgBreakPoint: 00000000`77ef4050 cc int 3 0:000> t ntdll!DbgBreakPoint+0x1: 00000000`77ef4051 c3 ret 0:000> t *** WARNING: Unable to verify checksum for nativeapi.exe *** ERROR: Module load completed but symbols could not be loaded for nativeapi.exe nativeapi+0x143c: 00000000`0040143c 488b8c24a0010000 mov rcx,[rsp+0x1a0] ss:00000000`0012fc80=00000000002901da 0:000> t nativeapi+0x1444: 00000000`00401444 ff15ce6d0000 call qword ptr [nativeapi+0x8218 (0000000000408218)] ds:00000000`00408218=0000000077be1e60 0:000> t USER32!ZwUserGetDC: 00000000`77be1e60 4c8bd1 mov r10,rcx 0:000> t USER32!ZwUserGetDC+0x3: 00000000`77be1e63 b80a100000 mov eax,0x100a 0:000> t USER32!ZwUserGetDC+0x8: 00000000`77be1e68 0f05 syscall 0:000> t USER32!ZwUserGetDC+0xa: 00000000`77be1e6a c3 ret 0:000> t nativeapi+0x144a: 00000000`0040144a 4889842470010000 mov [rsp+0x170],rax ss:00000000`0012fc50=000000000012fd88
USER32のZwUserGetDC()をコールすると、いくつかの処理をした後にsyscall命令を用いてカーネルモードへ移行します。(NTDLLのルーチンをコールしていない点に注意。)
起草日:2004年1月2日(日)(www.marbacka.net内の別のサイトで公開)
最終更新日:2017年2月19日(日)