SlideShare a Scribd company logo
Backdoor !!
vmware-tools と 統合サービスに見るハイパーバイザの呼び出し方
2010/4/12
VTCライトニングトーク発表内容
しろやまたかゆき<shiro.t@gmail.com>
Hypercall とは?
l ゲストOS からハイパーバイザを明示的に呼び出す方法
l Binary Translation や VMEXIT/VMRESUME に比べコストが低い
l 呼び出し方法が低コスト
l ハイパーバイザに都合のいいデータのやり取りが可能
l 準仮想化された OS で使用されている
l Xen 対応の Linux カーネルなど
Xen での Hypercall の実装
l 単純に int 命令でソフトウェア割り込みをかけているだけ
l Ring0 の Xen hyper-visor が割り込みをキャッチし、指定のルーチンを
呼び出している
http://www.ylug.jp/download/hypercall_ylug_20061027.pdf
Hypercall は準仮想化だけのもの?
l いえ、類似/同等の機能は完全仮想化のハイパーバイザにもあります!
l 性能上の理由
l Binary Translation や VMEXIT/VMRESUME に比べコストが低い
l 仮想化ならではの機能の実現
l VM間 / VM-Hypervisor 間の通信や制御 (VMCI)
例: VMCI
int a, s, len;
char buf[255];
struct sockaddr_vm addr = { 0 };
s = socket(PF_VSOCK_VMCI, SOCK_STREAM, 0);
addr.svm_family = AF_VSOCK_VMCI;
addr.svm_cid = VMADDR_CID_ANY;
addr.svm_rid = 2000;
bind(s, (struct sockaddr *) &addr, sizeofaddr);
listen(s, 5);
a = accept(s, (struct sockaddr *) &addr, &len);
len = recv(a, buf, sizeof buf, 0);
int a, s, len;
char *buf = “Hello, world!”;
struct sockaddr_vm addr = { 0 };
s = socket(PF_VSOCK_VMCI, SOCK_STREAM, 0);
addr.svm_family = AF_VSOCK_VMCI;
addr.svm_cid = GUEST2;
addr.svm_rid = 2000;
connect(s, (struct sockaddr *) &addr, sizeof addr);
len = send(s, buf, len, 0);
基本はソケットプログラミング
通常のPF_INETの代わりに
PF_VSOCK_VMCIに変更。
読み書き(send/recv)は変わらず
Hyper-­visor
Application
Guest  OS
仮想マシン
Application
Guest  OS
仮想マシン
Server
Client
ESX / Hyper-V の Hypercall
l では、ESX / Hyper-V の Hypercall って どうやってるの?
ソースコードにきいてみよう!
VMware の場合: open-vm-tools
Open Virtual Machine Tools
l vmware-tools のソースコードは公開されている (2007.9.4~)
l Linux, FreeBSD, Solaris 用
l vmsync など、標準の VMware Tools にないモジュールも存在
http://open-­vm-­tools.sourceforge.net/
Microsoft の場合
l Hyper-V の統合サービス(Linux向け)のソースコードを公開!(2009.7.21)
l これを読めば Hyper-V の hypercall も解明できる?
で、どうやってダウンロードすればいいの?
l MS のサイトを漁りまわったけどソースコードを発見できず!!
l 公開を報じる国内記事は多々あれど、ソースそのもののリンクはどこにもない
l 駄目ぢゃん、っと思ってたら...
で、どうやってダウンロードすればいいの?
l Linux-Kernel ML に Greg-KH 氏が投稿していた
l パッチを 54 分割して...
l 何とか苦労して取り出しました
l 最近のカーネルソースには既に含まれている模様
ソースツリー: open-vm-tools の場合
l open-vm-tools
l 綺麗な階層構造、Makfile 完備
l さまざまなOSでのビルドを前提としている
l コード数、約24万行
- 「find –name ‘*.[ch]’ -print0 | xargs -0 wc –l 」の実行結果より
ソースツリー: open-vm-tools の場合
l open-vm-tools の階層構造
+-­-­ autom4te.cache/
+-­-­ checkvm/
+-­-­ config/
+-­-­ docs/
+-­-­ hgfsclient/
+-­-­ hgfsmounter/
+-­-­ lib/
+-­-­ libguestlib/
+-­-­ libvmtools/
+-­-­ m4/
+-­-­ modules/
|      +-­-­ freebsd/
|      +-­-­ linux/
|      +-­-­ solaris/
+-­-­ rpctool/
+-­-­ scripts/
+-­-­ services/
|      +-­-­ plugins/
||      +-­-­ vmtoolsd/
+-­-­ tests/
+-­-­ toolbox/
+-­-­ vmblock-­fuse/
+-­-­ vmware-­user/
+-­-­ vmware-­user-­suid-­wrapper/
+-­-­ xferlogs/  
|      +-­-­ linux/
|      |      +-­-­ pvscsi/
|      |      +-­-­ shared/
|      |      +-­-­ vmblock/
|      |      +-­-­ vmci/
|      |      +-­-­ vmhgfs/
|      |      +-­-­ vmmemctl/
|      |      +-­-­ vmsync/
|      |      +-­-­ vmxnet/
|      |      +-­-­ vsock/
独自のツリー構造
多くのOSに対応
共通化モジュール、ユーザランドツール、
ドライバなど綺麗に分離されている
ソースツリー: Hyper-V の場合
l linux integration component
l linux-kernel に対するパッチで、Linux にべったりの構造
- カーネルパッチだけ?ユーザランドに何もない??
l driver/staging/hv 以下に集中配置
l 約2万行
ソースツリー: Hyper-V の場合
ファイル一覧
BlkVsc.c HvVpApi.h Vmbus.c
Channel.c Kconfig VmbusApi.h
Channel.h List.h VmbusChannelInterface.h
ChannelInterface.c Makefile VmbusPacketFormat.h
ChannelInterface.h Makefile.rej VmbusPrivate.h
ChannelMessages.h NetVsc.c blkvsc_drv.c
ChannelMgmt.c NetVsc.h hv.diff
ChannelMgmt.h NetVscApi.h logging.h
Connection.c RingBuffer.c netvsc_drv.c
Hv.c RingBuffer.h nvspprotocol.h
Hv.h RndisFilter.c osd.c
HvHalApi.h RndisFilter.h osd.h
HvHcApi.h Sources.c rndis.h
HvPtApi.h StorVsc.c storvsc_drv.c
HvStatus.h StorVscApi.h vmbus.h
HvSynicApi.h TODO vmbus_drv.c
HvTypes.h VersionInfo.h vstorage.h
Linux への侵食方法:VMware の場合
あくまで「物理デバイスに対するドライバ」の立場
l VMware-tools の有無に関わらず、仮想デバイスが存在する前提
l PCIバス上にデバイスがつながっているように見える
l PCIバスのデバイス検出手順に従い、ドライバがロードされていく
l VendorID: 0x15AD で、指定
の DeviceID をもつドライバが
選定される
l 選定されたドライバのprobe 関数を
実行して、本当に対応するデバイスか
を確認させる
l 失敗が帰ったら、次の候補となる
ドライバを探す
/* Our own PCI IDs
* VMware SVGA II (Unified VGA)
* VMware SVGA (PCI Accelerator)
* VMware vmxnet (Idealized NIC)
* VMware vmxscsi (Abortive idealized SCSI controller)
* VMware chipset (Subsystem ID for our motherboards)
* VMware e1000 (Subsystem ID)
* VMware vmxnet3 (Uniform Pass Through NIC)
*/
#define PCI_VENDOR_ID_VMWARE 0x15AD
#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710
#define PCI_DEVICE_ID_VMWARE_NET 0x0720
#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730
#define PCI_DEVICE_ID_VMWARE_VMCI 0x0740
#define PCI_DEVICE_ID_VMWARE_CHIPSET 0x1976
#define PCI_DEVICE_ID_VMWARE_82545EM 0x0750 /* single port */
#define PCI_DEVICE_ID_VMWARE_82546EB 0x0760 /* dual port */
#define PCI_DEVICE_ID_VMWARE_EHCI 0x0770
#define PCI_DEVICE_ID_VMWARE_UHCI 0x0774
#define PCI_DEVICE_ID_VMWARE_XHCI 0x0778
#define PCI_DEVICE_ID_VMWARE_1394 0x0780
#define PCI_DEVICE_ID_VMWARE_BRIDGE 0x0790
#define PCI_DEVICE_ID_VMWARE_ROOTPORT 0x07A0
#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0
#define PCI_DEVICE_ID_VMWARE_VMXWIFI 0x07B8
#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0
#define PCI_DEVICE_ID_VMWARE_82574 0x07D0
lib/include/vm_device_version.h  より
Linux への侵食方法:VMware の場合
余談: vmxnet の Morphing
l ESX 2.x では、vlance と vmxnet は区別されてました
l vlance vendorID: 0x1022(AMD) deviceID: 0x2000
l vmxnet vendorID: 0x15AD(VMware) deviceID: 0x0720
l ESX 3.x 以降で、vlance -> vmxnet の入れ替えしました?
Linux への侵食方法:VMware の場合
余談: vmxnet の Morphing
l ESX 3.x 以降の vlance は、vmxnet を「兼用」している
l たまたま、AMD-PCNET が 32byte しか IO空間を使ってなかった点を利用
l 64byte まで取れるIO空間の後ろ32byte に vmxnet の IO空間を追加
/*
* Since this is a vlance adapter we can only use it if
* its I/0 space is big enough for the adapter to be
* capable of morphing. This is the first requirement
* for this adapter to potentially be morphable. The
* layout of a morphable LANCE adapter is
*
* I/O space:
*
* |------------------|
* | LANCE IO PORTS |
* |------------------|
* | MORPH PORT |
* |------------------|
* | VMXNET IO PORTS |
* |------------------|
*
* VLance has 8 ports of size 4 bytes, the morph port is 4 bytes, and
* Vmxnet has 10 ports of size 4 bytes.
*
* We shift up the ioaddr with the size of the LANCE I/O space since
* we want to access the vmxnet ports. We also shift the ioaddr up by
* the MORPH_PORT_SIZE so other port access can be independent of
* whether we are Vmxnet or a morphed VLance. This means that when
* we want to access the MORPH port we need to subtract the size
* from ioaddr to get to it.
*/
Linux への侵食方法:VMware の場合
余談: vmxnet の Morphing
l vmxnet ドライバの probe 関数(vmxnet_probe_device)の挙動
l PCI の Vendor ID を取得
- 0x15AD (VMware) なら、そのまま vmxnet デバイスと判断
• 旧 vmxnet との互換性の確保
- 0x1022 (AMD) の場合
• IO空間のサイズを取得し、64byte とサイズを比較
• それより小さかったら? 「うちの子じゃない」 で probe に失敗を返す
• 64byte 以上なら、「うちの子だから」と認定
• morph port に outw で値を書き込み、vmxnet として振舞わせる
Linux への侵食方法:VMware の場合
static int
vmxnet_morph_device(unsigned int morphAddr) // IN
{
uint16 magic;
/* Read morph port to verify that we can morph the adapter. */
magic = inw(morphAddr);
if (magic != LANCE_CHIP && magic != VMXNET_CHIP) {
printk(KERN_ERR "Invalid magic, read: 0x%08X¥n", magic);
return -1;
}
/* Morph adapter. */
outw(VMXNET_CHIP, morphAddr);
/* Verify that we morphed correctly. */
magic = inw(morphAddr);
if (magic != VMXNET_CHIP) {
printk(KERN_ERR "Couldn't morph adapter. Invalid magic, read: 0x%08X¥n",
magic);
goto morph_back;
}
return 0;
morph_back:
/* Morph back to LANCE hw. */
outw(LANCE_CHIP, morphAddr);
return -1;
}
VMM
Linux への侵食方法:VMware の場合
l あくまで正規のデバイスドライバとしてロードされる
l 比較的、物理デバイスに近いエミュレーションがなされている
l Backdoor を使ってデバイスエミュレーションをある程度「バイパス」する
Linux  kernel
vmxnet_drv VGA LSILogic
NIC VGA SCSI
VendorID:  xxxx
DeviceID  :  xxxx
VendorID:  xxxx
DeviceID  :  xxxx
VendorID:  xxxx
DeviceID  :  xxxx
PCI  バス Backdoor
vmsync
vmUser
vmmemctl
VMkernel
vmtools   提供ドライバ
ネイティブドライバ
Backdoor : IO空間の in/out 命令
l VMware の Backdoor は、指定のIO空間への in /out 命令
l in / out : x86 のもつ IO 空間へのデータの読み書きの命令
l NICなどの一般的なデバイスは IO空間の一部を通じてデータをやり取りする
- グラフィックカードなどのより大きな空間を必要とするものは、メモリ空間
にマップされる
- PCI は IO空間 / メモリマップのどちらの方法もサポートする
l VMware ではこの in / out 命令を転用している
l 詳細: http://chitchat.at.infoseek.co.jp/vmware/backdoorj.html
Backdoor : IO空間の in/out 命令
static  void
BalloonTimerHandler(void  *clientData)  //  IN
{
Balloon  *b  =  (Balloon  *)  clientData;;
uint32  target  =  0;;  //  Silence  compiler  warning.
int  status;;
/*  update  stats  */
STATS_INC(b-­>stats.timer);;
/*  reset,  if  specified  */
if  (b-­>resetFlag)  {
BalloonReset(b);;
}
/*  contact  monitor  via  backdoor  */
status  =  BalloonMonitorGetTarget(b,  &target);;
/*  decrement  slowPageAllocationCycles  counter  */
if  (b-­>slowPageAllocationCycles  >  0)  {
b-­>slowPageAllocationCycles-­-­;;
}
if  (status  ==  BALLOON_SUCCESS)  {
/*  update  target,  adjust  size  */
b-­>nPagesTarget  =  target;;
(void)  BalloonAdjustSize(b,  target);;
}
}
Backdoor : IO空間の in/out 命令
static  void
BalloonTimerHandler(void  *clientData)  //  IN
{
Balloon  *b  =  (Balloon  *)  clientData;;
uint32  target  =  0;;  //  Silence  compiler  warning.
int  status;;
/*  update  stats  */
STATS_INC(b-­>stats.timer);;
/*  reset,  if  specified  */
if  (b-­>resetFlag)  {
BalloonReset(b);;
}
/*  contact  monitor  via  backdoor  */
status  =  BalloonMonitorGetTarget(b,  &target);;
/*  decrement  slowPageAllocationCycles  counter  */
if  (b-­>slowPageAllocationCycles  >  0)  {
b-­>slowPageAllocationCycles-­-­;;
}
if  (status  ==  BALLOON_SUCCESS)  {
/*  update  target,  adjust  size  */
b-­>nPagesTarget  =  target;;
(void)  BalloonAdjustSize(b,  target);;
}
}
static  int
BalloonMonitorGetTarget(Balloon  *b,          //  IN
uint32  *target)  //  OUT
{
Backdoor_proto  bp;;
unsigned  long  limit;;
uint32  limit32;;
uint32  status;;
limit  =  OS_ReservedPageGetLimit();;
/*  Ensure  limit  fits  in  32-­bits  */
limit32  =  (uint32)limit;;
if  (limit32  !=  limit)  {
return  BALLOON_FAILURE;;
}
/*  prepare  backdoor  args  */
bp.in.cx.halfs.low  =  BALLOON_BDOOR_CMD_TARGET;;
bp.in.size  =  limit;;
/*  invoke  backdoor  */
Backdoor_Balloon(&bp);;
/*  parse  return  values  */
status    =  bp.out.ax.word;;
*target  =  bp.out.bx.word;;
Backdoor : IO空間の in/out 命令
static  void
BalloonTimerHandler(void  *clientData)  //  IN
{
Balloon  *b  =  (Balloon  *)  clientData;;
uint32  target  =  0;;  //  Silence  compiler  warning.
int  status;;
/*  update  stats  */
STATS_INC(b-­>stats.timer);;
/*  reset,  if  specified  */
if  (b-­>resetFlag)  {
BalloonReset(b);;
}
/*  contact  monitor  via  backdoor  */
status  =  BalloonMonitorGetTarget(b,  &target);;
/*  decrement  slowPageAllocationCycles  counter  */
if  (b-­>slowPageAllocationCycles  >  0)  {
b-­>slowPageAllocationCycles-­-­;;
}
if  (status  ==  BALLOON_SUCCESS)  {
/*  update  target,  adjust  size  */
b-­>nPagesTarget  =  target;;
(void)  BalloonAdjustSize(b,  target);;
}
}
static  int
BalloonMonitorGetTarget(Balloon  *b,          //  IN
uint32  *target)  //  OUT
{
Backdoor_proto  bp;;
unsigned  long  limit;;
uint32  limit32;;
uint32  status;;
limit  =  OS_ReservedPageGetLimit();;
/*  Ensure  limit  fits  in  32-­bits  */
limit32  =  (uint32)limit;;
if  (limit32  !=  limit)  {
return  BALLOON_FAILURE;;
}
/*  prepare  backdoor  args  */
bp.in.cx.halfs.low  =  BALLOON_BDOOR_CMD_TARGET;;
bp.in.size  =  limit;;
/*  invoke  backdoor  */
Backdoor_Balloon(&bp);;
/*  parse  return  values  */
status    =  bp.out.ax.word;;
*target  =  bp.out.bx.word;;
static  INLINE
void  Backdoor_Balloon(Backdoor_proto  *myBp)  {
myBp-­>in.ax.word  =  BALLOON_BDOOR_MAGIC;;
myBp-­>in.dx.halfs.low  =  BALLOON_BDOOR_PORT;;
Backdoor_InOut(myBp);;
}
Backdoor : IO空間の in/out 命令
Backdoor_InOut(Backdoor_proto *myBp) // IN/OUT
{
uint32 dummy;
__asm__ __volatile__(
#ifdef __PIC__
"pushl %%ebx" "¥n¥t"
#endif
"pushl %%eax" "¥n¥t"
"movl 20(%%eax), %%edi" "¥n¥t"
"movl 16(%%eax), %%esi" "¥n¥t"
"movl 12(%%eax), %%edx" "¥n¥t"
"movl 8(%%eax), %%ecx" "¥n¥t"
"movl 4(%%eax), %%ebx" "¥n¥t"
"movl (%%eax), %%eax" "¥n¥t"
"inl %%dx, %%eax" "¥n¥t"
"xchgl %%eax, (%%esp)" "¥n¥t"
"movl %%edi, 20(%%eax)" "¥n¥t"
"movl %%esi, 16(%%eax)" "¥n¥t"
"movl %%edx, 12(%%eax)" "¥n¥t"
"movl %%ecx, 8(%%eax)" "¥n¥t"
"movl %%ebx, 4(%%eax)" "¥n¥t"
"popl (%%eax)" "¥n¥t"
#ifdef __PIC__
"popl %%ebx" "¥n¥t"
#endif
: "=a" (dummy)
: "0" (myBp)
/*
* vmware can modify the whole VM state without the compiler knowing
* it. So far it does not modify EFLAGS. --hpreg
*/
:
#ifndef __PIC__
"ebx",
#endif
"ecx", "edx", "esi", "edi", "memory"
);
}
この inl 命令の実行した瞬間に
VMkernel 側に処理が渡り、該当する
機能が実行され、結果が vCPU の
EAX 、ECX 、 EDX 、 ESI、EDI レジスタ
に書き込まれる
Hyper-V のドライバイメージ
l Hyper-V の場合は、デバイスではなく「バス」を追加している
l PCI バスの下に、なんかバスがある...
l なんかバスが「外」に伸びてるっぽい...
VMM
Linux  kernel
レガシNIC VGA IDE
VendorID:  xxxx
DeviceID  :  xxxx
VendorID:  xxxx
DeviceID  :  xxxx
VendorID:  xxxx
DeviceID  :  xxxx
PCI  バス
ネイティブドライバ
21140 VGA IDE
VMBUS
Backdoor
vmbus_drv
netvsc_drv storage_drv
NIC SCSI
Hyper-­V
ParentVM
Hyper-V のドライバイメージ
l Hyper-V の場合は、デバイスではなく「バス」を追加している
l PCI バスの下に、なんかバスがある...
l なんかバスが「外」に伸びてるっぽい...
Linux の侵食方法 : Hyper-V の場合
l とにかく vmbus_drv デバイスドライバをロードする
l VMBUS という何らかの「バス」があると Linux に誤認させる
l VMBUS も、PCI と同じようにバス上のノードの検出を行う
- VendorID と Device ID ではなく、ClassID という GUID で識別
- ノードごと、netvsc_drv, storagevsc_drv, blkvsc_drv がロードされる
• VSC : Virtualization Service Client の略
l 各 VSC はデバイスドライバだが、その下にはエミュレーションされたデバイス
はまったく存在しない!!
Linux の侵食方法 : Hyper-V の場合
http://enterprise.watch.impress.co.jp/cda/parts/image_for_link/41502-­13748-­4-­1.html
本当にこの通りでした...
Linux の侵食方法 : Hyper-V の場合
もう少し詳しい 階層構造
l 大きく4層に分かれる
l *_drv : Linux のデバイスドライバ(カーネルモジュール)としての体裁を整える
l Vsc, Vmbus : 各ドライバの実態となる実装
l Channel, Connection : VMBUS の通信機能の実装
l osd : メモリ確保など
OS機能の抽象化
l Hv : Hyper-V との
実際のインターフェイス
Linux  kernel
osd
VMM
Vmbus
vmbus_drvstoragevsc_drvnetvsc_drv blcvsc_drv
Hv
Channel
Connection
Channel  Mgmt
StorVscNetVsc BlcVsc
Linux  Kernel  とのインターフェイス
ドライバー中心部分
VMBUS  通信機能
Backdoor : そのメモリに触ると...
Hyper-V のバックドアは特定のメモリアドレス
l Hv はロードされると以下の振る舞いをする
l CPUID 命令を実行し、Hyper-V の上かを確認する
- CPUID(1) の ECXの31bit 目を確認
l 続けて CPUID 命令を実行し、ハイパーバイザのベンダー(!)や
バージョンを取得する
l メモリを1ページ確保する
- これは通常の valloc が使用され、実行時により異なるページが
割り当てられる
l wmsr でそのメモリの物理アドレスを vCPU に書き込む(!)
- MSR: Model Specific Register
• PentiumPro 以降のCPUにある、製品独自の設定を保存したり、
プロファイリング用のカウンタとなるレジスタ
• 詳細: http://mcn.oops.jp/wiki/index.php?CPU%2FCPUID%2FMSR
l 以降、Hypercall はこのメモリへのアクセスすると、Hypercall が発生する
Backdoor : Hv初期化部分、Hyper-V 上かを確認
Name:
HvQueryHypervisorPresence()
Description:
Query the cpuid for presense of windows hypervisor
--*/
static int
HvQueryHypervisorPresence (
void
)
{
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
unsigned int op;
eax = 0;
ebx = 0;
ecx = 0;
edx = 0;
op = HvCpuIdFunctionVersionAndFeatures;
do_cpuid(op, &eax, &ebx, &ecx, &edx);
return (ecx & HV_PRESENT_BIT);
}
Backdoor : Hv初期化部分、Hyper-V 上かを確認
Name:
HvQueryHypervisorPresence()
Description:
Query the cpuid for presense of windows hypervisor
--*/
static int
HvQueryHypervisorPresence (
void
)
{
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
unsigned int op;
eax = 0;
ebx = 0;
ecx = 0;
edx = 0;
op = HvCpuIdFunctionVersionAndFeatures;
do_cpuid(op, &eax, &ebx, &ecx, &edx);
return (ecx & HV_PRESENT_BIT);
}
typedef enum _HV_CPUID_FUNCTION
{
HvCpuIdFunctionVersionAndFeatures = 0x00000001,
HvCpuIdFunctionHvVendorAndMaxFunction = 0x40000000,
HvCpuIdFunctionHvInterface = 0x40000001,
//
// The remaining functions depend on the value of HvCpuIdFunctionInterface
//
HvCpuIdFunctionMsHvVersion = 0x40000002,
HvCpuIdFunctionMsHvFeatures = 0x40000003,
HvCpuIdFunctionMsHvEnlightenmentInformation = 0x40000004,
HvCpuIdFunctionMsHvImplementationLimits = 0x40000005
} HV_CPUID_FUNCTION, *PHV_CPUID_FUNCTION;
Backdoor : Hv初期化部分、Hyper-V 上かを確認
Name:
HvQueryHypervisorPresence()
Description:
Query the cpuid for presense of windows hypervisor
--*/
static int
HvQueryHypervisorPresence (
void
)
{
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
unsigned int op;
eax = 0;
ebx = 0;
ecx = 0;
edx = 0;
op = HvCpuIdFunctionVersionAndFeatures;
do_cpuid(op, &eax, &ebx, &ecx, &edx);
return (ecx & HV_PRESENT_BIT);
}
static inline void do_cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx,
unsigned int *edx)
{
__asm__ __volatile__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) : "0" (op),
"c" (ecx));
}
Backdoor : Hv初期化部分、Hyper-V 上かを確認
Name:
HvQueryHypervisorPresence()
Description:
Query the cpuid for presense of windows hypervisor
--*/
static int
HvQueryHypervisorPresence (
void
)
{
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
unsigned int op;
eax = 0;
ebx = 0;
ecx = 0;
edx = 0;
op = HvCpuIdFunctionVersionAndFeatures;
do_cpuid(op, &eax, &ebx, &ecx, &edx);
return (ecx & HV_PRESENT_BIT);
}
//
// #defines
//
#define HV_PRESENT_BIT 0x80000000
Backdoor : Hv初期化部分、Hyper-V 上かを確認
Hyper-V 上の仮想マシンでの
CPUID 。確かに ECX の31bit目が
立っている
ESX上の仮想マシン
31bit 目は立っていない
0x8C082201
0x80000000
0x80000000
OR
0x00080201
0x80000000
0x00000000
OR
Backdoor : Hv初期化部分、アクセス用のアドレスを設定
if  (gHvContext.GuestId  ==  HV_LINUX_GUEST_ID)
{
//  Allocate  the  hypercall  page  memory
//virtAddr  =  PageAlloc(1);;
virtAddr  =  VirtualAllocExec(PAGE_SIZE);;
if  (!virtAddr)
{
DPRINT_ERR(VMBUS,  "unable  to  allocate  hypercall  page!!");;
goto  Cleanup;;
}
hypercallMsr.Enable  =  1;;
//hypercallMsr.GuestPhysicalAddress  =  Logical2PhysicalAddr(virtAddr)  >>  PAGE_SHIFT;;
hypercallMsr.GuestPhysicalAddress  =  Virtual2Physical(virtAddr)  >>  PAGE_SHIFT;;
WriteMsr(HV_X64_MSR_HYPERCALL,  hypercallMsr.AsUINT64);;
//  Confirm  that  hypercall  page  did  get  setup.
hypercallMsr.AsUINT64  =  0;;
hypercallMsr.AsUINT64  =  ReadMsr(HV_X64_MSR_HYPERCALL);;
if  (!hypercallMsr.Enable)
{
DPRINT_ERR(VMBUS,  "unable  to  set  hypercall  page!!");;
goto  Cleanup;;
}
gHvContext.HypercallPage  =  virtAddr;;
osd.c にて定義。単に __valloc を
呼び出しているのみ。
単なるメモリ確保のため、どのアドレスが
変えるかは実行依存の模様
仮想アドレスを物理アドレスに書き換えた後、
CPU の MSR レジスタにアドレスを書き込む
Backdoor : Hypercall の実際
static u64
HvDoHypercall (
u64 Control,
void* Input,
void* Output
)
{
#ifdef CONFIG_X86_64
u64 hvStatus=0;
u64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0;
u64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0;
volatile void* hypercallPage = gHvContext.HypercallPage;
DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p output phys %llx virt %p hypercall %p>",
Control,
inputAddress,
Input,
outputAddress,
Output,
hypercallPage);
__asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress): "r8");
__asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage));
DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus);
return hvStatus;
RCXに命令コードを、RDX に入力データのアドレスを
突っ込んだ後、hypercallPage に call でジャンプし、
Hypercall を行っている (コールゲート?)
Backdoor : そのメモリに触ると...
l 割り込み、どうするのん?
l VMware の場合、各デバイスは PCI 上のデバイスのため、PCIバスを通じて
個々のデバイスが (ゲスト)OSへ 割り込みをかけることができた
- = VMM 側からゲストOSにデータを投げることができた
l Hyper-V の場合は?
l Linux Intergrated Module では、 IRQ 5 を VMBUS の割り込みとして使用
余談: なぜ、Hyper-V の起動ディスクは IDE only なのか
l VMBUS がないと統合モジュールが動かないため
l OS ロード前は、VMBUS などというバスを認識できない
l そもそも 仮想マシンの上の BIOS レベルで VMBUS ドライバを実装する必要
l OS ロード後なら、追加的に VMBUS をロードできる
まとめ
l 同じハイパーバイザ型の 仮想化ソフトウェアでも、Hypercall の
方法は各社各様
l 意外ときっちり実装している ESX の VMM
l vmxnet ドライバも割と普通に IO 処理を行っている
l 物理とは大きく異なる Hyper-V の VMM
l エミュレートされたデバイスとは別に、本当に架空のデバイスを生成
l VMBUS という架空のバスを通じて架空のデバイスを接続
l 原理的に、morphing はできない。
- エミュレートデバイスと架空のデバイスは永久に混在する見込み

