VMware Backdoor I/O port

つい先日VMwareバックドアI/Oポートという、GuestからHostマシンのちょっとした制御が出来る方法があるということを知ったのだが(参考)、実行にはIN/OUTのマシン語命令が必要ということで多分ユーザーランドのプログラムじゃ実行出来ねーんだろうなーと思いつつも試しにやってみたら出来てやんの。
(追記)参照先でもVMware Command Line Toolsというツールを提供していて、そいつも実行できるのならそりゃ出来るか・・


試しにやってみたコードは以下(VC++2005 Std.でコンパイル出来た)


#include "stdio.h"

/* デバイスの情報取得 */
int vm_getDeviceStatus(int dev_num, char* dev, int* stat)
{
int r_eax, r_ebx;
int i;

for (i = 0; i < 10; i++) {
r_ebx = (dev_num << 16) + i * 4;
__asm {
mov eax, 564D5868h
mov ebx, [r_ebx]
mov ecx, 0bh
mov edx, 5658h
in eax, dx
mov [r_eax], eax
mov [r_ebx], ebx
}
dev[i*4 + 0] = (r_ebx & 0x000000FF) >> 0;
dev[i*4 + 1] = (r_ebx & 0x0000FF00) >> 8;
dev[i*4 + 2] = (r_ebx & 0x00FF0000) >> 16;
dev[i*4 + 3] = (r_ebx & 0xFF000000) >> 24;
}
__asm {
mov eax, 564D5868h
mov ebx, 24h
mov ecx, 0bh
mov edx, 5658h
in eax, dx
mov [r_eax], eax
mov [r_ebx], ebx
}
*stat = r_ebx;
return r_eax;
}

/* デバイス接続・切断 */
int vm_setDeviceStatus(int dev_num, int on_off)
{
int r_eax, r_ebx;
r_ebx = (on_off*0x8000 << 16) + dev_num;
__asm {
mov eax, 564D5868h
mov ebx, [r_ebx]
mov ecx, 0ch
mov edx, 5658h
in eax, dx
mov [r_eax], eax
mov [r_ebx], ebx
}
return r_eax;
}

int main(int argc, char* argv[])
{
int stat, rc, i;
char dev[40];

for (i = 0; i < 52; i++) {
vm_getDeviceStatus(i, dev, &stat);
printf("dev:%d, name:%s, stat:%d\n", i, dev, stat);
}

/* 実験環境でNICと表示されたデバイスをオフラインに */
rc = vm_setDeviceStatus(1, 0);
printf("rc:%d\n", rc);

return 0;
}

手元の環境(VMware Workstation 6.0.4 / Guest:Windows Server 2003 SP1)で実行してみた結果は以下で、Administratorでない一般のユーザー権限でも実行可能。


dev:0, name:sound, stat:0
dev:1, name:Ethernet0, stat:0
dev:2, name:floppy0, stat:0
dev:3, name:ide1:0, stat:0
dev:4, name:, stat:0
dev:5, name:, stat:0
〜〜〜途中省略〜〜〜
dev:50, name:, stat:0
dev:51, name:, stat:0
rc:1

バイス接続状態の取得がちゃんと出来てないっぽいかな・・まあいいや。
最初はGuestマシンの電源落とさないと付け外しの出来ないSCSI HDDの制御がこれで出来ないかと思って調べ始めたのだけど、どうも上記の方法では制御できないらしい。
一般ユーザーがNICのON/OFF制御出来ちゃうのは不味いんじゃないのと思ったけど、良く考えるとVMware toolsを使っても出来る事か。そういえばESXiとかのサーバー版ではどうなってんだろ。