_UNDOCUMENTED CORNER_ edited by Andrew Schulman [Listing One] // VM.C -- Display information about Windows Virtual Machines // bcc -W -2 vm.c (Borland EasyWin) or cl -Mq -G2 vm.c (Microsoft QuickWin) // Andrew Schulman, December 1993 #include #include #include #include #include "windows.h" #define VXD_VxDCall 1 #define VxD_Get_InfoBlock 7 #define Generic_Dev_ID 0x28c0 #define Get_Next_VM_Handle 0x01003BL #define Get_Sys_VM_Handle 0x010003L typedef void far *FP; // from ddk vmm.inc typedef struct { DWORD CB_VM_Status, CB_High_Linear, CB_Client_Pointer, CB_VMID; // etc.: we don't need any undocumented VM_CB fields for this } VM_CB; // Virtual Machine Control Block #pragma pack(1) ///// VM_InfoBlock: see Figure 2 ///// typedef struct { DWORD CallNum, Reserved1; DWORD InEAX, InEBX, InECX, InEDX, InEBP, InESI, InEDI; DWORD Reserved2, Reserved3; DWORD OutEAX, OutEBX, OutECX, OutEDX, OutEBP, OutESI, OutEDI; WORD OutFS, OutGS, OutEFLAGS; } VxDParams; static FP API = (FP) 0; void show_vm(DWORD vm, VM_CB far *vm_cb); VM_InfoBlock far *get_vm_info(DWORD vm); WORD GetVMInfoBlockOffset(void); void InitVxDAPI(void); FP GetVxDAPI(WORD vxd_id); FP map_linear(DWORD lin_addr, DWORD num_bytes); void free_mapped_linear(FP fp); DWORD GetSysVMHandle(void), GetNextVMHandle(DWORD vm); BOOL VxDCall(VxDParams far *fp); void fail(char *s) { puts(s); exit(1); } main() { VM_CB far *vm_cb; DWORD sys_vm = GetSysVMHandle(); DWORD vm = sys_vm; while (vm_cb = (VM_CB far *) map_linear(vm, sizeof(VM_CB)+0x2000)) { show_vm(vm, vm_cb); free_mapped_linear(vm_cb); if ((vm = GetNextVMHandle(vm)) == sys_vm) break; // GetNextVMHandle makes look like circular list } return 0; } void show_vm(DWORD vm, VM_CB far *vm_cb) { VM_InfoBlock far *info; printf("#%lu\tVMCB=%08lX high_lin=%08lX", vm_cb->CB_VMID, vm, vm_cb->CB_High_Linear); // could show undoc information here too if (info = get_vm_info(vm)) { char buf[33]; _fstrncpy(buf, info->AppName, 32); buf[33] = '\0'; printf(" %04Xh \"%s\"", info->hWnd, buf); free_mapped_linear(info); } printf("\n"); } VM_InfoBlock far *get_vm_info(DWORD vm) { DWORD ofs = (DWORD) GetVMInfoBlockOffset(); if (! ofs) return (VM_InfoBlock far *) 0; // call not supported ofs += vm; // add in handle to VMCB return (VM_InfoBlock far *) map_linear(ofs, sizeof(VM_InfoBlock)); // caller must call free_mapped_linear } WORD GetVMInfoBlockOffset(void) { WORD ofs = 0; InitVxDAPI(); _asm mov ax, VxD_Get_InfoBlock _asm call dword ptr [API] _asm jc done _asm mov ofs, bx done: return ofs; } void InitVxDAPI(void) { if (! API) // one-time initialization if (! (API = GetVxDAPI(Generic_Dev_ID))) fail("This program requires device=VXD.386"); } FP GetVxDAPI(WORD vxd_id) { _asm push di _asm mov ax, 1684h _asm mov bx, vxd_id _asm xor di, di _asm mov es, di _asm int 2fh _asm mov ax, di _asm mov dx, es _asm pop di // returns in DX:AX } FP map_linear(DWORD lin_addr, DWORD num_bytes) { WORD sel; _asm mov sel, ds if ((sel = AllocSelector(sel)) == 0) return (FP) 0; SetSelectorBase(sel, lin_addr); SetSelectorLimit(sel, num_bytes - 1); return MAKELP(sel, 0); } void free_mapped_linear(FP fp) { FreeSelector(FP_SEG(fp)); } DWORD GetSysVMHandle(void) { VxDParams p; p.CallNum = Get_Sys_VM_Handle; return (VxDCall(&p)) ? p.OutEBX : 0; } DWORD GetNextVMHandle(DWORD vm) { VxDParams p; p.CallNum = Get_Next_VM_Handle; p.InEBX = vm; return (VxDCall(&p)) ? p.OutEBX : 0; } BOOL VxDCall(VxDParams far *fp) { InitVxDAPI(); _asm les bx, dword ptr fp _asm mov ax, VXD_VxDCall _asm call dword ptr [API] _asm jc error return TRUE; error: return FALSE; } Figure 2: The VM_InfoBlock, a pointer to which appears in ESI during a Create_VM message. #pragma pack(1) typedef struct { DWORD lin; WORD sel; } SELLIN; // use lin; ignore sel typedef struct { DWORD SGVMI_Flags; /* initial SHELL_GetVMInfo flags */ DWORD PIF_Bits; SELLIN Comspec; /* COMSPEC string */ SELLIN CmdLine; /* command line */ SELLIN CurDrive; /* current drive string */ WORD MaxAllocPages, MinAllocPages; WORD ForeGroundPrio, BackGroundPrio; WORD MaxEMS_Kbytes, MinEMS_Kbytes; WORD MaxXMS_Kbytes, MinXMS_Kbytes; WORD hWnd; /* Window handle for WinOldAp */ WORD Offset2C; /* ??? */ char AppName[32]; /* Name from PIF "Window Title" */ } VM_InfoBlock;