More Related Content

What's hot

ARM LinuxのMMUはわかりにくい
ARM LinuxのMMUはわかりにくいARM LinuxのMMUはわかりにくい
ARM LinuxのMMUはわかりにくい
wata2ki
 
Building a Stretched Cluster using Virtual SAN 6.1
Building a Stretched Cluster using Virtual SAN 6.1Building a Stretched Cluster using Virtual SAN 6.1
Building a Stretched Cluster using Virtual SAN 6.1
Duncan Epping
 
【第二回 ゼロからはじめる Oracle Solaris 11】02 Solaris 11 を支える最強のファイルシステム ZFS ~ ZFS ファイルシ...
【第二回 ゼロからはじめる Oracle Solaris 11】02 Solaris 11 を支える最強のファイルシステム ZFS ~ ZFS ファイルシ...【第二回 ゼロからはじめる Oracle Solaris 11】02 Solaris 11 を支える最強のファイルシステム ZFS ~ ZFS ファイルシ...
【第二回 ゼロからはじめる Oracle Solaris 11】02 Solaris 11 を支える最強のファイルシステム ZFS ~ ZFS ファイルシ...
SolarisJP
 
Kibanaでsysstatを可視化する
Kibanaでsysstatを可視化するKibanaでsysstatを可視化する
Kibanaでsysstatを可視化する
Kensuke Maeda
 
