WOW64からのシステムコール概要 のまとめ
要点をコードで。Win7(RC)x64でのみ動くので、あくまで例示ということで。
まとめ1:eaxにシステムコール番号、ecxにディスパッチ関数番号を入れて、call dword ptr fs:[0C0h] するとWOW64からシステムコールを発行できる
このプログラムは、自分でWOW64のNtGetCurrentProcessorNumberを定義して実行する。
// call dword ptr fs:[0C0h] // add esp, 4 #define call_X86SwitchTo64BitMode \ __asm _emit 0x64 \ __asm _emit 0xff \ __asm _emit 0x15 \ __asm _emit 0xc0 \ __asm _emit 0x00 \ __asm _emit 0x00 \ __asm _emit 0x00 \ __asm add esp, 4 \ __declspec(naked) ULONG NtGetCurrentProcessorNumber() { __asm { mov eax, 0CBh mov ecx, 19h call_X86SwitchTo64BitMode ret } } int _tmain() { if (::IsDebuggerPresent()) __debugbreak(); SetProcessAffinityMask(GetCurrentProcess(), 1); std::cout << NtGetCurrentProcessorNumber() << std::endl; SetProcessAffinityMask(GetCurrentProcess(), 2); std::cout << NtGetCurrentProcessorNumber() << std::endl; return 0; }
0 1
まとめ2:0x33セグメントへのジャンプでx64モードに切り替わり、0x23セグメントへのジャンプでx86モードに切り替わる
このプログラムは、自力でx64へスイッチしてネイティブNtGetCurrentProcessorNumberを呼び出す。
// // Visual Studioのデバッガでは追いかけることができないです。WinDbgをつかってね // int _tmain() { BYTE x86SwitchTo64BitModeCode[] = { 0xea, 0xff, 0xff, 0xff, 0xff, 0x33, 0x00, // jmp 0033h:ffffffffh (オフセット部は実行時に書き換え) }; BYTE x64SwitchTo32BitModeCode[] = { 0x90, // nop (or int 3) 0xb8, 0xcb, 0x00, 0x00, 0x00, // mov eax,0CBh (ntdll!NtGetCurrentProcessorNumber) 0x0f, 0x05, // syscall 0x41, 0xc7, 0x46, 0x04, 0x23, 0x00, 0x00, 0x00, // mov dword ptr [r14+4], 23h 0x41, 0xc7, 0x46, 0x00, 0xff, 0xff, 0xff, 0xff, // mov dword ptr [r14], ffffffffh (オフセット部は実行時に書き換え) 0x41, 0xff, 0x2e, // jmp fword ptr [r14] }; BYTE x86ReturnCode[] = { 0xc3, }; // ret if (::IsDebuggerPresent()) __debugbreak(); BOOL result = FALSE; DWORD old_protect = 0; // スタブにするアドレスを取得 // スタックやヒープからコードを実行するのもあれなので // ここはアグレッシブにAPIコードを書き換えてそれを実行してみる(破壊的) FARPROC x86Return = GetProcAddress(GetModuleHandle(_T("kernel32")), "GetEnvironmentStringsA"); FARPROC x86SwitchTo64BitMode = GetProcAddress(GetModuleHandle(_T("kernel32")), "GetEnvironmentStringsW"); FARPROC x64SwitchTo32BitMode = GetProcAddress(GetModuleHandle(_T("kernelbase")), "GetEnvironmentStringsW"); // ちゃんと取得できていて、かつ重複していないこと _ASSERT(x86Return && x86SwitchTo64BitMode && x64SwitchTo32BitMode && x86Return != x86SwitchTo64BitMode && x86Return != x64SwitchTo32BitMode && x86SwitchTo64BitMode != x64SwitchTo32BitMode); // コードのオフセット部を構築 memcpy(&x86SwitchTo64BitModeCode[1], &x64SwitchTo32BitMode, sizeof(x64SwitchTo32BitMode)); memcpy(&x64SwitchTo32BitModeCode[20], &x86Return, sizeof(x86Return)); // x64へのジャンプコードを書き込み result = VirtualProtect(x86SwitchTo64BitMode, sizeof(x86SwitchTo64BitModeCode), PAGE_EXECUTE_READWRITE, &old_protect); memcpy(x86SwitchTo64BitMode, x86SwitchTo64BitModeCode, sizeof(x86SwitchTo64BitModeCode)); result = VirtualProtect(x86SwitchTo64BitMode, sizeof(x86SwitchTo64BitModeCode), old_protect, &old_protect); std::cout << "x86 to x64 code: (" << x86SwitchTo64BitMode << "h)\n" << " : jmp 0x0033:" << x64SwitchTo32BitMode << "h\n"; // x86へのジャンプコードを書き込み result = VirtualProtect(x64SwitchTo32BitMode, sizeof(x64SwitchTo32BitModeCode), PAGE_EXECUTE_READWRITE, &old_protect); memcpy(x64SwitchTo32BitMode, x64SwitchTo32BitModeCode, sizeof(x64SwitchTo32BitModeCode)); result = VirtualProtect(x64SwitchTo32BitMode, sizeof(x64SwitchTo32BitModeCode), old_protect, &old_protect); std::cout << "x64 to x86 code: (" << x64SwitchTo32BitMode << "h)\n" << " : nop ; or int 3h\n" << " : mov eax,0CBh ; ntdll!NtGetCurrentProcessorNumber\n" << " : syscall\n" << " : mov dword ptr [r14+4], 23h\n" << " : mov dword ptr [r14], " << x86Return << "h\n" << " : jmp fword ptr [r14]\n"; // callしてx64へいくのでx86に戻ってきたときにretを result = VirtualProtect(x86Return, sizeof(x86ReturnCode), PAGE_EXECUTE_READWRITE, &old_protect); memcpy(x86Return, x86ReturnCode, sizeof(x86ReturnCode)); result = VirtualProtect(x86Return, sizeof(x86ReturnCode), old_protect, &old_protect); std::cout << "x86 ret code : (" << x86Return << "h)\n" << " : ret\n"; SetProcessAffinityMask(GetCurrentProcess(), 1); // x64にいってネイティブのNtGetCurrentProcessorNumberを呼んでくるでござる! if (::IsDebuggerPresent()) __debugbreak(); DWORD CurrentProcessorNumber1 = x86SwitchTo64BitMode(); if (::IsDebuggerPresent()) __debugbreak(); SetProcessAffinityMask(GetCurrentProcess(), 2); DWORD CurrentProcessorNumber2 = x86SwitchTo64BitMode(); std::cout << CurrentProcessorNumber1 << "\n" << CurrentProcessorNumber2 << std::endl; return 0; }
出力。
x86 to x64 code: (756C5849h) : jmp 0x0033:74CADD77h x64 to x86 code: (74CADD77h) : nop ; or int 3h : mov eax,0CBh ; ntdll!NtGetCurrentProcessorNumber : syscall : mov dword ptr [r14+4], 23h : mov dword ptr [r14], 756CF360h : jmp fword ptr [r14] x86 ret code : (756CF360h) : ret 0 1
; 1 kernel32!GetEnvironmentStringsWStub: 756c5849 ea77ddca743300 jmp 0033:74CADD77 ; 2(ここでx64になってる) KERNELBASE!GetEnvironmentStringsW: 00000000`74cadd77 90 nop 00000000`74cadd78 b8cb000000 mov eax,0CBh 00000000`74cadd7d 0f05 syscall 00000000`74cadd7f 41c7460423000000 mov dword ptr [r14+4],23h 00000000`74cadd87 41c7460060f36c75 mov dword ptr [r14],offset kernel32!GetEnvironmentStrings (00000000`756cf360) 00000000`74cadd8f 41ff2e jmp fword ptr [r14] ; 3(x86にもどってる) kernel32!GetEnvironmentStrings: 756cf360 c3 ret
おk(ただし地味)