/* * smdetect.cpp * * Created by Daniel Fernandez (soyfeliz@48bits.com) on 19/03/2010 * * Copyright (c) 2010 48BITS * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the project's author nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #ifdef _WIN32 #include #else #include #endif class Buffer { int *buffer; unsigned int size; unsigned long long gettime() { struct timeval tv; gettimeofday(&tv, NULL); return ((unsigned long long) tv.tv_sec) * 1000000ULL + (unsigned long long) tv.tv_usec; } public: enum Exceptions { ALLOC_FAILED, LOCK_FAILED, }; Buffer(unsigned int sz, bool locking, unsigned int seconds) : size(sz) { #ifdef _WIN32 HANDLE hProcess(GetCurrentProcess()); SIZE_T minws, maxws; buffer = (int *) VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); if (buffer == NULL) throw ALLOC_FAILED; if (locking == true) { GetProcessWorkingSetSize(hProcess, &minws, &maxws); SetProcessWorkingSetSize(hProcess, minws + size, maxws + size); if (VirtualLock(buffer, size) == 0) throw LOCK_FAILED; } #else buffer = (int *) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if (buffer == MAP_FAILED) throw ALLOC_FAILED; if (locking == true && mlock(buffer, size) == -1) throw LOCK_FAILED; #endif for (unsigned int x(0); x != size/sizeof(int); ++x) buffer[x] = 0x443d3d38; #ifdef _WIN32 Sleep(seconds * 1000); #else sleep(seconds); #endif } ~Buffer() { #ifdef _WIN32 VirtualUnlock(buffer, size); VirtualFree(buffer, 0, MEM_RELEASE); #else munmap(buffer, size); #endif } unsigned long long measureWrite() { unsigned long long start(gettime()); for (unsigned int x(0); x != size/sizeof(int); ++x) buffer[x] = x; return gettime() - start; } }; unsigned long long getTime(unsigned int bsize, bool locking, unsigned int sleep_seconds = 0) { Buffer buf(bsize, locking, sleep_seconds); return buf.measureWrite(); } int main(int argc, char *argv[]) { unsigned int buffer_size(15*1024*4096); unsigned int sleep_time(60); unsigned int threshold(98); bool locking(true); char c; while ((c = getopt(argc, argv, "pm:s:t:")) != -1) { switch(c) { case 'p': locking = false; break; case 'm': buffer_size = (atoi(optarg) * 1024 * 1024) & ~4095; break; case 's': sleep_time = atoi(optarg); break; case 't': threshold = atoi(optarg); break; case '?': std::cout << "\nOptions:\n" << "-m size\t buffer size in Mb (default 60mb)\n" << "-s time\t sleep time in second (default 60secs)\n" << "-t num\t threshold (default 98)\n" << "-p\t disable locking (default enabled)" << std::endl; return -1; } } try { unsigned long long t1(getTime(buffer_size, locking)); unsigned long long t2(getTime(buffer_size, locking, sleep_time)); int variation((std::abs((long long)(t2 - t1))*100)/t1); std::cout << "First write: " << t1 << "\nSecond write: " << t2 << "\nVariation: " << variation << "%\n" << (variation >= threshold ? "VMM detected!" : "no VMM detected") << std::endl; } catch (Buffer::Exceptions e) { if (e == Buffer::ALLOC_FAILED) { std::cout << "Can't alloc buffer, try with a smaller size (-m)\n" "Or check your capabilities" << std::endl; } if (e == Buffer::LOCK_FAILED) { std::cout << "Can't lock buffer, check your capabilities\n" "Or use -p flag" << std::endl; } } return 0; }