Qemu Introduction
Qemu IntroductionQemu Introduction
Qemu Introduction
Chiawei Wang
 
OVF, OVA, ovftool
OVF, OVA, ovftoolOVF, OVA, ovftool
OVF, OVA, ovftool
tshiroyama
 
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
Masahito Zembutsu
 
UEFIによるELFバイナリの起動
UEFIによるELFバイナリの起動UEFIによるELFバイナリの起動
UEFIによるELFバイナリの起動
uchan_nos
 
負荷軽減!整合性もバッチリ!Veeamのストレージ連携セミナー!!
負荷軽減!整合性もバッチリ!Veeamのストレージ連携セミナー!!負荷軽減!整合性もバッチリ!Veeamのストレージ連携セミナー!!
負荷軽減!整合性もバッチリ!Veeamのストレージ連携セミナー!!
株式会社クライム
 
Esxi troubleshooting
Esxi troubleshootingEsxi troubleshooting
Esxi troubleshooting
Ovi Chis
 
RHEL7/CentOS7 NetworkManager徹底入門
RHEL7/CentOS7 NetworkManager徹底入門RHEL7/CentOS7 NetworkManager徹底入門
RHEL7/CentOS7 NetworkManager徹底入門
Etsuji Nakai
 
ゼロからはじめるKVM超入門
ゼロからはじめるKVM超入門ゼロからはじめるKVM超入門
ゼロからはじめるKVM超入門
VirtualTech Japan Inc.
 
