Ⅰ. はじめに
タイトルの通り「Windowsでsyscallする方法」です。
この記事はWOW64を対象とした内容になっています。
x64向けはこちら
http://kagasu.hatenablog.com/entry/2018/01/03/200337
Ⅱ. 環境
Windows 10 64bit 1709
Ⅱ. サンプルプログラム
サンプルとしてNtWriteVirtualMemoryを呼び出す例です。
プラットフォームはx86としてコンパイルして下さい。
x64と指定すると __asmが使えない為コンパイルに失敗します。
#include <Windows.h> #include <iostream> __declspec(naked) NTSTATUS __stdcall NtWriteVirtualMemory(HANDLE processHandle, PVOID baseAddress, PVOID buffer, ULONG numberOfBytesToWrite, PDWORD numberOfBytesWritten) { __asm { mov eax, 0x3A mov edx, fs:[0xC0] call edx ret 0x14 } } int main() { auto x = 100; auto y = 999; std::cout << "x:" << x << std::endl; DWORD numBytesWritten = 0; NTSTATUS success = NtWriteVirtualMemory(GetCurrentProcess(), &x, &y, sizeof(y), &numBytesWritten); std::cout << "x:" << x << std::endl; return 0; }
Ⅲ. 実行結果
Ⅳ. 解説
ntdll.dllを逆アセンブルして、そのままインラインアセンブリ(__asm) で書いています。
1: __declspec(naked) NTSTATUS __stdcall NtWriteVirtualMemory(HANDLE processHandle, PVOID baseAddress, PVOID buffer, ULONG numberOfBytesToWrite, PDWORD numberOfBytesWritten) 2: { 3: __asm 4: { 5: mov eax, 0x3A 6: mov edx, fs:[0xC0] 7: call edx 8: ret 0x14 9: } 10: }
5行目について
Windows 10 64bit 1709の場合NtWriteVirtualMemory のsyscallインデックスは0x3Aです。
OSやOSのバージョンによって変わります。
以下のWebサイトにsyscallインデックスがまとまっています。
http://j00ru.vexillium.org/syscalls/nt/32/
http://j00ru.vexillium.org/syscalls/nt/64/
6行目について
Windows 64bitにはWOW64と呼ばれるサブシステムがあります。
WOW64の場合syscallのポインタはFS:[0xC0]に格納されています。
https://en.wikipedia.org/wiki/Win32_Thread_Information_Block
8行目について
__stdcallとして関数を作っているので引数20バイト(0x14)分のスタックを関数の終わりのretでずらす必要があります。
printf("%dバイト", sizeof(HANDLE) + sizeof(PVOID) + sizeof(PVOID) + sizeof(ULONG) + sizeof(PDWORD)); // 出力 // 20バイト