Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Talking to VMWare's backdoor port

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Talking to VMWare's backdoor port

    Communicating with VMWare when you're running inside it is fairly straight forward... basically you just set up a few registers with certain parameters and then call a port.

    This backdoor port acts as a bridge between the virtual machine and the host machine, allowing them to talk to each other. And this is what VMWare Tools does, allowing you to do such things as copy files to and from the virtual machine and host machine. Without this backdoor port such features wouldn't be possible.

    Saying hello to VMWare is easy. For example, to retrieve the VMWare version number you set the following registers:
    EAX = &h564D5868 ("VMXh") ;'Magic number' used by VM to identify calls made to it
    CX = &h000A ;Command number (&hA = Get Version)
    DX = &h5658 ;Port number


    CX is used to specify the command. EAX and DX are constants. The return values are stored in eax, and ebx/ecx/edx as needed. That's basically all there is to it!

    If you try to make such a call when you're NOT running from within VMWare your program will crash because of the call to privileged port instruction "in", so we simply need to set up a Structured Exception Handler first.

    So while the virtual machine is isolated from the host machine this backdoor port shows that it's not completely isolated ...

    For example, this demo when run from within a virtual machine will show you the current clipboard text of the HOST machine even though it is supposedly isolated. You could for example write a program that runs inside VMWare that sits in a loop, checking the contents of the host machines clipboard every second and logging it ... something of an 'intra-machine clipboard logger'. You can also SET the clipboard text on the host from within the virtual machine, although i haven't included code for that.

    This demo also shows other things such as memory size, CPU speed, screen dimensions, and a few others. Some are related to the virtual machine, some to the host, and some to both (such as getting clipboard text).

    You can also use the backdoor port to copy files from the host to the virtual machine and back, but I haven't included any code for that here.

    You can find more information about the VMWare backdoor port at http://chitchat.at.infoseek.co.jp/vmware/backdoor.html, it's what I used to help write this.

    Code:
    #COMPILE EXE
    #REGISTER NONE
    #INCLUDE "WIN32API.INC"
     
    TYPE SEH
         dwPrevLink AS DWORD
         dwCurrentHandler AS DWORD
         dwSafeOffset AS DWORD
         dwPrevEsp AS DWORD
         dwPrevEbp AS DWORD
    END TYPE
     
    TYPE VMWareReply
     eax AS DWORD
     ebx AS DWORD
     ecx AS DWORD
     edx AS DWORD
    END TYPE
     
    FUNCTION SEH_Handler CDECL( ptExcept AS EXCEPTION_RECORD PTR, ptFrame AS SEH PTR, ptContext AS CONTEXT PTR, BYVAL pdwDispatch AS DWORD) AS LONG
     @ptContext.regEip = @ptFrame.dwSafeOffset
    END FUNCTION
     
    FUNCTION VMWareCall (VMReply AS VMWareReply, BYVAL vmebx AS DWORD, BYVAL vmecx AS DWORD, BYVAL vmedx AS DWORD) AS LONG
       #REGISTER NONE
       LOCAL lEbp AS LONG, lEsp AS LONG, tSeh AS SEH, ptrReply AS DWORD
       ptrReply = VARPTR(VMReply)
       ! push dword fs:[0]
       tSeh.dwCurrentHandler = CODEPTR(SEH_HANDLER)
       tSeh.dwSafeOffset = CODEPTR(Except)
       ! lea esi, tSeh
       ! mov fs:[0], esi
       ! mov lEsp, esp
       ! mov lEbp, ebp
       tSeh.dwPrevEsp = lEsp
       tSeh.dwPrevEbp = lEbp
       ! mov      eax, "VMXh"
       ! mov      ebx, vmebx
       ! mov      ecx, vmecx
       ! mov      edx, vmedx
       ! in       eax, dx
       ! push esi
       ! mov esi, ptrReply
       ! mov [esi],    eax
       ! mov [esi+4],  ebx
       ! mov [esi+8],  ecx
       ! mov [esi+12], edx
       ! pop esi
       FUNCTION = 1
    Except:
    ! pop dword fs:[0]
    END FUNCTION
    
    '### VMWARE CALLS ######################################################################
    
    FUNCTION GetVMVersion() AS STRING       '// Returns VMWare version and product type
    LOCAL VMReply AS VMWareReply, sVer AS STRING
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h0000000A, BYVAL &h00005658) <> 1 THEN
       FUNCTION = "Error": EXIT FUNCTION
    ELSE
       SELECT CASE VMReply.ecx
           CASE 1: sVer = "Express"
           CASE 2: sVer = "ESX Server"
           CASE 3: sVer = "GSX Server"
           CASE 4: sVer = "Workstation"
       END SELECT
       sVer = sVer & " (Version: " & HEX$(VMReply.eax) & ")"
       FUNCTION = sVer
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMHardwareVersion() AS STRING  '// Returns virtual machine hardware version
    LOCAL VMReply AS VMWareReply
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000011, BYVAL &h00005658) <> 1 THEN
       FUNCTION = "Error": EXIT FUNCTION
    ELSE
       SELECT CASE VMReply.eax
           CASE 1, 2: FUNCTION = TRIM$(STR$(VMReply.eax)) & " - WS3.x/GSX2.x"
           CASE 3: FUNCTION = "3 - WS4.x, ESX2.x, GSX3.x, ACE1.x, and with WS5.x"
           CASE 4: FUNCTION = "4 - WS5.x"
           CASE ELSE: FUNCTION = TRIM$(STR$(VMReply.eax)) & " - Unknown"
       END SELECT
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMCPUSpeed() AS STRING       '// Returns host CPU speed in MHz
    LOCAL VMReply AS VMWareReply
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000001, BYVAL &h00005658) <> 1 THEN
       FUNCTION = "Error": EXIT FUNCTION
    ELSE
       FUNCTION = TRIM$(STR$(VMReply.eax)) & "MHz"
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMCursorPos() AS STRING       '// Returns current cursor position
    LOCAL VMReply AS VMWareReply
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000004, BYVAL &h00005658) <> 1 THEN
       FUNCTION = "Error": EXIT FUNCTION
    ELSE
       FUNCTION = "X=" & TRIM$(STR$(LOWRD(VMReply.eax))) & " Y=" & TRIM$(STR$(HIWRD(VMReply.eax)))
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMHostScreenSize() AS STRING  '// Returns dimensions of the host screen size
    LOCAL VMReply AS VMWareReply
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h0000000F, BYVAL &h00005658) <> 1 THEN
       FUNCTION = "Error": EXIT FUNCTION
    ELSE
       FUNCTION = TRIM$(STR$(LOWRD(VMReply.eax))) & " x " & TRIM$(STR$(HIWRD(VMReply.eax)))
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMClipboardTextLen() AS DWORD '// Returns length of text in clipboard
    LOCAL VMReply AS VMWareReply, sBuf AS STRING
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000006, BYVAL &h00005658) <> 1 THEN
       EXIT FUNCTION
    ELSE
       FUNCTION = VMReply.eax
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMMemorySize() AS STRING   '// Returns amount of memory assigned to the virtual machine
    LOCAL VMReply AS VMWareReply
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000014, BYVAL &h00005658) <> 1 THEN
       EXIT FUNCTION
    ELSE
       FUNCTION = TRIM$(STR$(VMReply.eax)) & " MBs"
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMHostSystemTime() AS STRING   '// Returns hosts current system time (GMT)
    LOCAL VMReply AS VMWareReply, sTime AS STRING
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000017, BYVAL &h00005658) <> 1 THEN
       EXIT FUNCTION
    ELSE
       sTime = HEX$(VMReply.eax,8) & " (Timezone: " & TRIM$(STR$(VMReply.edx)) & ")"
       FUNCTION = sTime
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMClipboardText() AS STRING '// Returns text from clipboard
    LOCAL VMReply AS VMWareReply, sBuf AS STRING, txtLen AS LONG, dwPtr AS DWORD PTR
    txtLen = GetVMClipboardTextLen
    IF txtLen <= 0 THEN
        FUNCTION = "{Empty}": EXIT FUNCTION
    END IF
    sBuf = STRING$(txtLen+4,0)
    dwPtr = STRPTR(sBuf)
    DO
     IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000007, BYVAL &h00005658) <> 1 THEN
       FUNCTION = "Error": EXIT FUNCTION
     ELSE
       IF VMReply.eax = 0 THEN EXIT DO
       @dwPtr = VMReply.eax
       dwPtr = dwPtr + 4
     END IF
    LOOP
    FUNCTION = LEFT$(sBuf, txtLen)
    END FUNCTION
    
    
    FUNCTION InsideVMWare() AS LONG '// Returns 1 if we're running inside VMWare
     LOCAL VMReply AS VMWareReply
     FUNCTION = VMWareCall(VMReply, BYVAL 0, BYVAL &h0000000A, BYVAL &h00005658)
    END FUNCTION
    
    
    FUNCTION PBMAIN() AS LONG
    IF InsideVMWare <> 1 THEN
        STDOUT "Not running in VMWare."
        WAITKEY$: EXIT FUNCTION
    END IF
    STDOUT "Type/Version: " & GetVMVersion
    STDOUT "CPU Speed: " & GetVMCPUSpeed
    STDOUT "Cursor: " & GetVMCursorPos
    STDOUT "Host Screen Size: " & GetVMHostScreenSize
    STDOUT "Clipboard Text: " & GetVMClipboardText
    STDOUT "Virtual Hardware Version: " & GetVMHardwareVersion
    STDOUT "Memory: " & GetVMMemorySize
    STDOUT "Host System Time (unix-style timestamp): " & GetVMHostSystemTime
    STDOUT "Done."
    WAITKEY$
    END FUNCTION
    Last edited by Wayne Diamond; 25 Jul 2008, 04:34 PM.
    -

  • #2
    I had a request regarding the above old 2008 code which isn't compiling as-is in the latest PB compilers, so I've updated it to support both the latest PBCC and PBWin, and I've just tested it under the latest VMWare 8 and it's still working fine (which is to be expected I guess for necessary backwards compatibility).

    The VMWare backdoor commands page no longer exists, but the latest online version (2010) can be found archived here - I recommend saving a local copy:


    2014 revision for PBCC5/6 & PBWin9/10...
    Code:
    #COMPILE EXE
    #REGISTER NONE
    #INCLUDE "WIN32API.INC"
    
    TYPE SEH
        dwPrevLink AS DWORD
        dwCurrentHandler AS DWORD
        dwSafeOffset AS DWORD
        dwPrevEsp AS DWORD
        dwPrevEbp AS DWORD
    END TYPE
    
    TYPE VMWareReply
     eax AS DWORD
     ebx AS DWORD
     ecx AS DWORD
     edx AS DWORD
    END TYPE
    
    FUNCTION SEH_Handler CDECL( BYVAL ptExcept AS EXCEPTION_RECORD PTR, BYVAL ptFrame AS SEH PTR, BYVAL ptContext AS CONTEXT PTR, BYVAL pdwDispatch AS DWORD) AS LONG
     @ptContext.regEip = @ptFrame.dwSafeOffset
    END FUNCTION
    
    FUNCTION VMWareCall (VMReply AS VMWareReply, BYVAL vmebx AS DWORD, BYVAL vmecx AS DWORD, BYVAL vmedx AS DWORD) AS LONG  '// VMWare backdoor call master gateway function
      #REGISTER NONE
      LOCAL lEbp AS LONG, lEsp AS LONG, tSeh AS SEH, ptrReply AS DWORD
      ptrReply = VARPTR(VMReply)
      ! push dword fs:[0]
      tSeh.dwCurrentHandler = CODEPTR(SEH_HANDLER)
      tSeh.dwSafeOffset = CODEPTR(Except)
      ! lea esi, tSeh
      ! mov fs:[0], esi
      ! mov lEsp, esp
      ! mov lEbp, ebp
      tSeh.dwPrevEsp = lEsp
      tSeh.dwPrevEbp = lEbp
      ! mov      eax, "VMXh"
      ! mov      ebx, vmebx
      ! mov      ecx, vmecx
      ! mov      edx, vmedx
      ! in      eax, dx
      ! push esi
      ! mov esi, ptrReply
      ! mov [esi],    eax
      ! mov [esi+4],  ebx
      ! mov [esi+8],  ecx
      ! mov [esi+12], edx
      ! pop esi
      FUNCTION = 1
    Except:
    ! pop dword fs:[0]
    END FUNCTION
    
    
    '### VMWARE CALLS ######################################################################
    
    FUNCTION GetVMVersion() AS STRING      '// Returns VMWare version and product type
    LOCAL VMReply AS VMWareReply, sVer AS STRING
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h0000000A, BYVAL &h00005658) <> 1 THEN
      FUNCTION = "Error": EXIT FUNCTION
    ELSE
      SELECT CASE VMReply.ecx   '// not updated since 2008, there may be more/newer/different versions...
          CASE 1: sVer = "Express"
          CASE 2: sVer = "ESX Server"
          CASE 3: sVer = "GSX Server"
          CASE 4: sVer = "Workstation"
      END SELECT
      sVer = sVer & " (Version: " & HEX$(VMReply.eax) & ")"
      FUNCTION = sVer
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMHardwareVersion() AS STRING  '// Returns virtual machine hardware version
    LOCAL VMReply AS VMWareReply
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000011, BYVAL &h00005658) <> 1 THEN
      FUNCTION = "Error": EXIT FUNCTION
    ELSE
      SELECT CASE VMReply.eax
          CASE 1, 2: FUNCTION = TRIM$(STR$(VMReply.eax)) & " - WS3.x/GSX2.x"
          CASE 3: FUNCTION = "3 - WS4.x, ESX2.x, GSX3.x, ACE1.x, and with WS5.x"
          CASE 4: FUNCTION = "4 - WS5.x"
          CASE ELSE: FUNCTION = TRIM$(STR$(VMReply.eax)) & " - Unknown"
      END SELECT
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMCPUSpeed() AS STRING      '// Returns host CPU speed in MHz
    LOCAL VMReply AS VMWareReply
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000001, BYVAL &h00005658) <> 1 THEN
      FUNCTION = "Error": EXIT FUNCTION
    ELSE
      FUNCTION = TRIM$(STR$(VMReply.eax)) & "MHz"
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMCursorPos() AS STRING      '// Returns current cursor position
    LOCAL VMReply AS VMWareReply
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000004, BYVAL &h00005658) <> 1 THEN
      FUNCTION = "Error": EXIT FUNCTION
    ELSE
      FUNCTION = "X=" & TRIM$(STR$(LOWRD(VMReply.eax))) & " Y=" & TRIM$(STR$(HIWRD(VMReply.eax)))
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMHostScreenSize() AS STRING  '// Returns dimensions of the host screen size
    LOCAL VMReply AS VMWareReply
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h0000000F, BYVAL &h00005658) <> 1 THEN
      FUNCTION = "Error": EXIT FUNCTION
    ELSE
      FUNCTION = TRIM$(STR$(LOWRD(VMReply.eax))) & " x " & TRIM$(STR$(HIWRD(VMReply.eax)))
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMClipboardTextLen() AS DWORD '// Returns length of text in clipboard
    LOCAL VMReply AS VMWareReply, sBuf AS STRING
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000006, BYVAL &h00005658) <> 1 THEN
      EXIT FUNCTION
    ELSE
      FUNCTION = VMReply.eax
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMMemorySize() AS STRING  '// Returns amount of memory assigned to the virtual machine
    LOCAL VMReply AS VMWareReply
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000014, BYVAL &h00005658) <> 1 THEN
      EXIT FUNCTION
    ELSE
      FUNCTION = TRIM$(STR$(VMReply.eax)) & " MBs"
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMHostSystemTime() AS STRING  '// Returns hosts current system time (GMT)
    LOCAL VMReply AS VMWareReply, sTime AS STRING
    IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000017, BYVAL &h00005658) <> 1 THEN
      EXIT FUNCTION
    ELSE
      sTime = HEX$(VMReply.eax,8) & " (Timezone: " & TRIM$(STR$(VMReply.edx)) & ")"
      FUNCTION = sTime
    END IF
    END FUNCTION
    
    
    FUNCTION GetVMClipboardText() AS STRING '// Returns text from clipboard
    LOCAL VMReply AS VMWareReply, sBuf AS STRING, txtLen AS LONG, dwPtr AS DWORD PTR
    txtLen = GetVMClipboardTextLen
    IF txtLen <= 0 THEN
        FUNCTION = "{Empty}": EXIT FUNCTION
    END IF
    sBuf = STRING$(txtLen+4,0)
    dwPtr = STRPTR(sBuf)
    DO
     IF VMWareCall(VMReply, BYVAL 0, BYVAL &h00000007, BYVAL &h00005658) <> 1 THEN
      FUNCTION = "Error": EXIT FUNCTION
     ELSE
      IF VMReply.eax = 0 THEN EXIT DO
      @dwPtr = VMReply.eax
      dwPtr = dwPtr + 4
     END IF
    LOOP
    FUNCTION = LEFT$(sBuf, txtLen)
    END FUNCTION
    
    
    FUNCTION InsideVMWare() AS LONG '// Returns 1 if we're running inside VMWare
     LOCAL VMReply AS VMWareReply
     FUNCTION = VMWareCall(VMReply, BYVAL 0, BYVAL &h0000000A, BYVAL &h00005658)
    END FUNCTION
    
    
    FUNCTION PBMAIN() AS LONG
    IF InsideVMWare <> 1 THEN STDOUT "Not running in VMWare.": GOTO TheEnd
    ? "Type/Version: " & GetVMVersion
    ? "CPU Speed: " & GetVMCPUSpeed
    ? "Cursor: " & GetVMCursorPos
    ? "Host Screen Size: " & GetVMHostScreenSize
    ? "Clipboard Text: " & GetVMClipboardText
    ? "Virtual Hardware Version: " & GetVMHardwareVersion
    ? "Memory: " & GetVMMemorySize
    ? "Host System Time (unix-style timestamp): " & GetVMHostSystemTime
    TheEnd:
    #IF %DEF(%PB_CC32)
     WAITKEY$
    #ENDIF
    END FUNCTION
    Last edited by Wayne Diamond; 26 Nov 2014, 11:20 AM.
    -

    Comment

    Working...
    X