VMware vSphere Performance Troubleshooting
VMware vSphere Performance TroubleshootingVMware vSphere Performance Troubleshooting
VMware vSphere Performance Troubleshooting
Dan Brinkmann
 
半日でわかる コンテナー技術 (入門編)
半日でわかる コンテナー技術 (入門編)半日でわかる コンテナー技術 (入門編)
半日でわかる コンテナー技術 (入門編)
Toru Makabe
 
/etc/network/interfaces について
/etc/network/interfaces について/etc/network/interfaces について
/etc/network/interfaces について
Kazuhiro Nishiyama
 
OpenStack超入門シリーズ いまさら聞けないNeutronの使い方
OpenStack超入門シリーズ いまさら聞けないNeutronの使い方OpenStack超入門シリーズ いまさら聞けないNeutronの使い方
OpenStack超入門シリーズ いまさら聞けないNeutronの使い方
Toru Makabe
 
OpenStack概要 ~仮想ネットワーク~
OpenStack概要 ~仮想ネットワーク~OpenStack概要 ~仮想ネットワーク~
OpenStack概要 ~仮想ネットワーク~
Masaya Aoyama
 
OpenStack Ironicによるベアメタルプロビジョニング
OpenStack IronicによるベアメタルプロビジョニングOpenStack Ironicによるベアメタルプロビジョニング
OpenStack Ironicによるベアメタルプロビジョニング
Yuuki Mori
 
vsphere-esxi-vcenter-server-703-storage-guide-中文.pdf
vsphere-esxi-vcenter-server-703-storage-guide-中文.pdfvsphere-esxi-vcenter-server-703-storage-guide-中文.pdf
vsphere-esxi-vcenter-server-703-storage-guide-中文.pdf
裝機安 Angelo
 
AlmaLinux と Rocky Linux の誕生経緯&比較
AlmaLinux と Rocky Linux の誕生経緯&比較AlmaLinux と Rocky Linux の誕生経緯&比較
AlmaLinux と Rocky Linux の誕生経緯&比較
beyond Co., Ltd.
 

What's hot (20)

ARM LinuxのMMUはわかりにくい
ARM LinuxのMMUはわかりにくいARM LinuxのMMUはわかりにくい
ARM LinuxのMMUはわかりにくい
 
Building a Stretched Cluster using Virtual SAN 6.1
Building a Stretched Cluster using Virtual SAN 6.1Building a Stretched Cluster using Virtual SAN 6.1
Building a Stretched Cluster using Virtual SAN 6.1
 
【第二回 ゼロからはじめる Oracle Solaris 11】02 Solaris 11 を支える最強のファイルシステム ZFS ~ ZFS ファイルシ...
【第二回 ゼロからはじめる Oracle Solaris 11】02 Solaris 11 を支える最強のファイルシステム ZFS ~ ZFS ファイルシ...【第二回 ゼロからはじめる Oracle Solaris 11】02 Solaris 11 を支える最強のファイルシステム ZFS ~ ZFS ファイルシ...
【第二回 ゼロからはじめる Oracle Solaris 11】02 Solaris 11 を支える最強のファイルシステム ZFS ~ ZFS ファイルシ...
 
Kibanaでsysstatを可視化する
Kibanaでsysstatを可視化するKibanaでsysstatを可視化する
Kibanaでsysstatを可視化する
 
Qemu Introduction
Qemu IntroductionQemu Introduction
Qemu Introduction
 
OVF, OVA, ovftool
OVF, OVA, ovftoolOVF, OVA, ovftool
OVF, OVA, ovftool
 
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
 
UEFIによるELFバイナリの起動
UEFIによるELFバイナリの起動UEFIによるELFバイナリの起動
UEFIによるELFバイナリの起動
 
負荷軽減!整合性もバッチリ!Veeamのストレージ連携セミナー!!
負荷軽減!整合性もバッチリ!Veeamのストレージ連携セミナー!!負荷軽減!整合性もバッチリ!Veeamのストレージ連携セミナー!!
負荷軽減!整合性もバッチリ!Veeamのストレージ連携セミナー!!
 
Esxi troubleshooting
Esxi troubleshootingEsxi troubleshooting
Esxi troubleshooting
 
RHEL7/CentOS7 NetworkManager徹底入門
RHEL7/CentOS7 NetworkManager徹底入門RHEL7/CentOS7 NetworkManager徹底入門
RHEL7/CentOS7 NetworkManager徹底入門
 
ゼロからはじめるKVM超入門
ゼロからはじめるKVM超入門ゼロからはじめるKVM超入門
ゼロからはじめるKVM超入門
 
VMware vSphere Performance Troubleshooting
VMware vSphere Performance TroubleshootingVMware vSphere Performance Troubleshooting
VMware vSphere Performance Troubleshooting
 
半日でわかる コンテナー技術 (入門編)
半日でわかる コンテナー技術 (入門編)半日でわかる コンテナー技術 (入門編)
半日でわかる コンテナー技術 (入門編)
 
/etc/network/interfaces について
/etc/network/interfaces について/etc/network/interfaces について
/etc/network/interfaces について
 
OpenStack超入門シリーズ いまさら聞けないNeutronの使い方
OpenStack超入門シリーズ いまさら聞けないNeutronの使い方OpenStack超入門シリーズ いまさら聞けないNeutronの使い方
OpenStack超入門シリーズ いまさら聞けないNeutronの使い方
 
OpenStack概要 ~仮想ネットワーク~
OpenStack概要 ~仮想ネットワーク~OpenStack概要 ~仮想ネットワーク~
OpenStack概要 ~仮想ネットワーク~
 
OpenStack Ironicによるベアメタルプロビジョニング
OpenStack IronicによるベアメタルプロビジョニングOpenStack Ironicによるベアメタルプロビジョニング
OpenStack Ironicによるベアメタルプロビジョニング
 
vsphere-esxi-vcenter-server-703-storage-guide-中文.pdf
vsphere-esxi-vcenter-server-703-storage-guide-中文.pdfvsphere-esxi-vcenter-server-703-storage-guide-中文.pdf
vsphere-esxi-vcenter-server-703-storage-guide-中文.pdf
 
AlmaLinux と Rocky Linux の誕生経緯&比較
AlmaLinux と Rocky Linux の誕生経緯&比較AlmaLinux と Rocky Linux の誕生経緯&比較
AlmaLinux と Rocky Linux の誕生経緯&比較
 

Similar to Backdoor!! vmware-tools と 統合サービスに見るハイパーバイザの呼び出し方

