Puppetmaster Strikes Back

Vincent Mussot and I implemented new virtualization counter-countermeasures in puppetmaster. This time we can detect and thwart 6 tests out of 7 in ScoopyNG. In addition to the SIDT test, we counter the SLDT, SGDT and STR techniques in a similar way: instrument the binary until one of these instructions is found, intercept the memory address it writes to and patch the return value.

The 2 other tests use the VMware backdoor (the in eax instruction, with a magic value in eax and edx). We thwart it by detecting the backdoor trigger, and changing the magic values (this way an exception is raised, as if there were no backdoor). We then restore the magic values to add a little bit of stealth.

You can compile and run puppetmaster with the latest version (27887) of Pin on Windows and Linux. The makefile for the free version of Visual C++ is given below.

// puppetmaster.cpp
// Usage: pin -t <puppetmaster.dll> -- <binary> [arguments]\n
// Currently supported anti-virtualisation techniques: SIDT, SLDT, SGDT, STR, VMWare channel
// works with pin-2.6-27887-msvc9

#include <string>
#include "pin.H"

int needRestore = 0;

VOID poisonSIDT(ADDRINT memIp) {
 char *data = (char *)memIp;
 unsigned int* m = (unsigned int *)(data+2);
 *m = 0xd00dbeef; // if ((idt_base >> 24) == 0xff) -> vmware detected
}

void poisonSLDT(ADDRINT memIp) {
 char *data = (char *)memIp;
 unsigned int* m = (unsigned int *)(data);
 *m = 0xdead0000; // if (ldt_base != 0xdead0000) -> vmware detected
}

void poisonSGDT(ADDRINT memIp) {
 char *data = (char *)memIp;
 unsigned int* m = (unsigned int *)(data+2);
 *m = 0xdeadbabe; // if ((gdt_base >> 24) == 0xff) -> vmware detected
}

void poisonSTR(ADDRINT memIp) {
 char *data = (char *)memIp;
 unsigned int* m = (unsigned int *)(data);
 *m = 0xbebaadde; // if ((mem[0] == 0x00) && (mem[1] == 0x40)) -> vmware detected
}

void poisonVMWareChannel() {
 unsigned int EAX_save;
 unsigned short int DX_save;
 __asm {
 mov EAX_save, eax
 mov DX_save, dx
 }
 if ((EAX_save == 0x564D5868) && (DX_save == 0x5658)){
 __asm {
 mov dx, 0x0004
 }
 needRestore = 1;
 }
 else needRestore = 0;
}

void restoreVMWareChannel() {
 if (needRestore == 1) {
 __asm {
 mov eax, 0x564D5868
 mov dx, 0x5658
 }
 needRestore = 0;
 }
}

VOID Instruction(INS ins, VOID *v) {
 string buffer = INS_Disassemble(ins);
 if (buffer.substr(0,4) == "sidt")
 INS_InsertCall(ins, IPOINT_AFTER, (AFUNPTR)poisonSIDT, IARG_MEMORYWRITE_EA, IARG_END);
 else if (buffer.substr(0,4) == "sldt")
 INS_InsertCall(ins, IPOINT_AFTER, (AFUNPTR)poisonSLDT, IARG_MEMORYWRITE_EA, IARG_END);
 else if (buffer.substr(0,4) == "sgdt")
 INS_InsertCall(ins, IPOINT_AFTER, (AFUNPTR)poisonSGDT, IARG_MEMORYWRITE_EA, IARG_END);
 else if (buffer.substr(0,3) == "str")
 INS_InsertCall(ins, IPOINT_AFTER, (AFUNPTR)poisonSTR, IARG_MEMORYWRITE_EA, IARG_END);
 else if (buffer.substr(0,6) == "in eax") {
 INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)poisonVMWareChannel, IARG_END);
 INS_InsertCall(ins, IPOINT_AFTER, (AFUNPTR)restoreVMWareChannel, IARG_END);
 }
}

int main(int argc, char * argv[]) {
 PIN_Init(argc, argv);
 INS_AddInstrumentFunction(Instruction, 0);
 PIN_StartProgram();
 return 0;
}

Here is the Nmakefile for the Nmake utility:


# Nmakefile
######################################################################################
# This is the NMAKE file for building and testing PIN toos contained in one of the
# subdirectories of the PinTool project or PIN kit.
#
# For description of targets and options, see Nmakefile in the root directory.
######################################################################################

!if "$(PIN_HOME)"==""
PIN_HOME=..
!endif

# Define tools to be buit and tested
######################################################################################
COMMON_TOOLS=puppetmaster.dll

# Include building and testing rules from the root Nmakefile.
######################################################################################
INCLUDE_SUB_RULES=1
!INCLUDE $(PIN_HOME)\Nmakefile

Build instructions:

  • download and install Pin and Visual C++
  • under $PIN_HOME\source\tools, create a puppetmaster directory
  • put puppetmaster.cpp and the Nmakefile in that directory
  • from that directory, run ..\nmake.bat puppetmaster.dll

Now you can run it and use your newly acquired ninja skills on ScoopyNG:

<pre>C:\pin-2.6-27887-msvc9-ia32_intel64-windows\source\tools\puppetmaster>pin -t obj-ia32\puppetmaster.dll -- ScoopyNG.exe
####################################################
::       ScoopyNG - The VMware Detection Tool     ::
::              Windows version v1.0              ::

[+] Test 1: IDT
IDT base: 0xd00dbeef
Result  : Native OS

[+] Test 2: LDT
LDT base: 0xdead0000
Result  : Native OS

[+] Test 3: GDT
GDT base: 0xdeadbabe
Result  : Native OS

[+] Test 4: STR
STR base: 0xdeadbabe
Result  : Native OS

[+] Test 5: VMware "get version" command
Result  : Native OS

[+] Test 6: VMware "get memory size" command
Result  : Native OS

::                   tk,  2008                    ::
::               [ www.trapkit.de ]               ::
####################################################

Note: we do not support the last test in ScoopyNG because Pin does not currently support far rets in different code segments. But as far as I can tell the bug that this last test uses has been patched, I was not able to trigger it. It should probably be considered deprecated.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s