備忘録

備忘録

Windowsでsyscallする方法

Ⅰ. はじめに

タイトルの通り「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;
}

Ⅲ. 実行結果

f:id:kagasu:20171217171626p:plain

Ⅳ. 解説

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バイト