/* This file is part of VMware backdoor tool for Solaris guest written by Markus Gyger. It compiles both with Sun's compiler and gcc, and also on Linux. Place both vmw.c and vmw_door.s files in a same directory then execute: cc -O -DHAVE_CLOCK_SETTIME -o vmw vmw.c vmw_door.s -lrt */ #include #include #include #include #include #include #include #include #define VMW_VERS 6 #define VMW_ADDR ('V' << 24 | 'M' << 16 | 'X' << 8 | 'h') #define VMW_PORT ('V' << 8 | 'X') typedef struct vmw_door_t { int eax, ebx, ecx, edx; } vmw_door_t; #ifdef __i386 extern int vmw_door(vmw_door_t *); #else static int vmw_door(vmw_door_t *r) { raise(SIGSEGV); return r->eax; } #endif static sigjmp_buf sigsegvbuffer; static void sigsegvhandler(int sig) { siglongjmp(sigsegvbuffer, sig); } int main(int argc, char *argv[]) { vmw_door_t regs = { VMW_ADDR, 0, 0x0a, VMW_PORT }; struct sigaction action, oldaction; int c, cmd = 'V', quiet = 0; /* parse command line options */ while ((c = getopt(argc, argv, ":pqrtV")) != -1) switch (c) { default: cmd = c; break; case 'q': quiet++; break; case ':': case '?': fprintf(stderr, "usage: %s [-q] [-p|-r|-t|-V]\n" "\t-p print product name\n" "\t-q be quiet (return exit status)\n" "\t-r print screen size\n" "\t-t set time and date\n" "\t-V print version (default)\n", argv[0]); return 2; } /* setup signal handler to catch segmentation violation */ sigemptyset(&action.sa_mask); action.sa_flags = SA_RESTART; action.sa_handler = sigsegvhandler; sigaction(SIGSEGV, &action, &oldaction); if (sigsetjmp(sigsegvbuffer, 1) != 0) { sigaction(SIGSEGV, &oldaction, 0); if (!quiet) puts("Not running on VMware"); return 1; } vmw_door(®s); sigaction(SIGSEGV, &oldaction, 0); if (regs.ebx != VMW_ADDR) { if (!quiet) fprintf(stderr, "Incorrect virtual machine version " "%x (should be %x)\n", regs.ebx, VMW_ADDR); return 3; } if (regs.eax != VMW_VERS) { fprintf(stderr, "VMware software version %d (should be %d)\n", regs.eax, VMW_VERS); return 4; } /* print version */ if (cmd == 'V') { if (!quiet) printf("VMware software version %d (good)\n", regs.eax); /* print product name */ } else if (cmd == 'p') { const char *product[] = { "Express", "ESX Server", "GSX Server", "Workstation" }; if (regs.ecx < 1 || regs.ecx > 4) puts("Unknown"); else puts(product[regs.ecx - 1]); /* print screen size */ } else if (cmd == 'r') { int x, y; vmw_door_t regs = { VMW_ADDR, 0, 0x0f, VMW_PORT }; vmw_door(®s); x = regs.eax >> 16; y = regs.eax << 16 >> 16; if (x < 0 || y < 0) puts("0 0"); else printf("%d %d\n", x, y); /* set time and date */ } else if (cmd == 't') { int ret = -1; vmw_door_t regs = { VMW_ADDR, 0, 0x17, VMW_PORT }; vmw_door(®s); #if HAVE_CLOCK_SETTIME if (ret == -1) { struct timespec timespec; timespec.tv_sec = regs.eax; timespec.tv_nsec = regs.ebx * 1000L + regs.ecx / 1000; ret = clock_settime(CLOCK_REALTIME, ×pec); if (ret == -1 && errno != ENOSYS) { perror("clock_settime()"); return 5; } } #endif /* HAVE_CLOCK_SETTIME */ #if HAVE_SETTIMEOFDAY if (ret == -1) { struct timeval timeval; timeval.tv_sec = regs.eax; timeval.tv_usec = regs.ebx; ret = settimeofday(&timeval, 0); if (ret == -1) { perror("settimeofday()"); return 6; } } #endif /* HAVE_SETTIMEOFDAY */ #if HAVE_STIME if (ret == -1) { time_t now = regs.eax; ret = stime(&now); if (ret == -1) { perror("stime()"); return 6; } } #endif /* HAVE_STIME */ if (ret == -1) { fprintf(stderr, "No function available to set time\n"); return 7; } if (!quiet) { char s[80]; time_t now = time(0); if (strftime(s, sizeof s, "%Y-%m-%d %T %Z", localtime(&now)) > 0) puts(s); else return 8; } } else return 9; return 0; }