OS Features  H  FileSystem  Registry  Generic OS Queries  Global OS object  UI artifacts  OS Features  Processes  Network  CPU  Hardware  Firmware tables  Hooks  Timing  WMI  Human-like behavior  macOS


OS features detection methods

Evasions in this group use peculiarities of how OS work.


 

1. Checking debug privileges

If the malware is running under debugger or in a sandbox like Cuckoo its process token will have a debug privilege in the enabled state. It happens because this privilege is enabled in the parent process and inherited by the malware process.

The malware tries to open crucial system processes like csrss.exesmss.exelsass.exe with PROCESS_ALL_ACCESS access right and then tries to terminate them. This will fail in a normal case when the malware is executed from the explorer or command line because even an Administrator user can’t terminate those processes. But this will succeed if the process token has the debug privilege in the enabled state. Termination of crucial system process leads OS to crash into BSOD with an error 0x000000F4 so the emulation process will be aborted.

Functions to get snapshot of running processes:

Function used to open the process:

Code sample

 

/*
If we're being debugged and the process has SeDebugPrivileges 
privileges then OpenProcess call will be successful.
This requires administrator privilege!
In Windows XP, Vista and 7, calling OpenProcess with 
PROCESS_ALL_ACCESS will fait even with SeDebugPrivilege enabled,
That's why I used PROCESS_QUERY_LIMITED_INFORMATION
*/

DWORD GetCsrssProcessId()
{
if (API::IsAvailable(API_IDENTIFIER::API_CsrGetProcessId))
{
auto CsrGetProcessId = static_cast<pCsrGetId>(API::GetAPI(API_IDENTIFIER::API_CsrGetProcessId));

return CsrGetProcessId();
}
else
return GetProcessIdFromName(_T("csrss.exe"));
}


BOOL CanOpenCsrss()
{
HANDLE hCsrss = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCsrssProcessId());
if (hCsrss != NULL)
{
CloseHandle(hCsrss);
return TRUE;
}
else
return FALSE;
}

Credits for this code sample: al-khaser project

Signature recommendations

 

If OpenProcess requests all the possible rights when opening one of the critical system processes — it’s a strong indicator of malware trying to apply this evasion technique.


 

2. Using unbalanced stack

This technique was presented at Virus Bulletin 2016 by Check Point Malware Reverse Engineering Team. It is described by this link.

To track process behaviour, the CuckooMon/Cuckoo Monitor module hooks relevant functions. In this type of architecture, the hook is called before the original function. A hooked function may use some space on the stack in addition to that used by the original function. Therefore, the total space on the stack used by the hooked function may be larger than the space used only by the original function.

Problem: The malware has information about how much space the called function uses on the stack. It can therefore move the stack pointer towards lower addresses at an offset that is suffi cient to store the function arguments, local variables and return address to reserve space for them. The malware fi lls the space below the stack pointer with some relevant data. It then moves the stack pointer to the original location and calls the library function. If the function is not hooked, the malware fi lls in the reserved space before the relevant data (see Figure 1). If the function is hooked, the malware overlaps relevant data, because the space that was reserved for the original function’s local variables is smaller than the space occupied by the hook and the original function’s local variables combined. The relevant data is therefore corrupted (see Figure 2). If it stores pointers to some functions that are used later during the execution process, the malware jumps to arbitrary code, occasionally crashing the application.

 
Stack on non-hooked and on hooked function call.

Solution: To avoid this behaviour, the Cuckoo Monitor/CuckooMon module can use a two-stage hooking process. In the fi rst stage, instead of the hook’s code execution, it can move the stack pointer towards lower addresses of a specifi c size that will be enough for the malware’s relevant data. Then, the function’s arguments are copied under the new stack pointer. Only after these preparatory operations have been completed is the second stage hook (which performs the real hooking) called. Relevant data fi lled in by the malware resides on upper stack addresses, thus it is not affected in any way by the called function.

Code sample

 

bool Cuckoo::CheckUnbalancedStack() const {
usf_t f = {
{ lib_name_t(L"ntdll"), { 
{sizeof(void *), NULL, "ZwDelayExecution", ARG_ITEM(kZwDelayExecutionArgs) }
} }
};
const uint8_t canary[8] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF };

uint32_t args_size;
const void *args_buff;
uint32_t reserved_size;
uint32_t reserved_size_after_call;
uint32_t canary_size;
FARPROC func;
bool us_detected;
void *canary_addr = (void *)&canary[0];
  
static_assert((sizeof(canary) % sizeof(void *)) == 0, "Invalid canary alignement");
  
for (auto it = f.begin(), end = f.end(); it != end; ++it) {
for (auto &vi : it->second) {
vi.func_addr = GetProcAddress(GetModuleHandleW(it->first.c_str()), vi.func_name.c_str());

// call to Unbalanced Stack
args_size = vi.args_size;
args_buff = vi.args_buff;
canary_size = sizeof(canary);
reserved_size = sizeof(void *) + vi.local_vars_size + canary_size;
reserved_size_after_call = reserved_size + args_size;
func = vi.func_addr;
us_detected = false;

__asm {
pusha
mov ecx, args_size
sub esp, ecx
mov esi, args_buff
mov edi, esp
cld
rep movsb
sub esp, reserved_size
mov ecx, canary_size
mov esi, canary_addr
mov edi, esp
rep movsb
add esp, reserved_size
mov eax, func
call eax
sub esp, reserved_size_after_call
mov ecx, canary_size
mov esi, canary_addr
mov edi, esp
repz cmpsb
cmp ecx, 0
setnz us_detected
add esp, reserved_size_after_call
popa
}

if (us_detected)
return true;
}
}

return false;  
}

Signature recommendations

 

Signature recommendations are not provided as it’s pretty tricky to track such a behavior on malware side.


 

Countermeasures


 

Credits

Credits go to open-source project from where code samples were taken:

Though Check Point tool InviZzzible has them all implemented, due to modular structure of the code it would require more space to show a code sample from this tool for the same purposes. That’s why we’ve decided to use other great open-source projects for examples throughout the encyclopedia.