Именование хэндлов и получение типа
Скрытие хэндлов тривиально, но немного сложнее определить какие хэндлы
мы должны скрыть. Если у нас есть, например, скрытый процесс, нас следует
скрыть все его хэндлы и все хэндлы связанные с ним. Скрытие хэндлов этого
процесса также тривиально. Мы просто сравниваем ProcessId хэндла и PID нашего
процесса, если они равны мы прячем хэндл. Но хэндлы других процессов должны
быть проименованы прежде, чем мы сможем сравнивать их с чем-либо. Количество
хэндлов в системе обычно очень велико, поэтому лучшее, что мы можем сделать -
это сравнить тип хэндла прежде, чем попытаться проименовать его. Именование
типов сохранит много времени для хэндлов, которые нас не интересуют.
Именование хэндла и типа хэндла может быть выполнено с помощью функции
NtQueryObject.
NTSTATUS ZwQueryObject(
IN HANDLE ObjectHandle,
IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
OUT PVOID ObjectInformation,
IN ULONG ObjectInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
ObjectHandle - хэндл, информацию о котором мы хотим получить,
ObjectInformationClass - тип информации, которая будет сохранена в буфер
ObjectInformation размером ObjectInformationLength байт.
Мы будем использовать классы ObjectNameInformation и
ObjectAllTypesInformation. Класс ObjectNameInfromation заполнит буфер
структурой OBJECT_NAME_INFORMATION, а класс ObjectAllTypesInformation
структурой OBJECT_ALL_TYPES_INFORMATION.
#define ObjectNameInformation 1
#define ObjectAllTypesInformation 3
typedef struct _OBJECT_NAME_INFORMATION {
UNICODE_STRING Name;
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
Поле Name определяет имя хэндла.
typedef struct _OBJECT_TYPE_INFORMATION {
UNICODE_STRING Name;
ULONG ObjectCount;
ULONG HandleCount;
ULONG Reserved1[4];
ULONG PeakObjectCount;
ULONG PeakHandleCount;
ULONG Reserved2[4];
ULONG InvalidAttributes;
GENERIC_MAPPING GenericMapping;
ULONG ValidAccess;
UCHAR Unknown;
BOOLEAN MaintainHandleDatabase;
POOL_TYPE PoolType;
ULONG PagedPoolUsage;
ULONG NonPagedPoolUsage;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
typedef struct _OBJECT_ALL_TYPES_INFORMATION {
ULONG NumberOfTypes;
OBJECT_TYPE_INFORMATION TypeInformation;
} OBJECT_ALL_TYPES_INFORMATION, *POBJECT_ALL_TYPES_INFORMATION;
Поле Name определяет имя типа объекта, которое следует сразу после
каждой структуры OBJECT_TYPE_INFORMATION. Следующая структура
OBJECT_TYPE_INFORMATION расположена после этого имени и выровнена на границу
четырех байт.
ObjectTypeNumber из структуры SYSTEM_HANDLE_INFORMATION - это индекс
в массиве TypeInformation.
Сложнее получить имя хэндла из другого процесса. Существуют два способа
сделать это. Первый состоит в том, чтобы скопировать хэндл функцией
NtDuplicateObject в наш процесс и затем проименовать его. Этот метод не
сработает для некоторых специфических типов хэндлов. Но он не срабатывает
довольно редко, поэтому мы можем оставаться спокойными и использовать его.
NtDuplicateObject(
IN HANDLE SourceProcessHandle,
IN HANDLE SourceHandle,
IN HANDLE TargetProcessHandle,
OUT PHANDLE TargetHandle OPTIONAL,
IN ACCESS_MASK DesiredAccess,
IN ULONG Attributes,
IN ULONG Options
);
SourceProcessHandle - хэндл процесса, который владеет SourceHandle,
то есть хэндлом, который мы хотим скопировать. TargetProcessHandle - это хэндл
процесса, в который мы хотим копировать. Это хэндл нашего процесса в нашем
случае. TargetHandle - указатель, куда будет сохранена копия хэндла. Параметр
DesiredAccess должен быть равен PROCESS_QUERY_INFORMATION, а Attribures
и Options - нулю.
Второй способ именования, работающий со всеми хэндлами, состоит в
использовании системного драйвера. Исходный код этого метода доступен в
проекте OpHandle на моем сайте https://rootkit.host.sk.
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!