VMwareユーザのためのdocker入門 ~Re:Virtualization Night #1~
VMwareユーザのためのdocker入門 ~Re:Virtualization Night #1~VMwareユーザのためのdocker入門 ~Re:Virtualization Night #1~
VMwareユーザのためのdocker入門 ~Re:Virtualization Night #1~
Masaomi Kudo
 
Osc2009 Do Xen Hara
Osc2009 Do Xen HaraOsc2009 Do Xen Hara
Osc2009 Do Xen Hara
Kazuhisa Hara
 
BHyVeってなんや
BHyVeってなんやBHyVeってなんや
BHyVeってなんやTakuya ASADA
 
Lxc on cloud
Lxc on cloudLxc on cloud
Lxc on cloud
Yukihiko SAWANOBORI
 
Wakame Project - 自作クラウド研究会
Wakame Project - 自作クラウド研究会Wakame Project - 自作クラウド研究会
Wakame Project - 自作クラウド研究会
axsh co., LTD.
 
コンテナネットワーキング(CNI)最前線
コンテナネットワーキング(CNI)最前線コンテナネットワーキング(CNI)最前線
コンテナネットワーキング(CNI)最前線
Motonori Shindo
 
OpenStackネットワーキング管理者入門 - OpenStack最新情報セミナー 2014年8月
OpenStackネットワーキング管理者入門 - OpenStack最新情報セミナー 2014年8月OpenStackネットワーキング管理者入門 - OpenStack最新情報セミナー 2014年8月
OpenStackネットワーキング管理者入門 - OpenStack最新情報セミナー 2014年8月
VirtualTech Japan Inc.
 
Trema での Open vSwitch
Trema での Open vSwitchTrema での Open vSwitch
Trema での Open vSwitchkazuyas
 
VPP事始め
VPP事始めVPP事始め
VPP事始め
npsg
 
20120822_dstn技術交流会_仮想化について
20120822_dstn技術交流会_仮想化について20120822_dstn技術交流会_仮想化について
20120822_dstn技術交流会_仮想化についてdstn
 
Unsafe Nested Virtualization on Intel CPU
Unsafe Nested Virtualization on Intel CPUUnsafe Nested Virtualization on Intel CPU
Unsafe Nested Virtualization on Intel CPU
Takaaki Fukai
 
FD.io VPP事始め
FD.io VPP事始めFD.io VPP事始め
FD.io VPP事始め
tetsusat
 
Mellanox Vxlan offload Performance on linux
Mellanox Vxlan offload Performance on linux Mellanox Vxlan offload Performance on linux
Mellanox Vxlan offload Performance on linux
Yuki Kitajima
 
勉強会0614 vagrant
勉強会0614 vagrant勉強会0614 vagrant
勉強会0614 vagrant
Yu Ito
 
近頃のDockerネットワーク
近頃のDockerネットワーク近頃のDockerネットワーク
近頃のDockerネットワーク
Yuji Oshima
 
Bhyve code reading
Bhyve code readingBhyve code reading
Bhyve code readingTakuya ASADA
 
Open vSwitchソースコードの全体像
Open vSwitchソースコードの全体像 Open vSwitchソースコードの全体像
Open vSwitchソースコードの全体像 Sho Shimizu
 
LinAction Theme Docker
LinAction Theme DockerLinAction Theme Docker
LinAction Theme Docker
cyberblack28 Ichikawa
 
第3回「マイクロソフトの仮想化と、クラウドの今後」(2011/06/16 on しすなま!) ②IBM資料
第3回「マイクロソフトの仮想化と、クラウドの今後」(2011/06/16 on しすなま!) ②IBM資料第3回「マイクロソフトの仮想化と、クラウドの今後」(2011/06/16 on しすなま!) ②IBM資料
第3回「マイクロソフトの仮想化と、クラウドの今後」(2011/06/16 on しすなま!) ②IBM資料
System x 部 (生!) : しすなま! @ Lenovo Enterprise Solutions Ltd.
 

Similar to Backdoor!! vmware-tools と 統合サービスに見るハイパーバイザの呼び出し方 (20)

VMwareユーザのためのdocker入門 ~Re:Virtualization Night #1~
VMwareユーザのためのdocker入門 ~Re:Virtualization Night #1~VMwareユーザのためのdocker入門 ~Re:Virtualization Night #1~
VMwareユーザのためのdocker入門 ~Re:Virtualization Night #1~
 
Osc2009 Do Xen Hara
Osc2009 Do Xen HaraOsc2009 Do Xen Hara
Osc2009 Do Xen Hara
 
BHyVeってなんや
BHyVeってなんやBHyVeってなんや
BHyVeってなんや
 
Lxc on cloud
Lxc on cloudLxc on cloud
Lxc on cloud
 
Bhyve Internals
Bhyve InternalsBhyve Internals
Bhyve Internals
 
Wakame Project - 自作クラウド研究会
Wakame Project - 自作クラウド研究会Wakame Project - 自作クラウド研究会
Wakame Project - 自作クラウド研究会
 
コンテナネットワーキング(CNI)最前線
コンテナネットワーキング(CNI)最前線コンテナネットワーキング(CNI)最前線
コンテナネットワーキング(CNI)最前線
 
OpenStackネットワーキング管理者入門 - OpenStack最新情報セミナー 2014年8月
OpenStackネットワーキング管理者入門 - OpenStack最新情報セミナー 2014年8月OpenStackネットワーキング管理者入門 - OpenStack最新情報セミナー 2014年8月
OpenStackネットワーキング管理者入門 - OpenStack最新情報セミナー 2014年8月
 
Trema での Open vSwitch
Trema での Open vSwitchTrema での Open vSwitch
Trema での Open vSwitch
 
VPP事始め
VPP事始めVPP事始め
VPP事始め
 
20120822_dstn技術交流会_仮想化について
20120822_dstn技術交流会_仮想化について20120822_dstn技術交流会_仮想化について
20120822_dstn技術交流会_仮想化について
 
Unsafe Nested Virtualization on Intel CPU
Unsafe Nested Virtualization on Intel CPUUnsafe Nested Virtualization on Intel CPU
Unsafe Nested Virtualization on Intel CPU
 
FD.io VPP事始め
FD.io VPP事始めFD.io VPP事始め
FD.io VPP事始め
 
Mellanox Vxlan offload Performance on linux
Mellanox Vxlan offload Performance on linux Mellanox Vxlan offload Performance on linux
Mellanox Vxlan offload Performance on linux
 
勉強会0614 vagrant
勉強会0614 vagrant勉強会0614 vagrant
勉強会0614 vagrant
 
近頃のDockerネットワーク
近頃のDockerネットワーク近頃のDockerネットワーク
近頃のDockerネットワーク
 
Bhyve code reading
Bhyve code readingBhyve code reading
Bhyve code reading
 
Open vSwitchソースコードの全体像
Open vSwitchソースコードの全体像 Open vSwitchソースコードの全体像
Open vSwitchソースコードの全体像
 
LinAction Theme Docker
LinAction Theme DockerLinAction Theme Docker
LinAction Theme Docker
 
第3回「マイクロソフトの仮想化と、クラウドの今後」(2011/06/16 on しすなま!) ②IBM資料
第3回「マイクロソフトの仮想化と、クラウドの今後」(2011/06/16 on しすなま!) ②IBM資料第3回「マイクロソフトの仮想化と、クラウドの今後」(2011/06/16 on しすなま!) ②IBM資料
第3回「マイクロソフトの仮想化と、クラウドの今後」(2011/06/16 on しすなま!) ②IBM資料
 

Recently uploaded

Generating Automatic Feedback on UI Mockups with Large Language Models
Generating Automatic Feedback on UI Mockups with Large Language ModelsGenerating Automatic Feedback on UI Mockups with Large Language Models
Generating Automatic Feedback on UI Mockups with Large Language Models
harmonylab
 
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
Matsushita Laboratory
 
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
Toru Tamaki
 
This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.
chiefujita1
 
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
t m
 
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさJSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
0207sukipio
 
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
Matsushita Laboratory
 
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアルLoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
CRI Japan, Inc.
 

Recently uploaded (8)

Generating Automatic Feedback on UI Mockups with Large Language Models
Generating Automatic Feedback on UI Mockups with Large Language ModelsGenerating Automatic Feedback on UI Mockups with Large Language Models
Generating Automatic Feedback on UI Mockups with Large Language Models
 
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
ReonHata_便利の副作用に気づかせるための発想支援手法の評価---行為の増減の提示による気づきへの影響---
 
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
論文紹介:When Visual Prompt Tuning Meets Source-Free Domain Adaptive Semantic Seg...
 
This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.This is the company presentation material of RIZAP Technologies, Inc.
This is the company presentation material of RIZAP Technologies, Inc.
 
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
遺伝的アルゴリズムと知識蒸留による大規模言語モデル(LLM)の学習とハイパーパラメータ最適化
 
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさJSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
JSAI_類似画像マッチングによる器への印象付与手法の妥当性検証_ver.3_高橋りさ
 
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
TaketoFujikawa_物語のコンセプトに基づく情報アクセス手法の基礎検討_JSAI2024
 
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアルLoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
LoRaWAN 4チャンネル電流センサー・コンバーター CS01-LB 日本語マニュアル
 

