Это, одна из ссылок из моего перевода "Фантастические руткиты". Рекомендую прочитать, все равно интересно ведь)
Введение
В предыдущей статье мы увидели, что независимо от того, используем ли мы прерывание int 0x2e или инструкцию sysenter, в ядре используется один и тот же метод. Мы также определили, что в обоих случаях вызывается KiSystemService. В этой статье мы рассмотрим, как это происходит на самом деле.
При использовании прерывания 0x2e или инструкции sysenter номер системного сервиса используется для определения того, какой системный вызов будет вызван. Мы уже видели, что номер системной службы передается в регистр EAX, который на машинах IA-32 является 32-разрядным регистром. Однако не сразу понятно, как это значение используется в дальнейшем.
Первое, что приходит в голову, это то, что это просто индекс в некоторой таблице, которая содержит указатели на системные процедуры, которые будут вызываться. Это довольно близко к тому, как значение используется на самом деле, но следует отметить, что 32 бита не используются в качестве индекса, поскольку в этом случае нам пришлось бы иметь таблицу указателей размером 4 ГБ или многоуровневую таблицу, что непрактично и не нужно.
Сервисный номер системы состоит из следующих частей:
В Windows таблица SSDT (System Service Dispatch Table) представляет собой таблицу, указывающую на функции ядра, которые обрабатываются в ntoskrnl.exe. ntoskrnl.exe отвечает за различные задачи, такие как аппаратная виртуализация, управление процессами и памятью, управление кэшем, планирование процессов и т.д. [5] В системах Windows используются только две таблицы, которые называются KeServiceDescriptorTable и KeServiceDescriptorTableShadow.
На рисунке ниже мы видим адрес и первый элемент обеих таблиц в памяти.
Обе эти таблицы содержат структуры SST (System Service Tables), которые состоят из следующих элементов (обобщенно из [4]):
На рисунке выше мы видим первый SST таблицы KeServiceDescriptorTable, длина которого составляет 16 байт. Это SST, указывающий на SSDT, содержащий основные функции Windows. Значения SST следующие:
Представим поля данной SST:
Для дампа функций ядра Windows из таблицы KiServiceTable можно воспользоваться командой Windbg "dps KiServiceTable" следующим образом (обратите внимание, что представлена только первая часть функций):
Сделаем также дамп первой части функций, содержащихся в таблице W32pServiceTable. Это видно ниже, где для отображения функций мы использовали команду "dps W32pServiceTable":
Заметили ли вы, что таблица KiServiceTable содержит основные функции Windows, а таблица W32pServiceTable - графические функции, о которых мы уже говорили? Приведенные выше результаты подтверждают это.
Представление примера
Ниже показан пример, который мы будем использовать в этой части статьи. В примере просто вызывается функция ZwQuerySystemInformation непосредственно из библиотеки ntdll.dll. Вызвать функцию напрямую мы не можем, поэтому сначала необходимо загрузить библиотеку ntdll.dll, а затем получить адрес функции ZwQuerySystemInformation. В ответ мы получаем адрес в памяти, где находится функция, поэтому для вызова функции необходимо применить прототип функции. На самом деле программа определяет, отлаживает ли системный отладчик в данный момент операционную систему или нет.
Запустив программу под отладчиком ядра Windbg, мы получим следующий вывод программы:
Видно, что программа правильно определила наличие системного отладчика. На рисунке ниже представлена дизассемблированная инструкция функции ZwQuerySystemInformation:
Видно, что реализация функции ZwQuerySystemInformation в библиотеке ntdll.dll - это всего лишь процедура, вызывающая ядро и не предоставляющая собственно сервис. В приведенном выше коде мы записываем в регистр EAX шестнадцатеричное число 0xAD - номер системного сервиса, о котором мы говорили в статье. Поскольку число 0xAD находится в диапазоне 0x000-0xFF, мы фактически используем таблицу KeServiceDescriptorTable для получения всей информации, необходимой нам для вызова функции ядра.
Сначала рассмотрим адрес, загружаемый в регистр EDX:
В приведенном выше коде мы читаем адрес 0x7c90e510 в памяти регистра EDX и вызываем его. Адрес 0x7c90e510 является адресом функции KiFastSystemCall, что видно из приведенного ниже вывода:
KiFastSystemCall выполняет инструкцию sysenter, которая должна вызвать соответствующую системную функцию в ядре. Мы уже знаем, что при выполнении инструкции sysenter вызывается функция KiFastCallEntry, поэтому нам необходимо установить точку останова на этой функции следующим образом:
После этого мы можем запустить программу командой g, и функция будет выглядеть так, как показано ниже:
Давайте дизассемблируем всю функцию KiFastCallEntry, чтобы понять, что она делает. Дизассемблированные инструкции приведены ниже:
Рассмотрим первую инструкцию в функции KiFastCallEntry, в которой используется значение регистра EAX, то есть для выполнения какого-либо действия используется системный служебный номер. Эта инструкция показана ниже:
Поначалу эти инструкции могут показаться странными, но вскоре они начинают обретать смысл. Все операции можно увидеть на рисунке ниже. Начнем с того, что весь служебный номер системы хранится в регистре EAX, а затем переносится в регистр EDI. Это видно на первой части рисунка, где младшие 12 бит - это собственно системный сервисный номер, а средние два бита определяют используемую таблицу SSDT, в то время как старшие 18 бит не используются.
Инструкция shr сдвигает все биты регистра EDI вправо на 8. Это видно на средней части рисунка, где младшие 4 бита используются для представления теперь уже поврежденного служебного номера системы, а средние два бита по-прежнему являются номером SSDT. Верхние 26 бит не используются. Инструкция next and обнуляет младшие четыре бита, оставляя неизменными только два средних бита. В конце приведенного выше кода номер SSDT сохраняется в 4-5-м битах регистра ECX.
Поскольку в регистр EAX мы передаем номер системного сервиса 0xAD, то действительно следует установить условную точку останова в WinDbg, так как в противном случае мы не сможем управлять выполнением так, как нам хочется. Это связано с тем, что функция KiFastCallEntry вызывается самим ядром так много раз, что нет смысла вручную проверять, содержит ли регистр EAX нужный номер системной службы. Нужно установить условную точку останова по адресу 0x8053d68d и проверить, равно ли значение в регистре EAX значению 0xAD (номер нашего системного сервиса).
Мы можем установить условную точку останова следующим образом:
После этого следует запустить программу в обычном режиме и наблюдать за происходящим. Выполнение должно занять значительно больше времени, так как WinDbg должен сравнивать значение в регистре EAX при каждом прохождении этой кодовой точки, что происходит довольно часто.
Рассмотрим пример в точке, где он попадает в точку останова, то есть значение в регистре EAX должно быть установлено в 0xAD:
Первое число в регистре EAX - 0xad (10101101), которое мы сдвигаем вправо на 8 бит. Таким образом, получается число 0x0, которое затем AND-ed с числом 0x30. В результате преобразований получается число 0x000000.
Поскольку мы только что вычислили значение, хранящееся в регистре ECX, целесообразно продолжить наблюдение за кодом, рассмотрев инструкции, использующие значение регистра ECX. Сейчас мы этого делать не будем, так как статья может получиться слишком длинной, но в целом вы поняли, о чем идет речь.
Заключение
В этой статье мы рассмотрели внутреннее устройство того, что происходит при вызове инструкции sysenter. Мы могли бы углубиться в эту тему, но я не хотел делать статью слишком длинной. Самое главное, что следует запомнить, - это то, как вычисляется номер системного сервиса и как этот сервис вызывается.
Ссылки:
[1] Переход в пространство:
[2] Ручная проверка таблицы диспетчеризации служб (SSDT) для обнаружения хуков:
[3] Охота на руткиты с помощью Windbg: www.reconstructer.org/…/Hunting%20rootkits%20with%20Windbg.pdf.
[4] Анализ руткита BlackEnergy версии 2 – SecuraBit: www.securabit.com/wp…/Rootkit-Analysis-Hiding-SSDT-Hooks1.pdf.
[5] ntoskrnl.exe:
[6] SYSENTER:
[7] Справочник по набору инструкций x86:
Статья про руткиты(Рекомендую прочитать): Фантастические руткиты: И где их найти
Введение
В предыдущей статье мы увидели, что независимо от того, используем ли мы прерывание int 0x2e или инструкцию sysenter, в ядре используется один и тот же метод. Мы также определили, что в обоих случаях вызывается KiSystemService. В этой статье мы рассмотрим, как это происходит на самом деле.
При использовании прерывания 0x2e или инструкции sysenter номер системного сервиса используется для определения того, какой системный вызов будет вызван. Мы уже видели, что номер системной службы передается в регистр EAX, который на машинах IA-32 является 32-разрядным регистром. Однако не сразу понятно, как это значение используется в дальнейшем.
Первое, что приходит в голову, это то, что это просто индекс в некоторой таблице, которая содержит указатели на системные процедуры, которые будут вызываться. Это довольно близко к тому, как значение используется на самом деле, но следует отметить, что 32 бита не используются в качестве индекса, поскольку в этом случае нам пришлось бы иметь таблицу указателей размером 4 ГБ или многоуровневую таблицу, что непрактично и не нужно.
Сервисный номер системы состоит из следующих частей:
- bits 0-11: номер системной службы, которую необходимо вызвать
- bits 12-13: используемая таблица дескрипторов сервисов
- bits 14-31: не используется
В Windows таблица SSDT (System Service Dispatch Table) представляет собой таблицу, указывающую на функции ядра, которые обрабатываются в ntoskrnl.exe. ntoskrnl.exe отвечает за различные задачи, такие как аппаратная виртуализация, управление процессами и памятью, управление кэшем, планирование процессов и т.д. [5] В системах Windows используются только две таблицы, которые называются KeServiceDescriptorTable и KeServiceDescriptorTableShadow.
На рисунке ниже мы видим адрес и первый элемент обеих таблиц в памяти.
Обе эти таблицы содержат структуры SST (System Service Tables), которые состоят из следующих элементов (обобщенно из [4]):
- ServiceTable: указатель на массив адресов SSDT, указывающих на функции ядра
- CounterTable: не используется
- ServiceLimit: количество элементов в массиве SSDT
- ArgumentTable: указатель на массив аргументов SSPT (System Service Parameter Table)
На рисунке выше мы видим первый SST таблицы KeServiceDescriptorTable, длина которого составляет 16 байт. Это SST, указывающий на SSDT, содержащий основные функции Windows. Значения SST следующие:
- ServiceTable: 80501b8c (указатель на KiServiceTable)
- CounterTable: не используется
- ServiceLimit: 0x11c (hex) = 286 (dec)
- ArgumentTable: 80502000 (указатель на KiArgumentTable)
Представим поля данной SST:
- ServiceTable: bf99e900 (указатель на W32pServiceTable)
- CounterTable: не используется
- ServiceLimit: 0x29b (hex) = 667 (dec)
- ArgumentTable: bf99f610 (указатель на W32pArgumentTable)
- 0000xxxx xxxxxxxx: используемая KeServiceDescriptorTable, где х может быть 0 или 1, из чего следует, что первая таблица используется, если номера системных сервисов находятся в диапазоне 0x0 - 0xFF.
- 0001yyyy yyyyyyyy: используемая KeServiceDescriptorTableShadow, где y может быть 0 или 1, из чего следует, что вторая таблица используется, если системные сервисные номера находятся в диапазоне 0x1000 - 0x1FF.
Для дампа функций ядра Windows из таблицы KiServiceTable можно воспользоваться командой Windbg "dps KiServiceTable" следующим образом (обратите внимание, что представлена только первая часть функций):
Сделаем также дамп первой части функций, содержащихся в таблице W32pServiceTable. Это видно ниже, где для отображения функций мы использовали команду "dps W32pServiceTable":
Заметили ли вы, что таблица KiServiceTable содержит основные функции Windows, а таблица W32pServiceTable - графические функции, о которых мы уже говорили? Приведенные выше результаты подтверждают это.
Представление примера
Ниже показан пример, который мы будем использовать в этой части статьи. В примере просто вызывается функция ZwQuerySystemInformation непосредственно из библиотеки ntdll.dll. Вызвать функцию напрямую мы не можем, поэтому сначала необходимо загрузить библиотеку ntdll.dll, а затем получить адрес функции ZwQuerySystemInformation. В ответ мы получаем адрес в памяти, где находится функция, поэтому для вызова функции необходимо применить прототип функции. На самом деле программа определяет, отлаживает ли системный отладчик в данный момент операционную систему или нет.
C++:
#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <Winternl.h>
int _tmain(int argc, _TCHAR* argv[]) {
__asm { int 3 }
typedef long NTSTATUS;
#define STATUS_SUCCESS ((NTSTATUS)0L)
HANDLE hProcess = GetCurrentProcess();
typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION {
BOOLEAN DebuggerEnabled;
BOOLEAN DebuggerNotPresent;
} SYSTEM_KERNEL_DEBUGGER_INFORMATION, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION;
enum SYSTEM_INFORMATION_CLASS { SystemKernelDebuggerInformation = 35 };
typedef NTSTATUS (__stdcall *ZW_QUERY_SYSTEM_INFORMATION)(IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength);
ZW_QUERY_SYSTEM_INFORMATION ZwQuerySystemInformation;
SYSTEM_KERNEL_DEBUGGER_INFORMATION Info;
/* load the ntdll.dll */
HMODULE hModule = LoadLibrary(_T("ntdll.dll"));
ZwQuerySystemInformation = (ZW_QUERY_SYSTEM_INFORMATION)GetProcAddress(hModule, "ZwQuerySystemInformation");
if(ZwQuerySystemInformation == NULL) {
printf("Error: could not find the function ZwQuerySystemInformation in library ntdll.dll.");
exit(-1);
}
printf("ZwQuerySystemInformation is located at 0x%08x in ntdll.dll.n", (unsigned int)ZwQuerySystemInformation);
if (STATUS_SUCCESS == ZwQuerySystemInformation(SystemKernelDebuggerInformation, &Info, sizeof(Info), NULL)) {
if (Info.DebuggerEnabled && !Info.DebuggerNotPresent) {
printf("System debugger is present.");
}
else {
printf("System debugger is not present.");
}
}
/* wait */
getchar();
return 0;
}
Запустив программу под отладчиком ядра Windbg, мы получим следующий вывод программы:
Видно, что программа правильно определила наличие системного отладчика. На рисунке ниже представлена дизассемблированная инструкция функции ZwQuerySystemInformation:
Видно, что реализация функции ZwQuerySystemInformation в библиотеке ntdll.dll - это всего лишь процедура, вызывающая ядро и не предоставляющая собственно сервис. В приведенном выше коде мы записываем в регистр EAX шестнадцатеричное число 0xAD - номер системного сервиса, о котором мы говорили в статье. Поскольку число 0xAD находится в диапазоне 0x000-0xFF, мы фактически используем таблицу KeServiceDescriptorTable для получения всей информации, необходимой нам для вызова функции ядра.
Сначала рассмотрим адрес, загружаемый в регистр EDX:
В приведенном выше коде мы читаем адрес 0x7c90e510 в памяти регистра EDX и вызываем его. Адрес 0x7c90e510 является адресом функции KiFastSystemCall, что видно из приведенного ниже вывода:
KiFastSystemCall выполняет инструкцию sysenter, которая должна вызвать соответствующую системную функцию в ядре. Мы уже знаем, что при выполнении инструкции sysenter вызывается функция KiFastCallEntry, поэтому нам необходимо установить точку останова на этой функции следующим образом:
После этого мы можем запустить программу командой g, и функция будет выглядеть так, как показано ниже:
Давайте дизассемблируем всю функцию KiFastCallEntry, чтобы понять, что она делает. Дизассемблированные инструкции приведены ниже:
Код:
kd> u KiFastCallEntry l100
nt!KiFastCallEntry:
8053d600 b923000000 mov ecx,23h
8053d605 6a30 push 30h
8053d607 0fa1 pop fs
8053d609 8ed9 mov ds,cx
8053d60b 8ec1 mov es,cx
8053d60d 8b0d40f0dfff mov ecx,dword ptr ds:[0FFDFF040h]
8053d613 8b6104 mov esp,dword ptr [ecx+4]
8053d616 6a23 push 23h
8053d618 52 push edx
8053d619 9c pushfd
8053d61a 6a02 push 2
8053d61c 83c208 add edx,8
8053d61f 9d popfd
8053d620 804c240102 or byte ptr [esp+1],2
8053d625 6a1b push 1Bh
8053d627 ff350403dfff push dword ptr ds:[0FFDF0304h]
8053d62d 6a00 push 0
8053d62f 55 push ebp
8053d630 53 push ebx
8053d631 56 push esi
8053d632 57 push edi
8053d633 8b1d1cf0dfff mov ebx,dword ptr ds:[0FFDFF01Ch]
8053d639 6a3b push 3Bh
8053d63b 8bb324010000 mov esi,dword ptr [ebx+124h]
8053d641 ff33 push dword ptr [ebx]
8053d643 c703ffffffff mov dword ptr [ebx],0FFFFFFFFh
8053d649 8b6e18 mov ebp,dword ptr [esi+18h]
8053d64c 6a01 push 1
8053d64e 83ec48 sub esp,48h
8053d651 81ed9c020000 sub ebp,29Ch
8053d657 c6864001000001 mov byte ptr [esi+140h],1
8053d65e 3bec cmp ebp,esp
8053d660 759a jne nt!KiFastCallEntry2+0x47 (8053d5fc)
8053d662 83652c00 and dword ptr [ebp+2Ch],0
8053d666 462cff test byte ptr [esi+2Ch],0FFh
8053d66a 89ae34010000 mov dword ptr [esi+134h],ebp
8053d670 0f854afeffff jne nt!Dr_FastCallDrSave (8053d4c0)
8053d676 8b5d60 mov ebx,dword ptr [ebp+60h]
8053d679 8b7d68 mov edi,dword ptr [ebp+68h]
8053d67c 89550c mov dword ptr [ebp+0Ch],edx
8053d67f c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h
8053d686 895d00 mov dword ptr [ebp],ebx
8053d689 897d04 mov dword ptr [ebp+4],edi
8053d68c fb sti
8053d68d 8bf8 mov edi,eax
8053d68f c1ef08 shr edi,8
8053d692 83e730 and edi,30h
8053d695 8bcf mov ecx,edi
8053d697 03bee0000000 add edi,dword ptr [esi+0E0h]
8053d69d 8bd8 mov ebx,eax
8053d69f 25ff0f0000 and eax,0FFFh
8053d6a4 3b4708 cmp eax,dword ptr [edi+8]
8053d6a7 0f8345fdffff jae nt!KiBBTUnexpectedRange (8053d3f2)
8053d6ad 83f910 cmp ecx,10h
8053d6b0 751a jne nt!KiFastCallEntry+0xcc (8053d6cc)
8053d6b2 8b0d18f0dfff mov ecx,dword ptr ds:[0FFDFF018h]
8053d6b8 33db xor ebx,ebx
8053d6ba 0b99700f0000 or ebx,dword ptr [ecx+0F70h]
8053d6c0 740a je nt!KiFastCallEntry+0xcc (8053d6cc)
8053d6c2 52 push edx
8053d6c3 50 push eax
8053d6c4 ff15e4305580 call dword ptr [nt!KeGdiFlushUserBatch (805530e4)]
8053d6ca 58 pop eax
8053d6cb 5a pop edx
8053d6cc ff0538f6dfff inc dword ptr ds:[0FFDFF638h]
8053d6d2 8bf2 mov esi,edx
8053d6d4 8b5f0c mov ebx,dword ptr [edi+0Ch]
8053d6d7 33c9 xor ecx,ecx
8053d6d9 8a0c18 mov cl,byte ptr [eax+ebx]
8053d6dc 8b3f mov edi,dword ptr [edi]
8053d6de 8b1c87 mov ebx,dword ptr [edi+eax*4]
8053d6e1 2be1 sub esp,ecx
8053d6e3 c1e902 shr ecx,2
8053d6e6 8bfc mov edi,esp
8053d6e8 3b35d48a5580 cmp esi,dword ptr [nt!MmUserProbeAddress (80558ad4)]
8053d6ee 0f83a8010000 jae nt!KiSystemCallExit2+0x9f (8053d89c)
8053d6f4 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
8053d6f6 ffd3 call ebx
8053d6f8 8be5 mov esp,ebp
8053d6fa 8b0d24f1dfff mov ecx,dword ptr ds:[0FFDFF124h]
8053d700 8b553c mov edx,dword ptr [ebp+3Ch]
8053d703 899134010000 mov dword ptr [ecx+134h],edx
Рассмотрим первую инструкцию в функции KiFastCallEntry, в которой используется значение регистра EAX, то есть для выполнения какого-либо действия используется системный служебный номер. Эта инструкция показана ниже:
Код:
8053d68d 8bf8 mov edi,eax
8053d68f c1ef08 shr edi,8
8053d692 83e730 and edi,30h
8053d695 8bcf mov ecx,edi
Поначалу эти инструкции могут показаться странными, но вскоре они начинают обретать смысл. Все операции можно увидеть на рисунке ниже. Начнем с того, что весь служебный номер системы хранится в регистре EAX, а затем переносится в регистр EDI. Это видно на первой части рисунка, где младшие 12 бит - это собственно системный сервисный номер, а средние два бита определяют используемую таблицу SSDT, в то время как старшие 18 бит не используются.
Инструкция shr сдвигает все биты регистра EDI вправо на 8. Это видно на средней части рисунка, где младшие 4 бита используются для представления теперь уже поврежденного служебного номера системы, а средние два бита по-прежнему являются номером SSDT. Верхние 26 бит не используются. Инструкция next and обнуляет младшие четыре бита, оставляя неизменными только два средних бита. В конце приведенного выше кода номер SSDT сохраняется в 4-5-м битах регистра ECX.
Поскольку в регистр EAX мы передаем номер системного сервиса 0xAD, то действительно следует установить условную точку останова в WinDbg, так как в противном случае мы не сможем управлять выполнением так, как нам хочется. Это связано с тем, что функция KiFastCallEntry вызывается самим ядром так много раз, что нет смысла вручную проверять, содержит ли регистр EAX нужный номер системной службы. Нужно установить условную точку останова по адресу 0x8053d68d и проверить, равно ли значение в регистре EAX значению 0xAD (номер нашего системного сервиса).
Мы можем установить условную точку останова следующим образом:
Код:
kd> bp 8053d68d "j @eax = 0x000000ad '';'gc'"
kd> bl
0 e 8053d68d 0001 (0001) nt!KiFastCallEntry+0x8d "j @eax = 0x000000ad '';'gc'"
После этого следует запустить программу в обычном режиме и наблюдать за происходящим. Выполнение должно занять значительно больше времени, так как WinDbg должен сравнивать значение в регистре EAX при каждом прохождении этой кодовой точки, что происходит довольно часто.
Рассмотрим пример в точке, где он попадает в точку останова, то есть значение в регистре EAX должно быть установлено в 0xAD:
Код:
kd> g
nt!KiFastCallEntry+0x8d:
8053d6dd 8bf8 mov edi,eax
kd> r eax, ecx, edi
eax=000000ad ecx=80042000 edi=7c90e514
kd> p
nt!KiFastCallEntry+0x8f:
8053d6df c1ef08 shr edi,8
kd> r eax, ecx, edi
eax=000000ad ecx=80042000 edi=000000ad
kd> p
nt!KiFastCallEntry+0x92:
8053d6e2 83e730 and edi,30h
kd> r eax, ecx, edi
eax=000000ad ecx=80042000 edi=00000000
kd> p
nt!KiFastCallEntry+0x95:
8053d6e5 8bcf mov ecx,edi
Первое число в регистре EAX - 0xad (10101101), которое мы сдвигаем вправо на 8 бит. Таким образом, получается число 0x0, которое затем AND-ed с числом 0x30. В результате преобразований получается число 0x000000.
Поскольку мы только что вычислили значение, хранящееся в регистре ECX, целесообразно продолжить наблюдение за кодом, рассмотрев инструкции, использующие значение регистра ECX. Сейчас мы этого делать не будем, так как статья может получиться слишком длинной, но в целом вы поняли, о чем идет речь.
Заключение
В этой статье мы рассмотрели внутреннее устройство того, что происходит при вызове инструкции sysenter. Мы могли бы углубиться в эту тему, но я не хотел делать статью слишком длинной. Самое главное, что следует запомнить, - это то, как вычисляется номер системного сервиса и как этот сервис вызывается.
Ссылки:
[1] Переход в пространство:
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
.[2] Ручная проверка таблицы диспетчеризации служб (SSDT) для обнаружения хуков:
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
.[3] Охота на руткиты с помощью Windbg: www.reconstructer.org/…/Hunting%20rootkits%20with%20Windbg.pdf.
[4] Анализ руткита BlackEnergy версии 2 – SecuraBit: www.securabit.com/wp…/Rootkit-Analysis-Hiding-SSDT-Hooks1.pdf.
[5] ntoskrnl.exe:
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
.[6] SYSENTER:
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
.[7] Справочник по набору инструкций x86:
Вы должны зарегистрироваться, чтобы увидеть внешние ссылки
.Статья про руткиты(Рекомендую прочитать): Фантастические руткиты: И где их найти
Оригинал: https://resources.infosecinstitute[.]com/topics/reverse-engineering/the-sysenter-instruction-internals/