diff --git a/pafish/Makefile.linux b/pafish/Makefile.linux index 635b470..8172a83 100644 --- a/pafish/Makefile.linux +++ b/pafish/Makefile.linux @@ -4,9 +4,9 @@ LINK = i686-w64-mingw32-gcc WINDRES = i686-w64-mingw32-windres OBJ = Objects/MingW/main.o Objects/MingW/common.o Objects/MingW/utils.o Objects/MingW/debuggers.o Objects/MingW/sandboxie.o \ Objects/MingW/vbox.o Objects/MingW/gensandbox.o Objects/MingW/wine.o Objects/MingW/vmware.o \ - Objects/MingW/qemu.o Objects/MingW/hooks.o Objects/MingW/cpu.o Objects/MingW/pafish_private.res + Objects/MingW/qemu.o Objects/MingW/hooks.o Objects/MingW/cpu.o Objects/MingW/cuckoo.o Objects/MingW/pafish_private.res LINKOBJ = $(OBJ) -LIBS = -lwsock32 -liphlpapi -lsetupapi -lmpr -s +LIBS = -lwsock32 -liphlpapi -lsetupapi -lmpr -lole32 -lwbemuuid -loleaut32 -s INCS = BIN = Output/MingW/pafish.exe CFLAGS = $(INCS) -Wall -Wextra -O0 @@ -57,5 +57,8 @@ Objects/MingW/hooks.o: $(GLOBALDEPS) hooks.c Objects/MingW/cpu.o: $(GLOBALDEPS) cpu.c $(CC) -c cpu.c -o Objects/MingW/cpu.o $(CFLAGS) +Objects/MingW/cuckoo.o: $(GLOBALDEPS) cuckoo.c + $(CC) -c cuckoo.c -o Objects/MingW/cuckoo.o $(CFLAGS) + Objects/MingW/pafish_private.res: Objects/MingW/pafish_private.rc $(WINDRES) Objects/MingW/pafish_private.rc --input-format=rc -o Objects/MingW/pafish_private.res -O coff diff --git a/pafish/Makefile.win b/pafish/Makefile.win index 92a6673..965b9bb 100644 --- a/pafish/Makefile.win +++ b/pafish/Makefile.win @@ -4,9 +4,9 @@ LINK = gcc.exe WINDRES = windres.exe OBJ = Objects/MingW/main.o Objects/MingW/common.o Objects/MingW/utils.o Objects/MingW/debuggers.o Objects/MingW/sandboxie.o \ Objects/MingW/vbox.o Objects/MingW/gensandbox.o Objects/MingW/wine.o Objects/MingW/vmware.o \ - Objects/MingW/qemu.o Objects/MingW/hooks.o Objects/MingW/cpu.o Objects/MingW/pafish_private.res + Objects/MingW/qemu.o Objects/MingW/hooks.o Objects/MingW/cpu.o Objects/MingW/cuckoo.o Objects/MingW/pafish_private.res LINKOBJ = $(OBJ) -LIBS = -lwsock32 -liphlpapi -lsetupapi -lmpr -s +LIBS = -lwsock32 -liphlpapi -lsetupapi -lmpr -lole32 -lwbemuuid -loleaut32 -s INCS = BIN = Output/MingW/pafish.exe CFLAGS = $(INCS) -Wall -Wextra -O0 @@ -57,5 +57,8 @@ Objects/MingW/hooks.o: $(GLOBALDEPS) hooks.c Objects/MingW/cpu.o: $(GLOBALDEPS) cpu.c $(CC) -c cpu.c -o Objects/MingW/cpu.o $(CFLAGS) +Objects/MingW/cuckoo.o: $(GLOBALDEPS) cuckoo.c + $(CC) -c cuckoo.c -o Objects/MingW/cuckoo.o $(CFLAGS) + Objects/MingW/pafish_private.res: Objects/MingW/pafish_private.rc $(WINDRES) Objects/MingW/pafish_private.rc --input-format=rc -o Objects/MingW/pafish_private.res -O coff diff --git a/pafish/cuckoo.c b/pafish/cuckoo.c new file mode 100644 index 0000000..d0ac6f6 --- /dev/null +++ b/pafish/cuckoo.c @@ -0,0 +1,64 @@ + +#include +#include + +#include "types.h" +#include "cuckoo.h" + +/** + * Cuckoo Sandbox definitions. + */ +/** + * Extra space allocated with the hooks information structure. + */ +#define TLS_HOOK_INFO_RETADDR_SPACE 0x100 + +/** + * Hook informnation stored by Cuckoo at FS:[TLS_HOOK_INFO]. + */ +struct hook_info { + unsigned int depth_count; + unsigned int hook_count; + unsigned int retaddr_esp; + unsigned int last_error; + unsigned int ret_last_error; + unsigned int eax; + unsigned int ecx; + unsigned int edx; + unsigned int ebx; + unsigned int esp; + unsigned int ebp; + unsigned int esi; + unsigned int edi; +}; + +/** + * Read the address of the hooks information in the TLS. + */ +struct hook_info *read_hook_info() { + void *result = NULL; + + __asm__ volatile ("mov %%fs:0x44,%%eax" : "=a" (result)); + + return result; +} + +/** + * Cuckoo stores the return addresses in a extra space allocated in conjunction + * with the hook information function. The only way to check if the structure + * is valid is to calculate what is the minimum and maximum value for the + * return address value location. + */ +int cuckoo_check_tls() { + struct hook_info *info = read_hook_info(); + + if (info == NULL) { + return FALSE; + } + + unsigned int minimum = ((unsigned int) info + sizeof(struct hook_info)); + unsigned int maximum = minimum + TLS_HOOK_INFO_RETADDR_SPACE; + + return (info != NULL) && (info->retaddr_esp >= minimum && info->retaddr_esp <= maximum) ? + TRUE : FALSE; +} diff --git a/pafish/cuckoo.h b/pafish/cuckoo.h new file mode 100644 index 0000000..f21bd72 --- /dev/null +++ b/pafish/cuckoo.h @@ -0,0 +1,8 @@ + +#ifndef CUCKOO_H +#define CUCKOO_H + +int cuckoo_check_tls(); + +#endif + diff --git a/pafish/gensandbox.c b/pafish/gensandbox.c index c4edca0..19f4023 100644 --- a/pafish/gensandbox.c +++ b/pafish/gensandbox.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "types.h" #include "gensandbox.h" diff --git a/pafish/main.c b/pafish/main.c index 630dfae..3120e5d 100644 --- a/pafish/main.c +++ b/pafish/main.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "types.h" #include "common.h" @@ -16,6 +17,7 @@ #include "vmware.h" #include "qemu.h" #include "cpu.h" +#include "cuckoo.h" /* Pafish (Paranoid fish) @@ -367,6 +369,14 @@ int main(void) } else print_not_traced(); + printf("[*] Looking for VBox devices using WMI ... "); + if (vbox_wmi_devices() == TRUE) { + write_log("VirtualBox device identifiers traced using WMI"); + print_traced(); + write_trace("hi_virtualbox_wmi"); + } + else print_not_traced(); + /* VMware detection tricks */ printf("\n[-] VMware detection\n"); printf("[*] Scsi port 0,1,2 ->bus->target id->logical unit id-> 0 identifier ... "); @@ -417,6 +427,14 @@ int main(void) } else print_not_traced(); + printf("[*] Looking for VMware serial number ... "); + if (vmware_wmi_serial() == TRUE) { + write_log("VMware serial number traced using WMI"); + print_traced(); + write_trace("hi_vmware_wmi"); + } + else print_not_traced(); + /* Qemu detection tricks */ printf("\n[-] Qemu detection\n"); printf("[*] Scsi port->bus->target id->logical unit id-> 0 identifier ... "); @@ -435,6 +453,16 @@ int main(void) } else print_not_traced(); + /* Cuckoo detection tricks */ + printf("\n[-] Cuckoo detection\n"); + printf("[*] Looking in the TLS for the hooks information structure ... "); + if (cuckoo_check_tls() == TRUE) { + write_log("Cuckoo hooks information structure traced in the TLS"); + print_traced(); + write_trace("hi_cuckoo"); + } + else print_not_traced(); + printf("\n\n"); printf("[-] Feel free to RE me, check log file for more information."); diff --git a/pafish/qemu.c b/pafish/qemu.c index 9367612..0c40ae5 100644 --- a/pafish/qemu.c +++ b/pafish/qemu.c @@ -1,6 +1,7 @@ #include #include +#include #include "qemu.h" #include "types.h" diff --git a/pafish/utils.c b/pafish/utils.c index bace44e..c741c9d 100644 --- a/pafish/utils.c +++ b/pafish/utils.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "utils.h" #include "types.h" @@ -177,3 +178,106 @@ int pafish_check_mac_vendor(char * mac_vendor) { return res; } +/** + * Initialise the WMI client that will connect to the local machine WMI + * namespace. It will return TRUE if the connection was successful, FALSE + * otherwise. + */ +int wmi_initialize(const wchar_t *query_namespace, IWbemServices **services) { + BSTR namespace; + IWbemLocator *locator = NULL; + int result; + + HRESULT hresult = CoInitializeEx(0, COINIT_MULTITHREADED); + + if (FAILED(hresult)) { + return FALSE; + } + + hresult = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); + + if (FAILED(hresult)) { + CoUninitialize(); + + return FALSE; + } + + hresult = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, + &IID_IWbemLocator, (LPVOID *) & locator); + + if (FAILED(hresult)) { + CoUninitialize(); + + return FALSE; + } + + namespace = SysAllocString(query_namespace); + + // Connect to the namespace with the current user and obtain pointer + // services to make IWbemServices calls. + hresult = locator->lpVtbl->ConnectServer(locator, namespace, NULL, NULL, NULL, 0, + NULL, NULL, services); + + result = FAILED(hresult) ? FALSE : TRUE; + + SysFreeString(namespace); + locator->lpVtbl->Release(locator); + + return result; +} + +/** + * Execute the suplied WMI query and call the row checking function for each row returned. + */ +int wmi_check_query(IWbemServices *services, const wchar_t *language, const wchar_t *query, + wmi_check_row check_row) { + int status = FALSE; + IEnumWbemClassObject *queryrows = NULL; + IWbemClassObject * batchrows[10]; + BSTR wmilang = SysAllocString(language); + BSTR wmiquery = SysAllocString(query); + + // Execute the query. + HRESULT result = services->lpVtbl->ExecQuery( + services, wmilang, wmiquery, WBEM_FLAG_BIDIRECTIONAL, NULL, &queryrows); + + if (!FAILED(result) && (queryrows != NULL)) { + ULONG index, count = 0; + result = WBEM_S_NO_ERROR; + + while (WBEM_S_NO_ERROR == result && status == FALSE) { + // Retrieve 10 rows (instances) each time. + result = queryrows->lpVtbl->Next(queryrows, WBEM_INFINITE, 10, + batchrows, &count); + + if (!SUCCEEDED(result)) { + continue; + } + + for (index = 0; index < count && status == FALSE; index++) { + status = check_row(batchrows[index]); + + batchrows[index]->lpVtbl->Release(batchrows[index]); + } + } + + queryrows->lpVtbl->Release(queryrows); + } + + SysFreeString(wmiquery); + SysFreeString(wmilang); + + return status; +} + +/** + * Cleanup WMI. + */ +void wmi_cleanup(IWbemServices *services) { + if (services != NULL) { + services->lpVtbl->Release(services); + } + + CoUninitialize(); +} diff --git a/pafish/utils.h b/pafish/utils.h index 5dc4cc6..7e8dda0 100644 --- a/pafish/utils.h +++ b/pafish/utils.h @@ -16,4 +16,17 @@ inline int pafish_exists_file(char * filename); int pafish_check_mac_vendor(char * mac_vendor); +/** + * Prototype for the WMI caller implemented function for checking the + * WMI query results. + */ +typedef int (*wmi_check_row) (IWbemClassObject *); + +int wmi_initialize(const wchar_t *, IWbemServices **); + +int wmi_check_query(IWbemServices *, const wchar_t *, const wchar_t *, + wmi_check_row check_row); + +void wmi_cleanup(IWbemServices *); + #endif diff --git a/pafish/vbox.c b/pafish/vbox.c index 85ed12c..84b0463 100644 --- a/pafish/vbox.c +++ b/pafish/vbox.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "vbox.h" #include "utils.h" @@ -251,3 +252,36 @@ int vbox_processes(int writelogs) { return res; } +/** + * Check if the device identifier ("PCI\\VEN_80EE&DEV_CAFE") in the returned rows. + */ +int vbox_wmi_check_row(IWbemClassObject *row) { + CIMTYPE type = CIM_ILLEGAL; + VARIANT value; + + HRESULT hresult = row->lpVtbl->Get(row, L"DeviceId", 0, &value, &type, 0); + + if (FAILED(hresult) || V_VT(&value) == VT_NULL || type != CIM_STRING) { + return FALSE; + } + + return (wcsstr(V_BSTR(&value), L"PCI\\VEN_80EE&DEV_CAFE") != NULL) ? TRUE : FALSE; +} + +/** + * Check for devices VirtualBox devices using WMI. + */ +int vbox_wmi_devices() { + IWbemServices *services = NULL; + + if (wmi_initialize(L"root\\cimv2", &services) != TRUE) { + return FALSE; + } + + int result = wmi_check_query(services, L"WQL", L"SELECT DeviceId FROM Win32_PnPEntity", + &vbox_wmi_check_row); + + wmi_cleanup(services); + + return result; +} diff --git a/pafish/vbox.h b/pafish/vbox.h index 7721220..1da7df0 100644 --- a/pafish/vbox.h +++ b/pafish/vbox.h @@ -25,4 +25,6 @@ int vbox_network_share(); int vbox_processes(int writelogs); +int vbox_wmi_devices(); + #endif diff --git a/pafish/vmware.c b/pafish/vmware.c index cda2a3c..f6feb0e 100644 --- a/pafish/vmware.c +++ b/pafish/vmware.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "vmware.h" #include "types.h" @@ -74,3 +75,37 @@ int vmware_devices(int writelogs) { } return res; } + +/** + * Check the serial number ("VMware") in the returned rows. + */ +int vmware_wmi_check_row(IWbemClassObject *row) { + CIMTYPE type = CIM_ILLEGAL; + VARIANT value; + + HRESULT hresult = row->lpVtbl->Get(row, L"SerialNumber", 0, &value, &type, 0); + + if (FAILED(hresult) || V_VT(&value) == VT_NULL || type != CIM_STRING) { + return FALSE; + } + + return (wcsstr(V_BSTR(&value), L"VMware") != NULL) ? TRUE : FALSE; +} + +/** + * Check for the computer serial using WMI. + */ +int vmware_wmi_serial() { + IWbemServices *services = NULL; + + if (wmi_initialize(L"root\\cimv2", &services) != TRUE) { + return FALSE; + } + + int result = wmi_check_query(services, L"WQL", L"SELECT SerialNumber FROM Win32_Bios", + &vmware_wmi_check_row); + + wmi_cleanup(services); + + return result; +} diff --git a/pafish/vmware.h b/pafish/vmware.h index 0802019..e75be74 100644 --- a/pafish/vmware.h +++ b/pafish/vmware.h @@ -14,4 +14,6 @@ int vmware_mac(); int vmware_devices(); +int vmware_wmi_serial(); + #endif diff --git a/pafish/wine.c b/pafish/wine.c index 8ec08c5..f2c2e8e 100644 --- a/pafish/wine.c +++ b/pafish/wine.c @@ -1,5 +1,6 @@ #include +#include #include "wine.h" #include "types.h"