2012-04-10 25 views
9

Tôi đang cố gắng phát triển một ứng dụng phát hiện chương trình đang chạy bên trong máy ảo.Cửa sổ 64 bit Phát hiện VMware

Đối với Windows 32-bit, đã có phương pháp giải thích trong liên kết sau: http://www.codeproject.com/Articles/9823/Detect-if-your-program-is-running-inside-a-Virtual

Tôi cố gắng để thích nghi với mã về Virtual PC và VMware phát hiện trong một hệ điều hành Windows 64-bit. Đối với VMware, mã có thể phát hiện thành công trong hệ điều hành Windows XP 64 bit. Nhưng chương trình bị treo khi tôi chạy nó trong một hệ thống bản địa (Windows 7 64-bit OS).

Tôi đặt mã trong tệp .asm và xác định bước xây dựng tùy chỉnh bằng tệp ml64.exe. Mã asm cho 64-bit Windows là:

IsInsideVM proc 

     push rdx 
     push rcx 
     push rbx 

     mov rax, 'VMXh' 
     mov rbx, 0  ; any value but not the MAGIC VALUE 
     mov rcx, 10 ; get VMWare version 
     mov rdx, 'VX' ; port number 

     in  rax, dx ; read port 
         ; on return EAX returns the VERSION 
     cmp rbx, 'VMXh'; is it a reply from VMWare? 
     setz al   ; set return value 
     movzx rax,al 

     pop rbx 
     pop rcx 
     pop rdx 

     ret 
IsInsideVM endp 

tôi gọi phần này trong một file cpp như:

__try 
{ 
returnValue = IsInsideVM(); 
} 
__except(1) 
{ 
    returnValue = false; 
} 

Cảm ơn trước.

+1

Vâng vâng, cố gắng truy cập các cổng phần cứng, một hoạt động đặc quyền, sẽ bẫy trong mã người dùng. Bạn cần phải nắm bắt ngoại lệ bằng SEH. Có vẻ như bạn đang cố gắng, nhưng bạn chưa hiển thị (1) tùy chọn trình biên dịch hoặc (2) theo dõi trình gỡ lỗi. –

Trả lời

4

Các cũ viên thuốc màu đỏ từ Joanna có thể làm việc: random backup page of invisiblethings.org blog:

Nuốt thuốc tránh thai Red là nhiều hơn hoặc ít tương đương với đoạn mã sau (trả phi zero khi trong Matrix):

int swallow_redpill() { 
    unsigned char m[2+4], rpill[] = "\x0f\x01\x0d\x00\x00\x00\x00\xc3"; 
    *((unsigned*)&rpill[3]) = (unsigned)m; 
    ((void(*)())&rpill)(); 
    return (m[5]>0xd0) ? 1 : 0; 
} 

Trái tim của mã này thực sự là lệnh SIDT (được mã hóa là 0F010D [addr]), lưu trữ nội dung của bảng đăng ký mô tả ngắt (IDTR) trong toán hạng đích, thực ra là vị trí bộ nhớ. Điều đặc biệt và thú vị về lệnh SIDT là, nó có thể được thực hiện trong chế độ không đặc quyền (ring3) nhưng nó trả về nội dung của thanh ghi nhạy cảm, được sử dụng nội bộ bởi hệ điều hành.

Vì chỉ có một đăng ký IDTR, nhưng có ít nhất hai hệ điều hành chạy đồng thời (tức là máy chủ và hệ điều hành khách), VMM cần phải định vị lại IDTR của khách ở nơi an toàn, để nó không xung đột với một máy chủ. Thật không may, VMM không thể biết nếu (và khi) quá trình chạy trong hệ điều hành khách thực thi lệnh SIDT, vì nó không phải là đặc quyền (và nó không tạo ra ngoại lệ). Do đó quá trình sẽ nhận được địa chỉ được di chuyển của bảng IDT. Nó đã được quan sát thấy rằng trên VMWare, địa chỉ relocated của IDT là tại địa chỉ 0xffXXXXXX, trong khi trên Virtual PC nó là 0xe8XXXXXX. Điều này đã được thử nghiệm trên VMWare Workstation 4 và Virtual PC 2004, cả hai đều chạy trên hệ điều hành Windows XP host.

Lưu ý: Tôi chưa thử nghiệm bản thân nhưng nhìn nó sử dụng cách tiếp cận không có đặc quyền. Nếu nó không hoạt động lúc đầu cho x64, một số tinh chỉnh có thể hữu ích.

Ngoài ra, vừa phát hiện ra một câu hỏi với nội dung có thể giúp bạn: Detecting VMM on linux

0

tôi đoán là chức năng của bạn corrups đăng ký.

Chạy trên phần cứng thực (không phải VM) có thể kích hoạt ngoại lệ tại "trong rax, dx". Nếu điều này xảy ra thì điều khiển được chuyển tới trình xử lý ngoại lệ của bạn, điều này đặt kết quả, nhưng không khôi phục sổ đăng ký. Hành vi này sẽ hoàn toàn bất ngờ bởi người gọi. Ví dụ, nó có thể lưu thứ gì đó vào thanh ghi EBX/RBX, sau đó gọi mã asm, mã asm của bạn "mov RBX, 0", nó thực hiện, bắt ngoại lệ, đặt kết quả, trả về - và sau đó người gọi suddently nhận ra rằng dữ liệu đã lưu của mình không còn trong EBX/RBX nữa!Nếu có một số con trỏ được lưu trữ trong EBX/RBX - bạn sẽ gặp khó khăn. Chuyện gì cũng có thể xảy ra.

Chắc chắn, mã asm của bạn lưu/khôi phục thanh ghi, nhưng điều này chỉ xảy ra khi không có ngoại lệ. I E. nếu mã của bạn đang chạy trên máy ảo. Sau đó, mã của bạn thực hiện đường dẫn thực thi bình thường của nó, không có ngoại lệ nào được nâng lên, thanh ghi sẽ được khôi phục bình thường. Nhưng nếu có ngoại lệ - POP của bạn sẽ bị bỏ qua, vì việc thực thi sẽ được chuyển tới trình xử lý ngoại lệ.

Mã đúng có lẽ nên làm PUSH/POP bên ngoài thử/ngoại trừ khối, chứ không phải bên trong.

+0

Có lẽ 'setjmp' và' longjmp' có thể được sử dụng để buộc bảo vệ thanh ghi và ngăn xếp con trỏ (một biến toàn cầu có thể được sử dụng để cho phép kết quả tồn tại longjmp) –

+0

Có thể bạn có thể sử dụng SetUnhandledExceptionFilter để bắt lỗi, fiddle với PEXCEPTION_POINTERS điều chỉnh địa chỉ 'tiếp tục', sau đó quay lại EXCEPTION_CONTINUE_EXECUTION. –