Backdoor!! vmware-tools と 統合サービスに見るハイパーバイザの呼び出し方

  • 1. Backdoor !! vmware-tools と 統合サービスに見るハイパーバイザの呼び出し方 2010/4/12 VTCライトニングトーク発表内容 しろやまたかゆき<shiro.t@gmail.com>
  • 2. Hypercall とは? l ゲストOS からハイパーバイザを明示的に呼び出す方法 l Binary Translation や VMEXIT/VMRESUME に比べコストが低い l 呼び出し方法が低コスト l ハイパーバイザに都合のいいデータのやり取りが可能 l 準仮想化された OS で使用されている l Xen 対応の Linux カーネルなど
  • 3. Xen での Hypercall の実装 l 単純に int 命令でソフトウェア割り込みをかけているだけ l Ring0 の Xen hyper-visor が割り込みをキャッチし、指定のルーチンを 呼び出している http://www.ylug.jp/download/hypercall_ylug_20061027.pdf
  • 4. Hypercall は準仮想化だけのもの? l いえ、類似/同等の機能は完全仮想化のハイパーバイザにもあります! l 性能上の理由 l Binary Translation や VMEXIT/VMRESUME に比べコストが低い l 仮想化ならではの機能の実現 l VM間 / VM-Hypervisor 間の通信や制御 (VMCI)
  • 5. 例: VMCI int a, s, len; char buf[255]; struct sockaddr_vm addr = { 0 }; s = socket(PF_VSOCK_VMCI, SOCK_STREAM, 0); addr.svm_family = AF_VSOCK_VMCI; addr.svm_cid = VMADDR_CID_ANY; addr.svm_rid = 2000; bind(s, (struct sockaddr *) &addr, sizeofaddr); listen(s, 5); a = accept(s, (struct sockaddr *) &addr, &len); len = recv(a, buf, sizeof buf, 0); int a, s, len; char *buf = “Hello, world!”; struct sockaddr_vm addr = { 0 }; s = socket(PF_VSOCK_VMCI, SOCK_STREAM, 0); addr.svm_family = AF_VSOCK_VMCI; addr.svm_cid = GUEST2; addr.svm_rid = 2000; connect(s, (struct sockaddr *) &addr, sizeof addr); len = send(s, buf, len, 0); 基本はソケットプログラミング 通常のPF_INETの代わりに PF_VSOCK_VMCIに変更。 読み書き(send/recv)は変わらず Hyper-­visor Application Guest  OS 仮想マシン Application Guest  OS 仮想マシン Server Client
  • 6. ESX / Hyper-V の Hypercall l では、ESX / Hyper-V の Hypercall って どうやってるの? ソースコードにきいてみよう!
  • 7. VMware の場合: open-vm-tools Open Virtual Machine Tools l vmware-tools のソースコードは公開されている (2007.9.4~) l Linux, FreeBSD, Solaris 用 l vmsync など、標準の VMware Tools にないモジュールも存在 http://open-­vm-­tools.sourceforge.net/
  • 8. Microsoft の場合 l Hyper-V の統合サービス(Linux向け)のソースコードを公開!(2009.7.21) l これを読めば Hyper-V の hypercall も解明できる?
  • 9. で、どうやってダウンロードすればいいの? l MS のサイトを漁りまわったけどソースコードを発見できず!! l 公開を報じる国内記事は多々あれど、ソースそのもののリンクはどこにもない l 駄目ぢゃん、っと思ってたら...
  • 10. で、どうやってダウンロードすればいいの? l Linux-Kernel ML に Greg-KH 氏が投稿していた l パッチを 54 分割して... l 何とか苦労して取り出しました l 最近のカーネルソースには既に含まれている模様
  • 11. ソースツリー: open-vm-tools の場合 l open-vm-tools l 綺麗な階層構造、Makfile 完備 l さまざまなOSでのビルドを前提としている l コード数、約24万行 - 「find –name ‘*.[ch]’ -print0 | xargs -0 wc –l 」の実行結果より
  • 12. ソースツリー: open-vm-tools の場合 l open-vm-tools の階層構造 +-­-­ autom4te.cache/ +-­-­ checkvm/ +-­-­ config/ +-­-­ docs/ +-­-­ hgfsclient/ +-­-­ hgfsmounter/ +-­-­ lib/ +-­-­ libguestlib/ +-­-­ libvmtools/ +-­-­ m4/ +-­-­ modules/ |      +-­-­ freebsd/ |      +-­-­ linux/ |      +-­-­ solaris/ +-­-­ rpctool/ +-­-­ scripts/ +-­-­ services/ |      +-­-­ plugins/ ||      +-­-­ vmtoolsd/ +-­-­ tests/ +-­-­ toolbox/ +-­-­ vmblock-­fuse/ +-­-­ vmware-­user/ +-­-­ vmware-­user-­suid-­wrapper/ +-­-­ xferlogs/   |      +-­-­ linux/ |      |      +-­-­ pvscsi/ |      |      +-­-­ shared/ |      |      +-­-­ vmblock/ |      |      +-­-­ vmci/ |      |      +-­-­ vmhgfs/ |      |      +-­-­ vmmemctl/ |      |      +-­-­ vmsync/ |      |      +-­-­ vmxnet/ |      |      +-­-­ vsock/ 独自のツリー構造 多くのOSに対応 共通化モジュール、ユーザランドツール、 ドライバなど綺麗に分離されている
  • 13. ソースツリー: Hyper-V の場合 l linux integration component l linux-kernel に対するパッチで、Linux にべったりの構造 - カーネルパッチだけ?ユーザランドに何もない?? l driver/staging/hv 以下に集中配置 l 約2万行
  • 14. ソースツリー: Hyper-V の場合 ファイル一覧 BlkVsc.c HvVpApi.h Vmbus.c Channel.c Kconfig VmbusApi.h Channel.h List.h VmbusChannelInterface.h ChannelInterface.c Makefile VmbusPacketFormat.h ChannelInterface.h Makefile.rej VmbusPrivate.h ChannelMessages.h NetVsc.c blkvsc_drv.c ChannelMgmt.c NetVsc.h hv.diff ChannelMgmt.h NetVscApi.h logging.h Connection.c RingBuffer.c netvsc_drv.c Hv.c RingBuffer.h nvspprotocol.h Hv.h RndisFilter.c osd.c HvHalApi.h RndisFilter.h osd.h HvHcApi.h Sources.c rndis.h HvPtApi.h StorVsc.c storvsc_drv.c HvStatus.h StorVscApi.h vmbus.h HvSynicApi.h TODO vmbus_drv.c HvTypes.h VersionInfo.h vstorage.h
  • 15. Linux への侵食方法:VMware の場合 あくまで「物理デバイスに対するドライバ」の立場 l VMware-tools の有無に関わらず、仮想デバイスが存在する前提 l PCIバス上にデバイスがつながっているように見える l PCIバスのデバイス検出手順に従い、ドライバがロードされていく l VendorID: 0x15AD で、指定 の DeviceID をもつドライバが 選定される l 選定されたドライバのprobe 関数を 実行して、本当に対応するデバイスか を確認させる l 失敗が帰ったら、次の候補となる ドライバを探す /* Our own PCI IDs * VMware SVGA II (Unified VGA) * VMware SVGA (PCI Accelerator) * VMware vmxnet (Idealized NIC) * VMware vmxscsi (Abortive idealized SCSI controller) * VMware chipset (Subsystem ID for our motherboards) * VMware e1000 (Subsystem ID) * VMware vmxnet3 (Uniform Pass Through NIC) */ #define PCI_VENDOR_ID_VMWARE 0x15AD #define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 #define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 #define PCI_DEVICE_ID_VMWARE_NET 0x0720 #define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 #define PCI_DEVICE_ID_VMWARE_VMCI 0x0740 #define PCI_DEVICE_ID_VMWARE_CHIPSET 0x1976 #define PCI_DEVICE_ID_VMWARE_82545EM 0x0750 /* single port */ #define PCI_DEVICE_ID_VMWARE_82546EB 0x0760 /* dual port */ #define PCI_DEVICE_ID_VMWARE_EHCI 0x0770 #define PCI_DEVICE_ID_VMWARE_UHCI 0x0774 #define PCI_DEVICE_ID_VMWARE_XHCI 0x0778 #define PCI_DEVICE_ID_VMWARE_1394 0x0780 #define PCI_DEVICE_ID_VMWARE_BRIDGE 0x0790 #define PCI_DEVICE_ID_VMWARE_ROOTPORT 0x07A0 #define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0 #define PCI_DEVICE_ID_VMWARE_VMXWIFI 0x07B8 #define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0 #define PCI_DEVICE_ID_VMWARE_82574 0x07D0 lib/include/vm_device_version.h  より
  • 16. Linux への侵食方法:VMware の場合 余談: vmxnet の Morphing l ESX 2.x では、vlance と vmxnet は区別されてました l vlance vendorID: 0x1022(AMD) deviceID: 0x2000 l vmxnet vendorID: 0x15AD(VMware) deviceID: 0x0720 l ESX 3.x 以降で、vlance -> vmxnet の入れ替えしました?
  • 17. Linux への侵食方法:VMware の場合 余談: vmxnet の Morphing l ESX 3.x 以降の vlance は、vmxnet を「兼用」している l たまたま、AMD-PCNET が 32byte しか IO空間を使ってなかった点を利用 l 64byte まで取れるIO空間の後ろ32byte に vmxnet の IO空間を追加 /* * Since this is a vlance adapter we can only use it if * its I/0 space is big enough for the adapter to be * capable of morphing. This is the first requirement * for this adapter to potentially be morphable. The * layout of a morphable LANCE adapter is * * I/O space: * * |------------------| * | LANCE IO PORTS | * |------------------| * | MORPH PORT | * |------------------| * | VMXNET IO PORTS | * |------------------| * * VLance has 8 ports of size 4 bytes, the morph port is 4 bytes, and * Vmxnet has 10 ports of size 4 bytes. * * We shift up the ioaddr with the size of the LANCE I/O space since * we want to access the vmxnet ports. We also shift the ioaddr up by * the MORPH_PORT_SIZE so other port access can be independent of * whether we are Vmxnet or a morphed VLance. This means that when * we want to access the MORPH port we need to subtract the size * from ioaddr to get to it. */
  • 18. Linux への侵食方法:VMware の場合 余談: vmxnet の Morphing l vmxnet ドライバの probe 関数(vmxnet_probe_device)の挙動 l PCI の Vendor ID を取得 - 0x15AD (VMware) なら、そのまま vmxnet デバイスと判断 • 旧 vmxnet との互換性の確保 - 0x1022 (AMD) の場合 • IO空間のサイズを取得し、64byte とサイズを比較 • それより小さかったら? 「うちの子じゃない」 で probe に失敗を返す • 64byte 以上なら、「うちの子だから」と認定 • morph port に outw で値を書き込み、vmxnet として振舞わせる
  • 19. Linux への侵食方法:VMware の場合 static int vmxnet_morph_device(unsigned int morphAddr) // IN { uint16 magic; /* Read morph port to verify that we can morph the adapter. */ magic = inw(morphAddr); if (magic != LANCE_CHIP && magic != VMXNET_CHIP) { printk(KERN_ERR "Invalid magic, read: 0x%08X¥n", magic); return -1; } /* Morph adapter. */ outw(VMXNET_CHIP, morphAddr); /* Verify that we morphed correctly. */ magic = inw(morphAddr); if (magic != VMXNET_CHIP) { printk(KERN_ERR "Couldn't morph adapter. Invalid magic, read: 0x%08X¥n", magic); goto morph_back; } return 0; morph_back: /* Morph back to LANCE hw. */ outw(LANCE_CHIP, morphAddr); return -1; }
  • 20. VMM Linux への侵食方法:VMware の場合 l あくまで正規のデバイスドライバとしてロードされる l 比較的、物理デバイスに近いエミュレーションがなされている l Backdoor を使ってデバイスエミュレーションをある程度「バイパス」する Linux  kernel vmxnet_drv VGA LSILogic NIC VGA SCSI VendorID:  xxxx DeviceID  :  xxxx VendorID:  xxxx DeviceID  :  xxxx VendorID:  xxxx DeviceID  :  xxxx PCI  バス Backdoor vmsync vmUser vmmemctl VMkernel vmtools   提供ドライバ ネイティブドライバ
  • 21. Backdoor : IO空間の in/out 命令 l VMware の Backdoor は、指定のIO空間への in /out 命令 l in / out : x86 のもつ IO 空間へのデータの読み書きの命令 l NICなどの一般的なデバイスは IO空間の一部を通じてデータをやり取りする - グラフィックカードなどのより大きな空間を必要とするものは、メモリ空間 にマップされる - PCI は IO空間 / メモリマップのどちらの方法もサポートする l VMware ではこの in / out 命令を転用している l 詳細: http://chitchat.at.infoseek.co.jp/vmware/backdoorj.html
  • 22. Backdoor : IO空間の in/out 命令 static  void BalloonTimerHandler(void  *clientData)  //  IN { Balloon  *b  =  (Balloon  *)  clientData;; uint32  target  =  0;;  //  Silence  compiler  warning. int  status;; /*  update  stats  */ STATS_INC(b-­>stats.timer);; /*  reset,  if  specified  */ if  (b-­>resetFlag)  { BalloonReset(b);; } /*  contact  monitor  via  backdoor  */ status  =  BalloonMonitorGetTarget(b,  &target);; /*  decrement  slowPageAllocationCycles  counter  */ if  (b-­>slowPageAllocationCycles  >  0)  { b-­>slowPageAllocationCycles-­-­;; } if  (status  ==  BALLOON_SUCCESS)  { /*  update  target,  adjust  size  */ b-­>nPagesTarget  =  target;; (void)  BalloonAdjustSize(b,  target);; } }
  • 23. Backdoor : IO空間の in/out 命令 static  void BalloonTimerHandler(void  *clientData)  //  IN { Balloon  *b  =  (Balloon  *)  clientData;; uint32  target  =  0;;  //  Silence  compiler  warning. int  status;; /*  update  stats  */ STATS_INC(b-­>stats.timer);; /*  reset,  if  specified  */ if  (b-­>resetFlag)  { BalloonReset(b);; } /*  contact  monitor  via  backdoor  */ status  =  BalloonMonitorGetTarget(b,  &target);; /*  decrement  slowPageAllocationCycles  counter  */ if  (b-­>slowPageAllocationCycles  >  0)  { b-­>slowPageAllocationCycles-­-­;; } if  (status  ==  BALLOON_SUCCESS)  { /*  update  target,  adjust  size  */ b-­>nPagesTarget  =  target;; (void)  BalloonAdjustSize(b,  target);; } } static  int BalloonMonitorGetTarget(Balloon  *b,          //  IN uint32  *target)  //  OUT { Backdoor_proto  bp;; unsigned  long  limit;; uint32  limit32;; uint32  status;; limit  =  OS_ReservedPageGetLimit();; /*  Ensure  limit  fits  in  32-­bits  */ limit32  =  (uint32)limit;; if  (limit32  !=  limit)  { return  BALLOON_FAILURE;; } /*  prepare  backdoor  args  */ bp.in.cx.halfs.low  =  BALLOON_BDOOR_CMD_TARGET;; bp.in.size  =  limit;; /*  invoke  backdoor  */ Backdoor_Balloon(&bp);; /*  parse  return  values  */ status    =  bp.out.ax.word;; *target  =  bp.out.bx.word;;
  • 24. Backdoor : IO空間の in/out 命令 static  void BalloonTimerHandler(void  *clientData)  //  IN { Balloon  *b  =  (Balloon  *)  clientData;; uint32  target  =  0;;  //  Silence  compiler  warning. int  status;; /*  update  stats  */ STATS_INC(b-­>stats.timer);; /*  reset,  if  specified  */ if  (b-­>resetFlag)  { BalloonReset(b);; } /*  contact  monitor  via  backdoor  */ status  =  BalloonMonitorGetTarget(b,  &target);; /*  decrement  slowPageAllocationCycles  counter  */ if  (b-­>slowPageAllocationCycles  >  0)  { b-­>slowPageAllocationCycles-­-­;; } if  (status  ==  BALLOON_SUCCESS)  { /*  update  target,  adjust  size  */ b-­>nPagesTarget  =  target;; (void)  BalloonAdjustSize(b,  target);; } } static  int BalloonMonitorGetTarget(Balloon  *b,          //  IN uint32  *target)  //  OUT { Backdoor_proto  bp;; unsigned  long  limit;; uint32  limit32;; uint32  status;; limit  =  OS_ReservedPageGetLimit();; /*  Ensure  limit  fits  in  32-­bits  */ limit32  =  (uint32)limit;; if  (limit32  !=  limit)  { return  BALLOON_FAILURE;; } /*  prepare  backdoor  args  */ bp.in.cx.halfs.low  =  BALLOON_BDOOR_CMD_TARGET;; bp.in.size  =  limit;; /*  invoke  backdoor  */ Backdoor_Balloon(&bp);; /*  parse  return  values  */ status    =  bp.out.ax.word;; *target  =  bp.out.bx.word;; static  INLINE void  Backdoor_Balloon(Backdoor_proto  *myBp)  { myBp-­>in.ax.word  =  BALLOON_BDOOR_MAGIC;; myBp-­>in.dx.halfs.low  =  BALLOON_BDOOR_PORT;; Backdoor_InOut(myBp);; }
  • 25. Backdoor : IO空間の in/out 命令 Backdoor_InOut(Backdoor_proto *myBp) // IN/OUT { uint32 dummy; __asm__ __volatile__( #ifdef __PIC__ "pushl %%ebx" "¥n¥t" #endif "pushl %%eax" "¥n¥t" "movl 20(%%eax), %%edi" "¥n¥t" "movl 16(%%eax), %%esi" "¥n¥t" "movl 12(%%eax), %%edx" "¥n¥t" "movl 8(%%eax), %%ecx" "¥n¥t" "movl 4(%%eax), %%ebx" "¥n¥t" "movl (%%eax), %%eax" "¥n¥t" "inl %%dx, %%eax" "¥n¥t" "xchgl %%eax, (%%esp)" "¥n¥t" "movl %%edi, 20(%%eax)" "¥n¥t" "movl %%esi, 16(%%eax)" "¥n¥t" "movl %%edx, 12(%%eax)" "¥n¥t" "movl %%ecx, 8(%%eax)" "¥n¥t" "movl %%ebx, 4(%%eax)" "¥n¥t" "popl (%%eax)" "¥n¥t" #ifdef __PIC__ "popl %%ebx" "¥n¥t" #endif : "=a" (dummy) : "0" (myBp) /* * vmware can modify the whole VM state without the compiler knowing * it. So far it does not modify EFLAGS. --hpreg */ : #ifndef __PIC__ "ebx", #endif "ecx", "edx", "esi", "edi", "memory" ); } この inl 命令の実行した瞬間に VMkernel 側に処理が渡り、該当する 機能が実行され、結果が vCPU の EAX 、ECX 、 EDX 、 ESI、EDI レジスタ に書き込まれる
  • 26. Hyper-V のドライバイメージ l Hyper-V の場合は、デバイスではなく「バス」を追加している l PCI バスの下に、なんかバスがある... l なんかバスが「外」に伸びてるっぽい... VMM Linux  kernel レガシNIC VGA IDE VendorID:  xxxx DeviceID  :  xxxx VendorID:  xxxx DeviceID  :  xxxx VendorID:  xxxx DeviceID  :  xxxx PCI  バス ネイティブドライバ 21140 VGA IDE VMBUS Backdoor vmbus_drv netvsc_drv storage_drv NIC SCSI Hyper-­V ParentVM
  • 27. Hyper-V のドライバイメージ l Hyper-V の場合は、デバイスではなく「バス」を追加している l PCI バスの下に、なんかバスがある... l なんかバスが「外」に伸びてるっぽい...
  • 28. Linux の侵食方法 : Hyper-V の場合 l とにかく vmbus_drv デバイスドライバをロードする l VMBUS という何らかの「バス」があると Linux に誤認させる l VMBUS も、PCI と同じようにバス上のノードの検出を行う - VendorID と Device ID ではなく、ClassID という GUID で識別 - ノードごと、netvsc_drv, storagevsc_drv, blkvsc_drv がロードされる • VSC : Virtualization Service Client の略 l 各 VSC はデバイスドライバだが、その下にはエミュレーションされたデバイス はまったく存在しない!!
  • 29. Linux の侵食方法 : Hyper-V の場合 http://enterprise.watch.impress.co.jp/cda/parts/image_for_link/41502-­13748-­4-­1.html 本当にこの通りでした...
  • 30. Linux の侵食方法 : Hyper-V の場合 もう少し詳しい 階層構造 l 大きく4層に分かれる l *_drv : Linux のデバイスドライバ(カーネルモジュール)としての体裁を整える l Vsc, Vmbus : 各ドライバの実態となる実装 l Channel, Connection : VMBUS の通信機能の実装 l osd : メモリ確保など OS機能の抽象化 l Hv : Hyper-V との 実際のインターフェイス Linux  kernel osd VMM Vmbus vmbus_drvstoragevsc_drvnetvsc_drv blcvsc_drv Hv Channel Connection Channel  Mgmt StorVscNetVsc BlcVsc Linux  Kernel  とのインターフェイス ドライバー中心部分 VMBUS  通信機能
  • 31. Backdoor : そのメモリに触ると... Hyper-V のバックドアは特定のメモリアドレス l Hv はロードされると以下の振る舞いをする l CPUID 命令を実行し、Hyper-V の上かを確認する - CPUID(1) の ECXの31bit 目を確認 l 続けて CPUID 命令を実行し、ハイパーバイザのベンダー(!)や バージョンを取得する l メモリを1ページ確保する - これは通常の valloc が使用され、実行時により異なるページが 割り当てられる l wmsr でそのメモリの物理アドレスを vCPU に書き込む(!) - MSR: Model Specific Register • PentiumPro 以降のCPUにある、製品独自の設定を保存したり、 プロファイリング用のカウンタとなるレジスタ • 詳細: http://mcn.oops.jp/wiki/index.php?CPU%2FCPUID%2FMSR l 以降、Hypercall はこのメモリへのアクセスすると、Hypercall が発生する
  • 32. Backdoor : Hv初期化部分、Hyper-V 上かを確認 Name: HvQueryHypervisorPresence() Description: Query the cpuid for presense of windows hypervisor --*/ static int HvQueryHypervisorPresence ( void ) { unsigned int eax; unsigned int ebx; unsigned int ecx; unsigned int edx; unsigned int op; eax = 0; ebx = 0; ecx = 0; edx = 0; op = HvCpuIdFunctionVersionAndFeatures; do_cpuid(op, &eax, &ebx, &ecx, &edx); return (ecx & HV_PRESENT_BIT); }
  • 33. Backdoor : Hv初期化部分、Hyper-V 上かを確認 Name: HvQueryHypervisorPresence() Description: Query the cpuid for presense of windows hypervisor --*/ static int HvQueryHypervisorPresence ( void ) { unsigned int eax; unsigned int ebx; unsigned int ecx; unsigned int edx; unsigned int op; eax = 0; ebx = 0; ecx = 0; edx = 0; op = HvCpuIdFunctionVersionAndFeatures; do_cpuid(op, &eax, &ebx, &ecx, &edx); return (ecx & HV_PRESENT_BIT); } typedef enum _HV_CPUID_FUNCTION { HvCpuIdFunctionVersionAndFeatures = 0x00000001, HvCpuIdFunctionHvVendorAndMaxFunction = 0x40000000, HvCpuIdFunctionHvInterface = 0x40000001, // // The remaining functions depend on the value of HvCpuIdFunctionInterface // HvCpuIdFunctionMsHvVersion = 0x40000002, HvCpuIdFunctionMsHvFeatures = 0x40000003, HvCpuIdFunctionMsHvEnlightenmentInformation = 0x40000004, HvCpuIdFunctionMsHvImplementationLimits = 0x40000005 } HV_CPUID_FUNCTION, *PHV_CPUID_FUNCTION;
  • 34. Backdoor : Hv初期化部分、Hyper-V 上かを確認 Name: HvQueryHypervisorPresence() Description: Query the cpuid for presense of windows hypervisor --*/ static int HvQueryHypervisorPresence ( void ) { unsigned int eax; unsigned int ebx; unsigned int ecx; unsigned int edx; unsigned int op; eax = 0; ebx = 0; ecx = 0; edx = 0; op = HvCpuIdFunctionVersionAndFeatures; do_cpuid(op, &eax, &ebx, &ecx, &edx); return (ecx & HV_PRESENT_BIT); } static inline void do_cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) { __asm__ __volatile__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) : "0" (op), "c" (ecx)); }
  • 35. Backdoor : Hv初期化部分、Hyper-V 上かを確認 Name: HvQueryHypervisorPresence() Description: Query the cpuid for presense of windows hypervisor --*/ static int HvQueryHypervisorPresence ( void ) { unsigned int eax; unsigned int ebx; unsigned int ecx; unsigned int edx; unsigned int op; eax = 0; ebx = 0; ecx = 0; edx = 0; op = HvCpuIdFunctionVersionAndFeatures; do_cpuid(op, &eax, &ebx, &ecx, &edx); return (ecx & HV_PRESENT_BIT); } // // #defines // #define HV_PRESENT_BIT 0x80000000
  • 36. Backdoor : Hv初期化部分、Hyper-V 上かを確認 Hyper-V 上の仮想マシンでの CPUID 。確かに ECX の31bit目が 立っている ESX上の仮想マシン 31bit 目は立っていない 0x8C082201 0x80000000 0x80000000 OR 0x00080201 0x80000000 0x00000000 OR
  • 37. Backdoor : Hv初期化部分、アクセス用のアドレスを設定 if  (gHvContext.GuestId  ==  HV_LINUX_GUEST_ID) { //  Allocate  the  hypercall  page  memory //virtAddr  =  PageAlloc(1);; virtAddr  =  VirtualAllocExec(PAGE_SIZE);; if  (!virtAddr) { DPRINT_ERR(VMBUS,  "unable  to  allocate  hypercall  page!!");; goto  Cleanup;; } hypercallMsr.Enable  =  1;; //hypercallMsr.GuestPhysicalAddress  =  Logical2PhysicalAddr(virtAddr)  >>  PAGE_SHIFT;; hypercallMsr.GuestPhysicalAddress  =  Virtual2Physical(virtAddr)  >>  PAGE_SHIFT;; WriteMsr(HV_X64_MSR_HYPERCALL,  hypercallMsr.AsUINT64);; //  Confirm  that  hypercall  page  did  get  setup. hypercallMsr.AsUINT64  =  0;; hypercallMsr.AsUINT64  =  ReadMsr(HV_X64_MSR_HYPERCALL);; if  (!hypercallMsr.Enable) { DPRINT_ERR(VMBUS,  "unable  to  set  hypercall  page!!");; goto  Cleanup;; } gHvContext.HypercallPage  =  virtAddr;; osd.c にて定義。単に __valloc を 呼び出しているのみ。 単なるメモリ確保のため、どのアドレスが 変えるかは実行依存の模様 仮想アドレスを物理アドレスに書き換えた後、 CPU の MSR レジスタにアドレスを書き込む
  • 38. Backdoor : Hypercall の実際 static u64 HvDoHypercall ( u64 Control, void* Input, void* Output ) { #ifdef CONFIG_X86_64 u64 hvStatus=0; u64 inputAddress = (Input)? GetPhysicalAddress(Input) : 0; u64 outputAddress = (Output)? GetPhysicalAddress(Output) : 0; volatile void* hypercallPage = gHvContext.HypercallPage; DPRINT_DBG(VMBUS, "Hypercall <control %llx input phys %llx virt %p output phys %llx virt %p hypercall %p>", Control, inputAddress, Input, outputAddress, Output, hypercallPage); __asm__ __volatile__ ("mov %0, %%r8" : : "r" (outputAddress): "r8"); __asm__ __volatile__ ("call *%3" : "=a"(hvStatus): "c" (Control), "d" (inputAddress), "m" (hypercallPage)); DPRINT_DBG(VMBUS, "Hypercall <return %llx>", hvStatus); return hvStatus; RCXに命令コードを、RDX に入力データのアドレスを 突っ込んだ後、hypercallPage に call でジャンプし、 Hypercall を行っている (コールゲート?)
  • 39. Backdoor : そのメモリに触ると... l 割り込み、どうするのん? l VMware の場合、各デバイスは PCI 上のデバイスのため、PCIバスを通じて 個々のデバイスが (ゲスト)OSへ 割り込みをかけることができた - = VMM 側からゲストOSにデータを投げることができた l Hyper-V の場合は? l Linux Intergrated Module では、 IRQ 5 を VMBUS の割り込みとして使用
  • 40. 余談: なぜ、Hyper-V の起動ディスクは IDE only なのか l VMBUS がないと統合モジュールが動かないため l OS ロード前は、VMBUS などというバスを認識できない l そもそも 仮想マシンの上の BIOS レベルで VMBUS ドライバを実装する必要 l OS ロード後なら、追加的に VMBUS をロードできる
  • 41. まとめ l 同じハイパーバイザ型の 仮想化ソフトウェアでも、Hypercall の 方法は各社各様 l 意外ときっちり実装している ESX の VMM l vmxnet ドライバも割と普通に IO 処理を行っている l 物理とは大きく異なる Hyper-V の VMM l エミュレートされたデバイスとは別に、本当に架空のデバイスを生成 l VMBUS という架空のバスを通じて架空のデバイスを接続 l 原理的に、morphing はできない。 - エミュレートデバイスと架空のデバイスは永久に混在する見込み